[Scummvm-cvs-logs] CVS: scummvm/common config-manager.cpp,NONE,1.1 config-manager.h,NONE,1.1 singleton.h,NONE,1.1 module.mk,1.10,1.11 config-file.cpp,1.18,NONE config-file.h,1.10,NONE

Max Horn fingolfin at users.sourceforge.net
Wed Oct 8 15:00:14 CEST 2003


Update of /cvsroot/scummvm/scummvm/common
In directory sc8-pr-cvs1:/tmp/cvs-serv6106/common

Modified Files:
	module.mk 
Added Files:
	config-manager.cpp config-manager.h singleton.h 
Removed Files:
	config-file.cpp config-file.h 
Log Message:
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

--- NEW FILE: config-manager.cpp ---
/* 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: /cvsroot/scummvm/scummvm/common/config-manager.cpp,v 1.1 2003/10/08 21:59:22 fingolfin Exp $
 *
 */

#include "common/config-manager.h"

#if defined(UNIX)
#include <sys/param.h>
#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

--- NEW FILE: config-manager.h ---
/* 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: /cvsroot/scummvm/scummvm/common/config-manager.h,v 1.1 2003/10/08 21:59:22 fingolfin Exp $
 *
 */

#ifndef COMMON_CONFIG_H
#define COMMON_CONFIG_H

#include "common/list.h"
#include "common/map.h"
#include "common/singleton.h"
#include "common/str.h"
#include "common/util.h"

namespace Common {

class File;


/**
 * The (singleton) configuration manager, used to query & set configuration
 * values using string keys.
 *
 * @todo Implement the callback based notification system (outline below)
 *       which sends out notifications to interested parties whenever the value
 *       of some specific (or any) configuration key changes.
 */
class ConfigManager : public Singleton<ConfigManager> {
public:
	class Domain : public StringMap {
//		friend class ConfigManager;
	public:
		const String &get(const String &key) const {
			Node *node = findNode(_root, key);
			return node ? node->_value : String::emptyString;
		}
/*
		void	set(const String &key, const String &value);
		void	set(const String &key, int value);
		void	set(const String &key, bool value);
*/
	};

	typedef Map<String, Domain> DomainMap;
	
	/** The name of the application domain (normally 'scummvm'). */
	static const String kApplicationDomain;

	bool				hasKey(const String &key) const;
	bool				hasKey(const String &key, const String &dom) const;

	const String &		get(const String &key) const;
	const String &		get(const String &key, const String &dom) const;
	int					getInt(const String &key, const String &dom = String::emptyString) const;
	bool				getBool(const String &key, const String &dom = String::emptyString) const;

	void				set(const String &key, const String &value);
	void				set(const String &key, const String &value, const String &dom);
	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);

//	void				addDomain(const String &name);
	void				removeGameDomain(const String &name);
	void				renameGameDomain(const String &oldName, const String &newName);
	bool				hasGameDomain(const String &domain) const;
	const DomainMap &	getGameDomains() const { return _gameDomains; }

/*
	TODO: Callback/change notification system
	typedef void (*ConfigCallback)(const ConstString &key, void *refCon);

	void   registerCallback(const ConstString &key, ConfigCallback cfgc, void *refCon)
	void unregisterCallback(const ConstString &key, ConfigCallback cfgc)
*/

private:
	friend class Singleton<ConfigManager>;
	ConfigManager();

	void			loadFile(const String &filename);
	void			writeDomain(FILE *file, const String &name, const Domain &domain);
	
//	Domain			_runtimeDomain;
	DomainMap		_gameDomains;
	DomainMap		_globalDomains;
	Domain			_defaultsDomain;
	
	List<Domain *>	_searchOrder;

	String			_activeDomain;
	String			_filename;
};

}	// End of namespace Common

/** Shortcut for accessing the configuration manager. */
#define ConfMan		Common::ConfigManager::instance()

#endif

--- NEW FILE: singleton.h ---
/* 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: /cvsroot/scummvm/scummvm/common/singleton.h,v 1.1 2003/10/08 21:59:22 fingolfin Exp $
 *
 */

#ifndef COMMON_SINGLETON_H
#define COMMON_SINGLETON_H

namespace Common {

/**
 * Generic template base class for implementing the singleton design pattern.
 */
template <class T>
class Singleton
{
public:
	static T& instance() {
		// TODO: We aren't thread safe. For now we ignore it since the
		// only thing using this singleton template is the config manager,
		// and that is first instantiated long before any threads.
		// TODO: We don't leak, but the destruction order is nevertheless
		// semi-random. If we use multiple singletons, the destruction
		// order might become an issue. There are various approaches
		// to solve that problem, but for now this is sufficient
		static T singleton;
		return singleton;
	}
protected:
	Singleton<T>()		{ }
	~Singleton<T>()		{ }

private:
	Singleton(const Singleton&);
	Singleton& operator= (const Singleton&);
}; 

}	// End of namespace Common

#endif

Index: module.mk
===================================================================
RCS file: /cvsroot/scummvm/scummvm/common/module.mk,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- module.mk	29 Sep 2003 21:58:40 -0000	1.10
+++ module.mk	8 Oct 2003 21:59:22 -0000	1.11
@@ -1,7 +1,7 @@
 MODULE := common
 
 MODULE_OBJS := \
-	common/config-file.o \
+	common/config-manager.o \
 	common/file.o \
 	common/scaler.o \
 	common/str.o \

--- config-file.cpp DELETED ---

--- config-file.h DELETED ---





More information about the Scummvm-git-logs mailing list