[Scummvm-cvs-logs] scummvm master -> de952ae0b9226a67c8d20916e29f81258a2f6223

lordhoto lordhoto at gmail.com
Fri Aug 9 00:57:25 CEST 2013


This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
63750d6780 COMMON: Rename ConfigFile to INIFile.
6da6e4e686 COMMON: Remove outdated comments on INIFile.
0dae60a357 COMMON: Remove commented out include in config-manager.h.
de952ae0b9 Merge pull request #373 from lordhoto/ini-file


Commit: 63750d678068aa92ee95dc9de2b2908a983b489d
    https://github.com/scummvm/scummvm/commit/63750d678068aa92ee95dc9de2b2908a983b489d
Author: Johannes Schickel (lordhoto at scummvm.org)
Date: 2013-08-08T07:28:38-07:00

Commit Message:
COMMON: Rename ConfigFile to INIFile.

This clears up that 'ConfigFile' is actually a class handling only INI-files.

Changed paths:
  A common/ini-file.cpp
  A common/ini-file.h
  R common/config-file.cpp
  R common/config-file.h
    common/config-manager.h
    common/module.mk
    engines/composer/composer.h
    engines/gob/iniconfig.cpp
    engines/gob/iniconfig.h
    engines/mohawk/livingbooks.cpp
    engines/mohawk/livingbooks.h
    engines/mohawk/livingbooks_lbx.cpp
    engines/scumm/he/script_v80he.cpp
    engines/testbed/config.cpp
    engines/testbed/config.h



diff --git a/common/config-file.cpp b/common/config-file.cpp
deleted file mode 100644
index 0ce6dcf..0000000
--- a/common/config-file.cpp
+++ /dev/null
@@ -1,392 +0,0 @@
-/* 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.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "common/config-file.h"
-#include "common/file.h"
-#include "common/savefile.h"
-#include "common/system.h"
-#include "common/textconsole.h"
-
-namespace Common {
-
-bool ConfigFile::isValidName(const String &name) {
-	const char *p = name.c_str();
-	while (*p && (isAlnum(*p) || *p == '-' || *p == '_' || *p == '.'))
-		p++;
-	return *p == 0;
-}
-
-ConfigFile::ConfigFile() {
-}
-
-ConfigFile::~ConfigFile() {
-}
-
-void ConfigFile::clear() {
-	_sections.clear();
-}
-
-bool ConfigFile::loadFromFile(const String &filename) {
-	File file;
-	if (file.open(filename))
-		return loadFromStream(file);
-	else
-		return false;
-}
-
-bool ConfigFile::loadFromSaveFile(const char *filename) {
-	assert(g_system);
-	SaveFileManager *saveFileMan = g_system->getSavefileManager();
-	SeekableReadStream *loadFile;
-
-	assert(saveFileMan);
-	if (!(loadFile = saveFileMan->openForLoading(filename)))
-		return false;
-
-	bool status = loadFromStream(*loadFile);
-	delete loadFile;
-	return status;
-}
-
-bool ConfigFile::loadFromStream(SeekableReadStream &stream) {
-	Section section;
-	KeyValue kv;
-	String comment;
-	int lineno = 0;
-
-	// TODO: Detect if a section occurs multiple times (or likewise, if
-	// a key occurs multiple times inside one section).
-
-	while (!stream.eos() && !stream.err()) {
-		lineno++;
-
-		// Read a line
-		String line = stream.readLine();
-
-		if (line.size() == 0) {
-			// Do nothing
-		} else if (line[0] == '#' || line[0] == ';' || line.hasPrefix("//")) {
-			// Accumulate comments here. Once we encounter either the start
-			// of a new section, or a key-value-pair, we associate the value
-			// of the 'comment' variable with that entity. The semicolon and
-			// C++-style comments are used for Living Books games in Mohawk.
-			comment += line;
-			comment += "\n";
-		} else if (line[0] == '(') {
-			// HACK: The following is a hack added by Kirben to support the
-			// "map.ini" used in the HE SCUMM game "SPY Fox in Hold the Mustard".
-			//
-			// It would be nice if this hack could be restricted to that game,
-			// but the current design of this class doesn't allow to do that
-			// in a nice fashion (a "isMustard" parameter is *not* a nice
-			// solution).
-			comment += line;
-			comment += "\n";
-		} else if (line[0] == '[') {
-			// It's a new section which begins here.
-			const char *p = line.c_str() + 1;
-			// Get the section name, and check whether it's valid (that
-			// is, verify that it only consists of alphanumerics,
-			// periods, dashes and underscores). Mohawk Living Books games
-			// can have periods in their section names.
-			while (*p && (isAlnum(*p) || *p == '-' || *p == '_' || *p == '.'))
-				p++;
-
-			if (*p == '\0')
-				error("ConfigFile::loadFromStream: missing ] in line %d", lineno);
-			else if (*p != ']')
-				error("ConfigFile::loadFromStream: Invalid character '%c' occurred in section name in line %d", *p, lineno);
-
-			// Previous section is finished now, store it.
-			if (!section.name.empty())
-				_sections.push_back(section);
-
-			section.name = String(line.c_str() + 1, p);
-			section.keys.clear();
-			section.comment = comment;
-			comment.clear();
-
-			assert(isValidName(section.name));
-		} else {
-			// This line should be a line with a 'key=value' pair, or an empty one.
-
-			// Skip leading whitespaces
-			const char *t = line.c_str();
-			while (isSpace(*t))
-				t++;
-
-			// Skip empty lines / lines with only whitespace
-			if (*t == 0)
-				continue;
-
-			// If no section has been set, this config file is invalid!
-			if (section.name.empty()) {
-				error("ConfigFile::loadFromStream: Key/value pair found outside a section in line %d", lineno);
-			}
-
-			// 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
-			kv.key = String(t, p);
-			kv.value = String(p + 1);
-
-			// Trim of spaces
-			kv.key.trim();
-			kv.value.trim();
-
-			// Store comment
-			kv.comment = comment;
-			comment.clear();
-
-			assert(isValidName(kv.key));
-
-			section.keys.push_back(kv);
-		}
-	}
-
-	// Save last section
-	if (!section.name.empty())
-		_sections.push_back(section);
-
-	return (!stream.err() || stream.eos());
-}
-
-bool ConfigFile::saveToFile(const String &filename) {
-	DumpFile file;
-	if (file.open(filename))
-		return saveToStream(file);
-	else
-		return false;
-}
-
-bool ConfigFile::saveToSaveFile(const char *filename) {
-	assert(g_system);
-	SaveFileManager *saveFileMan = g_system->getSavefileManager();
-	WriteStream *saveFile;
-
-	assert(saveFileMan);
-	if (!(saveFile = saveFileMan->openForSaving(filename)))
-		return false;
-
-	bool status = saveToStream(*saveFile);
-	delete saveFile;
-	return status;
-}
-
-bool ConfigFile::saveToStream(WriteStream &stream) {
-	for (List<Section>::iterator i = _sections.begin(); i != _sections.end(); ++i) {
-		// Write out the section comment, if any
-		if (! i->comment.empty()) {
-			stream.writeString(i->comment);
-		}
-
-		// Write out the section name
-		stream.writeByte('[');
-		stream.writeString(i->name);
-		stream.writeByte(']');
-		stream.writeByte('\n');
-
-		// Write out the key/value pairs
-		for (List<KeyValue>::iterator kv = i->keys.begin(); kv != i->keys.end(); ++kv) {
-			// Write out the comment, if any
-			if (! kv->comment.empty()) {
-				stream.writeString(kv->comment);
-			}
-			// Write out the key/value pair
-			stream.writeString(kv->key);
-			stream.writeByte('=');
-			stream.writeString(kv->value);
-			stream.writeByte('\n');
-		}
-	}
-
-	stream.flush();
-	return !stream.err();
-}
-
-void ConfigFile::addSection(const String &section) {
-	Section *s = getSection(section);
-	if (s)
-		return;
-
-	Section newSection;
-	newSection.name = section;
-	_sections.push_back(newSection);
-}
-
-void ConfigFile::removeSection(const String &section) {
-	assert(isValidName(section));
-	for (List<Section>::iterator i = _sections.begin(); i != _sections.end(); ++i) {
-		if (section.equalsIgnoreCase(i->name)) {
-			_sections.erase(i);
-			return;
-		}
-	}
-}
-
-bool ConfigFile::hasSection(const String &section) const {
-	assert(isValidName(section));
-	const Section *s = getSection(section);
-	return s != 0;
-}
-
-void ConfigFile::renameSection(const String &oldName, const String &newName) {
-	assert(isValidName(oldName));
-	assert(isValidName(newName));
-
-	Section *os = getSection(oldName);
-	const Section *ns = getSection(newName);
-	if (os) {
-		// HACK: For now we just print a warning, for more info see the TODO
-		// below.
-		if (ns)
-			warning("ConfigFile::renameSection: Section name \"%s\" already used", newName.c_str());
-		else
-			os->name = newName;
-	}
-	// TODO: Check here whether there already is a section with the
-	// new name. Not sure how to cope with that case, we could:
-	// - simply remove the existing "newName" section
-	// - error out
-	// - merge the two sections "oldName" and "newName"
-}
-
-
-bool ConfigFile::hasKey(const String &key, const String &section) const {
-	assert(isValidName(key));
-	assert(isValidName(section));
-
-	const Section *s = getSection(section);
-	if (!s)
-		return false;
-	return s->hasKey(key);
-}
-
-void ConfigFile::removeKey(const String &key, const String &section) {
-	assert(isValidName(key));
-	assert(isValidName(section));
-
-	Section *s = getSection(section);
-	if (s)
-		 s->removeKey(key);
-}
-
-bool ConfigFile::getKey(const String &key, const String &section, String &value) const {
-	assert(isValidName(key));
-	assert(isValidName(section));
-
-	const Section *s = getSection(section);
-	if (!s)
-		return false;
-	const KeyValue *kv = s->getKey(key);
-	if (!kv)
-		return false;
-	value = kv->value;
-	return true;
-}
-
-void ConfigFile::setKey(const String &key, const String &section, const String &value) {
-	assert(isValidName(key));
-	assert(isValidName(section));
-	// TODO: Verify that value is valid, too. In particular, it shouldn't
-	// contain CR or LF...
-
-	Section *s = getSection(section);
-	if (!s) {
-		KeyValue newKV;
-		newKV.key = key;
-		newKV.value = value;
-
-		Section newSection;
-		newSection.name = section;
-		newSection.keys.push_back(newKV);
-
-		_sections.push_back(newSection);
-	} else {
-		s->setKey(key, value);
-	}
-}
-
-const ConfigFile::SectionKeyList ConfigFile::getKeys(const String &section) const {
-	const Section *s = getSection(section);
-
-	return s->getKeys();
-}
-
-ConfigFile::Section *ConfigFile::getSection(const String &section) {
-	for (List<Section>::iterator i = _sections.begin(); i != _sections.end(); ++i) {
-		if (section.equalsIgnoreCase(i->name)) {
-			return &(*i);
-		}
-	}
-	return 0;
-}
-
-const ConfigFile::Section *ConfigFile::getSection(const String &section) const {
-	for (List<Section>::const_iterator i = _sections.begin(); i != _sections.end(); ++i) {
-		if (section.equalsIgnoreCase(i->name)) {
-			return &(*i);
-		}
-	}
-	return 0;
-}
-
-bool ConfigFile::Section::hasKey(const String &key) const {
-	return getKey(key) != 0;
-}
-
-const ConfigFile::KeyValue* ConfigFile::Section::getKey(const String &key) const {
-	for (List<KeyValue>::const_iterator i = keys.begin(); i != keys.end(); ++i) {
-		if (key.equalsIgnoreCase(i->key)) {
-			return &(*i);
-		}
-	}
-	return 0;
-}
-
-void ConfigFile::Section::setKey(const String &key, const String &value) {
-	for (List<KeyValue>::iterator i = keys.begin(); i != keys.end(); ++i) {
-		if (key.equalsIgnoreCase(i->key)) {
-			i->value = value;
-			return;
-		}
-	}
-
-	KeyValue newKV;
-	newKV.key = key;
-	newKV.value = value;
-	keys.push_back(newKV);
-}
-
-void ConfigFile::Section::removeKey(const String &key) {
-	for (List<KeyValue>::iterator i = keys.begin(); i != keys.end(); ++i) {
-		if (key.equalsIgnoreCase(i->key)) {
-			keys.erase(i);
-			return;
-		}
-	}
-}
-
-} // End of namespace Common
diff --git a/common/config-file.h b/common/config-file.h
deleted file mode 100644
index 8bba851..0000000
--- a/common/config-file.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/* 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.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef COMMON_CONFIG_FILE_H
-#define COMMON_CONFIG_FILE_H
-
-#include "common/hash-str.h"
-#include "common/list.h"
-#include "common/str.h"
-
-namespace Common {
-
-class SeekableReadStream;
-class WriteStream;
-
-/**
- * This class allows reading/writing INI style config files.
- * It is used by the ConfigManager for storage, but can also
- * be used by other code if it needs to read/write custom INI
- * files.
- *
- * Lines starting with a '#' are ignored (i.e. treated as comments).
- * Some effort is made to preserve comments, though.
- *
- * This class makes no attempts to provide fast access to key/value pairs.
- * In particular, it stores all sections and k/v pairs in lists, not
- * in dictionaries/maps. This makes it very easy to read/write the data
- * from/to files, but of course is not appropriate for fast access.
- * The main reason is that this class is indeed geared toward doing precisely
- * that!
- * If you need fast access to the game config, use higher level APIs, like the
- * one provided by ConfigManager.
- */
-class ConfigFile {
-public:
-	struct KeyValue {
-		String key;
-		String value;
-		String comment;
-	};
-
-	typedef List<KeyValue> SectionKeyList;
-
-	/** A section in a config file. I.e. corresponds to something like this:
-	 *   [mySection]
-	 *   key=value
-	 *
-	 * Comments are also stored, to keep users happy who like editing their
-	 * config files manually.
-	 */
-	struct Section {
-		String name;
-		List<KeyValue> keys;
-		String comment;
-
-		bool hasKey(const String &key) const;
-		const KeyValue* getKey(const String &key) const;
-		void setKey(const String &key, const String &value);
-		void removeKey(const String &key);
-		const SectionKeyList getKeys() const { return keys; }
-	};
-
-	typedef List<Section> SectionList;
-
-public:
-	ConfigFile();
-	~ConfigFile();
-
-	// TODO: Maybe add a copy constructor etc.?
-
-	/**
-	 * Check whether the given string is a valid section or key name.
-	 * For that, it must only consist of letters, numbers, dashes and
-	 * underscores. In particular, white space and "#", "=", "[", "]"
-	 * are not valid!
-	 */
-	static bool isValidName(const String &name);
-
-	/** Reset everything stored in this config file. */
-	void	clear();
-
-	bool	loadFromFile(const String &filename);
-	bool	loadFromSaveFile(const char *filename);
-	bool	loadFromStream(SeekableReadStream &stream);
-	bool	saveToFile(const String &filename);
-	bool	saveToSaveFile(const char *filename);
-	bool	saveToStream(WriteStream &stream);
-
-	bool	hasSection(const String &section) const;
-	void	addSection(const String &section);
-	void	removeSection(const String &section);
-	void	renameSection(const String &oldName, const String &newName);
-
-	bool	hasKey(const String &key, const String &section) const;
-	bool	getKey(const String &key, const String &section, String &value) const;
-	void	setKey(const String &key, const String &section, const String &value);
-	void	removeKey(const String &key, const String &section);
-
-	const SectionList getSections() const { return _sections; }
-	const SectionKeyList getKeys(const String &section) const;
-
-	void listKeyValues(StringMap &kv);
-
-private:
-	SectionList _sections;
-
-	Section *getSection(const String &section);
-	const Section *getSection(const String &section) const;
-};
-
-/*
-- ConfigMan owns a config file
-- allow direct access to that config file (for the launcher)
-- simplify and unify the regular ConfigMan API in exchange
-
-
-*/
-
-} // End of namespace Common
-
-#endif
diff --git a/common/config-manager.h b/common/config-manager.h
index d43a7be..45a1f2d 100644
--- a/common/config-manager.h
+++ b/common/config-manager.h
@@ -24,7 +24,7 @@
 #define COMMON_CONFIG_MANAGER_H
 
 #include "common/array.h"
-//#include "common/config-file.h"
+//#include "common/ini-file.h"
 #include "common/hashmap.h"
 #include "common/singleton.h"
 #include "common/str.h"
diff --git a/common/ini-file.cpp b/common/ini-file.cpp
new file mode 100644
index 0000000..be5247d
--- /dev/null
+++ b/common/ini-file.cpp
@@ -0,0 +1,392 @@
+/* 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.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/ini-file.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "common/textconsole.h"
+
+namespace Common {
+
+bool INIFile::isValidName(const String &name) {
+	const char *p = name.c_str();
+	while (*p && (isAlnum(*p) || *p == '-' || *p == '_' || *p == '.'))
+		p++;
+	return *p == 0;
+}
+
+INIFile::INIFile() {
+}
+
+INIFile::~INIFile() {
+}
+
+void INIFile::clear() {
+	_sections.clear();
+}
+
+bool INIFile::loadFromFile(const String &filename) {
+	File file;
+	if (file.open(filename))
+		return loadFromStream(file);
+	else
+		return false;
+}
+
+bool INIFile::loadFromSaveFile(const char *filename) {
+	assert(g_system);
+	SaveFileManager *saveFileMan = g_system->getSavefileManager();
+	SeekableReadStream *loadFile;
+
+	assert(saveFileMan);
+	if (!(loadFile = saveFileMan->openForLoading(filename)))
+		return false;
+
+	bool status = loadFromStream(*loadFile);
+	delete loadFile;
+	return status;
+}
+
+bool INIFile::loadFromStream(SeekableReadStream &stream) {
+	Section section;
+	KeyValue kv;
+	String comment;
+	int lineno = 0;
+
+	// TODO: Detect if a section occurs multiple times (or likewise, if
+	// a key occurs multiple times inside one section).
+
+	while (!stream.eos() && !stream.err()) {
+		lineno++;
+
+		// Read a line
+		String line = stream.readLine();
+
+		if (line.size() == 0) {
+			// Do nothing
+		} else if (line[0] == '#' || line[0] == ';' || line.hasPrefix("//")) {
+			// Accumulate comments here. Once we encounter either the start
+			// of a new section, or a key-value-pair, we associate the value
+			// of the 'comment' variable with that entity. The semicolon and
+			// C++-style comments are used for Living Books games in Mohawk.
+			comment += line;
+			comment += "\n";
+		} else if (line[0] == '(') {
+			// HACK: The following is a hack added by Kirben to support the
+			// "map.ini" used in the HE SCUMM game "SPY Fox in Hold the Mustard".
+			//
+			// It would be nice if this hack could be restricted to that game,
+			// but the current design of this class doesn't allow to do that
+			// in a nice fashion (a "isMustard" parameter is *not* a nice
+			// solution).
+			comment += line;
+			comment += "\n";
+		} else if (line[0] == '[') {
+			// It's a new section which begins here.
+			const char *p = line.c_str() + 1;
+			// Get the section name, and check whether it's valid (that
+			// is, verify that it only consists of alphanumerics,
+			// periods, dashes and underscores). Mohawk Living Books games
+			// can have periods in their section names.
+			while (*p && (isAlnum(*p) || *p == '-' || *p == '_' || *p == '.'))
+				p++;
+
+			if (*p == '\0')
+				error("INIFile::loadFromStream: missing ] in line %d", lineno);
+			else if (*p != ']')
+				error("INIFile::loadFromStream: Invalid character '%c' occurred in section name in line %d", *p, lineno);
+
+			// Previous section is finished now, store it.
+			if (!section.name.empty())
+				_sections.push_back(section);
+
+			section.name = String(line.c_str() + 1, p);
+			section.keys.clear();
+			section.comment = comment;
+			comment.clear();
+
+			assert(isValidName(section.name));
+		} else {
+			// This line should be a line with a 'key=value' pair, or an empty one.
+
+			// Skip leading whitespaces
+			const char *t = line.c_str();
+			while (isSpace(*t))
+				t++;
+
+			// Skip empty lines / lines with only whitespace
+			if (*t == 0)
+				continue;
+
+			// If no section has been set, this config file is invalid!
+			if (section.name.empty()) {
+				error("INIFile::loadFromStream: Key/value pair found outside a section in line %d", lineno);
+			}
+
+			// 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
+			kv.key = String(t, p);
+			kv.value = String(p + 1);
+
+			// Trim of spaces
+			kv.key.trim();
+			kv.value.trim();
+
+			// Store comment
+			kv.comment = comment;
+			comment.clear();
+
+			assert(isValidName(kv.key));
+
+			section.keys.push_back(kv);
+		}
+	}
+
+	// Save last section
+	if (!section.name.empty())
+		_sections.push_back(section);
+
+	return (!stream.err() || stream.eos());
+}
+
+bool INIFile::saveToFile(const String &filename) {
+	DumpFile file;
+	if (file.open(filename))
+		return saveToStream(file);
+	else
+		return false;
+}
+
+bool INIFile::saveToSaveFile(const char *filename) {
+	assert(g_system);
+	SaveFileManager *saveFileMan = g_system->getSavefileManager();
+	WriteStream *saveFile;
+
+	assert(saveFileMan);
+	if (!(saveFile = saveFileMan->openForSaving(filename)))
+		return false;
+
+	bool status = saveToStream(*saveFile);
+	delete saveFile;
+	return status;
+}
+
+bool INIFile::saveToStream(WriteStream &stream) {
+	for (List<Section>::iterator i = _sections.begin(); i != _sections.end(); ++i) {
+		// Write out the section comment, if any
+		if (! i->comment.empty()) {
+			stream.writeString(i->comment);
+		}
+
+		// Write out the section name
+		stream.writeByte('[');
+		stream.writeString(i->name);
+		stream.writeByte(']');
+		stream.writeByte('\n');
+
+		// Write out the key/value pairs
+		for (List<KeyValue>::iterator kv = i->keys.begin(); kv != i->keys.end(); ++kv) {
+			// Write out the comment, if any
+			if (! kv->comment.empty()) {
+				stream.writeString(kv->comment);
+			}
+			// Write out the key/value pair
+			stream.writeString(kv->key);
+			stream.writeByte('=');
+			stream.writeString(kv->value);
+			stream.writeByte('\n');
+		}
+	}
+
+	stream.flush();
+	return !stream.err();
+}
+
+void INIFile::addSection(const String &section) {
+	Section *s = getSection(section);
+	if (s)
+		return;
+
+	Section newSection;
+	newSection.name = section;
+	_sections.push_back(newSection);
+}
+
+void INIFile::removeSection(const String &section) {
+	assert(isValidName(section));
+	for (List<Section>::iterator i = _sections.begin(); i != _sections.end(); ++i) {
+		if (section.equalsIgnoreCase(i->name)) {
+			_sections.erase(i);
+			return;
+		}
+	}
+}
+
+bool INIFile::hasSection(const String &section) const {
+	assert(isValidName(section));
+	const Section *s = getSection(section);
+	return s != 0;
+}
+
+void INIFile::renameSection(const String &oldName, const String &newName) {
+	assert(isValidName(oldName));
+	assert(isValidName(newName));
+
+	Section *os = getSection(oldName);
+	const Section *ns = getSection(newName);
+	if (os) {
+		// HACK: For now we just print a warning, for more info see the TODO
+		// below.
+		if (ns)
+			warning("INIFile::renameSection: Section name \"%s\" already used", newName.c_str());
+		else
+			os->name = newName;
+	}
+	// TODO: Check here whether there already is a section with the
+	// new name. Not sure how to cope with that case, we could:
+	// - simply remove the existing "newName" section
+	// - error out
+	// - merge the two sections "oldName" and "newName"
+}
+
+
+bool INIFile::hasKey(const String &key, const String &section) const {
+	assert(isValidName(key));
+	assert(isValidName(section));
+
+	const Section *s = getSection(section);
+	if (!s)
+		return false;
+	return s->hasKey(key);
+}
+
+void INIFile::removeKey(const String &key, const String &section) {
+	assert(isValidName(key));
+	assert(isValidName(section));
+
+	Section *s = getSection(section);
+	if (s)
+		 s->removeKey(key);
+}
+
+bool INIFile::getKey(const String &key, const String &section, String &value) const {
+	assert(isValidName(key));
+	assert(isValidName(section));
+
+	const Section *s = getSection(section);
+	if (!s)
+		return false;
+	const KeyValue *kv = s->getKey(key);
+	if (!kv)
+		return false;
+	value = kv->value;
+	return true;
+}
+
+void INIFile::setKey(const String &key, const String &section, const String &value) {
+	assert(isValidName(key));
+	assert(isValidName(section));
+	// TODO: Verify that value is valid, too. In particular, it shouldn't
+	// contain CR or LF...
+
+	Section *s = getSection(section);
+	if (!s) {
+		KeyValue newKV;
+		newKV.key = key;
+		newKV.value = value;
+
+		Section newSection;
+		newSection.name = section;
+		newSection.keys.push_back(newKV);
+
+		_sections.push_back(newSection);
+	} else {
+		s->setKey(key, value);
+	}
+}
+
+const INIFile::SectionKeyList INIFile::getKeys(const String &section) const {
+	const Section *s = getSection(section);
+
+	return s->getKeys();
+}
+
+INIFile::Section *INIFile::getSection(const String &section) {
+	for (List<Section>::iterator i = _sections.begin(); i != _sections.end(); ++i) {
+		if (section.equalsIgnoreCase(i->name)) {
+			return &(*i);
+		}
+	}
+	return 0;
+}
+
+const INIFile::Section *INIFile::getSection(const String &section) const {
+	for (List<Section>::const_iterator i = _sections.begin(); i != _sections.end(); ++i) {
+		if (section.equalsIgnoreCase(i->name)) {
+			return &(*i);
+		}
+	}
+	return 0;
+}
+
+bool INIFile::Section::hasKey(const String &key) const {
+	return getKey(key) != 0;
+}
+
+const INIFile::KeyValue* INIFile::Section::getKey(const String &key) const {
+	for (List<KeyValue>::const_iterator i = keys.begin(); i != keys.end(); ++i) {
+		if (key.equalsIgnoreCase(i->key)) {
+			return &(*i);
+		}
+	}
+	return 0;
+}
+
+void INIFile::Section::setKey(const String &key, const String &value) {
+	for (List<KeyValue>::iterator i = keys.begin(); i != keys.end(); ++i) {
+		if (key.equalsIgnoreCase(i->key)) {
+			i->value = value;
+			return;
+		}
+	}
+
+	KeyValue newKV;
+	newKV.key = key;
+	newKV.value = value;
+	keys.push_back(newKV);
+}
+
+void INIFile::Section::removeKey(const String &key) {
+	for (List<KeyValue>::iterator i = keys.begin(); i != keys.end(); ++i) {
+		if (key.equalsIgnoreCase(i->key)) {
+			keys.erase(i);
+			return;
+		}
+	}
+}
+
+} // End of namespace Common
diff --git a/common/ini-file.h b/common/ini-file.h
new file mode 100644
index 0000000..c7da6de
--- /dev/null
+++ b/common/ini-file.h
@@ -0,0 +1,140 @@
+/* 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.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef COMMON_INI_FILE_H
+#define COMMON_INI_FILE_H
+
+#include "common/hash-str.h"
+#include "common/list.h"
+#include "common/str.h"
+
+namespace Common {
+
+class SeekableReadStream;
+class WriteStream;
+
+/**
+ * This class allows reading/writing INI style config files.
+ * It is used by the ConfigManager for storage, but can also
+ * be used by other code if it needs to read/write custom INI
+ * files.
+ *
+ * Lines starting with a '#' are ignored (i.e. treated as comments).
+ * Some effort is made to preserve comments, though.
+ *
+ * This class makes no attempts to provide fast access to key/value pairs.
+ * In particular, it stores all sections and k/v pairs in lists, not
+ * in dictionaries/maps. This makes it very easy to read/write the data
+ * from/to files, but of course is not appropriate for fast access.
+ * The main reason is that this class is indeed geared toward doing precisely
+ * that!
+ * If you need fast access to the game config, use higher level APIs, like the
+ * one provided by ConfigManager.
+ */
+class INIFile {
+public:
+	struct KeyValue {
+		String key;
+		String value;
+		String comment;
+	};
+
+	typedef List<KeyValue> SectionKeyList;
+
+	/** A section in a ini file. I.e. corresponds to something like this:
+	 *   [mySection]
+	 *   key=value
+	 *
+	 * Comments are also stored, to keep users happy who like editing their
+	 * ini files manually.
+	 */
+	struct Section {
+		String name;
+		List<KeyValue> keys;
+		String comment;
+
+		bool hasKey(const String &key) const;
+		const KeyValue* getKey(const String &key) const;
+		void setKey(const String &key, const String &value);
+		void removeKey(const String &key);
+		const SectionKeyList getKeys() const { return keys; }
+	};
+
+	typedef List<Section> SectionList;
+
+public:
+	INIFile();
+	~INIFile();
+
+	// TODO: Maybe add a copy constructor etc.?
+
+	/**
+	 * Check whether the given string is a valid section or key name.
+	 * For that, it must only consist of letters, numbers, dashes and
+	 * underscores. In particular, white space and "#", "=", "[", "]"
+	 * are not valid!
+	 */
+	static bool isValidName(const String &name);
+
+	/** Reset everything stored in this ini file. */
+	void	clear();
+
+	bool	loadFromFile(const String &filename);
+	bool	loadFromSaveFile(const char *filename);
+	bool	loadFromStream(SeekableReadStream &stream);
+	bool	saveToFile(const String &filename);
+	bool	saveToSaveFile(const char *filename);
+	bool	saveToStream(WriteStream &stream);
+
+	bool	hasSection(const String &section) const;
+	void	addSection(const String &section);
+	void	removeSection(const String &section);
+	void	renameSection(const String &oldName, const String &newName);
+
+	bool	hasKey(const String &key, const String &section) const;
+	bool	getKey(const String &key, const String &section, String &value) const;
+	void	setKey(const String &key, const String &section, const String &value);
+	void	removeKey(const String &key, const String &section);
+
+	const SectionList getSections() const { return _sections; }
+	const SectionKeyList getKeys(const String &section) const;
+
+	void listKeyValues(StringMap &kv);
+
+private:
+	SectionList _sections;
+
+	Section *getSection(const String &section);
+	const Section *getSection(const String &section) const;
+};
+
+/*
+- ConfigMan owns a config file
+- allow direct access to that config file (for the launcher)
+- simplify and unify the regular ConfigMan API in exchange
+
+
+*/
+
+} // End of namespace Common
+
+#endif
diff --git a/common/module.mk b/common/module.mk
index 9f9126c..1b34d15 100644
--- a/common/module.mk
+++ b/common/module.mk
@@ -2,7 +2,6 @@ MODULE := common
 
 MODULE_OBJS := \
 	archive.o \
-	config-file.o \
 	config-manager.o \
 	coroutines.o \
 	dcl.o \
@@ -15,6 +14,7 @@ MODULE_OBJS := \
 	gui_options.o \
 	hashmap.o \
 	iff_container.o \
+	ini-file.o \
 	installshield_cab.o \
 	language.o \
 	localization.o \
diff --git a/engines/composer/composer.h b/engines/composer/composer.h
index 33a5356..7d80224 100644
--- a/engines/composer/composer.h
+++ b/engines/composer/composer.h
@@ -23,7 +23,7 @@
 #ifndef COMPOSER_H
 #define COMPOSER_H
 
-#include "common/config-file.h"
+#include "common/ini-file.h"
 #include "common/random.h"
 #include "common/system.h"
 #include "common/debug.h"
@@ -174,7 +174,7 @@ private:
 	Common::List<Sprite> _sprites;
 
 	uint _directoriesToStrip;
-	Common::ConfigFile _bookIni;
+	Common::INIFile _bookIni;
 	Common::String _bookGroup;
 	Common::List<Library> _libraries;
 	Common::Array<PendingPageChange> _pendingPageChanges;
diff --git a/engines/gob/iniconfig.cpp b/engines/gob/iniconfig.cpp
index bba5317..032231b 100644
--- a/engines/gob/iniconfig.cpp
+++ b/engines/gob/iniconfig.cpp
@@ -73,7 +73,7 @@ bool INIConfig::getConfig(const Common::String &file, Config &config) {
 }
 
 bool INIConfig::openConfig(const Common::String &file, Config &config) {
-	config.config  = new Common::ConfigFile();
+	config.config  = new Common::INIFile();
 	config.created = false;
 
 	if (!config.config->loadFromFile(file)) {
@@ -89,7 +89,7 @@ bool INIConfig::openConfig(const Common::String &file, Config &config) {
 }
 
 bool INIConfig::createConfig(const Common::String &file, Config &config) {
-	config.config  = new Common::ConfigFile();
+	config.config  = new Common::INIFile();
 	config.created = true;
 
 	_configs.setVal(file, config);
diff --git a/engines/gob/iniconfig.h b/engines/gob/iniconfig.h
index bf60f2d..c189017 100644
--- a/engines/gob/iniconfig.h
+++ b/engines/gob/iniconfig.h
@@ -24,7 +24,7 @@
 #define GOB_INICONFIG_H
 
 #include "common/str.h"
-#include "common/config-file.h"
+#include "common/ini-file.h"
 #include "common/hashmap.h"
 
 namespace Gob {
@@ -43,7 +43,7 @@ public:
 
 private:
 	struct Config {
-		Common::ConfigFile *config;
+		Common::INIFile *config;
 		bool created;
 	};
 
diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp
index efa0dd3..634ff44 100644
--- a/engines/mohawk/livingbooks.cpp
+++ b/engines/mohawk/livingbooks.cpp
@@ -311,8 +311,8 @@ void MohawkEngine_LivingBooks::loadBookInfo(const Common::String &filename) {
 	//     - fDebugWindow                (always 0?)
 
 	if (_bookInfoFile.hasSection("Globals")) {
-		const Common::ConfigFile::SectionKeyList globals = _bookInfoFile.getKeys("Globals");
-		for (Common::ConfigFile::SectionKeyList::const_iterator i = globals.begin(); i != globals.end(); i++) {
+		const Common::INIFile::SectionKeyList globals = _bookInfoFile.getKeys("Globals");
+		for (Common::INIFile::SectionKeyList::const_iterator i = globals.begin(); i != globals.end(); i++) {
 			Common::String command = Common::String::format("%s = %s", i->key.c_str(), i->value.c_str());
 			LBCode tempCode(this, 0);
 			uint offset = tempCode.parseCode(command);
diff --git a/engines/mohawk/livingbooks.h b/engines/mohawk/livingbooks.h
index 76da7d8..615fcd0 100644
--- a/engines/mohawk/livingbooks.h
+++ b/engines/mohawk/livingbooks.h
@@ -28,7 +28,7 @@
 #include "mohawk/livingbooks_graphics.h"
 #include "mohawk/sound.h"
 
-#include "common/config-file.h"
+#include "common/ini-file.h"
 #include "common/rect.h"
 #include "common/queue.h"
 #include "common/random.h"
@@ -759,7 +759,7 @@ public:
 
 private:
 	LivingBooksConsole *_console;
-	Common::ConfigFile _bookInfoFile;
+	Common::INIFile _bookInfoFile;
 
 	Common::String getBookInfoFileName() const;
 	void loadBookInfo(const Common::String &filename);
diff --git a/engines/mohawk/livingbooks_lbx.cpp b/engines/mohawk/livingbooks_lbx.cpp
index 2b8b22e..dcf8caa 100644
--- a/engines/mohawk/livingbooks_lbx.cpp
+++ b/engines/mohawk/livingbooks_lbx.cpp
@@ -33,7 +33,7 @@ public:
 	bool call(uint callId, const Common::Array<LBValue> &params, LBValue &result);
 
 protected:
-	Common::ConfigFile _dataFile;
+	Common::INIFile _dataFile;
 	Common::String _curSection;
 
 	void open(const Common::String &filename);
@@ -77,8 +77,8 @@ bool LBXDataFile::call(uint callId, const Common::Array<LBValue> &params, LBValu
 	case kLBXDataFileGetSectionList:
 		{
 		Common::SharedPtr<LBList> list = Common::SharedPtr<LBList>(new LBList);
-		Common::ConfigFile::SectionList sections = _dataFile.getSections();
-		for (Common::List<Common::ConfigFile::Section>::const_iterator i = sections.begin(); i != sections.end(); ++i)
+		Common::INIFile::SectionList sections = _dataFile.getSections();
+		for (Common::List<Common::INIFile::Section>::const_iterator i = sections.begin(); i != sections.end(); ++i)
 			list->array.push_back(LBValue(i->name));
 		result = LBValue(list);
 		}
@@ -103,8 +103,8 @@ bool LBXDataFile::call(uint callId, const Common::Array<LBValue> &params, LBValu
 			error("incorrect number of parameters (%d) to LBXDataFile::loadCurSectionVars", params.size());
 
 		{
-		const Common::ConfigFile::SectionKeyList globals = _dataFile.getKeys(_curSection);
-		for (Common::ConfigFile::SectionKeyList::const_iterator i = globals.begin(); i != globals.end(); i++) {
+		const Common::INIFile::SectionKeyList globals = _dataFile.getKeys(_curSection);
+		for (Common::INIFile::SectionKeyList::const_iterator i = globals.begin(); i != globals.end(); i++) {
 			Common::String command = Common::String::format("%s = %s", i->key.c_str(), i->value.c_str());
 			LBCode tempCode(_vm, 0);
 			uint offset = tempCode.parseCode(command);
diff --git a/engines/scumm/he/script_v80he.cpp b/engines/scumm/he/script_v80he.cpp
index eb62b65..ae43d71 100644
--- a/engines/scumm/he/script_v80he.cpp
+++ b/engines/scumm/he/script_v80he.cpp
@@ -23,7 +23,7 @@
 #ifdef ENABLE_HE
 
 #include "common/archive.h"
-#include "common/config-file.h"
+#include "common/ini-file.h"
 #include "common/config-manager.h"
 #include "common/macresman.h"
 #include "common/savefile.h"
@@ -180,7 +180,7 @@ void ScummEngine_v80he::o80_readConfigFile() {
 		}
 	} else {
 		// Normal Windows INI files
-		Common::ConfigFile confFile;
+		Common::INIFile confFile;
 		if (!strcmp((char *)filename + r, "map.ini"))
 			confFile.loadFromFile((const char *)filename + r);
 		else
@@ -250,7 +250,7 @@ void ScummEngine_v80he::o80_writeConfigFile() {
 			memcpy(section, "BluesTreasureHunt-Disc2\0", 24);
 	}
 
-	Common::ConfigFile ConfFile;
+	Common::INIFile ConfFile;
 	ConfFile.loadFromSaveFile((const char *)filename + r);
 	ConfFile.setKey((char *)option, (char *)section, (char *)string);
 	ConfFile.saveToSaveFile((const char *)filename + r);
diff --git a/engines/testbed/config.cpp b/engines/testbed/config.cpp
index 6b56616..a40d239 100644
--- a/engines/testbed/config.cpp
+++ b/engines/testbed/config.cpp
@@ -213,22 +213,22 @@ void TestbedConfigManager::parseConfigFile() {
 		return;
 	}
 	_configFileInterface.loadFromStream(*rs);
-	Common::ConfigFile::SectionList sections = _configFileInterface.getSections();
+	Common::INIFile::SectionList sections = _configFileInterface.getSections();
 	Testsuite *currTS = 0;
 
-	for (Common::ConfigFile::SectionList::const_iterator i = sections.begin(); i != sections.end(); i++) {
+	for (Common::INIFile::SectionList::const_iterator i = sections.begin(); i != sections.end(); i++) {
 		if (i->name.equalsIgnoreCase("Global")) {
 			// Global params may be directly queried, ignore them
 		} else {
 			// A testsuite, process it.
 			currTS = getTestsuiteByName(i->name);
-			Common::ConfigFile::SectionKeyList kList = i->getKeys();
+			Common::INIFile::SectionKeyList kList = i->getKeys();
 			if (!currTS) {
 				Testsuite::logPrintf("Warning! Error in config: Testsuite %s not found\n", i->name.c_str());
 				continue;
 			}
 
-			for (Common::ConfigFile::SectionKeyList::const_iterator j = kList.begin(); j != kList.end(); j++) {
+			for (Common::INIFile::SectionKeyList::const_iterator j = kList.begin(); j != kList.end(); j++) {
 				if (j->key.equalsIgnoreCase("this")) {
 					currTS->enable(stringToBool(j->value));
 				} else {
diff --git a/engines/testbed/config.h b/engines/testbed/config.h
index fd5588a..d611ae4 100644
--- a/engines/testbed/config.h
+++ b/engines/testbed/config.h
@@ -24,7 +24,7 @@
 
 
 #include "common/array.h"
-#include "common/config-file.h"
+#include "common/ini-file.h"
 #include "common/str-array.h"
 #include "common/tokenizer.h"
 
@@ -62,7 +62,7 @@ public:
 private:
 	Common::Array<Testsuite *> &_testsuiteList;
 	Common::String	_configFileName;
-	Common::ConfigFile	_configFileInterface;
+	Common::INIFile	_configFileInterface;
 	void parseConfigFile();
 };
 


Commit: 6da6e4e68628bba656c3c3e1d2f6f9e27013f8f8
    https://github.com/scummvm/scummvm/commit/6da6e4e68628bba656c3c3e1d2f6f9e27013f8f8
Author: Johannes Schickel (lordhoto at scummvm.org)
Date: 2013-08-08T07:30:38-07:00

Commit Message:
COMMON: Remove outdated comments on INIFile.

These very old comments claimed that ConfigManager uses INIFile. This is not
true however. Thus removing them should clear things up a little bit.

Changed paths:
    common/ini-file.h



diff --git a/common/ini-file.h b/common/ini-file.h
index c7da6de..1d94ce7 100644
--- a/common/ini-file.h
+++ b/common/ini-file.h
@@ -34,9 +34,6 @@ class WriteStream;
 
 /**
  * This class allows reading/writing INI style config files.
- * It is used by the ConfigManager for storage, but can also
- * be used by other code if it needs to read/write custom INI
- * files.
  *
  * Lines starting with a '#' are ignored (i.e. treated as comments).
  * Some effort is made to preserve comments, though.
@@ -47,8 +44,6 @@ class WriteStream;
  * from/to files, but of course is not appropriate for fast access.
  * The main reason is that this class is indeed geared toward doing precisely
  * that!
- * If you need fast access to the game config, use higher level APIs, like the
- * one provided by ConfigManager.
  */
 class INIFile {
 public:
@@ -127,14 +122,6 @@ private:
 	const Section *getSection(const String &section) const;
 };
 
-/*
-- ConfigMan owns a config file
-- allow direct access to that config file (for the launcher)
-- simplify and unify the regular ConfigMan API in exchange
-
-
-*/
-
 } // End of namespace Common
 
 #endif


Commit: 0dae60a3577a78f75ae3cf2d2dc88177ba6f128e
    https://github.com/scummvm/scummvm/commit/0dae60a3577a78f75ae3cf2d2dc88177ba6f128e
Author: Johannes Schickel (lordhoto at scummvm.org)
Date: 2013-08-08T07:32:41-07:00

Commit Message:
COMMON: Remove commented out include in config-manager.h.

Changed paths:
    common/config-manager.h



diff --git a/common/config-manager.h b/common/config-manager.h
index 45a1f2d..6295a93 100644
--- a/common/config-manager.h
+++ b/common/config-manager.h
@@ -24,7 +24,6 @@
 #define COMMON_CONFIG_MANAGER_H
 
 #include "common/array.h"
-//#include "common/ini-file.h"
 #include "common/hashmap.h"
 #include "common/singleton.h"
 #include "common/str.h"


Commit: de952ae0b9226a67c8d20916e29f81258a2f6223
    https://github.com/scummvm/scummvm/commit/de952ae0b9226a67c8d20916e29f81258a2f6223
Author: Johannes Schickel (lordhoto at gmail.com)
Date: 2013-08-08T15:56:17-07:00

Commit Message:
Merge pull request #373 from lordhoto/ini-file

Rename ConfigFile to INIFile and remove outdated comments

Changed paths:
  A common/ini-file.cpp
  A common/ini-file.h
  R common/config-file.cpp
  R common/config-file.h
    common/config-manager.h
    common/module.mk
    engines/composer/composer.h
    engines/gob/iniconfig.cpp
    engines/gob/iniconfig.h
    engines/mohawk/livingbooks.cpp
    engines/mohawk/livingbooks.h
    engines/mohawk/livingbooks_lbx.cpp
    engines/scumm/he/script_v80he.cpp
    engines/testbed/config.cpp
    engines/testbed/config.h









More information about the Scummvm-git-logs mailing list