2007-05-30 21:56:52 +00:00
|
|
|
/* ScummVM - Graphic Adventure Engine
|
|
|
|
*
|
|
|
|
* ScummVM is the legal property of its developers, whose names
|
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
|
|
* file distributed with this source distribution.
|
2003-10-08 21:59:23 +00:00
|
|
|
*
|
|
|
|
* This program 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 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
* This program 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 this program; if not, write to the Free Software
|
2005-10-18 01:30:26 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2003-10-08 21:59:23 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "common/config-manager.h"
|
2011-04-24 08:34:27 +00:00
|
|
|
#include "common/debug.h"
|
2005-04-22 18:10:02 +00:00
|
|
|
#include "common/file.h"
|
2008-10-23 07:59:10 +00:00
|
|
|
#include "common/fs.h"
|
2008-08-03 16:54:18 +00:00
|
|
|
#include "common/system.h"
|
2011-04-24 08:34:27 +00:00
|
|
|
#include "common/textconsole.h"
|
2003-10-08 21:59:23 +00:00
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
static bool isValidDomainName(const Common::String &domName) {
|
|
|
|
const char *p = domName.c_str();
|
2012-02-20 15:03:39 +00:00
|
|
|
while (*p && (Common::isAlnum(*p) || *p == '-' || *p == '_'))
|
2005-02-22 18:11:36 +00:00
|
|
|
p++;
|
|
|
|
return *p == 0;
|
|
|
|
}
|
|
|
|
|
2003-10-08 21:59:23 +00:00
|
|
|
namespace Common {
|
|
|
|
|
2011-06-27 23:06:23 +00:00
|
|
|
DECLARE_SINGLETON(ConfigManager);
|
|
|
|
|
2011-08-06 08:01:34 +00:00
|
|
|
char const *const ConfigManager::kApplicationDomain = "scummvm";
|
|
|
|
char const *const ConfigManager::kTransientDomain = "__TRANSIENT";
|
2005-09-03 16:08:27 +00:00
|
|
|
|
2009-05-10 17:33:31 +00:00
|
|
|
#ifdef ENABLE_KEYMAPPER
|
2011-08-06 08:01:34 +00:00
|
|
|
char const *const ConfigManager::kKeymapperDomain = "keymapper";
|
2009-05-10 17:33:31 +00:00
|
|
|
#endif
|
|
|
|
|
2003-10-08 21:59:23 +00:00
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
|
2009-12-30 23:01:36 +00:00
|
|
|
ConfigManager::ConfigManager() : _activeDomain(0) {
|
2004-12-25 19:03:13 +00:00
|
|
|
}
|
|
|
|
|
2010-11-15 13:37:06 +00:00
|
|
|
void ConfigManager::defragment() {
|
|
|
|
ConfigManager *newInstance = new ConfigManager();
|
|
|
|
newInstance->copyFrom(*_singleton);
|
|
|
|
delete _singleton;
|
|
|
|
_singleton = newInstance;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConfigManager::copyFrom(ConfigManager &source) {
|
|
|
|
_transientDomain = source._transientDomain;
|
|
|
|
_gameDomains = source._gameDomains;
|
2010-12-29 15:16:31 +00:00
|
|
|
_miscDomains = source._miscDomains;
|
2010-11-15 13:37:06 +00:00
|
|
|
_appDomain = source._appDomain;
|
|
|
|
_defaultsDomain = source._defaultsDomain;
|
|
|
|
#ifdef ENABLE_KEYMAPPER
|
|
|
|
_keymapperDomain = source._keymapperDomain;
|
|
|
|
#endif
|
|
|
|
_domainSaveOrder = source._domainSaveOrder;
|
|
|
|
_activeDomainName = source._activeDomainName;
|
|
|
|
_activeDomain = &_gameDomains[_activeDomainName];
|
|
|
|
_filename = source._filename;
|
|
|
|
}
|
|
|
|
|
2003-10-08 21:59:23 +00:00
|
|
|
|
2004-12-25 19:03:13 +00:00
|
|
|
void ConfigManager::loadDefaultConfigFile() {
|
2008-08-03 16:54:18 +00:00
|
|
|
// Open the default config file
|
2009-01-29 22:09:06 +00:00
|
|
|
assert(g_system);
|
2009-01-23 03:30:40 +00:00
|
|
|
SeekableReadStream *stream = g_system->createConfigReadStream();
|
2011-01-18 21:13:47 +00:00
|
|
|
_filename.clear(); // clear the filename to indicate that we are using the default config file
|
2008-07-30 15:44:34 +00:00
|
|
|
|
2008-08-09 22:42:03 +00:00
|
|
|
// ... load it, if available ...
|
2010-04-13 10:08:17 +00:00
|
|
|
if (stream) {
|
2008-08-09 22:42:03 +00:00
|
|
|
loadFromStream(*stream);
|
2008-12-22 11:22:15 +00:00
|
|
|
|
2010-04-13 10:08:17 +00:00
|
|
|
// ... and close it again.
|
|
|
|
delete stream;
|
2005-10-08 19:10:05 +00:00
|
|
|
|
2010-04-13 10:08:17 +00:00
|
|
|
} else {
|
|
|
|
// No config file -> create new one!
|
2010-11-01 16:00:53 +00:00
|
|
|
debug("Default configuration file missing, creating a new one");
|
2010-04-13 10:08:17 +00:00
|
|
|
|
|
|
|
flushToDisk();
|
|
|
|
}
|
2004-02-07 04:53:59 +00:00
|
|
|
}
|
|
|
|
|
2004-12-25 19:03:13 +00:00
|
|
|
void ConfigManager::loadConfigFile(const String &filename) {
|
2004-02-07 04:53:59 +00:00
|
|
|
_filename = filename;
|
2003-10-08 21:59:23 +00:00
|
|
|
|
2008-10-02 16:58:59 +00:00
|
|
|
FSNode node(filename);
|
2005-04-22 18:10:02 +00:00
|
|
|
File cfg_file;
|
2008-09-30 15:42:19 +00:00
|
|
|
if (!cfg_file.open(node)) {
|
2011-02-27 23:09:36 +00:00
|
|
|
debug("Creating configuration file: %s", filename.c_str());
|
2003-10-08 21:59:23 +00:00
|
|
|
} else {
|
2011-02-27 23:09:36 +00:00
|
|
|
debug("Using configuration file: %s", _filename.c_str());
|
2008-08-03 16:54:18 +00:00
|
|
|
loadFromStream(cfg_file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-18 21:13:47 +00:00
|
|
|
/**
|
2010-12-29 15:16:31 +00:00
|
|
|
* Add a ready-made domain based on its name and contents
|
|
|
|
* The domain name should not already exist in the ConfigManager.
|
|
|
|
**/
|
2011-08-06 07:47:19 +00:00
|
|
|
void ConfigManager::addDomain(const String &domainName, const ConfigManager::Domain &domain) {
|
2010-12-29 15:16:31 +00:00
|
|
|
if (domainName.empty())
|
|
|
|
return;
|
|
|
|
if (domainName == kApplicationDomain) {
|
|
|
|
_appDomain = domain;
|
|
|
|
#ifdef ENABLE_KEYMAPPER
|
2011-04-06 19:17:42 +00:00
|
|
|
} else if (domainName == kKeymapperDomain) {
|
2010-12-29 15:16:31 +00:00
|
|
|
_keymapperDomain = domain;
|
|
|
|
#endif
|
|
|
|
} else if (domain.contains("gameid")) {
|
|
|
|
// If the domain contains "gameid" we assume it's a game domain
|
|
|
|
if (_gameDomains.contains(domainName))
|
|
|
|
warning("Game domain %s already exists in ConfigManager", domainName.c_str());
|
|
|
|
|
|
|
|
_gameDomains[domainName] = domain;
|
|
|
|
|
|
|
|
_domainSaveOrder.push_back(domainName);
|
2011-01-13 16:38:14 +00:00
|
|
|
|
|
|
|
// Check if we have the same misc domain. For older config files
|
|
|
|
// we could have 'ghost' domains with the same name, so delete
|
|
|
|
// the ghost domain
|
|
|
|
if (_miscDomains.contains(domainName))
|
|
|
|
_miscDomains.erase(domainName);
|
2010-12-29 15:16:31 +00:00
|
|
|
} else {
|
|
|
|
// Otherwise it's a miscellaneous domain
|
|
|
|
if (_miscDomains.contains(domainName))
|
|
|
|
warning("Misc domain %s already exists in ConfigManager", domainName.c_str());
|
|
|
|
|
|
|
|
_miscDomains[domainName] = domain;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-08-03 16:54:18 +00:00
|
|
|
void ConfigManager::loadFromStream(SeekableReadStream &stream) {
|
2010-12-29 15:16:31 +00:00
|
|
|
String domainName;
|
2008-08-03 16:54:18 +00:00
|
|
|
String comment;
|
2010-12-29 15:16:31 +00:00
|
|
|
Domain domain;
|
2008-08-03 16:54:18 +00:00
|
|
|
int lineno = 0;
|
|
|
|
|
|
|
|
_appDomain.clear();
|
|
|
|
_gameDomains.clear();
|
2010-12-29 15:16:31 +00:00
|
|
|
_miscDomains.clear();
|
2008-08-03 16:54:18 +00:00
|
|
|
_transientDomain.clear();
|
|
|
|
_domainSaveOrder.clear();
|
|
|
|
|
2009-05-10 17:33:31 +00:00
|
|
|
#ifdef ENABLE_KEYMAPPER
|
|
|
|
_keymapperDomain.clear();
|
|
|
|
#endif
|
|
|
|
|
2008-08-03 16:54:18 +00:00
|
|
|
// TODO: Detect if a domain occurs multiple times (or likewise, if
|
|
|
|
// a key occurs multiple times inside one domain).
|
|
|
|
|
2009-05-19 11:42:14 +00:00
|
|
|
while (!stream.eos() && !stream.err()) {
|
2008-08-03 16:54:18 +00:00
|
|
|
lineno++;
|
|
|
|
|
|
|
|
// Read a line
|
2008-09-03 18:40:49 +00:00
|
|
|
String line = stream.readLine();
|
2008-08-03 16:54:18 +00:00
|
|
|
|
|
|
|
if (line.size() == 0) {
|
|
|
|
// Do nothing
|
|
|
|
} else if (line[0] == '#') {
|
|
|
|
// Accumulate comments here. Once we encounter either the start
|
|
|
|
// of a new domain, or a key-value-pair, we associate the value
|
|
|
|
// of the 'comment' variable with that entity.
|
|
|
|
comment += line;
|
2008-09-03 18:40:49 +00:00
|
|
|
comment += "\n";
|
2008-08-03 16:54:18 +00:00
|
|
|
} else if (line[0] == '[') {
|
|
|
|
// It's a new domain which begins here.
|
2010-12-29 15:16:31 +00:00
|
|
|
// Determine where the previously accumulated domain goes, if we accumulated anything.
|
|
|
|
addDomain(domainName, domain);
|
|
|
|
domain.clear();
|
2008-08-03 16:54:18 +00:00
|
|
|
const char *p = line.c_str() + 1;
|
|
|
|
// Get the domain name, and check whether it's valid (that
|
|
|
|
// is, verify that it only consists of alphanumerics,
|
|
|
|
// dashes and underscores).
|
2012-01-28 00:15:49 +00:00
|
|
|
while (*p && (isAlnum(*p) || *p == '-' || *p == '_'))
|
2008-08-03 16:54:18 +00:00
|
|
|
p++;
|
|
|
|
|
|
|
|
if (*p == '\0')
|
|
|
|
error("Config file buggy: missing ] in line %d", lineno);
|
|
|
|
else if (*p != ']')
|
2009-02-17 19:54:11 +00:00
|
|
|
error("Config file buggy: Invalid character '%c' occurred in section name in line %d", *p, lineno);
|
2008-08-03 16:54:18 +00:00
|
|
|
|
2010-12-29 15:16:31 +00:00
|
|
|
domainName = String(line.c_str() + 1, p);
|
2008-08-03 16:54:18 +00:00
|
|
|
|
2010-12-29 15:16:31 +00:00
|
|
|
domain.setDomainComment(comment);
|
2008-08-03 16:54:18 +00:00
|
|
|
comment.clear();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// This line should be a line with a 'key=value' pair, or an empty one.
|
2008-12-22 11:22:15 +00:00
|
|
|
|
2008-08-03 16:54:18 +00:00
|
|
|
// Skip leading whitespaces
|
|
|
|
const char *t = line.c_str();
|
2012-01-28 00:15:49 +00:00
|
|
|
while (isSpace(*t))
|
2008-08-03 16:54:18 +00:00
|
|
|
t++;
|
|
|
|
|
|
|
|
// Skip empty lines / lines with only whitespace
|
|
|
|
if (*t == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// If no domain has been set, this config file is invalid!
|
2010-12-29 15:16:31 +00:00
|
|
|
if (domainName.empty()) {
|
2008-08-03 16:54:18 +00:00
|
|
|
error("Config file buggy: Key/value pair found outside a domain in line %d", lineno);
|
2008-07-20 16:52:25 +00:00
|
|
|
}
|
|
|
|
|
2008-08-03 16:54:18 +00:00
|
|
|
// Split string at '=' into 'key' and 'value'. First, find the "=" delimeter.
|
|
|
|
const char *p = strchr(t, '=');
|
|
|
|
if (!p)
|
|
|
|
error("Config file buggy: Junk found in line line %d: '%s'", lineno, t);
|
|
|
|
|
|
|
|
// Extract the key/value pair
|
|
|
|
String key(t, p);
|
|
|
|
String value(p + 1);
|
2008-12-22 11:22:15 +00:00
|
|
|
|
2008-08-03 16:54:18 +00:00
|
|
|
// Trim of spaces
|
|
|
|
key.trim();
|
|
|
|
value.trim();
|
|
|
|
|
|
|
|
// Finally, store the key/value pair in the active domain
|
2010-12-29 15:16:31 +00:00
|
|
|
domain[key] = value;
|
2008-08-03 16:54:18 +00:00
|
|
|
|
|
|
|
// Store comment
|
2010-12-29 15:16:31 +00:00
|
|
|
domain.setKVComment(key, comment);
|
2008-08-03 16:54:18 +00:00
|
|
|
comment.clear();
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
|
|
|
}
|
2010-12-29 15:16:31 +00:00
|
|
|
|
|
|
|
addDomain(domainName, domain); // Add the last domain found
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ConfigManager::flushToDisk() {
|
2006-06-03 15:34:48 +00:00
|
|
|
#ifndef __DC__
|
2008-08-03 16:54:18 +00:00
|
|
|
WriteStream *stream;
|
2003-10-08 21:59:23 +00:00
|
|
|
|
2008-08-03 16:54:18 +00:00
|
|
|
if (_filename.empty()) {
|
|
|
|
// Write to the default config file
|
2009-01-29 22:09:06 +00:00
|
|
|
assert(g_system);
|
2009-01-23 03:30:40 +00:00
|
|
|
stream = g_system->createConfigWriteStream();
|
2011-01-18 21:13:47 +00:00
|
|
|
if (!stream) // If writing to the config file is not possible, do nothing
|
2008-08-03 16:54:18 +00:00
|
|
|
return;
|
2003-10-08 21:59:23 +00:00
|
|
|
} else {
|
2008-08-03 16:54:18 +00:00
|
|
|
DumpFile *dump = new DumpFile();
|
|
|
|
assert(dump);
|
|
|
|
|
|
|
|
if (!dump->open(_filename)) {
|
|
|
|
warning("Unable to write configuration file: %s", _filename.c_str());
|
|
|
|
delete dump;
|
|
|
|
return;
|
2004-09-28 12:10:49 +00:00
|
|
|
}
|
2008-12-22 11:22:15 +00:00
|
|
|
|
2008-08-03 16:54:18 +00:00
|
|
|
stream = dump;
|
|
|
|
}
|
2004-09-28 12:10:49 +00:00
|
|
|
|
2010-08-23 10:00:40 +00:00
|
|
|
// Write the application domain
|
|
|
|
writeDomain(*stream, kApplicationDomain, _appDomain);
|
|
|
|
|
|
|
|
#ifdef ENABLE_KEYMAPPER
|
|
|
|
// Write the keymapper domain
|
|
|
|
writeDomain(*stream, kKeymapperDomain, _keymapperDomain);
|
|
|
|
#endif
|
|
|
|
|
2010-12-29 15:16:31 +00:00
|
|
|
DomainMap::const_iterator d;
|
|
|
|
|
|
|
|
// Write the miscellaneous domains next
|
|
|
|
for (d = _miscDomains.begin(); d != _miscDomains.end(); ++d) {
|
|
|
|
writeDomain(*stream, d->_key, d->_value);
|
|
|
|
}
|
2011-01-18 21:13:47 +00:00
|
|
|
|
2008-08-03 16:54:18 +00:00
|
|
|
// First write the domains in _domainSaveOrder, in that order.
|
|
|
|
// Note: It's possible for _domainSaveOrder to list domains which
|
2010-08-23 10:00:40 +00:00
|
|
|
// are not present anymore, so we validate each name.
|
2010-03-18 15:09:24 +00:00
|
|
|
Array<String>::const_iterator i;
|
2008-08-03 16:54:18 +00:00
|
|
|
for (i = _domainSaveOrder.begin(); i != _domainSaveOrder.end(); ++i) {
|
2010-08-23 10:00:40 +00:00
|
|
|
if (_gameDomains.contains(*i)) {
|
2008-08-03 16:54:18 +00:00
|
|
|
writeDomain(*stream, *i, _gameDomains[*i]);
|
2011-01-18 21:13:47 +00:00
|
|
|
}
|
2008-08-03 16:54:18 +00:00
|
|
|
}
|
2003-10-08 21:59:23 +00:00
|
|
|
|
2008-08-03 16:54:18 +00:00
|
|
|
// Now write the domains which haven't been written yet
|
|
|
|
for (d = _gameDomains.begin(); d != _gameDomains.end(); ++d) {
|
|
|
|
if (find(_domainSaveOrder.begin(), _domainSaveOrder.end(), d->_key) == _domainSaveOrder.end())
|
|
|
|
writeDomain(*stream, d->_key, d->_value);
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
2008-08-03 16:54:18 +00:00
|
|
|
|
|
|
|
delete stream;
|
|
|
|
|
2006-06-03 15:34:48 +00:00
|
|
|
#endif // !__DC__
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
2007-03-08 16:43:33 +00:00
|
|
|
void ConfigManager::writeDomain(WriteStream &stream, const String &name, const Domain &domain) {
|
2006-03-28 09:42:54 +00:00
|
|
|
if (domain.empty())
|
2011-01-18 21:13:47 +00:00
|
|
|
return; // Don't bother writing empty domains.
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2008-08-02 22:32:32 +00:00
|
|
|
// WORKAROUND: Fix for bug #1972625 "ALL: On-the-fly targets are
|
|
|
|
// written to the config file": Do not save domains that came from
|
|
|
|
// the command line
|
|
|
|
if (domain.contains("id_came_from_command_line"))
|
|
|
|
return;
|
|
|
|
|
2004-03-28 20:28:45 +00:00
|
|
|
String comment;
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2004-03-28 20:28:45 +00:00
|
|
|
// Write domain comment (if any)
|
|
|
|
comment = domain.getDomainComment();
|
2006-03-28 09:42:54 +00:00
|
|
|
if (!comment.empty())
|
2007-03-08 16:43:33 +00:00
|
|
|
stream.writeString(comment);
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2004-03-28 20:28:45 +00:00
|
|
|
// Write domain start
|
2007-03-08 16:43:33 +00:00
|
|
|
stream.writeByte('[');
|
|
|
|
stream.writeString(name);
|
|
|
|
stream.writeByte(']');
|
|
|
|
stream.writeByte('\n');
|
2003-10-08 21:59:23 +00:00
|
|
|
|
2004-03-28 20:28:45 +00:00
|
|
|
// Write all key/value pairs in this domain, including comments
|
2004-02-05 00:19:57 +00:00
|
|
|
Domain::const_iterator x;
|
2003-10-08 21:59:23 +00:00
|
|
|
for (x = domain.begin(); x != domain.end(); ++x) {
|
2007-03-08 16:43:33 +00:00
|
|
|
if (!x->_value.empty()) {
|
2004-03-28 20:28:45 +00:00
|
|
|
// Write comment (if any)
|
2004-03-29 19:15:23 +00:00
|
|
|
if (domain.hasKVComment(x->_key)) {
|
|
|
|
comment = domain.getKVComment(x->_key);
|
2007-03-08 16:43:33 +00:00
|
|
|
stream.writeString(comment);
|
2004-03-29 19:15:23 +00:00
|
|
|
}
|
2004-03-28 20:28:45 +00:00
|
|
|
// Write the key/value pair
|
2007-03-08 16:43:33 +00:00
|
|
|
stream.writeString(x->_key);
|
|
|
|
stream.writeByte('=');
|
|
|
|
stream.writeString(x->_value);
|
|
|
|
stream.writeByte('\n');
|
2004-03-28 20:28:45 +00:00
|
|
|
}
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
2007-03-08 16:43:33 +00:00
|
|
|
stream.writeByte('\n');
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
|
|
|
|
const ConfigManager::Domain *ConfigManager::getDomain(const String &domName) const {
|
|
|
|
assert(!domName.empty());
|
|
|
|
assert(isValidDomainName(domName));
|
2006-10-06 19:01:39 +00:00
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
if (domName == kTransientDomain)
|
|
|
|
return &_transientDomain;
|
|
|
|
if (domName == kApplicationDomain)
|
|
|
|
return &_appDomain;
|
2009-05-10 17:33:31 +00:00
|
|
|
#ifdef ENABLE_KEYMAPPER
|
|
|
|
if (domName == kKeymapperDomain)
|
|
|
|
return &_keymapperDomain;
|
|
|
|
#endif
|
2006-04-15 13:12:03 +00:00
|
|
|
if (_gameDomains.contains(domName))
|
|
|
|
return &_gameDomains[domName];
|
2011-01-13 11:30:37 +00:00
|
|
|
if (_miscDomains.contains(domName))
|
|
|
|
return &_miscDomains[domName];
|
2006-04-15 13:12:03 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ConfigManager::Domain *ConfigManager::getDomain(const String &domName) {
|
|
|
|
assert(!domName.empty());
|
|
|
|
assert(isValidDomainName(domName));
|
2006-10-06 19:01:39 +00:00
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
if (domName == kTransientDomain)
|
|
|
|
return &_transientDomain;
|
|
|
|
if (domName == kApplicationDomain)
|
|
|
|
return &_appDomain;
|
2009-05-10 17:33:31 +00:00
|
|
|
#ifdef ENABLE_KEYMAPPER
|
|
|
|
if (domName == kKeymapperDomain)
|
|
|
|
return &_keymapperDomain;
|
|
|
|
#endif
|
2006-04-15 13:12:03 +00:00
|
|
|
if (_gameDomains.contains(domName))
|
|
|
|
return &_gameDomains[domName];
|
2011-01-13 11:30:37 +00:00
|
|
|
if (_miscDomains.contains(domName))
|
|
|
|
return &_miscDomains[domName];
|
2006-04-15 13:12:03 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-10-08 21:59:23 +00:00
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
|
|
|
|
bool ConfigManager::hasKey(const String &key) const {
|
|
|
|
// Search the domains in the following order:
|
2006-04-15 13:12:03 +00:00
|
|
|
// 1) the transient domain,
|
|
|
|
// 2) the active game domain (if any),
|
|
|
|
// 3) the application domain.
|
2003-10-08 21:59:23 +00:00
|
|
|
// The defaults domain is explicitly *not* checked.
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2003-11-10 23:17:11 +00:00
|
|
|
if (_transientDomain.contains(key))
|
|
|
|
return true;
|
2003-11-07 16:54:58 +00:00
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
if (_activeDomain && _activeDomain->contains(key))
|
2003-10-08 21:59:23 +00:00
|
|
|
return true;
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
if (_appDomain.contains(key))
|
|
|
|
return true;
|
2003-11-07 16:54:58 +00:00
|
|
|
|
2003-10-08 21:59:23 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
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);
|
2003-10-08 21:59:23 +00:00
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
const Domain *domain = getDomain(domName);
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
if (!domain)
|
|
|
|
return false;
|
|
|
|
return domain->contains(key);
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
void ConfigManager::removeKey(const String &key, const String &domName) {
|
|
|
|
Domain *domain = getDomain(domName);
|
2003-11-05 00:57:00 +00:00
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
if (!domain)
|
|
|
|
error("ConfigManager::removeKey(%s, %s) called on non-existent domain",
|
2011-01-18 21:13:47 +00:00
|
|
|
key.c_str(), domName.c_str());
|
2006-04-15 13:12:03 +00:00
|
|
|
|
|
|
|
domain->erase(key);
|
2003-11-05 00:57:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-10-08 21:59:23 +00:00
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
|
2011-01-18 21:13:47 +00:00
|
|
|
const String &ConfigManager::get(const String &key) const {
|
2006-04-15 13:12:03 +00:00
|
|
|
if (_transientDomain.contains(key))
|
|
|
|
return _transientDomain[key];
|
|
|
|
else if (_activeDomain && _activeDomain->contains(key))
|
|
|
|
return (*_activeDomain)[key];
|
|
|
|
else if (_appDomain.contains(key))
|
|
|
|
return _appDomain[key];
|
2005-02-22 18:11:36 +00:00
|
|
|
|
2010-03-29 20:31:23 +00:00
|
|
|
return _defaultsDomain.getVal(key);
|
2006-04-15 13:12:03 +00:00
|
|
|
}
|
2003-10-08 21:59:23 +00:00
|
|
|
|
2011-01-18 21:13:47 +00:00
|
|
|
const String &ConfigManager::get(const String &key, const String &domName) const {
|
2006-04-15 13:12:03 +00:00
|
|
|
// 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);
|
2003-11-10 23:17:11 +00:00
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
const Domain *domain = getDomain(domName);
|
2003-11-10 23:17:11 +00:00
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
if (!domain)
|
|
|
|
error("ConfigManager::get(%s,%s) called on non-existent domain",
|
2011-01-18 21:13:47 +00:00
|
|
|
key.c_str(), domName.c_str());
|
2003-11-07 15:57:36 +00:00
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
if (domain->contains(key))
|
|
|
|
return (*domain)[key];
|
2003-11-08 22:43:46 +00:00
|
|
|
|
2010-03-29 20:31:23 +00:00
|
|
|
return _defaultsDomain.getVal(key);
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
int ConfigManager::getInt(const String &key, const String &domName) const {
|
|
|
|
String value(get(key, domName));
|
2004-03-28 18:29:27 +00:00
|
|
|
char *errpos;
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2004-03-31 18:00:46 +00:00
|
|
|
// For now, be tolerant against missing config keys. Strictly spoken, it is
|
|
|
|
// a bug in the calling code to retrieve an int for a key which isn't even
|
|
|
|
// present... and a default value of 0 seems rather arbitrary.
|
2006-03-28 09:42:54 +00:00
|
|
|
if (value.empty())
|
2004-03-31 18:00:46 +00:00
|
|
|
return 0;
|
|
|
|
|
2006-07-08 20:20:07 +00:00
|
|
|
// We use the special value '0' for the base passed to strtol. Doing that
|
2006-04-15 13:58:01 +00:00
|
|
|
// makes it possible to enter hex values as "0x1234", but also decimal
|
|
|
|
// values ("123") are still valid.
|
|
|
|
int ivalue = (int)strtol(value.c_str(), &errpos, 0);
|
2004-03-28 18:29:27 +00:00
|
|
|
if (value.c_str() == errpos)
|
2006-04-15 13:12:03 +00:00
|
|
|
error("ConfigManager::getInt(%s,%s): '%s' is not a valid integer",
|
2011-01-18 21:13:47 +00:00
|
|
|
key.c_str(), domName.c_str(), errpos);
|
2004-03-28 18:29:27 +00:00
|
|
|
|
|
|
|
return ivalue;
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
bool ConfigManager::getBool(const String &key, const String &domName) const {
|
|
|
|
String value(get(key, domName));
|
2011-06-16 13:51:04 +00:00
|
|
|
bool val;
|
2011-08-06 07:47:19 +00:00
|
|
|
if (parseBool(value, val))
|
2011-06-16 13:51:04 +00:00
|
|
|
return val;
|
2004-03-28 18:29:27 +00:00
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
error("ConfigManager::getBool(%s,%s): '%s' is not a valid bool",
|
2011-01-18 21:13:47 +00:00
|
|
|
key.c_str(), domName.c_str(), value.c_str());
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
void ConfigManager::set(const String &key, const String &value) {
|
|
|
|
// Remove the transient domain value, if any.
|
|
|
|
_transientDomain.erase(key);
|
2003-10-09 11:42:59 +00:00
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
// 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.
|
2006-04-21 20:59:05 +00:00
|
|
|
if (domName.empty()) {
|
|
|
|
set(key, value);
|
|
|
|
return;
|
|
|
|
}
|
2006-04-15 13:12:03 +00:00
|
|
|
|
|
|
|
Domain *domain = getDomain(domName);
|
|
|
|
|
|
|
|
if (!domain)
|
|
|
|
error("ConfigManager::set(%s,%s,%s) called on non-existent domain",
|
2011-01-18 21:13:47 +00:00
|
|
|
key.c_str(), value.c_str(), domName.c_str());
|
2006-04-15 13:12:03 +00:00
|
|
|
|
|
|
|
(*domain)[key] = value;
|
2006-10-06 19:01:39 +00:00
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
// 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...
|
2011-01-18 21:13:47 +00:00
|
|
|
#if 0
|
2006-04-15 13:12:03 +00:00
|
|
|
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);
|
2003-11-10 23:17:11 +00:00
|
|
|
}
|
|
|
|
}
|
2011-01-18 21:13:47 +00:00
|
|
|
#endif
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
2006-04-16 19:23:14 +00:00
|
|
|
void ConfigManager::setInt(const String &key, int value, const String &domName) {
|
2010-11-01 16:04:04 +00:00
|
|
|
set(key, String::format("%i", value), domName);
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
2006-04-16 19:23:14 +00:00
|
|
|
void ConfigManager::setBool(const String &key, bool value, const String &domName) {
|
2006-04-15 13:12:03 +00:00
|
|
|
set(key, String(value ? "true" : "false"), domName);
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
|
|
|
|
void ConfigManager::registerDefault(const String &key, const String &value) {
|
|
|
|
_defaultsDomain[key] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConfigManager::registerDefault(const String &key, const char *value) {
|
|
|
|
registerDefault(key, String(value));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConfigManager::registerDefault(const String &key, int value) {
|
2010-11-01 16:04:04 +00:00
|
|
|
registerDefault(key, String::format("%i", value));
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ConfigManager::registerDefault(const String &key, bool value) {
|
2006-04-15 13:12:03 +00:00
|
|
|
registerDefault(key, value ? "true" : "false");
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
void ConfigManager::setActiveDomain(const String &domName) {
|
|
|
|
if (domName.empty()) {
|
|
|
|
_activeDomain = 0;
|
|
|
|
} else {
|
|
|
|
assert(isValidDomainName(domName));
|
|
|
|
_activeDomain = & _gameDomains[domName];
|
|
|
|
}
|
|
|
|
_activeDomainName = domName;
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
2006-04-16 13:58:11 +00:00
|
|
|
void ConfigManager::addGameDomain(const String &domName) {
|
|
|
|
assert(!domName.empty());
|
|
|
|
assert(isValidDomainName(domName));
|
|
|
|
|
|
|
|
// TODO: Do we want to generate an error/warning if a domain with
|
|
|
|
// the given name already exists?
|
|
|
|
|
|
|
|
_gameDomains[domName];
|
2008-07-29 16:12:42 +00:00
|
|
|
|
|
|
|
// Add it to the _domainSaveOrder, if it's not already in there
|
|
|
|
if (find(_domainSaveOrder.begin(), _domainSaveOrder.end(), domName) == _domainSaveOrder.end())
|
|
|
|
_domainSaveOrder.push_back(domName);
|
2006-04-16 13:58:11 +00:00
|
|
|
}
|
|
|
|
|
2010-12-29 15:16:31 +00:00
|
|
|
void ConfigManager::addMiscDomain(const String &domName) {
|
|
|
|
assert(!domName.empty());
|
|
|
|
assert(isValidDomainName(domName));
|
|
|
|
|
|
|
|
_miscDomains[domName];
|
|
|
|
}
|
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
void ConfigManager::removeGameDomain(const String &domName) {
|
|
|
|
assert(!domName.empty());
|
|
|
|
assert(isValidDomainName(domName));
|
|
|
|
_gameDomains.erase(domName);
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
2010-12-29 15:16:31 +00:00
|
|
|
void ConfigManager::removeMiscDomain(const String &domName) {
|
|
|
|
assert(!domName.empty());
|
|
|
|
assert(isValidDomainName(domName));
|
|
|
|
_miscDomains.erase(domName);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-10-08 21:59:23 +00:00
|
|
|
void ConfigManager::renameGameDomain(const String &oldName, const String &newName) {
|
2010-12-29 15:16:31 +00:00
|
|
|
renameDomain(oldName, newName, _gameDomains);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConfigManager::renameMiscDomain(const String &oldName, const String &newName) {
|
|
|
|
renameDomain(oldName, newName, _miscDomains);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Common private function to rename both game and misc domains
|
|
|
|
**/
|
|
|
|
void ConfigManager::renameDomain(const String &oldName, const String &newName, DomainMap &map) {
|
2003-10-08 21:59:23 +00:00
|
|
|
if (oldName == newName)
|
|
|
|
return;
|
|
|
|
|
2006-03-28 09:42:54 +00:00
|
|
|
assert(!oldName.empty());
|
|
|
|
assert(!newName.empty());
|
2005-02-22 18:11:36 +00:00
|
|
|
assert(isValidDomainName(oldName));
|
|
|
|
assert(isValidDomainName(newName));
|
2003-10-09 11:42:59 +00:00
|
|
|
|
2006-03-31 07:30:43 +00:00
|
|
|
// _gameDomains[newName].merge(_gameDomains[oldName]);
|
2010-12-29 15:16:31 +00:00
|
|
|
Domain &oldDom = map[oldName];
|
|
|
|
Domain &newDom = map[newName];
|
2006-03-31 07:30:43 +00:00
|
|
|
Domain::const_iterator iter;
|
|
|
|
for (iter = oldDom.begin(); iter != oldDom.end(); ++iter)
|
|
|
|
newDom[iter->_key] = iter->_value;
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2010-12-29 15:16:31 +00:00
|
|
|
map.erase(oldName);
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
2006-04-15 13:12:03 +00:00
|
|
|
bool ConfigManager::hasGameDomain(const String &domName) const {
|
|
|
|
assert(!domName.empty());
|
|
|
|
return isValidDomainName(domName) && _gameDomains.contains(domName);
|
2003-10-08 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
2010-12-29 15:16:31 +00:00
|
|
|
bool ConfigManager::hasMiscDomain(const String &domName) const {
|
|
|
|
assert(!domName.empty());
|
|
|
|
return isValidDomainName(domName) && _miscDomains.contains(domName);
|
|
|
|
}
|
2004-03-29 19:15:23 +00:00
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
void ConfigManager::Domain::setDomainComment(const String &comment) {
|
|
|
|
_domainComment = comment;
|
|
|
|
}
|
|
|
|
const String &ConfigManager::Domain::getDomainComment() const {
|
|
|
|
return _domainComment;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConfigManager::Domain::setKVComment(const String &key, const String &comment) {
|
|
|
|
_keyValueComments[key] = comment;
|
|
|
|
}
|
|
|
|
const String &ConfigManager::Domain::getKVComment(const String &key) const {
|
|
|
|
return _keyValueComments[key];
|
|
|
|
}
|
|
|
|
bool ConfigManager::Domain::hasKVComment(const String &key) const {
|
|
|
|
return _keyValueComments.contains(key);
|
|
|
|
}
|
|
|
|
|
2011-01-18 21:13:47 +00:00
|
|
|
} // End of namespace Common
|