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:
parent
39fd3f6580
commit
36453885fc
60
src/Util.cpp
60
src/Util.cpp
|
@ -64,6 +64,66 @@ bool FileExists(const char *filename)
|
||||||
#endif
|
#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)
|
void utilReadScreenPixels(uint8_t *dest, int w, int h)
|
||||||
{
|
{
|
||||||
uint8_t *b = dest;
|
uint8_t *b = dest;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef UTIL_H
|
#ifndef UTIL_H
|
||||||
#define UTIL_H
|
#define UTIL_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include "System.h"
|
#include "System.h"
|
||||||
|
|
||||||
enum IMAGE_TYPE { IMAGE_UNKNOWN = -1, IMAGE_GBA = 0, IMAGE_GB = 1 };
|
enum IMAGE_TYPE { IMAGE_UNKNOWN = -1, IMAGE_GBA = 0, IMAGE_GB = 1 };
|
||||||
|
@ -13,6 +14,9 @@ typedef struct {
|
||||||
|
|
||||||
bool FileExists(const char *filename);
|
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);
|
void utilReadScreenPixels(uint8_t *dest, int w, int h);
|
||||||
bool utilWritePNGFile(const char *, int, int, uint8_t *);
|
bool utilWritePNGFile(const char *, int, int, uint8_t *);
|
||||||
bool utilWriteBMPFile(const char *, int, int, uint8_t *);
|
bool utilWriteBMPFile(const char *, int, int, uint8_t *);
|
||||||
|
|
|
@ -38,6 +38,9 @@ extern "C" {
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
#define GETCWD _getcwd
|
#define GETCWD _getcwd
|
||||||
#define snprintf sprintf
|
#define snprintf sprintf
|
||||||
|
#define stat _stat
|
||||||
|
#define mkdir(X,Y) (_mkdir(X))
|
||||||
|
#define S_ISDIR _S_IFDIR
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
#ifndef __GNUC__
|
#ifndef __GNUC__
|
||||||
|
@ -647,7 +650,7 @@ const char* FindConfigFile(const char *name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (homeDir) {
|
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))
|
if (FileExists(path))
|
||||||
{
|
{
|
||||||
return path;
|
return path;
|
||||||
|
@ -717,11 +720,11 @@ const char* FindConfigFile(const char *name)
|
||||||
|
|
||||||
void LoadConfigFile()
|
void LoadConfigFile()
|
||||||
{
|
{
|
||||||
#if !defined(_WIN32) && !defined(__APPLE__)
|
struct stat s;
|
||||||
homeDir = getenv("HOME");
|
std::string homeDirTmp = get_xdg_user_config_home() + FILE_SEP + DOT_DIR;
|
||||||
#else
|
homeDir = (char *)homeDirTmp.c_str();
|
||||||
homeDir = 0;
|
if (stat(homeDir, &s) == -1 || !S_ISDIR(s.st_mode))
|
||||||
#endif
|
mkdir(homeDir, 0755);
|
||||||
|
|
||||||
if (preferences == NULL)
|
if (preferences == NULL)
|
||||||
{
|
{
|
||||||
|
@ -738,11 +741,11 @@ void LoadConfigFile()
|
||||||
|
|
||||||
void SaveConfigFile()
|
void SaveConfigFile()
|
||||||
{
|
{
|
||||||
#if !defined(_WIN32) && !defined(__APPLE__)
|
struct stat s;
|
||||||
homeDir = getenv("HOME");
|
std::string homeDirTmp = get_xdg_user_config_home() + FILE_SEP + DOT_DIR;
|
||||||
#else
|
homeDir = (char *)homeDirTmp.c_str();
|
||||||
homeDir = 0;
|
if (stat(homeDir, &s) == -1 || !S_ISDIR(s.st_mode))
|
||||||
#endif
|
mkdir(homeDir, 0755);
|
||||||
|
|
||||||
const char* configFile = FindConfigFile("vbam.ini");
|
const char* configFile = FindConfigFile("vbam.ini");
|
||||||
|
|
||||||
|
|
|
@ -164,7 +164,7 @@ extern const char *saveDir;
|
||||||
extern const char *batteryDir;
|
extern const char *batteryDir;
|
||||||
|
|
||||||
// Directory within homedir to use for default save location.
|
// Directory within homedir to use for default save location.
|
||||||
#define DOT_DIR ".vbam"
|
#define DOT_DIR "visualboyadvance-m"
|
||||||
|
|
||||||
void SetHome(char *_arg0);
|
void SetHome(char *_arg0);
|
||||||
void SaveConfigFile();
|
void SaveConfigFile();
|
||||||
|
|
|
@ -71,6 +71,9 @@
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
#define GETCWD _getcwd
|
#define GETCWD _getcwd
|
||||||
#define snprintf sprintf
|
#define snprintf sprintf
|
||||||
|
#define stat _stat
|
||||||
|
#define mkdir(X,Y) (_mkdir(X))
|
||||||
|
#define S_ISDIR _S_IFDIR
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
#ifndef __GNUC__
|
#ifndef __GNUC__
|
||||||
|
@ -202,6 +205,7 @@ int sdlMirroringEnable = 1;
|
||||||
void systemConsoleMessage(const char*);
|
void systemConsoleMessage(const char*);
|
||||||
|
|
||||||
char* home;
|
char* home;
|
||||||
|
char homeDataDir[2048];
|
||||||
|
|
||||||
char screenMessageBuffer[21];
|
char screenMessageBuffer[21];
|
||||||
uint32_t screenMessageTime = 0;
|
uint32_t screenMessageTime = 0;
|
||||||
|
@ -246,7 +250,7 @@ void StartLirc(void)
|
||||||
fprintf(stdout, "Success\n");
|
fprintf(stdout, "Success\n");
|
||||||
//read the config file
|
//read the config file
|
||||||
char LIRCConfigLoc[2048];
|
char LIRCConfigLoc[2048];
|
||||||
sprintf(LIRCConfigLoc, "%s/%s/%s", homeDir, DOT_DIR, "lircrc");
|
sprintf(LIRCConfigLoc, "%s/%s", homeDataDir, "lircrc");
|
||||||
fprintf(stdout, "LIRC Config file:");
|
fprintf(stdout, "LIRC Config file:");
|
||||||
if (lirc_readconfig(LIRCConfigLoc, &LIRCConfigInfo, NULL) == 0) {
|
if (lirc_readconfig(LIRCConfigLoc, &LIRCConfigInfo, NULL) == 0) {
|
||||||
//check vbam dir for lircrc
|
//check vbam dir for lircrc
|
||||||
|
@ -366,8 +370,8 @@ FILE* sdlFindFile(const char* name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (homeDir) {
|
if (homeDir) {
|
||||||
fprintf(stdout, "Searching home directory: %s%c%s\n", homeDir, FILE_SEP, DOT_DIR);
|
fprintf(stdout, "Searching home directory: %s\n", homeDataDir);
|
||||||
sprintf(path, "%s%c%s%c%s", homeDir, FILE_SEP, DOT_DIR, FILE_SEP, name);
|
sprintf(path, "%s%c%s", homeDataDir, FILE_SEP, name);
|
||||||
f = fopen(path, "r");
|
f = fopen(path, "r");
|
||||||
if (f != NULL)
|
if (f != NULL)
|
||||||
return f;
|
return f;
|
||||||
|
@ -659,7 +663,7 @@ static char* sdlStateName(int num)
|
||||||
sprintf(stateName, "%s/%s%d.sgm", saveDir, sdlGetFilename(filename),
|
sprintf(stateName, "%s/%s%d.sgm", saveDir, sdlGetFilename(filename),
|
||||||
num + 1);
|
num + 1);
|
||||||
else if (homeDir)
|
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
|
else
|
||||||
sprintf(stateName, "%s%d.sgm", filename, num + 1);
|
sprintf(stateName, "%s%d.sgm", filename, num + 1);
|
||||||
|
|
||||||
|
@ -758,7 +762,7 @@ void sdlWriteBattery()
|
||||||
if (batteryDir)
|
if (batteryDir)
|
||||||
sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename));
|
sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename));
|
||||||
else if (homeDir)
|
else if (homeDir)
|
||||||
sprintf(buffer, "%s/%s/%s.sav", homeDir, DOT_DIR, sdlGetFilename(filename));
|
sprintf(buffer, "%s/%s.sav", homeDataDir, sdlGetFilename(filename));
|
||||||
else
|
else
|
||||||
sprintf(buffer, "%s.sav", filename);
|
sprintf(buffer, "%s.sav", filename);
|
||||||
|
|
||||||
|
@ -774,7 +778,7 @@ void sdlReadBattery()
|
||||||
if (batteryDir)
|
if (batteryDir)
|
||||||
sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename));
|
sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename));
|
||||||
else if (homeDir)
|
else if (homeDir)
|
||||||
sprintf(buffer, "%s/%s/%s.sav", homeDir, DOT_DIR, sdlGetFilename(filename));
|
sprintf(buffer, "%s/%s.sav", homeDataDir, sdlGetFilename(filename));
|
||||||
else
|
else
|
||||||
sprintf(buffer, "%s.sav", filename);
|
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)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
fprintf(stdout, "%s\n", VBA_NAME_AND_SUBVERSION);
|
fprintf(stdout, "%s\n", VBA_NAME_AND_SUBVERSION);
|
||||||
|
|
||||||
home = argv[0];
|
home = argv[0];
|
||||||
SetHome(home);
|
SetHome(home);
|
||||||
|
SetHomeDataDir();
|
||||||
|
|
||||||
frameSkip = 2;
|
frameSkip = 2;
|
||||||
gbBorderOn = 0;
|
gbBorderOn = 0;
|
||||||
|
@ -2213,7 +2226,7 @@ void systemScreenCapture(int a)
|
||||||
if (screenShotDir)
|
if (screenShotDir)
|
||||||
sprintf(buffer, "%s/%s%02d.bmp", screenShotDir, sdlGetFilename(filename), a);
|
sprintf(buffer, "%s/%s%02d.bmp", screenShotDir, sdlGetFilename(filename), a);
|
||||||
else if (homeDir)
|
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
|
else
|
||||||
sprintf(buffer, "%s%02d.bmp", filename, a);
|
sprintf(buffer, "%s%02d.bmp", filename, a);
|
||||||
|
|
||||||
|
@ -2222,7 +2235,7 @@ void systemScreenCapture(int a)
|
||||||
if (screenShotDir)
|
if (screenShotDir)
|
||||||
sprintf(buffer, "%s/%s%02d.png", screenShotDir, sdlGetFilename(filename), a);
|
sprintf(buffer, "%s/%s%02d.png", screenShotDir, sdlGetFilename(filename), a);
|
||||||
else if (homeDir)
|
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
|
else
|
||||||
sprintf(buffer, "%s%02d.png", filename, a);
|
sprintf(buffer, "%s%02d.png", filename, a);
|
||||||
emulator.emuWritePNG(buffer);
|
emulator.emuWritePNG(buffer);
|
||||||
|
|
|
@ -32,26 +32,6 @@
|
||||||
IMPLEMENT_APP(wxvbamApp)
|
IMPLEMENT_APP(wxvbamApp)
|
||||||
IMPLEMENT_DYNAMIC_CLASS(MainFrame, wxFrame)
|
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
|
// generate config file path
|
||||||
static void get_config_path(wxPathList& path, bool exists = true)
|
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("GetDataDir(): %s"), stdp.GetDataDir().mb_str());
|
||||||
wxLogDebug(wxT("GetLocalDataDir(): %s"), stdp.GetLocalDataDir().mb_str());
|
wxLogDebug(wxT("GetLocalDataDir(): %s"), stdp.GetLocalDataDir().mb_str());
|
||||||
wxLogDebug(wxT("GetPluginsDir(): %s"), stdp.GetPluginsDir().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);
|
wxLogDebug(wxT("XdgConfigDir: %s"), get_xdg_user_config_home() + current_app_name);
|
||||||
#endif
|
#endif
|
||||||
debug_dumped = true;
|
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),
|
// When native support for XDG dirs is available (wxWidgets >= 3.1),
|
||||||
// this will be no longer necessary
|
// this will be no longer necessary
|
||||||
#if defined(__LINUX__)
|
#if defined(__WXGTK__)
|
||||||
// XDG spec manual support
|
// XDG spec manual support
|
||||||
// ${XDG_CONFIG_HOME:-$HOME/.config}/`appname`
|
// ${XDG_CONFIG_HOME:-$HOME/.config}/`appname`
|
||||||
wxString old_config = wxString(getenv("HOME")) + "/.vbam";
|
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))
|
if (!wxDirExists(old_config) && wxIsWritable(new_config))
|
||||||
{
|
{
|
||||||
path.Add(new_config + current_app_name);
|
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
|
// 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.
|
// but subdir flag behaves differently 2.8 vs. 2.9. Oh well.
|
||||||
// NOTE: this does not support XDG (freedesktop.org) paths
|
// NOTE: this does not support XDG (freedesktop.org) paths
|
||||||
#if defined(__WXMSW__) || defined(__APPLE__)
|
|
||||||
wxString confname("vbam.ini");
|
wxString confname("vbam.ini");
|
||||||
#else
|
|
||||||
wxString confname("vbam.conf");
|
|
||||||
#endif
|
|
||||||
wxFileName vbamconf(GetConfigurationPath(), confname);
|
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,
|
cfg = new wxFileConfig(wxT("vbam"), wxEmptyString,
|
||||||
vbamconf.GetFullPath(),
|
vbamconf.GetFullPath(),
|
||||||
wxEmptyString, wxCONFIG_USE_LOCAL_FILE);
|
wxEmptyString, wxCONFIG_USE_LOCAL_FILE);
|
||||||
|
|
Loading…
Reference in New Issue