diff --git a/Makefiles/Makefile.UNIX b/Makefiles/Makefile.UNIX
index d499234..1e48361 100644
--- a/Makefiles/Makefile.UNIX
+++ b/Makefiles/Makefile.UNIX
@@ -69,6 +69,9 @@ PLATFORM_LDFLAGS = $(SDL2_LIBS) -lGL -lGLU -lz -lm -lstdc++ -lpthread -lSDL2_net
###############################################################################
# Core Makefile
###############################################################################
+
+PLATFORM_SRC_FILES = \
+ Src/OSD/Unix/FileSystemPath.cpp
include Makefiles/Rules.inc
diff --git a/Makefiles/Makefile.Win32 b/Makefiles/Makefile.Win32
index 3e86534..0d984dc 100644
--- a/Makefiles/Makefile.Win32
+++ b/Makefiles/Makefile.Win32
@@ -103,6 +103,7 @@ PLATFORM_LDFLAGS = -static -L$(sort $(PLATFORM_LIB_DIR)) $(SDL2_LIBS) $(PLATFORM
PLATFORM_SRC_FILES = \
Src/OSD/Windows/DirectInputSystem.cpp \
+ Src/OSD/Windows/FileSystemPath.cpp \
Src/OSD/Windows/WinOutputs.cpp
.PHONY: clean
diff --git a/Src/OSD/FileSystemPath.h b/Src/OSD/FileSystemPath.h
new file mode 100644
index 0000000..b23a92f
--- /dev/null
+++ b/Src/OSD/FileSystemPath.h
@@ -0,0 +1,40 @@
+/**
+ ** Supermodel
+ ** A Sega Model 3 Arcade Emulator.
+ ** Copyright 2003-2022 The Supermodel Team
+ **
+ ** This file is part of Supermodel.
+ **
+ ** Supermodel is free software: you can redistribute it and/or modify it under
+ ** the terms of the GNU General Public License as published by the Free
+ ** Software Foundation, either version 3 of the License, or (at your option)
+ ** any later version.
+ **
+ ** Supermodel is distributed in the hope that it will be useful, but WITHOUT
+ ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ ** more details.
+ **
+ ** You should have received a copy of the GNU General Public License along
+ ** with Supermodel. If not, see .
+ **/
+
+/*
+ * FileSystemPaths.h
+ *
+ * Header file for OS-dependent Supermodel files locations.
+ */
+
+#ifndef INCLUDED_FILESYSTEMPATH_H
+#define INCLUDED_FILESYSTEMPATH_H
+
+#include
+
+namespace FileSystemPath
+{
+ bool PathExists(std::string fileSystemPath); // Checks if a directory exists (returns true if exists, false if it doesn't)
+ std::string GetPath(std::string pathType); // Generates a path to be used by Supermodel files
+}
+
+
+#endif // INCLUDED_FILESYSTEMPATH_H
diff --git a/Src/OSD/SDL/Main.cpp b/Src/OSD/SDL/Main.cpp
index e0267e9..19fa4f4 100644
--- a/Src/OSD/SDL/Main.cpp
+++ b/Src/OSD/SDL/Main.cpp
@@ -66,6 +66,7 @@
#include "Util/Format.h"
#include "Util/NewConfig.h"
#include "Util/ConfigBuilders.h"
+#include "OSD/FileSystemPath.h"
#include "GameLoader.h"
#include "SDLInputSystem.h"
#include "SDLIncludes.h"
@@ -475,7 +476,7 @@ void Screenshot()
time_t now = std::time(nullptr);
tm* ltm = std::localtime(&now);
- sprintf(file, "Screenshot %.4d-%.2d-%.2d (%.2d-%.2d-%.2d).bmp", 1900 + ltm->tm_year, 1 + ltm->tm_mon, ltm->tm_mday, ltm->tm_hour, ltm->tm_min, ltm->tm_sec);
+ sprintf(file, "%sScreenshot %.4d-%.2d-%.2d (%.2d-%.2d-%.2d).bmp", FileSystemPath::GetPath("Screenshots").c_str(), 1900 + ltm->tm_year, 1 + ltm->tm_mon, ltm->tm_mday, ltm->tm_hour, ltm->tm_min, ltm->tm_sec);
info += file;
puts(info.c_str());
@@ -549,7 +550,7 @@ static void TestPolygonHeaderBits(IEmulator *Emu)
if ((unknownPolyBits[idx] & mask))
{
Emu->RenderFrame();
- std::string file = Util::Format() << "Analysis/" << GetFileBaseName(s_gfxStatePath) << "." << "poly" << "." << idx << "_" << Util::Hex(mask) << ".bmp";
+ std::string file = Util::Format() << s_analysisPath << GetFileBaseName(s_gfxStatePath) << "." << "poly" << "." << idx << "_" << Util::Hex(mask) << ".bmp";
SaveFrameBuffer(file);
}
}
@@ -565,7 +566,7 @@ static void TestPolygonHeaderBits(IEmulator *Emu)
if ((unknownCullingNodeBits[idx] & mask))
{
Emu->RenderFrame();
- std::string file = Util::Format() << "Analysis/" << GetFileBaseName(s_gfxStatePath) << "." << "culling" << "." << idx << "_" << Util::Hex(mask) << ".bmp";
+ std::string file = Util::Format() << s_analysisPath << GetFileBaseName(s_gfxStatePath) << "." << "culling" << "." << idx << "_" << Util::Hex(mask) << ".bmp";
SaveFrameBuffer(file);
}
}
@@ -574,7 +575,7 @@ static void TestPolygonHeaderBits(IEmulator *Emu)
glReadBuffer(readBuffer);
// Generate the HTML GUI
- std::string file = Util::Format() << "Analysis/_" << GetFileBaseName(s_gfxStatePath) << ".html";
+ std::string file = Util::Format() << s_analysisPath << "_" << GetFileBaseName(s_gfxStatePath) << ".html";
std::ofstream fs(file);
if (!fs.good())
ErrorLog("Unable to open '%s' for writing.", file.c_str());
@@ -615,7 +616,7 @@ static void SaveState(IEmulator *Model3)
{
CBlockFile SaveState;
- std::string file_path = Util::Format() << "Saves/" << Model3->GetGame().name << ".st" << s_saveSlot;
+ std::string file_path = Util::Format() << FileSystemPath::GetPath("Saves") << Model3->GetGame().name << ".st" << s_saveSlot;
if (OKAY != SaveState.Create(file_path, "Supermodel Save State", "Supermodel Version " SUPERMODEL_VERSION))
{
ErrorLog("Unable to save state to '%s'.", file_path.c_str());
@@ -640,7 +641,7 @@ static void LoadState(IEmulator *Model3, std::string file_path = std::string())
// Generate file path
if (file_path.empty())
- file_path = Util::Format() << "Saves/" << Model3->GetGame().name << ".st" << s_saveSlot;
+ file_path = Util::Format() << FileSystemPath::GetPath("Saves") << Model3->GetGame().name << ".st" << s_saveSlot;
// Open and check to make sure format is correct
if (OKAY != SaveState.Load(file_path))
@@ -674,7 +675,7 @@ static void SaveNVRAM(IEmulator *Model3)
{
CBlockFile NVRAM;
- std::string file_path = Util::Format() << "NVRAM/" << Model3->GetGame().name << ".nv";
+ std::string file_path = Util::Format() << FileSystemPath::GetPath("NVRAM") << Model3->GetGame().name << ".nv";
if (OKAY != NVRAM.Create(file_path, "Supermodel NVRAM State", "Supermodel Version " SUPERMODEL_VERSION))
{
ErrorLog("Unable to save NVRAM to '%s'. Make sure directory exists!", file_path.c_str());
@@ -697,7 +698,7 @@ static void LoadNVRAM(IEmulator *Model3)
CBlockFile NVRAM;
// Generate file path
- std::string file_path = Util::Format() << "NVRAM/" << Model3->GetGame().name << ".nv";
+ std::string file_path = Util::Format() << FileSystemPath::GetPath("NVRAM") << Model3->GetGame().name << ".nv";
// Open and check to make sure format is correct
if (OKAY != NVRAM.Load(file_path))
@@ -1448,8 +1449,10 @@ QuitError:
Entry Point and Command Line Procesing
******************************************************************************/
-static const char s_configFilePath[] = { "Config/Supermodel.ini" };
-static const char s_gameXMLFilePath[] = { "Config/Games.xml" };
+static const std::string s_analysisPath = Util::Format() << FileSystemPath::GetPath("Analysis");
+static const std::string s_configFilePath = Util::Format() << FileSystemPath::GetPath("Config") << "Supermodel.ini";
+static const std::string s_gameXMLFilePath = Util::Format() << FileSystemPath::GetPath("Config") << "Games.xml";
+static const std::string s_logFilePath = Util::Format() << FileSystemPath::GetPath("Log") << "Supermodel.log";
// Create and configure inputs
static bool ConfigureInputs(CInputs *Inputs, Util::Config::Node *fileConfig, Util::Config::Node *runtimeConfig, const Game &game, bool configure)
@@ -1640,8 +1643,8 @@ static void Help(void)
puts("General Options:");
puts(" -?, -h, -help, --help Print this help text");
puts(" -print-games List supported games and quit");
- printf(" -game-xml-file= ROM set definition file [Default: %s]\n", s_gameXMLFilePath);
- puts(" -log-output= Log output destination(s) [Default: Supermodel.log]");
+ printf(" -game-xml-file= ROM set definition file [Default: %s]\n", s_gameXMLFilePath.c_str());
+ printf(" -log-output= Log output destination(s) [Default: %s]\n", s_logFilePath.c_str());
puts(" -log-level= Logging threshold [Default: info]");
puts("");
puts("Core Options:");
@@ -1737,7 +1740,7 @@ struct ParsedCommandLine
{
// Logging is special: it is only parsed from the command line and
// therefore, defaults are needed early
- config.Set("LogOutput", "Supermodel.log");
+ config.Set("LogOutput", s_logFilePath.c_str());
config.Set("LogLevel", "info");
}
};
diff --git a/Src/OSD/Unix/FileSystemPath.cpp b/Src/OSD/Unix/FileSystemPath.cpp
new file mode 100644
index 0000000..b7a8e8c
--- /dev/null
+++ b/Src/OSD/Unix/FileSystemPath.cpp
@@ -0,0 +1,122 @@
+/**
+ ** Supermodel
+ ** A Sega Model 3 Arcade Emulator.
+ ** Copyright 2003-2022 The Supermodel Team
+ **
+ ** This file is part of Supermodel.
+ **
+ ** Supermodel is free software: you can redistribute it and/or modify it under
+ ** the terms of the GNU General Public License as published by the Free
+ ** Software Foundation, either version 3 of the License, or (at your option)
+ ** any later version.
+ **
+ ** Supermodel is distributed in the hope that it will be useful, but WITHOUT
+ ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ ** more details.
+ **
+ ** You should have received a copy of the GNU General Public License along
+ ** with Supermodel. If not, see .
+ **/
+
+#include "FileSystemPath.h"
+#include "Util/Format.h"
+#include
+#include
+#include
+#include
+#include
+
+namespace FileSystemPath
+{
+ // Checks if a directory exists (returns true if exists, false if it doesn't)
+ bool PathExists(std::string fileSystemPath)
+ {
+ bool pathExists = false;
+ struct stat pathInfo;
+
+ if (stat(fileSystemPath.c_str(), &pathInfo) == 0 && S_ISDIR(pathInfo.st_mode))
+ {
+ pathExists = true;
+ }
+
+ return pathExists;
+
+ }
+
+ // Generates a path to be used by Supermodel files
+ std::string GetPath(std::string pathType)
+ {
+ std::string finalPath = "";
+ std::string homePath = "";
+ struct passwd* pwd = getpwuid(getuid());
+
+ // Get user's HOME directory
+ if (pwd)
+ {
+ homePath = pwd->pw_dir;
+ }
+ else
+ {
+ homePath = getenv("HOME");
+ }
+
+ // If Config path exists in current directory or the user doesn't have a HOME directory use current directory
+ if (FileSystemPath::PathExists("Config") || homePath.empty())
+ {
+ // Use current directory
+ if (pathType == "Screenshots" || pathType == "Log")
+ {
+ finalPath = "";
+ }
+ else
+ {
+ // If directory doesn't exist, create it
+ if (!FileSystemPath::PathExists(pathType)) mkdir(pathType.c_str(), 0775);
+ finalPath = pathType;
+ }
+
+ }
+ // Check if $HOME/.supermodel exists
+ else if (FileSystemPath::PathExists(Util::Format() << homePath << "/.supermodel"))
+ {
+ // Use $HOME/.supermodel
+ finalPath = Util::Format() << homePath << "/.supermodel/" << pathType;
+ // If directory doesn't exist, create it
+ if (!FileSystemPath::PathExists(finalPath))
+ {
+ mkdir(finalPath.c_str(), 0775);
+ }
+ }
+ // On Linux one may want to follow the XDG base directory specs (https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)
+ else
+ {
+ // Use $HOME/.config/supermodel or $HOME/.local/share/supermodel depending on the file type
+ if (pathType == "Config")
+ {
+ finalPath = Util::Format() << homePath << "/.config/supermodel";
+ // If directory doesn't exist, create it
+ if (!FileSystemPath::PathExists(finalPath)) mkdir(finalPath.c_str(), 0775);
+ // If directory doesn't exist, create it
+ finalPath = Util::Format() << homePath << "/.config/supermodel/Config";
+ if (!FileSystemPath::PathExists(finalPath)) mkdir(finalPath.c_str(), 0775);
+
+ }
+ else
+ {
+ finalPath = Util::Format() << homePath << "/.local/share/supermodel";
+ // If directory doesn't exist, create it
+ if (!FileSystemPath::PathExists(finalPath)) mkdir(finalPath.c_str(), 0775);
+ // If directory doesn't exist, create it
+ finalPath = Util::Format() << homePath << "/.local/share/supermodel/" << pathType;
+ if (!FileSystemPath::PathExists(finalPath)) mkdir(finalPath.c_str(), 0775);
+ }
+
+ }
+
+ if (finalPath != "") finalPath = Util::Format() << finalPath << "/";
+
+ return finalPath;
+
+ }
+}
diff --git a/Src/OSD/Windows/FileSystemPath.cpp b/Src/OSD/Windows/FileSystemPath.cpp
new file mode 100644
index 0000000..66f9126
--- /dev/null
+++ b/Src/OSD/Windows/FileSystemPath.cpp
@@ -0,0 +1,37 @@
+/**
+ ** Supermodel
+ ** A Sega Model 3 Arcade Emulator.
+ ** Copyright 2003-2022 The Supermodel Team
+ **
+ ** This file is part of Supermodel.
+ **
+ ** Supermodel is free software: you can redistribute it and/or modify it under
+ ** the terms of the GNU General Public License as published by the Free
+ ** Software Foundation, either version 3 of the License, or (at your option)
+ ** any later version.
+ **
+ ** Supermodel is distributed in the hope that it will be useful, but WITHOUT
+ ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ ** more details.
+ **
+ ** You should have received a copy of the GNU General Public License along
+ ** with Supermodel. If not, see .
+ **/
+
+#include "FileSystemPath.h"
+#include
+
+namespace FileSystemPath
+{
+ // Generates a path to be used by Supermodel files
+ std::string GetPath(std::string pathType)
+ {
+ if (pathType == "Config") return "Config/";
+ if (pathType == "Screenshots") return "";
+ if (pathType == "Saves") return "Saves/";
+ if (pathType == "NVRAM") return "NVRAM/";
+ if (pathType == "Log") return "";
+ if (pathType == "Analysis") return "Analysis/";
+ }
+}