XDG followup work #94

* Apply save order for save states and batteries.
The order for save state/battery:
1. StateDir / BatteryDir;
2. The path of the current loaded game;
3. XDG Base Dir fallback.

* Use XDG Base Dir fallback to save screenshots and recordings.

* Apply search order for all dirs except recording (not implemented yet) of SDL port.
The order for battery/save state/screenshot is:
1. StateDir/BatteryDir/ScreenshotDir;
2. The path of the current loaded game;
3. XDG Base Dir (or equivalent) fallback.

* Refactor code.

* Fix freeing and setting pointer to NULL of SDL port.
This commit is contained in:
Edênis Freindorfer Azevedo 2019-03-18 05:08:53 -03:00 committed by Rafael Kitover
parent 2142a46dd5
commit a1f0c34ace
4 changed files with 126 additions and 83 deletions

View File

@ -64,14 +64,22 @@
#include "inputSDL.h" #include "inputSDL.h"
#include "text.h" #include "text.h"
// from: https://stackoverflow.com/questions/7608714/why-is-my-pointer-not-null-after-free
#define freeSafe(ptr) free(ptr); ptr = NULL;
#ifndef _WIN32 #ifndef _WIN32
#include <unistd.h> #include <unistd.h>
#define GETCWD getcwd #define GETCWD getcwd
#else // _WIN32 #else // _WIN32
#include <direct.h> #include <direct.h>
#include <io.h>
#define GETCWD _getcwd #define GETCWD _getcwd
#define snprintf sprintf #define snprintf sprintf
#define stat _stat #define stat _stat
#define access _access
#ifndef W_OK
#define W_OK 2
#endif
#define mkdir(X,Y) (_mkdir(X)) #define mkdir(X,Y) (_mkdir(X))
// from: https://www.linuxquestions.org/questions/programming-9/porting-to-win32-429334/ // from: https://www.linuxquestions.org/questions/programming-9/porting-to-win32-429334/
#ifndef S_ISDIR #ifndef S_ISDIR
@ -208,7 +216,8 @@ int sdlMirroringEnable = 1;
void systemConsoleMessage(const char*); void systemConsoleMessage(const char*);
char* home; char* home;
char homeDataDir[2048]; char homeConfigDir[1024];
char homeDataDir[1024];
char screenMessageBuffer[21]; char screenMessageBuffer[21];
uint32_t screenMessageTime = 0; uint32_t screenMessageTime = 0;
@ -253,7 +262,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", homeDataDir, "lircrc"); sprintf(LIRCConfigLoc, "%s%c%s", homeConfigDir, FILE_SEP, "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
@ -291,59 +300,47 @@ void StopLirc(void)
bool sdlCheckDirectory(const char* dir) bool sdlCheckDirectory(const char* dir)
{ {
bool res = false;
if (!dir || !dir[0]) {
return false;
}
struct stat buf; struct stat buf;
int len = strlen(dir); if (!dir || !dir[0])
return false;
char* p = (char*)dir + len - 1; if (stat(dir, &buf) == 0)
{
while (p != dir && (*p == '/' || *p == '\\')) { if (!(buf.st_mode & S_IFDIR))
*p = 0; {
p--; fprintf(stderr, "Error: %s is not a directory\n", dir);
return false;
}
return true;
} }
else
if (stat(dir, &buf) == 0) { {
if (!(buf.st_mode & S_IFDIR)) { fprintf(stderr, "Error: %s does not exist\n", dir);
fprintf(stderr, "Error: %s is not a directory\n", dir); return false;
}
res = true;
} else {
fprintf(stderr, "Error: %s does not exist\n", dir);
} }
return res;
} }
char* sdlGetFilename(char* name) char* sdlGetFilename(char* name)
{ {
static char filebuffer[2048]; char path[1024] = ""; // avoid warning about uninitialised value
char *filename = strrchr(name, FILE_SEP);
int len = strlen(name); if (filename)
strncpy(path, filename + 1, strlen(filename));
char* p = name + len - 1;
while (true) {
if (*p == '/' || *p == '\\') {
p++;
break;
}
len--;
p--;
if (len == 0)
break;
}
if (len == 0)
strcpy(filebuffer, name);
else else
strcpy(filebuffer, p); sprintf(path, "%s", name);
return filebuffer; return strdup(path);
}
char* sdlGetFilePath(char* name)
{
char path[1024] = ""; // avoid warning about uninitialised value
char *filename = strrchr(name, FILE_SEP);
if (filename)
strncpy(path, name, strlen(name) - strlen(filename));
else
sprintf(path, "%c%c", '.', FILE_SEP);
return strdup(path);
} }
FILE* sdlFindFile(const char* name) FILE* sdlFindFile(const char* name)
@ -661,15 +658,18 @@ static int sdlCalculateShift(uint32_t mask)
static char* sdlStateName(int num) static char* sdlStateName(int num)
{ {
static char stateName[2048]; static char stateName[2048];
char *gameDir = sdlGetFilePath(filename);
char *gameFile = sdlGetFilename(filename);
if (saveDir) if (saveDir)
sprintf(stateName, "%s/%s%d.sgm", saveDir, sdlGetFilename(filename), sprintf(stateName, "%s%c%s%d.sgm", saveDir, FILE_SEP, gameFile, num + 1);
num + 1); else if (access(gameDir, W_OK) == 0)
else if (homeDir) sprintf(stateName, "%s%c%s%d.sgm", gameDir, FILE_SEP, gameFile, 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%c%s%d.sgm", homeDataDir, FILE_SEP, gameFile, num + 1);
freeSafe(gameDir);
freeSafe(gameFile);
return stateName; return stateName;
} }
@ -760,37 +760,46 @@ void sdlWriteBackupStateExchange(int from, int to, int backup)
void sdlWriteBattery() void sdlWriteBattery()
{ {
char buffer[1048]; char buffer[2048];
char *gameDir = sdlGetFilePath(filename);
char *gameFile = sdlGetFilename(filename);
if (batteryDir) if (batteryDir)
sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename)); sprintf(buffer, "%s%c%s.sav", batteryDir, FILE_SEP, gameFile);
else if (homeDir) else if (access(gameDir, W_OK) == 0)
sprintf(buffer, "%s/%s.sav", homeDataDir, sdlGetFilename(filename)); sprintf(buffer, "%s%c%s.sav", gameDir, FILE_SEP, gameFile);
else else
sprintf(buffer, "%s.sav", filename); sprintf(buffer, "%s%c%s.sav", homeDataDir, FILE_SEP, gameFile);
emulator.emuWriteBattery(buffer); bool result = emulator.emuWriteBattery(buffer);
systemScreenMessage("Wrote battery"); if (result)
systemMessage(0, "Wrote battery '%s'", buffer);
freeSafe(gameFile);
freeSafe(gameDir);
} }
void sdlReadBattery() void sdlReadBattery()
{ {
char buffer[1048]; char buffer[2048];
char *gameDir = sdlGetFilePath(filename);
char *gameFile = sdlGetFilename(filename);
if (batteryDir) if (batteryDir)
sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename)); sprintf(buffer, "%s%c%s.sav", batteryDir, FILE_SEP, gameFile);
else if (homeDir) else if (access(gameDir, W_OK) == 0)
sprintf(buffer, "%s/%s.sav", homeDataDir, sdlGetFilename(filename)); sprintf(buffer, "%s%c%s.sav", gameDir, FILE_SEP, gameFile);
else else
sprintf(buffer, "%s.sav", filename); sprintf(buffer, "%s%c%s.sav", homeDataDir, FILE_SEP, gameFile);
bool res = false; bool result = emulator.emuReadBattery(buffer);
res = emulator.emuReadBattery(buffer); if (result)
systemMessage(0, "Loaded battery '%s'", buffer);
if (res) freeSafe(gameFile);
systemScreenMessage("Loaded battery"); freeSafe(gameDir);
} }
void sdlReadDesktopVideoMode() void sdlReadDesktopVideoMode()
@ -1644,6 +1653,14 @@ void handleRewinds()
} }
} }
void SetHomeConfigDir()
{
sprintf(homeConfigDir, "%s%s", get_xdg_user_config_home().c_str(), DOT_DIR);
struct stat s;
if (stat(homeDataDir, &s) == -1 || !S_ISDIR(s.st_mode))
mkdir(homeDataDir, 0755);
}
void SetHomeDataDir() void SetHomeDataDir()
{ {
sprintf(homeDataDir, "%s%s", get_xdg_user_data_home().c_str(), DOT_DIR); sprintf(homeDataDir, "%s%s", get_xdg_user_data_home().c_str(), DOT_DIR);
@ -1658,6 +1675,7 @@ int main(int argc, char** argv)
home = argv[0]; home = argv[0];
SetHome(home); SetHome(home);
SetHomeConfigDir();
SetHomeDataDir(); SetHomeDataDir();
frameSkip = 2; frameSkip = 2;
@ -2224,27 +2242,35 @@ void system10Frames(int rate)
void systemScreenCapture(int a) void systemScreenCapture(int a)
{ {
char buffer[2048]; char buffer[2048];
bool result = false;
char *gameDir = sdlGetFilePath(filename);
char *gameFile = sdlGetFilename(filename);
if (captureFormat) { if (captureFormat) {
if (screenShotDir) if (screenShotDir)
sprintf(buffer, "%s/%s%02d.bmp", screenShotDir, sdlGetFilename(filename), a); sprintf(buffer, "%s%c%s%02d.bmp", screenShotDir, FILE_SEP, gameFile, a);
else if (homeDir) else if (access(gameDir, W_OK) == 0)
sprintf(buffer, "%s/%s%02d.bmp", homeDataDir, sdlGetFilename(filename), a); sprintf(buffer, "%s%c%s%02d.bmp", gameDir, FILE_SEP, gameFile, a);
else else
sprintf(buffer, "%s%02d.bmp", filename, a); sprintf(buffer, "%s%c%s%02d.bmp", homeDataDir, FILE_SEP, gameFile, a);
emulator.emuWriteBMP(buffer); result = emulator.emuWriteBMP(buffer);
} else { } else {
if (screenShotDir) if (screenShotDir)
sprintf(buffer, "%s/%s%02d.png", screenShotDir, sdlGetFilename(filename), a); sprintf(buffer, "%s%c%s%02d.png", screenShotDir, FILE_SEP, gameFile, a);
else if (homeDir) else if (access(gameDir, W_OK) == 0)
sprintf(buffer, "%s/%s%02d.png", homeDataDir, sdlGetFilename(filename), a); sprintf(buffer, "%s%c%s%02d.png", gameDir, FILE_SEP, gameFile, a);
else else
sprintf(buffer, "%s%02d.png", filename, a); sprintf(buffer, "%s%c%s%02d.png", homeDataDir, FILE_SEP, gameFile, a);
emulator.emuWritePNG(buffer);
result = emulator.emuWritePNG(buffer);
} }
systemScreenMessage("Screen capture"); if (result)
systemScreenMessage("Screen capture");
freeSafe(gameFile);
freeSafe(gameDir);
} }
void systemSaveOldest() void systemSaveOldest()

View File

@ -461,6 +461,10 @@ void GameArea::recompute_dirs()
batdir = wxGetApp().GetAbsolutePath(gopts.battery_dir); batdir = wxGetApp().GetAbsolutePath(gopts.battery_dir);
} }
if (!wxIsWritable(batdir)) {
batdir = wxGetApp().GetDataDir();
}
statedir = gopts.state_dir; statedir = gopts.state_dir;
if (!statedir.size()) { if (!statedir.size()) {
@ -469,11 +473,9 @@ void GameArea::recompute_dirs()
statedir = wxGetApp().GetAbsolutePath(gopts.state_dir); statedir = wxGetApp().GetAbsolutePath(gopts.state_dir);
} }
if (!wxIsWritable(batdir)) if (!wxIsWritable(statedir)) {
batdir = wxGetApp().GetConfigurationPath(); statedir = wxGetApp().GetDataDir();
}
if (!wxIsWritable(statedir))
statedir = wxGetApp().GetConfigurationPath();
} }
void GameArea::UnloadGame(bool destruct) void GameArea::UnloadGame(bool destruct)

View File

@ -636,6 +636,16 @@ bool wxvbamApp::OnCmdLineParsed(wxCmdLineParser& cl)
return true; return true;
} }
wxString wxvbamApp::GetConfigDir()
{
return GetAbsolutePath(get_xdg_user_config_home() + DOT_DIR);
}
wxString wxvbamApp::GetDataDir()
{
return GetAbsolutePath(get_xdg_user_data_home() + DOT_DIR);
}
wxvbamApp::~wxvbamApp() { wxvbamApp::~wxvbamApp() {
if (home != NULL) if (home != NULL)
{ {
@ -774,7 +784,10 @@ wxString MainFrame::GetGamePath(wxString path)
game_path = wxFileName::GetCwd(); game_path = wxFileName::GetCwd();
if (!wxIsWritable(game_path)) if (!wxIsWritable(game_path))
game_path = wxGetApp().GetConfigurationPath(); {
game_path = wxGetApp().GetAbsolutePath(get_xdg_user_data_home() + DOT_DIR);
wxFileName::Mkdir(game_path, 0777, wxPATH_MKDIR_FULL);
}
return game_path; return game_path;
} }

View File

@ -88,6 +88,8 @@ public:
virtual bool UsingWayland() { return using_wayland; } virtual bool UsingWayland() { return using_wayland; }
virtual void OnInitCmdLine(wxCmdLineParser&); virtual void OnInitCmdLine(wxCmdLineParser&);
virtual bool OnCmdLineParsed(wxCmdLineParser&); virtual bool OnCmdLineParsed(wxCmdLineParser&);
virtual wxString GetConfigDir();
virtual wxString GetDataDir();
wxString GetConfigurationPath(); wxString GetConfigurationPath();
const wxString GetPluginsDir(); const wxString GetPluginsDir();
wxString GetAbsolutePath(wxString path); wxString GetAbsolutePath(wxString path);