From 3628629007e4b97b7b634d0545e3acd474c7708b Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 15 Apr 2006 13:12:03 +0000 Subject: - Replaced ConfigManager::_globalDomains by _appDomain (we don't support multiple global domains anymore) - Restructured parts of the ConfigManager to be more consistent and a bit easier to understand - Introduced ConfigManager::getDomain, potentially useful for code that needs to edit a specific domain (like the option dialogs) - Allow passing an empty string to ConfigManager::setActiveDomain(), to reset the active domain - Discard all transient config options (i.e. mostly command line settings) when entering the launcher, and after an engine exits - Introduced various hidden easter bugs. Happy easter, and have fun searching! svn-id: r21906 --- base/engine.cpp | 25 +++- base/gameDetector.cpp | 4 + base/main.cpp | 19 ++- common/config-manager.cpp | 317 +++++++++++++++++++++++++++------------------- common/config-manager.h | 67 +++++++--- 5 files changed, 274 insertions(+), 158 deletions(-) diff --git a/base/engine.cpp b/base/engine.cpp index fb46949050..a3767d1bf4 100644 --- a/base/engine.cpp +++ b/base/engine.cpp @@ -56,12 +56,18 @@ Engine::~Engine() { } void Engine::initCommonGFX(GameDetector &detector, bool defaultTo1XScaler) { + const Common::ConfigManager::Domain *transientDomain = ConfMan.getDomain(Common::ConfigManager::kTransientDomain); + const Common::ConfigManager::Domain *gameDomain = ConfMan.getDomain(detector._targetName); + + assert(transientDomain); + const bool useDefaultGraphicsMode = - !ConfMan.hasKey("gfx_mode", Common::ConfigManager::kTransientDomain) && + !transientDomain->contains("gfx_mode") && ( - !ConfMan.hasKey("gfx_mode", detector._targetName) || - !scumm_stricmp(ConfMan.get("gfx_mode", detector._targetName).c_str(), "normal") || - !scumm_stricmp(ConfMan.get("gfx_mode", detector._targetName).c_str(), "default") + !gameDomain || + !gameDomain->contains("gfx_mode") || + !scumm_stricmp(gameDomain->get("gfx_mode").c_str(), "normal") || + !scumm_stricmp(gameDomain->get("gfx_mode").c_str(), "default") ); // See if the game should default to 1x scaler @@ -77,12 +83,19 @@ void Engine::initCommonGFX(GameDetector &detector, bool defaultTo1XScaler) { } } + // Note: The following code deals with the fullscreen / ASR settings. This + // is a bit tricky, because there are three ways the user can affect these + // settings: Via the config file, via the command line, and via in-game + // hotkeys. + // Any global or command line settings already have been applied at the time + // we get here. Hence we only do something + // (De)activate aspect-ratio correction as determined by the config settings - if (ConfMan.hasKey("aspect_ratio", detector._targetName)) + if (gameDomain && gameDomain->contains("aspect_ratio")) _system->setFeatureState(OSystem::kFeatureAspectRatioCorrection, ConfMan.getBool("aspect_ratio")); // (De)activate fullscreen mode as determined by the config settings - if (ConfMan.hasKey("fullscreen", detector._targetName)) + if (gameDomain && gameDomain->contains("fullscreen")) _system->setFeatureState(OSystem::kFeatureFullscreenMode, ConfMan.getBool("fullscreen")); } diff --git a/base/gameDetector.cpp b/base/gameDetector.cpp index b21ccffb6b..fe762b4994 100644 --- a/base/gameDetector.cpp +++ b/base/gameDetector.cpp @@ -602,6 +602,10 @@ void GameDetector::setTarget(const String &target) { _gameid = ConfMan.get("gameid"); else _gameid = _targetName; + + // TODO: In the future, simply insert the gameid into the transient domain. + // That way, all code (including backends) can reliably access it. + //ConfMan.set("gameid", _gameid, Common::ConfigManager::kTransientDomain); } bool GameDetector::detectMain() { diff --git a/base/main.cpp b/base/main.cpp index fabcce5b89..afa163625c 100644 --- a/base/main.cpp +++ b/base/main.cpp @@ -314,8 +314,15 @@ extern "C" int scummvm_main(int argc, char *argv[]) { setupDummyPalette(system); // Unless a game was specified, show the launcher dialog - if (detector._targetName.empty()) + if (detector._targetName.empty()) { + // Discard any command line options. Those that affect the graphics + // mode etc. already have should have been handled by the backend at + // this point. And the others (like bootparam etc.) should not + // blindly be passed to the first game launched from the launcher. + ConfMan.getDomain(Common::ConfigManager::kTransientDomain)->clear(); + running = launcherDialog(detector, system); + } // FIXME: We're now looping the launcher. This, of course, doesn't // work as well as it should. In theory everything should be destroyed @@ -331,11 +338,11 @@ extern "C" int scummvm_main(int argc, char *argv[]) { if (result == 0) break; - // There are some command-line options that it's - // unlikely that we want to preserve now that we're - // going to start a different game. - ConfMan.removeKey("boot_param", ConfMan.kTransientDomain); - ConfMan.removeKey("save_slot", ConfMan.kTransientDomain); + // Discard any command line options. It's unlikely that the user + // wanted to apply them to *all* games ever launched. + ConfMan.getDomain(Common::ConfigManager::kTransientDomain)->clear(); + + // TODO: Reset the game detector fully // PluginManager::instance().unloadPlugins(); PluginManager::instance().loadPlugins(); diff --git a/common/config-manager.cpp b/common/config-manager.cpp index bf87fb3b71..5472b2b4cf 100644 --- a/common/config-manager.cpp +++ b/common/config-manager.cpp @@ -54,8 +54,8 @@ static char *rtrim(char *t) { return t; } -static bool isValidDomainName(const Common::String &domain) { - const char *p = domain.c_str(); +static bool isValidDomainName(const Common::String &domName) { + const char *p = domName.c_str(); while (*p && (isalnum(*p) || *p == '-' || *p == '_')) p++; return *p == 0; @@ -68,25 +68,17 @@ namespace Common { const String ConfigManager::kApplicationDomain("scummvm"); const String ConfigManager::kTransientDomain("__TRANSIENT"); -const String trueStr("true"); -const String falseStr("false"); - #else const char *ConfigManager::kApplicationDomain = "scummvm"; const char *ConfigManager::kTransientDomain = "__TRANSIENT"; -const char *trueStr = "true"; -const char *falseStr = "false"; - #endif #pragma mark - ConfigManager::ConfigManager() { - // Ensure the global domain(s) are setup. - _globalDomains[kApplicationDomain]; } @@ -121,13 +113,10 @@ void ConfigManager::loadDefaultConfigFile() { } void ConfigManager::loadConfigFile(const String &filename) { - _globalDomains.clear(); + _appDomain.clear(); _gameDomains.clear(); _transientDomain.clear(); - // Ensure the global domain(s) are setup. - _globalDomains[kApplicationDomain]; - _filename = filename; _domainSaveOrder.clear(); loadFile(_filename); @@ -181,8 +170,8 @@ void ConfigManager::loadFile(const String &filename) { } // Store domain comment - if (_globalDomains.contains(domain)) { - _globalDomains[domain].setDomainComment(comment); + if (domain == kApplicationDomain) { + _appDomain.setDomainComment(comment); } else { _gameDomains[domain].setDomainComment(comment); } @@ -212,8 +201,8 @@ void ConfigManager::loadFile(const String &filename) { set(key, value, domain); // Store comment - if (_globalDomains.contains(domain)) { - _globalDomains[domain].setKVComment(key, comment); + if (domain == kApplicationDomain) { + _appDomain.setKVComment(key, comment); } else { _gameDomains[domain].setKVComment(key, comment); } @@ -239,8 +228,8 @@ void ConfigManager::flushToDisk() { // are not present anymore. StringList::const_iterator i; for (i = _domainSaveOrder.begin(); i != _domainSaveOrder.end(); ++i) { - if (_globalDomains.contains(*i)) { - writeDomain(cfg_file, *i, _globalDomains[*i]); + if (kApplicationDomain == *i) { + writeDomain(cfg_file, *i, _appDomain); } else if (_gameDomains.contains(*i)) { writeDomain(cfg_file, *i, _gameDomains[*i]); } @@ -248,13 +237,9 @@ void ConfigManager::flushToDisk() { DomainMap::const_iterator d; - // Now write the global domains which weren't written yet - for (d = _globalDomains.begin(); d != _globalDomains.end(); ++d) { - if (!_domainSaveOrder.contains(d->_key)) - writeDomain(cfg_file, d->_key, d->_value); - } - - // Finally write the remaining game domains + // Now write the domains which haven't been written yet + if (!_domainSaveOrder.contains(kApplicationDomain)) + writeDomain(cfg_file, kApplicationDomain, _appDomain); for (d = _gameDomains.begin(); d != _gameDomains.end(); ++d) { if (!_domainSaveOrder.contains(d->_key)) writeDomain(cfg_file, d->_key, d->_value); @@ -295,91 +280,142 @@ void ConfigManager::writeDomain(FILE *file, const String &name, const Domain &do fprintf(file, "\n"); } + +#pragma mark - + + +const ConfigManager::Domain *ConfigManager::getDomain(const String &domName) const { + assert(!domName.empty()); + assert(isValidDomainName(domName)); + + if (domName == kTransientDomain) + return &_transientDomain; + if (domName == kApplicationDomain) + return &_appDomain; + if (_gameDomains.contains(domName)) + return &_gameDomains[domName]; + + return 0; +} + +ConfigManager::Domain *ConfigManager::getDomain(const String &domName) { + assert(!domName.empty()); + assert(isValidDomainName(domName)); + + if (domName == kTransientDomain) + return &_transientDomain; + if (domName == kApplicationDomain) + return &_appDomain; + if (_gameDomains.contains(domName)) + return &_gameDomains[domName]; + + return 0; +} + + #pragma mark - bool ConfigManager::hasKey(const String &key) const { // Search the domains in the following order: - // 1) Transient domain - // 2) Active game domain (if any) - // 3) All global domains + // 1) the transient domain, + // 2) the active game domain (if any), + // 3) the application domain. // The defaults domain is explicitly *not* checked. if (_transientDomain.contains(key)) return true; - if (!_activeDomain.empty() && _gameDomains[_activeDomain].contains(key)) + if (_activeDomain && _activeDomain->contains(key)) return true; - DomainMap::const_iterator iter; - for (iter = _globalDomains.begin(); iter != _globalDomains.end(); ++iter) { - if (iter->_value.contains(key)) - return true; - } + if (_appDomain.contains(key)) + return true; return false; } -bool ConfigManager::hasKey(const String &key, const String &dom) const { - assert(!dom.empty()); - assert(isValidDomainName(dom)); +bool ConfigManager::hasKey(const String &key, const String &domName) const { + // FIXME: For now we continue to allow empty domName to indicate + // "use 'default' domain". This is mainly needed for the SCUMM ConfigDialog + // and should be removed ASAP. + if (domName.empty()) + return hasKey(key); - if (dom == kTransientDomain) - return _transientDomain.contains(key); - if (_gameDomains.contains(dom)) - return _gameDomains[dom].contains(key); - if (_globalDomains.contains(dom)) - return _globalDomains[dom].contains(key); + const Domain *domain = getDomain(domName); - return false; + if (!domain) + return false; + return domain->contains(key); } -void ConfigManager::removeKey(const String &key, const String &dom) { - assert(!dom.empty()); - assert(isValidDomainName(dom)); +void ConfigManager::removeKey(const String &key, const String &domName) { + Domain *domain = getDomain(domName); - if (dom == kTransientDomain) - _transientDomain.erase(key); - else if (_gameDomains.contains(dom)) - _gameDomains[dom].erase(key); - else if (_globalDomains.contains(dom)) - _globalDomains[dom].erase(key); - else - error("Removing key '%s' from non-existent domain '%s'", key.c_str(), dom.c_str()); + if (!domain) + error("ConfigManager::removeKey(%s, %s) called on non-existent domain", + key.c_str(), domName.c_str()); + + domain->erase(key); } #pragma mark - -const String & ConfigManager::get(const String &key, const String &domain) const { - assert(isValidDomainName(domain)); +const String & ConfigManager::get(const String &key) const { + if (_transientDomain.contains(key)) + return _transientDomain[key]; + else if (_activeDomain && _activeDomain->contains(key)) + return (*_activeDomain)[key]; + else if (_appDomain.contains(key)) + return _appDomain[key]; + else if (_defaultsDomain.contains(key)) + return _defaultsDomain[key]; - // Search the domains in the following order: - // 1) Transient domain - // 2) Active game domain (if any) - // 3) All global domains - // 4) The defaults +#if !(defined(PALMOS_ARM) || defined(PALMOS_DEBUG) || defined(__GP32__)) + return String::emptyString; +#else + return ConfMan._emptyString; +#endif +} - if ((domain.empty() || domain == kTransientDomain) && _transientDomain.contains(key)) - return _transientDomain[key]; +const String & ConfigManager::get(const String &key, const String &domName) const { + // FIXME: For now we continue to allow empty domName to indicate + // "use 'default' domain". This is mainly needed for the SCUMM ConfigDialog + // and should be removed ASAP. + if (domName.empty()) + return get(key); - const String &dom = domain.empty() ? _activeDomain : domain; + const Domain *domain = getDomain(domName); - if (!dom.empty() && _gameDomains.contains(dom) && _gameDomains[dom].contains(key)) - return _gameDomains[dom][key]; + if (!domain) + error("ConfigManager::get(%s,%s) called on non-existent domain", + key.c_str(), domName.c_str()); - DomainMap::const_iterator iter; - for (iter = _globalDomains.begin(); iter != _globalDomains.end(); ++iter) { - if (iter->_value.contains(key)) - return iter->_value[key]; - } + if (domain->contains(key)) + return (*domain)[key]; return _defaultsDomain.get(key); + + if (!domain->contains(key)) { +#if 1 +#if !(defined(PALMOS_ARM) || defined(PALMOS_DEBUG) || defined(__GP32__)) + return String::emptyString; +#else + return ConfMan._emptyString; +#endif +#else + error("ConfigManager::get(%s,%s) called on non-existent key", + key.c_str(), domName.c_str()); +#endif + } + + return (*domain)[key]; } -int ConfigManager::getInt(const String &key, const String &dom) const { - String value(get(key, dom)); +int ConfigManager::getInt(const String &key, const String &domName) const { + String value(get(key, domName)); char *errpos; // For now, be tolerant against missing config keys. Strictly spoken, it is @@ -390,67 +426,91 @@ int ConfigManager::getInt(const String &key, const String &dom) const { int ivalue = (int)strtol(value.c_str(), &errpos, 10); if (value.c_str() == errpos) - error("Config file buggy: '%s' is not a valid integer", errpos); + error("ConfigManager::getInt(%s,%s): '%s' is not a valid integer", + key.c_str(), domName.c_str(), errpos); return ivalue; } -bool ConfigManager::getBool(const String &key, const String &dom) const { - String value(get(key, dom)); +bool ConfigManager::getBool(const String &key, const String &domName) const { + String value(get(key, domName)); - if ((value == trueStr) || (value == "yes") || (value == "1")) + if ((value == "true") || (value == "yes") || (value == "1")) return true; - if ((value == falseStr) || (value == "no") || (value == "0")) + if ((value == "false") || (value == "no") || (value == "0")) return false; - error("Config file buggy: '%s' is not a valid bool", value.c_str()); + error("ConfigManager::getBool(%s,%s): '%s' is not a valid bool", + key.c_str(), domName.c_str(), value.c_str()); } #pragma mark - -void ConfigManager::set(const String &key, const String &value, const String &dom) { - assert(isValidDomainName(dom)); - if (dom.empty()) { - // Remove the transient domain value - _transientDomain.erase(key); - - if (_activeDomain.empty()) - _globalDomains[kApplicationDomain][key] = value; - else - _gameDomains[_activeDomain][key] = value; +void ConfigManager::set(const String &key, const String &value) { + // Remove the transient domain value, if any. + _transientDomain.erase(key); - } else { - - if (dom == kTransientDomain) - _transientDomain[key] = value; - else { - if (_globalDomains.contains(dom)) { - _globalDomains[dom][key] = value; - if (_activeDomain.empty() || !_gameDomains[_activeDomain].contains(key)) - _transientDomain.erase(key); - } else { - _gameDomains[dom][key] = value; - if (dom == _activeDomain) - _transientDomain.erase(key); - } + // Write the new key/value pair into the active domain, resp. into + // the application domain if no game domain is active. + if (_activeDomain) + (*_activeDomain)[key] = value; + else + _appDomain[key] = value; +} + +void ConfigManager::set(const String &key, const String &value, const String &domName) { + // FIXME: For now we continue to allow empty domName to indicate + // "use 'default' domain". This is mainly needed for the SCUMM ConfigDialog + // and should be removed ASAP. + if (domName.empty()) + return set(key, value); + + Domain *domain = getDomain(domName); + + if (!domain) + error("ConfigManager::set(%s,%s,%s) called on non-existent domain", + key.c_str(), value.c_str(), domName.c_str()); + + (*domain)[key] = value; + + // TODO/FIXME: We used to erase the given key from the transient domain + // here. Do we still want to do that? + // It was probably there to simplify the options dialogs code: + // Imagine you are editing the current options (via the SCUMM ConfigDialog, + // for example). If you edit the game domain for that, but a matching + // entry in the transient domain is present, than your changes may not take + // effect. So you want to remove the key from the transient domain before + // adding it to the active domain. + // But doing this here seems rather evil... need to comb the options dialog + // code to find out if it's still necessary, and if that's the case, how + // to replace it in a clean fashion... +/* + if (domName == kTransientDomain) + _transientDomain[key] = value; + else { + if (domName == kApplicationDomain) { + _appDomain[key] = value; + if (_activeDomainName.empty() || !_gameDomains[_activeDomainName].contains(key)) + _transientDomain.erase(key); + } else { + _gameDomains[domName][key] = value; + if (domName == _activeDomainName) + _transientDomain.erase(key); } } +*/ } -void ConfigManager::set(const String &key, const char *value, const String &dom) { - set(key, String(value), dom); -} - -void ConfigManager::set(const String &key, int value, const String &dom) { +void ConfigManager::set(const String &key, int value, const String &domName) { char tmp[128]; snprintf(tmp, sizeof(tmp), "%i", value); - set(key, String(tmp), dom); + set(key, String(tmp), domName); } -void ConfigManager::set(const String &key, bool value, const String &dom) { - set(key, value ? trueStr : falseStr, dom); +void ConfigManager::set(const String &key, bool value, const String &domName) { + set(key, String(value ? "true" : "false"), domName); } @@ -472,24 +532,27 @@ void ConfigManager::registerDefault(const String &key, int value) { } void ConfigManager::registerDefault(const String &key, bool value) { - registerDefault(key, value ? trueStr : falseStr); + registerDefault(key, value ? "true" : "false"); } #pragma mark - -void ConfigManager::setActiveDomain(const String &domain) { - assert(!domain.empty()); - assert(isValidDomainName(domain)); - _activeDomain = domain; - _gameDomains[domain]; +void ConfigManager::setActiveDomain(const String &domName) { + if (domName.empty()) { + _activeDomain = 0; + } else { + assert(isValidDomainName(domName)); + _activeDomain = & _gameDomains[domName]; + } + _activeDomainName = domName; } -void ConfigManager::removeGameDomain(const String &domain) { - assert(!domain.empty()); - assert(isValidDomainName(domain)); - _gameDomains.erase(domain); +void ConfigManager::removeGameDomain(const String &domName) { + assert(!domName.empty()); + assert(isValidDomainName(domName)); + _gameDomains.erase(domName); } void ConfigManager::renameGameDomain(const String &oldName, const String &newName) { @@ -511,9 +574,9 @@ void ConfigManager::renameGameDomain(const String &oldName, const String &newNam _gameDomains.erase(oldName); } -bool ConfigManager::hasGameDomain(const String &domain) const { - assert(!domain.empty()); - return isValidDomainName(domain) && _gameDomains.contains(domain); +bool ConfigManager::hasGameDomain(const String &domName) const { + assert(!domName.empty()); + return isValidDomainName(domName) && _gameDomains.contains(domName); } diff --git a/common/config-manager.h b/common/config-manager.h index 8793a35db8..10313f64d5 100644 --- a/common/config-manager.h +++ b/common/config-manager.h @@ -92,37 +92,64 @@ public: void loadDefaultConfigFile(); void loadConfigFile(const String &filename); + /** + * Retrieve the config domain with the given name. + * @param domName the name of the domain to retrieve + * @return pointer to the domain, or 0 if the domain doesn't exist. + */ + Domain * getDomain(const String &domName); + const Domain * getDomain(const String &domName) const; + + + // + // Generic access methods: No domain specified, use the values from the + // various domains in the order of their priority. + // + bool hasKey(const String &key) const; - bool hasKey(const String &key, const String &dom) const; - - void removeKey(const String &key, const String &dom); + const String & get(const String &key) const; + void set(const String &key, const String &value); + +#if 1 + // + // Domain specific access methods: Acces *one specific* domain and modify it. + // TODO: I'd like to get rid of most of those if possible, or at least reduce + // their usage, by using getDomain as often as possible. For example in the + // options dialog code... + // + + bool hasKey(const String &key, const String &domName) const; + const String & get(const String &key, const String &domName) const; + void set(const String &key, const String &value, const String &domName); + + void removeKey(const String &key, const String &domName); +#endif - const String & get(const String &key, const String &dom = String::emptyString) const; - int getInt(const String &key, const String &dom = String::emptyString) const; - bool getBool(const String &key, const String &dom = String::emptyString) const; + // + // Some additional convenience accessors. + // + int getInt(const String &key, const String &domName = String::emptyString) const; + bool getBool(const String &key, const String &domName = String::emptyString) const; + void set(const String &key, int value, const String &domName = String::emptyString); + void set(const String &key, bool value, const String &domName = String::emptyString); - void set(const String &key, const String &value, const String &dom = String::emptyString); - void set(const String &key, const char *value, const String &dom = String::emptyString); - void set(const String &key, int value, const String &dom = String::emptyString); - void set(const String &key, bool value, const String &dom = String::emptyString); void registerDefault(const String &key, const String &value); void registerDefault(const String &key, const char *value); void registerDefault(const String &key, int value); void registerDefault(const String &key, bool value); -// ... void flushToDisk(); - void setActiveDomain(const String &domain); - const String & getActiveDomain() const { return _activeDomain; } + void setActiveDomain(const String &domName); + const String & getActiveDomain() const { return _activeDomainName; } -// void addDomain(const String &name); - void removeGameDomain(const String &name); +// void addDomain(const String &domName); + void removeGameDomain(const String &domName); void renameGameDomain(const String &oldName, const String &newName); - bool hasGameDomain(const String &domain) const; + bool hasGameDomain(const String &domName) const; const DomainMap & getGameDomains() const { return _gameDomains; } - + /* TODO: Callback/change notification system typedef void (*ConfigCallback)(const ConstString &key, void *refCon); @@ -140,12 +167,14 @@ private: Domain _transientDomain; DomainMap _gameDomains; - DomainMap _globalDomains; + Domain _appDomain; Domain _defaultsDomain; StringList _domainSaveOrder; - String _activeDomain; + String _activeDomainName; + Domain * _activeDomain; + String _filename; }; -- cgit v1.2.3