From 88afab2d2270b31a7816c1b50a2f22d0ca83d39d Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sun, 24 Feb 2019 19:14:55 -0330 Subject: [PATCH] More restructuring of the OSystem and derived class interaction - Each derived class no longer calls methods from the base class - The base class now directly queries the derived class with a pure virtual method, making sure it is called - Implemented 'basedir' commandline argument for Linux Windows and macOS currently won't compile. I'll work on those next. --- src/common/main.cxx | 4 +- src/emucore/OSystem.cxx | 40 ++++++++++++-------- src/emucore/OSystem.hxx | 68 ++++++++++++++++++++-------------- src/unix/OSystemUNIX.cxx | 33 ++++++++--------- src/unix/OSystemUNIX.hxx | 30 ++++++++++++--- src/windows/OSystemWINDOWS.cxx | 30 ++++----------- src/windows/OSystemWINDOWS.hxx | 33 ++++++++++++----- 7 files changed, 139 insertions(+), 99 deletions(-) diff --git a/src/common/main.cxx b/src/common/main.cxx index 5be707201..07ec5df8f 100644 --- a/src/common/main.cxx +++ b/src/common/main.cxx @@ -96,7 +96,7 @@ void parseCommandLine(int ac, char* av[], // configuration files are stored; we check for those next if(key == "baseinappdir") { - globalOpts[key] = true; + localOpts[key] = true; continue; } @@ -130,7 +130,7 @@ void checkForCustomBaseDir(Settings::Options& options) // If both of these are activated, the 'base in app dir' takes precedence auto it = options.find("baseinappdir"); if(it != options.end()) - OSystem::overrideBaseDir(); + OSystem::overrideBaseDirWithApp(); else { it = options.find("basedir"); diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index ba568a38c..12fa47674 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -169,6 +169,29 @@ bool OSystem::create() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::loadConfig(const Settings::Options& options) { + // Get base directory and config file from derived class + // It will decide whether it can override its default location + getBaseDirAndConfig(myBaseDir, myConfigFile, + myDefaultSaveDir, myDefaultLoadDir, + ourOverrideBaseDirWithApp, ourOverrideBaseDir); + + // Get fully-qualified pathnames, and make directories when needed + FilesystemNode node(myBaseDir); + if(!node.isDirectory()) + node.makeDir(); + myBaseDir = node.getPath(); + myConfigFile = FilesystemNode(myConfigFile).getPath(); + + FilesystemNode save(myDefaultSaveDir); + if(!save.isDirectory()) + save.makeDir(); + myDefaultSaveDir = node.getPath(); + + FilesystemNode load(myDefaultLoadDir); + if(!load.isDirectory()) + load.makeDir(); + myDefaultLoadDir = node.getPath(); + logMessage("Loading config options ...", 2); mySettings->load(configFile(), options); } @@ -241,22 +264,6 @@ void OSystem::setConfigPaths() #endif } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void OSystem::setBaseDir(const string& basedir) -{ - FilesystemNode node(basedir); - if(!node.isDirectory()) - node.makeDir(); - - myBaseDir = node.getPath(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void OSystem::setConfigFile(const string& file) -{ - myConfigFile = FilesystemNode(file).getPath(); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBInitStatus OSystem::createFrameBuffer() { @@ -734,3 +741,4 @@ void OSystem::mainLoop() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string OSystem::ourOverrideBaseDir = ""; +bool OSystem::ourOverrideBaseDirWithApp = false; diff --git a/src/emucore/OSystem.hxx b/src/emucore/OSystem.hxx index 37da00d17..5a2d6c99d 100644 --- a/src/emucore/OSystem.hxx +++ b/src/emucore/OSystem.hxx @@ -282,6 +282,13 @@ class OSystem */ const FilesystemNode& romFile() const { return myRomFile; } + /** + The default locations for saving and loading various files that + don't already have a specific location. + */ + const string& defaultSaveDir() const { return myDefaultSaveDir; } + const string& defaultLoadDir() const { return myDefaultLoadDir; } + /** Open the given ROM and return an array containing its contents. Also, the properties database is updated with a valid ROM name @@ -391,13 +398,12 @@ class OSystem derived classes are free to ignore this, as some can't use an alternate base directory. - If the default path is used, this indicates to attempt to use the - application directory directly. Again, this is not supported on - all systems, so it may be simply ignored. + Alternatively, attempt to use the application directory directly. + Again, this is not supported on all systems, so it may be simply + ignored. */ - static void overrideBaseDir(const string& path = "USE_APP_DIR") { - ourOverrideBaseDir = path; - } + static void overrideBaseDir(const string& path) { ourOverrideBaseDir = path; } + static void overrideBaseDirWithApp() { ourOverrideBaseDirWithApp = true; } public: ////////////////////////////////////////////////////////////////////// @@ -431,27 +437,30 @@ class OSystem */ virtual void stateChanged(EventHandlerState state) { } - /** - Returns the default save and load paths for various files - (snapshots, disassembly, roms, etc). Since this varies greatly - among different systems and is the one directory that most end-users - care about (vs. config file stuff that usually isn't user-modifiable), - we create a special method for it. - */ - virtual string defaultSaveDir() const { return string("~") + BSPF::PATH_SEPARATOR; } - virtual string defaultLoadDir() const { return string("~") + BSPF::PATH_SEPARATOR; } - protected: + ////////////////////////////////////////////////////////////////////// + // The following methods are system-specific and *must* be + // implemented in derived classes. + ////////////////////////////////////////////////////////////////////// /** - Set the base directory for all Stella files (these files may be - located in other places through settings). - */ - void setBaseDir(const string& basedir); + Determine the base directory and main configuration file from the + derived class. It can also use hints, as described below. - /** - Set the locations of config file + @param basedir The base directory for all configuration files + @param cfgfile The fully qualified pathname of the config file + (including the base directory) + @param savedir The default directory to save various other files + @param loaddir The default directory to load various other files + @param useappdir A hint that the base dir should be set to the + app directory; not all ports can do this, so + they are free to ignore it + @param usedir A hint that the base dir should be set to this + parameter; not all ports can do this, so + they are free to ignore it */ - void setConfigFile(const string& file); + virtual void getBaseDirAndConfig(string& basedir, string& cfgfile, + string& savedir, string& loaddir, + bool useappdir, const string& usedir) = 0; protected: // Pointer to the EventHandler object @@ -519,11 +528,6 @@ class OSystem // Indicates whether to stop the main loop bool myQuitLoop; - // If not empty, a hint for derived classes to use this as the - // base directory (where all settings are stored) - // Derived classes are free to ignore it and use their own defaults - static string ourOverrideBaseDir; - private: string myBaseDir; string myStateDir; @@ -531,6 +535,8 @@ class OSystem string mySnapshotLoadDir; string myNVRamDir; string myCfgDir; + string myDefaultSaveDir; + string myDefaultLoadDir; string myCheatFile; string myConfigFile; @@ -545,6 +551,12 @@ class OSystem FpsMeter myFpsMeter; + // If not empty, a hint for derived classes to use this as the + // base directory (where all settings are stored) + // Derived classes are free to ignore it and use their own defaults + static string ourOverrideBaseDir; + static bool ourOverrideBaseDirWithApp; + private: /** Creates the various framebuffers/renderers available in this system. diff --git a/src/unix/OSystemUNIX.cxx b/src/unix/OSystemUNIX.cxx index cbe9ea05f..e2b093a58 100644 --- a/src/unix/OSystemUNIX.cxx +++ b/src/unix/OSystemUNIX.cxx @@ -21,36 +21,35 @@ #include "Version.hxx" #include "OSystemUNIX.hxx" -/** - Each derived class is responsible for calling the following methods - in its constructor: - - setBaseDir() - setConfigFile() - - See OSystem.hxx for a further explanation -*/ - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -OSystemUNIX::OSystemUNIX() - : OSystem() +void OSystemUNIX::getBaseDirAndConfig(string& basedir, string& cfgfile, + string& savedir, string& loaddir, + bool useappdir, const string& usedir) { // Use XDG_CONFIG_HOME if defined, otherwise use the default const char* configDir = getenv("XDG_CONFIG_HOME"); if(configDir == nullptr) configDir = "~/.config"; + basedir = string(configDir) + "/stella"; + savedir = loaddir = "~/"; - string stellaDir = string(configDir) + "/stella"; - setBaseDir(stellaDir); + // Check to see if basedir overrides are active + if(useappdir) + cout << "ERROR: base dir in app folder not supported" << endl; + else if(usedir != "") + { + basedir = FilesystemNode(usedir).getPath(); + savedir = loaddir = basedir; + } // (Currently) non-documented alternative for using version-specific // config file ostringstream buf; - buf << stellaDir << "/stellarc" << "-" << STELLA_VERSION; + buf << basedir << "/stellarc" << "-" << STELLA_VERSION; // Use version-specific config file only if it already exists FilesystemNode altConfigFile(buf.str()); if(altConfigFile.exists() && altConfigFile.isWritable()) - setConfigFile(altConfigFile.getPath()); + cfgfile = altConfigFile.getPath(); else - setConfigFile(stellaDir + "/stellarc"); + cfgfile = basedir + "/stellarc"; } diff --git a/src/unix/OSystemUNIX.hxx b/src/unix/OSystemUNIX.hxx index eeec50c12..8d8bbf2f5 100644 --- a/src/unix/OSystemUNIX.hxx +++ b/src/unix/OSystemUNIX.hxx @@ -21,19 +21,39 @@ #include "OSystem.hxx" /** - This class defines UNIX-like OS's (Linux) system specific settings. + This class defines an OSystem object for UNIX-like OS's (Linux). + It is responsible for completely implementing getBaseDirAndConfig(), + to set the base directory, config file location, and various other + save/load locations. @author Stephen Anthony */ class OSystemUNIX : public OSystem { public: - /** - Create a new UNIX-specific operating system object - */ - OSystemUNIX(); + OSystemUNIX() = default; virtual ~OSystemUNIX() = default; + /** + Determine the base directory and main configuration file from the + derived class. It can also use hints, as described below. + + @param basedir The base directory for all configuration files + @param cfgfile The fully qualified pathname of the config file + (including the base directory) + @param savedir The default directory to save various other files + @param loaddir The default directory to load various other files + @param useappdir A hint that the base dir should be set to the + app directory; not all ports can do this, so + they are free to ignore it + @param usedir A hint that the base dir should be set to this + parameter; not all ports can do this, so + they are free to ignore it + */ + void getBaseDirAndConfig(string& basedir, string& cfgfile, + string& savedir, string& loaddir, + bool useappdir, const string& usedir) override; + private: // Following constructors and assignment operators not supported OSystemUNIX(const OSystemUNIX&) = delete; diff --git a/src/windows/OSystemWINDOWS.cxx b/src/windows/OSystemWINDOWS.cxx index 9a73ddad2..f5ab95765 100644 --- a/src/windows/OSystemWINDOWS.cxx +++ b/src/windows/OSystemWINDOWS.cxx @@ -21,22 +21,12 @@ #include "OSystemWINDOWS.hxx" -/** - Each derived class is responsible for calling the following methods - in its constructor: - - setBaseDir() - setConfigFile() - - See OSystem.hxx for a further explanation -*/ - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -OSystemWINDOWS::OSystemWINDOWS() - : OSystem() +void OSystemWINDOWS::getBaseDirAndConfig(string& basedir, string& cfgfile, + string& savedir, string& loaddir, + bool useappdir, const string& usedir) { - string basedir = ""; - +#if 0 // Check if the base directory should be overridden // Shouldn't normally be necessary, but is useful for those people that // don't want to clutter their 'My Documents' folder @@ -58,6 +48,7 @@ OSystemWINDOWS::OSystemWINDOWS() if(basedir != "") overrideBasedir = true; } } +#endif // If basedir hasn't been specified, use the 'home' directory if(!overrideBasedir) @@ -75,15 +66,9 @@ OSystemWINDOWS::OSystemWINDOWS() basedir = ".\\"; // otherwise, default to current directory } - setBaseDir(basedir); - setConfigFile(basedir + "stella.ini"); - - // Create default save/load dir - FilesystemNode node(defaultSaveDir()); - if(!node.exists()) - node.makeDir(); + cfgfile = basedir + "stella.ini"; } - +#if 0 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string OSystemWINDOWS::defaultSaveDir() const { @@ -97,3 +82,4 @@ string OSystemWINDOWS::defaultLoadDir() const { return defaultSaveDir(); } +#endif diff --git a/src/windows/OSystemWINDOWS.hxx b/src/windows/OSystemWINDOWS.hxx index c4d10d2f3..70bab08a0 100644 --- a/src/windows/OSystemWINDOWS.hxx +++ b/src/windows/OSystemWINDOWS.hxx @@ -21,23 +21,38 @@ #include "OSystem.hxx" /** - This class defines Windows system specific settings. + This class defines an OSystem object for Windows OS's. + It is responsible for completely implementing getBaseDirAndConfig(), + to set the base directory, config file location, and various other + save/load locations. + + @author Stephen Anthony */ class OSystemWINDOWS : public OSystem { public: - /** - Create a new WINDOWS operating system object - */ - OSystemWINDOWS(); + OSystemWINDOWS() = default; virtual ~OSystemWINDOWS() = default; - public: /** - Returns the default paths for loading/saving files. + Determine the base directory and main configuration file from the + derived class. It can also use hints, as described below. + + @param basedir The base directory for all configuration files + @param cfgfile The fully qualified pathname of the config file + (including the base directory) + @param savedir The default directory to save various other files + @param loaddir The default directory to load various other files + @param useappdir A hint that the base dir should be set to the + app directory; not all ports can do this, so + they are free to ignore it + @param usedir A hint that the base dir should be set to this + parameter; not all ports can do this, so + they are free to ignore it */ - string defaultSaveDir() const override; - string defaultLoadDir() const override; + void getBaseDirAndConfig(string& basedir, string& cfgfile, + string& savedir, string& loaddir, + bool useappdir, const string& usedir) override; private: // Following constructors and assignment operators not supported