Репозиторий Sisyphus
Последнее обновление: 1 октября 2023 | Пакетов: 18631 | Посещений: 37735284
en ru br
Репозитории ALT

Группа :: Эмуляторы
Пакет: supermodel

 Главная   Изменения   Спек   Патчи   Sources   Загрузить   Gear   Bugs and FR  Repocop 

Патч: Supermodel-predictable-paths.patch
Скачать


From dbdd33d887100414ba6b02061ce2981983969d76 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fernando=20Casas=20Sch=C3=B6ssow?=
 <casasfernando@outlook.com>
Date: Mon, 14 Nov 2022 20:06:09 +0100
Subject: [PATCH 1/5] Keep Supermodel files (config, nvram, saves, etc.) in a
 predictable path when running on Linux
---
 Makefiles/Makefile.UNIX            |   3 +
 Makefiles/Makefile.Win32           |   1 +
 Src/OSD/FileSystemPath.h           |  40 ++++++++++
 Src/OSD/SDL/Main.cpp               |  29 ++++---
 Src/OSD/Unix/FileSystemPath.cpp    | 122 +++++++++++++++++++++++++++++
 Src/OSD/Windows/FileSystemPath.cpp |  37 +++++++++
 6 files changed, 219 insertions(+), 13 deletions(-)
 create mode 100644 Src/OSD/FileSystemPath.h
 create mode 100644 Src/OSD/Unix/FileSystemPath.cpp
 create mode 100644 Src/OSD/Windows/FileSystemPath.cpp
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 <http://www.gnu.org/licenses/>.
+ **/
+
+/*
+ * FileSystemPaths.h
+ * 
+ * Header file for OS-dependent Supermodel files locations.
+ */
+
+#ifndef INCLUDED_FILESYSTEMPATH_H
+#define INCLUDED_FILESYSTEMPATH_H
+
+#include <string>
+
+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 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
  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=<file>   ROM set definition file [Default: %s]\n", s_gameXMLFilePath);
-  puts("  -log-output=<outputs>   Log output destination(s) [Default: Supermodel.log]");
+  printf("  -game-xml-file=<file>   ROM set definition file [Default: %s]\n", s_gameXMLFilePath.c_str());
+  printf("  -log-output=<outputs>   Log output destination(s) [Default: %s]\n", s_logFilePath.c_str());
   puts("  -log-level=<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 <http://www.gnu.org/licenses/>.
+ **/
+
+#include "FileSystemPath.h"
+#include "Util/Format.h"
+#include <string>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <unistd.h>
+
+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 <http://www.gnu.org/licenses/>.
+ **/
+
+#include "FileSystemPath.h"
+#include <string>
+
+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/";
+    }
+}
From 3aa11008be8207d04dc0be316ed7e1acdd6f36b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fernando=20Casas=20Sch=C3=B6ssow?=
 <casasfernando@outlook.com>
Date: Tue, 15 Nov 2022 17:40:01 +0100
Subject: [PATCH 2/5] Changed pathType from string var to enum
---
 Src/OSD/FileSystemPath.h           |  3 ++-
 Src/OSD/SDL/Main.cpp               | 18 +++++++-------
 Src/OSD/Unix/FileSystemPath.cpp    | 38 ++++++++++++++++++++++++------
 Src/OSD/Windows/FileSystemPath.cpp | 23 ++++++++++++------
 4 files changed, 58 insertions(+), 24 deletions(-)
diff --git a/Src/OSD/FileSystemPath.h b/Src/OSD/FileSystemPath.h
index b23a92f..b192f2b 100644
--- a/Src/OSD/FileSystemPath.h
+++ b/Src/OSD/FileSystemPath.h
@@ -32,8 +32,9 @@
 
 namespace FileSystemPath
 {
+    enum fsPathType { Analysis, Config, Log, NVRAM, Saves, Screenshots }; // Filesystem path types
     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
+    std::string GetPath(fsPathType pathType);  // Generates a path to be used by Supermodel files
 }
 
 
diff --git a/Src/OSD/SDL/Main.cpp b/Src/OSD/SDL/Main.cpp
index 19fa4f4..c98d5d9 100644
--- a/Src/OSD/SDL/Main.cpp
+++ b/Src/OSD/SDL/Main.cpp
@@ -476,7 +476,7 @@ void Screenshot()
     time_t now = std::time(nullptr);
     tm* ltm = std::localtime(&now);
 
-    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);
+    sprintf(file, "%sScreenshot %.4d-%.2d-%.2d (%.2d-%.2d-%.2d).bmp", FileSystemPath::GetPath(FileSystemPath::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());
@@ -616,7 +616,7 @@ static void SaveState(IEmulator *Model3)
 {
   CBlockFile  SaveState;
 
-  std::string file_path = Util::Format() << FileSystemPath::GetPath("Saves") << Model3->GetGame().name << ".st" << s_saveSlot;
+  std::string file_path = Util::Format() << FileSystemPath::GetPath(FileSystemPath::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());
@@ -641,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() << FileSystemPath::GetPath("Saves") << Model3->GetGame().name << ".st" << s_saveSlot;
+    file_path = Util::Format() << FileSystemPath::GetPath(FileSystemPath::Saves) << Model3->GetGame().name << ".st" << s_saveSlot;
 
   // Open and check to make sure format is correct
   if (OKAY != SaveState.Load(file_path))
@@ -675,7 +675,7 @@ static void SaveNVRAM(IEmulator *Model3)
 {
   CBlockFile  NVRAM;
 
-  std::string file_path = Util::Format() << FileSystemPath::GetPath("NVRAM") << Model3->GetGame().name << ".nv";
+  std::string file_path = Util::Format() << FileSystemPath::GetPath(FileSystemPath::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());
@@ -698,7 +698,7 @@ static void LoadNVRAM(IEmulator *Model3)
   CBlockFile  NVRAM;
 
   // Generate file path
-  std::string file_path = Util::Format() << FileSystemPath::GetPath("NVRAM") << Model3->GetGame().name << ".nv";
+  std::string file_path = Util::Format() << FileSystemPath::GetPath(FileSystemPath::NVRAM) << Model3->GetGame().name << ".nv";
 
   // Open and check to make sure format is correct
   if (OKAY != NVRAM.Load(file_path))
@@ -1449,10 +1449,10 @@ int Supermodel(const Game &game, ROMSet *rom_set, IEmulator *Model3, CInputs *In
  Entry Point and Command Line Procesing
 ******************************************************************************/
 
-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";
+static const std::string s_analysisPath = Util::Format() << FileSystemPath::GetPath(FileSystemPath::Analysis);
+static const std::string s_configFilePath = Util::Format() << FileSystemPath::GetPath(FileSystemPath::Config) << "Supermodel.ini";
+static const std::string s_gameXMLFilePath = Util::Format() << FileSystemPath::GetPath(FileSystemPath::Config) << "Games.xml";
+static const std::string s_logFilePath = Util::Format() << FileSystemPath::GetPath(FileSystemPath::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)
diff --git a/Src/OSD/Unix/FileSystemPath.cpp b/Src/OSD/Unix/FileSystemPath.cpp
index b7a8e8c..ce899fe 100644
--- a/Src/OSD/Unix/FileSystemPath.cpp
+++ b/Src/OSD/Unix/FileSystemPath.cpp
@@ -45,12 +45,36 @@ namespace FileSystemPath
     }
 
     // Generates a path to be used by Supermodel files
-    std::string GetPath(std::string pathType)
+    std::string GetPath(fsPathType pathType)
     {
         std::string finalPath = "";
         std::string homePath = "";
+        std::string strPathType = "";
 		struct passwd* pwd = getpwuid(getuid());
 
+        // Resolve pathType to string for later use
+        switch (pathType)
+        {
+            case Analysis:
+                strPathType = "Analysis";
+                break;
+            case Config:
+                strPathType = "Config";
+                break;
+            case Log:
+                strPathType = "Log";
+                break;
+            case NVRAM:
+                strPathType = "NVRAM";
+                break;
+            case Saves:
+                strPathType = "Saves";
+                break;
+            case Screenshots:
+                strPathType = "Screenshots";
+                break;
+        }
+
         // Get user's HOME directory
 		if (pwd)
 		{
@@ -65,15 +89,15 @@ namespace FileSystemPath
         if (FileSystemPath::PathExists("Config") || homePath.empty())
         {
             // Use current directory
-            if (pathType == "Screenshots" || pathType == "Log")
+            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;
+                if (!FileSystemPath::PathExists(strPathType)) mkdir(strPathType.c_str(), 0775);
+                finalPath = strPathType;
             }
 
         }
@@ -81,7 +105,7 @@ namespace FileSystemPath
         else if (FileSystemPath::PathExists(Util::Format() << homePath << "/.supermodel"))
         {
             // Use $HOME/.supermodel
-            finalPath = Util::Format() << homePath << "/.supermodel/" << pathType;
+            finalPath = Util::Format() << homePath << "/.supermodel/" << strPathType;
             // If directory doesn't exist, create it
             if (!FileSystemPath::PathExists(finalPath))
             {
@@ -92,7 +116,7 @@ namespace FileSystemPath
         else
         {
             // Use $HOME/.config/supermodel or $HOME/.local/share/supermodel depending on the file type
-            if (pathType == "Config")
+            if (pathType == Config)
             {
                 finalPath = Util::Format() << homePath << "/.config/supermodel";
                 // If directory doesn't exist, create it
@@ -108,7 +132,7 @@ namespace FileSystemPath
                 // 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;
+                finalPath = Util::Format() << homePath << "/.local/share/supermodel/" << strPathType;
                 if (!FileSystemPath::PathExists(finalPath)) mkdir(finalPath.c_str(), 0775);
             }
             
diff --git a/Src/OSD/Windows/FileSystemPath.cpp b/Src/OSD/Windows/FileSystemPath.cpp
index 66f9126..4390730 100644
--- a/Src/OSD/Windows/FileSystemPath.cpp
+++ b/Src/OSD/Windows/FileSystemPath.cpp
@@ -25,13 +25,22 @@
 namespace FileSystemPath
 {
     // Generates a path to be used by Supermodel files
-    std::string GetPath(std::string pathType)
+    std::string GetPath(fsPathType 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/";
+        switch (pathType)
+        {
+            case Analysis:
+                return "Analysis/";
+            case Config:
+                return "Config/";
+            case Log:
+                return "";
+            case NVRAM:
+                return "NVRAM/";
+            case Saves:
+                return "Saves/";
+            case Screenshots:
+                return "";
+        }
     }
 }
From 22dac30c031f8c9ff7dcb7ab6a40d8e4c184093c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fernando=20Casas=20Sch=C3=B6ssow?=
 <casasfernando@outlook.com>
Date: Mon, 21 Nov 2022 22:27:15 +0100
Subject: [PATCH 3/5] First review code changes (identation and cosmetic
 changes)
---
 Src/OSD/FileSystemPath.h           |  4 +-
 Src/OSD/Unix/FileSystemPath.cpp    | 88 ++++++++++++++++++------------
 Src/OSD/Windows/FileSystemPath.cpp | 26 ++++-----
 3 files changed, 67 insertions(+), 51 deletions(-)
diff --git a/Src/OSD/FileSystemPath.h b/Src/OSD/FileSystemPath.h
index b192f2b..3c04b62 100644
--- a/Src/OSD/FileSystemPath.h
+++ b/Src/OSD/FileSystemPath.h
@@ -32,9 +32,9 @@
 
 namespace FileSystemPath
 {
-    enum fsPathType { Analysis, Config, Log, NVRAM, Saves, Screenshots }; // Filesystem path types
+    enum PathType { Analysis, Config, Log, NVRAM, Saves, Screenshots }; // Filesystem path types
     bool PathExists(std::string fileSystemPath); // Checks if a directory exists (returns true if exists, false if it doesn't)
-    std::string GetPath(fsPathType pathType);  // Generates a path to be used by Supermodel files
+    std::string GetPath(PathType pathType);  // Generates a path to be used by Supermodel files
 }
 
 
diff --git a/Src/OSD/Unix/FileSystemPath.cpp b/Src/OSD/Unix/FileSystemPath.cpp
index ce899fe..4ab5916 100644
--- a/Src/OSD/Unix/FileSystemPath.cpp
+++ b/Src/OSD/Unix/FileSystemPath.cpp
@@ -45,45 +45,45 @@ namespace FileSystemPath
     }
 
     // Generates a path to be used by Supermodel files
-    std::string GetPath(fsPathType pathType)
+    std::string GetPath(PathType pathType)
     {
         std::string finalPath = "";
         std::string homePath = "";
         std::string strPathType = "";
-		struct passwd* pwd = getpwuid(getuid());
+        struct passwd* pwd = getpwuid(getuid());
 
         // Resolve pathType to string for later use
         switch (pathType)
         {
-            case Analysis:
-                strPathType = "Analysis";
-                break;
-            case Config:
-                strPathType = "Config";
-                break;
-            case Log:
-                strPathType = "Log";
-                break;
-            case NVRAM:
-                strPathType = "NVRAM";
-                break;
-            case Saves:
-                strPathType = "Saves";
-                break;
-            case Screenshots:
-                strPathType = "Screenshots";
-                break;
+        case Analysis:
+            strPathType = "Analysis";
+            break;
+        case Config:
+            strPathType = "Config";
+            break;
+        case Log:
+            strPathType = "Log";
+            break;
+        case NVRAM:
+            strPathType = "NVRAM";
+            break;
+        case Saves:
+            strPathType = "Saves";
+            break;
+        case Screenshots:
+            strPathType = "Screenshots";
+            break;
         }
 
         // Get user's HOME directory
-		if (pwd)
-		{
-			homePath = pwd->pw_dir;
-		}
-		else
-		{
-			homePath = getenv("HOME");
-		}
+        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())
@@ -96,10 +96,12 @@ namespace FileSystemPath
             else
             {
                 // If directory doesn't exist, create it
-                if (!FileSystemPath::PathExists(strPathType)) mkdir(strPathType.c_str(), 0775);
+                if (!FileSystemPath::PathExists(strPathType))
+                {
+                    mkdir(strPathType.c_str(), 0775);
+                }
                 finalPath = strPathType;
             }
-
         }
         // Check if $HOME/.supermodel exists
         else if (FileSystemPath::PathExists(Util::Format() << homePath << "/.supermodel"))
@@ -120,25 +122,39 @@ namespace FileSystemPath
             {
                 finalPath = Util::Format() << homePath << "/.config/supermodel";
                 // If directory doesn't exist, create it
-                if (!FileSystemPath::PathExists(finalPath)) mkdir(finalPath.c_str(), 0775);
+                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);
-                
+                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 (!FileSystemPath::PathExists(finalPath))
+                {
+                    mkdir(finalPath.c_str(), 0775);
+                }
                 // If directory doesn't exist, create it
                 finalPath = Util::Format() << homePath << "/.local/share/supermodel/" << strPathType;
-                if (!FileSystemPath::PathExists(finalPath)) mkdir(finalPath.c_str(), 0775);
+                if (!FileSystemPath::PathExists(finalPath))
+                {
+                    mkdir(finalPath.c_str(), 0775);
+                }
             }
             
         }
         
-        if (finalPath != "") finalPath = Util::Format() << finalPath << "/";
+        if (finalPath != "")
+        {
+            finalPath = Util::Format() << finalPath << "/";
+        }
 
         return finalPath;
 
diff --git a/Src/OSD/Windows/FileSystemPath.cpp b/Src/OSD/Windows/FileSystemPath.cpp
index 4390730..9536d27 100644
--- a/Src/OSD/Windows/FileSystemPath.cpp
+++ b/Src/OSD/Windows/FileSystemPath.cpp
@@ -25,22 +25,22 @@
 namespace FileSystemPath
 {
     // Generates a path to be used by Supermodel files
-    std::string GetPath(fsPathType pathType)
+    std::string GetPath(PathType pathType)
     {
         switch (pathType)
         {
-            case Analysis:
-                return "Analysis/";
-            case Config:
-                return "Config/";
-            case Log:
-                return "";
-            case NVRAM:
-                return "NVRAM/";
-            case Saves:
-                return "Saves/";
-            case Screenshots:
-                return "";
+        case Analysis:
+            return "Analysis/";
+        case Config:
+            return "Config/";
+        case Log:
+            return "";
+        case NVRAM:
+            return "NVRAM/";
+        case Saves:
+            return "Saves/";
+        case Screenshots:
+            return "";
         }
     }
 }
From 1c4a9cd90b3b458623db5c890523b23cd1248472 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fernando=20Casas=20Sch=C3=B6ssow?=
 <casasfernando@outlook.com>
Date: Sun, 4 Dec 2022 19:42:19 +0100
Subject: [PATCH 4/5] Switched to Util::Format() to generate screenshot
 filename
---
 Src/OSD/SDL/Main.cpp | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/Src/OSD/SDL/Main.cpp b/Src/OSD/SDL/Main.cpp
index c98d5d9..5562543 100644
--- a/Src/OSD/SDL/Main.cpp
+++ b/Src/OSD/SDL/Main.cpp
@@ -471,15 +471,24 @@ static void SaveFrameBuffer(const std::string& file)
 void Screenshot()
 {
     // Make a screenshot
-    char file[128];
-    std::string info = "Screenshot created: ";
     time_t now = std::time(nullptr);
     tm* ltm = std::localtime(&now);
-
-    sprintf(file, "%sScreenshot %.4d-%.2d-%.2d (%.2d-%.2d-%.2d).bmp", FileSystemPath::GetPath(FileSystemPath::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());
+    std::string file = Util::Format() << FileSystemPath::GetPath(FileSystemPath::Screenshots)
+        << "Screenshot_"
+        << std::setfill('0') << std::setw(4) << (1900 + ltm->tm_year)
+        << '-'
+        << std::setw(2) << (1 + ltm->tm_mon)
+        << '-'
+        << std::setw(2) << ltm->tm_mday
+        << "_("
+        << std::setw(2) << ltm->tm_hour
+        << '-'
+        << std::setw(2) << ltm->tm_min
+        << '-'
+        << std::setw(2) << ltm->tm_sec
+        << ").bmp";
+
+    std::cout << "Screenshot created: " << file << std::endl;
     SaveFrameBuffer(file);
 }
 
From ace45edffe6ede11e8e0b87a527d2f767eb7e045 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fernando=20Casas=20Sch=C3=B6ssow?=
 <casasfernando@outlook.com>
Date: Tue, 6 Dec 2022 13:25:20 +0100
Subject: [PATCH 5/5] Fixed build on macOS
---
 Makefiles/Makefile.OSX         |  3 +++
 Src/OSD/OSX/FileSystemPath.cpp | 46 ++++++++++++++++++++++++++++++++++
 2 files changed, 49 insertions(+)
 create mode 100644 Src/OSD/OSX/FileSystemPath.cpp
diff --git a/Makefiles/Makefile.OSX b/Makefiles/Makefile.OSX
index bb07732..1d23d1c 100644
--- a/Makefiles/Makefile.OSX
+++ b/Makefiles/Makefile.OSX
@@ -72,6 +72,9 @@ PLATFORM_LDFLAGS = $(SDL_LIBS) -lz -lm -lstdc++ -F/Library/Frameworks/
 ###############################################################################
 # Core Makefile
 ###############################################################################
+
+PLATFORM_SRC_FILES = \
+	Src/OSD/OSX/FileSystemPath.cpp
 
 include Makefiles/Rules.inc
 
diff --git a/Src/OSD/OSX/FileSystemPath.cpp b/Src/OSD/OSX/FileSystemPath.cpp
new file mode 100644
index 0000000..9536d27
--- /dev/null
+++ b/Src/OSD/OSX/FileSystemPath.cpp
@@ -0,0 +1,46 @@
+/**
+ ** 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 <http://www.gnu.org/licenses/>.
+ **/
+
+#include "FileSystemPath.h"
+#include <string>
+
+namespace FileSystemPath
+{
+    // Generates a path to be used by Supermodel files
+    std::string GetPath(PathType pathType)
+    {
+        switch (pathType)
+        {
+        case Analysis:
+            return "Analysis/";
+        case Config:
+            return "Config/";
+        case Log:
+            return "";
+        case NVRAM:
+            return "NVRAM/";
+        case Saves:
+            return "Saves/";
+        case Screenshots:
+            return "";
+        }
+    }
+}
 
дизайн и разработка: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
текущий майнтейнер: Michael Shigorin