From d1773647159f9ef1393d7a1d33204de5886edce5 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 8 Oct 2003 21:59:23 +0000 Subject: new config manager. not everything is completed, and some things will still be changed, but it seems to work well enough to put it into CVS svn-id: r10687 --- common/config-manager.cpp | 370 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 common/config-manager.cpp (limited to 'common/config-manager.cpp') diff --git a/common/config-manager.cpp b/common/config-manager.cpp new file mode 100644 index 0000000000..f90eefbbd3 --- /dev/null +++ b/common/config-manager.cpp @@ -0,0 +1,370 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2003 The ScummVM project + * + * 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 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include "common/config-manager.h" + +#if defined(UNIX) +#include +#ifndef MAXPATHLEN +#define MAXPATHLEN 256 +#endif +#ifdef MACOSX +#define DEFAULT_CONFIG_FILE "Library/Preferences/ScummVM Preferences" +#else +#define DEFAULT_CONFIG_FILE ".scummvmrc" +#endif +#else +#define DEFAULT_CONFIG_FILE "scummvm.ini" +#endif + +#define MAXLINELEN 256 + +static char *ltrim(char *t) { + while (*t == ' ') + t++; + return t; +} + +static char *rtrim(char *t) { + int l = strlen(t) - 1; + while (l >= 0 && t[l] == ' ') + t[l--] = 0; + return t; +} + + +namespace Common { + +const String ConfigManager::kApplicationDomain("scummvm"); + +const String trueStr("true"); +const String falseStr("false"); + + +#pragma mark - + + +ConfigManager::ConfigManager() { + +#if defined(UNIX) + char configFile[MAXPATHLEN]; + if(getenv("HOME") != NULL) + sprintf(configFile,"%s/%s", getenv("HOME"), DEFAULT_CONFIG_FILE); + else strcpy(configFile,DEFAULT_CONFIG_FILE); +#else + char configFile[256]; + #if defined (WIN32) && !defined(_WIN32_WCE) + GetWindowsDirectory(configFile, 256); + strcat(configFile, "\\"); + strcat(configFile, DEFAULT_CONFIG_FILE); + #elif defined(__PALM_OS__) + strcpy(configFile,"/PALM/Programs/ScummVM/"); + strcat(configFile, DEFAULT_CONFIG_FILE); + #else + strcpy(configFile, DEFAULT_CONFIG_FILE); + #endif +#endif + + // Ensure the global domain(s) are setup. + _globalDomains.addKey(kApplicationDomain); +#ifdef _WIN32_WCE + // WinCE for some reasons uses additional global domains. + _globalDomains.addKey("wince"); + _globalDomains.addKey("smartfon-keys"); +#endif + + _filename = configFile; + loadFile(_filename); +} + +void ConfigManager::loadFile(const String &filename) { + FILE *cfg_file; + char t[MAXLINELEN]; + String domain; + + if (!(cfg_file = fopen(filename.c_str(), "r"))) { + debug(1, "Unable to open configuration file: %s.\n", filename.c_str()); + } else { + while (!feof(cfg_file)) { + if (!fgets(t, MAXLINELEN, cfg_file)) + continue; + if (t[0] != '#') { + if (t[0] == '[') { + // It's a new domain which begins here. + char *p = strchr(t, ']'); + if (!p) { + error("Config file buggy: no ] at the end of the domain name.\n"); + } else { + *p = 0; + // TODO: Some kind of domain name verification might be nice. + // E.g. restrict to only a-zA-Z0-9 and maybe -_ or so... + domain = t + 1; + } + } else { + // It's a new key in the domain. + if (domain.isEmpty()) { + error("Config file buggy: we have a key without a domain first.\n"); + } + char *p = strchr(t, '\n'); + if (p) + *p = 0; + p = strchr(t, '\r'); + if (p) + *p = 0; + + if (!(p = strchr(t, '='))) { + if (strlen(t)) + warning("Config file buggy: there is junk: %s\n", t); + } else { + *p = 0; + String key = ltrim(rtrim(t)); + String value = ltrim(p + 1); + set(key, value, domain); + } + } + } + } + fclose(cfg_file); + } +} + +void ConfigManager::flushToDisk() { + FILE *cfg_file; + +// TODO +// if (!willwrite) +// return; + + if (!(cfg_file = fopen(_filename.c_str(), "w"))) { + warning("Unable to write configuration file: %s.\n", _filename.c_str()); + } else { + DomainMap::ConstIterator d; + + // First write the global domains + for (d = _globalDomains.begin(); d != _globalDomains.end(); ++d) { + writeDomain(cfg_file, d->_key, d->_value); + } + + // Second, write the game domains + for (d = _gameDomains.begin(); d != _gameDomains.end(); ++d) { + writeDomain(cfg_file, d->_key, d->_value); + } + + fclose(cfg_file); + } +} + +void ConfigManager::writeDomain(FILE *file, const String &name, const Domain &domain) { + if (domain.isEmpty()) + return; // Don't bother writing empty domains. + + fprintf(file, "[%s]\n", name.c_str()); + + StringMap::ConstIterator x; + for (x = domain.begin(); x != domain.end(); ++x) { + const String &value = x->_value; + if (!value.isEmpty()) + fprintf(file, "%s=%s\n", x->_key.c_str(), value.c_str()); + } + fprintf(file, "\n"); +} + +#pragma mark - + + +bool ConfigManager::hasKey(const String &key) const { + // Search the domains in the following order: + // 1) Run time domain + // 2) Active game domain (if any) + // 3) All global domains + // The defaults domain is explicitly *not* checked. + +// if (_runtimeDomain.contain(key)) +// return true; + + if (!_activeDomain.isEmpty() && _gameDomains[_activeDomain].contains(key)) + return true; + + DomainMap::ConstIterator iter; + for (iter = _globalDomains.begin(); iter != _globalDomains.end(); ++iter) { + if (iter->_value.contains(key)) + return true; + } + + return false; +} + + +bool ConfigManager::hasKey(const String &key, const String &dom) const { + assert(!dom.isEmpty()); + + if (_gameDomains.contains(dom)) + return _gameDomains[dom].contains(key); + if (_globalDomains.contains(dom)) + return _globalDomains[dom].contains(key); + + return false; +} + + +#pragma mark - + + +const String & ConfigManager::get(const String &key) const { + // Search the domains in the following order: + // 1) Run time domain + // 2) Active game domain (if any) + // 3) All global domains + // 4) The defaults + +// if (_runtimeDomain.contain(key)) +// return true; + + if (!_activeDomain.isEmpty() && _gameDomains[_activeDomain].contains(key)) + return _gameDomains[_activeDomain][key]; + + DomainMap::ConstIterator iter; + for (iter = _globalDomains.begin(); iter != _globalDomains.end(); ++iter) { + if (iter->_value.contains(key)) + return iter->_value[key]; + } + + return _defaultsDomain.get(key); +} + +const String & ConfigManager::get(const String &key, const String &dom) const { + if (dom.isEmpty()) + return get(key); + + // TODO: How exactly should we handle the case were the domain 'dom' + // is not found, or were dom is found, but doesn't contain 'key' ? + // Right now we just return an empty string. But might want to print + // out a warning, or even error out? + if (_gameDomains.contains(dom)) + return _gameDomains[dom].get(key); + if (_globalDomains.contains(dom)) + return _globalDomains[dom].get(key); + + return String::emptyString; +} + +int ConfigManager::getInt(const String &key, const String &dom) const { + String value(get(key, dom)); + // Convert the string to an integer. + // TODO: We should perform some error checking. + long v = strtol(value.c_str(), 0, 10); + return (int)v; +} + +bool ConfigManager::getBool(const String &key, const String &dom) const { + String value(get(key, dom)); + // '1', 'true' and 'yes' are accepted as true values; everything else + // maps to value 'false'. + return (value == "true") || (value == "yes") || (value == "1"); +} + + +#pragma mark - + + +void ConfigManager::set(const String &key, const String &value) { +#if 0 + // TODO ?!? +// _runtimeDomain[key] = value; +#else + if (_activeDomain.isEmpty()) + _globalDomains[kApplicationDomain][key] = value; + else + _gameDomains[_activeDomain][key] = value; +#endif +} + +void ConfigManager::set(const String &key, const String &value, const String &dom) { + if (_globalDomains.contains(dom)) + _globalDomains[dom][key] = value; + else + _gameDomains[dom][key] = value; +} + +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) { + char tmp[128]; + snprintf(tmp, sizeof(tmp), "%i", value); + set(key, String(tmp), dom); +} + +void ConfigManager::set(const String &key, bool value, const String &dom) { + set(key, value ? trueStr : falseStr, dom); +} + + +#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) { + char tmp[128]; + snprintf(tmp, sizeof(tmp), "%i", value); + registerDefault(key, tmp); +} + +void ConfigManager::registerDefault(const String &key, bool value) { + registerDefault(key, value ? trueStr : falseStr); +} + + +#pragma mark - + + +void ConfigManager::setActiveDomain(const String &domain) { + _activeDomain = domain; + _gameDomains.addKey(domain); +} + +void ConfigManager::removeGameDomain(const String &name) { + _gameDomains.remove(name); +} + +void ConfigManager::renameGameDomain(const String &oldName, const String &newName) { + if (oldName == newName) + return; + + _gameDomains[newName].merge(_gameDomains[oldName]); + + _gameDomains.remove(oldName); +} + +bool ConfigManager::hasGameDomain(const String &domain) const { + return _gameDomains.contains(domain); +} + +} // End of namespace Common -- cgit v1.2.3