/*
* The ManaPlus Client
* Copyright (C) 2004-2009 The Mana World Development Team
* Copyright (C) 2009-2010 The Mana Developers
* Copyright (C) 2011-2019 The ManaPlus Developers
*
* This file is part of The ManaPlus Client.
*
* 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
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef CONFIGURATION_H
#define CONFIGURATION_H
#include "utils/stringutils.h"
#ifdef ENABLE_PUGIXML
#include "utils/xmlwriter.h"
#else
#include "utils/xml.h"
#endif // ENABLE_PUGIXML
#include "defaults.h"
#include "localconsts.h"
class ConfigListener;
class ConfigurationObject;
/**
* Configuration list manager interface; responsible for
* serializing/deserializing configuration choices in containers.
*
* \param T Type of the container elements to serialise
* \param CONT Type of the container we (de)serialise
*/
template <class T, class CONT>
class ConfigurationListManager notfinal
{
public:
ConfigurationListManager()
{ }
A_DELETE_COPY(ConfigurationListManager)
/**
* Writes a value into a configuration object
*
* \param value The value to write out
* \param obj The configuation object to write to
* \return obj, or otherwise NULL to indicate that this option should
* be skipped
*/
virtual ConfigurationObject *writeConfigItem(const T &value,
ConfigurationObject
*const obj) const = 0;
/**
* Reads a value from a configuration object
*
* \param obj The configuration object to read from
* \param container The container to insert the object to
*/
virtual CONT readConfigItem(const ConfigurationObject *const obj,
CONT container)
const A_WARN_UNUSED = 0;
virtual ~ConfigurationListManager()
{ }
};
/**
* Configuration object, mapping values to names and possibly containing
* lists of further configuration objects
*
* \ingroup CORE
*/
class ConfigurationObject notfinal
{
friend class Configuration;
public:
A_DELETE_COPY(ConfigurationObject)
virtual ~ConfigurationObject();
/**
* Sets an option using a string value.
*
* \param key Option identifier.
* \param value Value.
*/
virtual void setValue(const std::string &key,
const std::string &value);
void deleteKey(const std::string &key);
/**
* Gets a value as string.
*
* \param key Option identifier.
* \param deflt Default option if not there or error.
*/
std::string getValue(const std::string &key,
const std::string &deflt) const A_WARN_UNUSED;
int getValue(const std::string &key,
const int deflt) const A_WARN_UNUSED;
int getValueInt(const std::string &key,
const int deflt) const A_WARN_UNUSED;
bool getValueBool(const std::string &key,
const bool deflt) const A_WARN_UNUSED;
unsigned getValue(const std::string &key,
const unsigned deflt) const A_WARN_UNUSED;
double getValue(const std::string &key,
const double deflt) const A_WARN_UNUSED;
/**
* Re-sets all data in the configuration
*/
void clear();
/**
* Serialises a container into a list of configuration options
*
* \param name Name of the list the elements should be stored under
* \param begin Iterator start
* \param end Iterator end
* \param manager An object capable of serialising T items
*/
template <class IT, class T, class CONT>
void setList(const std::string &name, IT begin, IT end,
ConfigurationListManager<T, CONT> *manager)
{
if (!manager)
return;
ConfigurationObject *nextobj = new ConfigurationObject;
deleteList(name);
ConfigurationList *list = &(mContainerOptions[name]);
for (IT it = begin; it != end; it++)
{
ConfigurationObject *const wrobj
= manager->writeConfigItem(*it, nextobj);
if (wrobj)
{ // wrote something
nextobj = new ConfigurationObject;
list->push_back(wrobj);
}
else
{
nextobj->clear(); // you never know...
}
}
delete nextobj;
}
/**
* Serialises a container into a list of configuration options
*
* \param name Name of the list the elements should be read from under
* \param empty Initial (empty) container to write to
* \param manager An object capable of deserialising items into CONT
*/
template<class T, class CONT>
CONT getList(const std::string &name, CONT empty,
ConfigurationListManager<T, CONT> *manager)
{
ConfigurationList *const list = &(mContainerOptions[name]);
CONT container = empty;
if (!manager)
return container;
for (ConfigurationList::const_iterator it = list->begin();
it != list->end();
++ it)
{
container = manager->readConfigItem(*it, container);
}
return container;
}
#ifdef DEBUG_CONFIG
void enableKeyLogging()
{ mLogKeys = true; }
void setIsMain(bool b)
{ mIsMain = b; }
#endif // DEBUG_CONFIG
protected:
ConfigurationObject();
virtual void initFromXML(XmlNodeConstPtrConst parentNode);
virtual void writeToXML(XmlTextWriterPtr writer);
void deleteList(const std::string &name);
typedef std::map<std::string, std::string> Options;
Options mOptions;
typedef std::list<ConfigurationObject *> ConfigurationList;
std::map<std::string, ConfigurationList> mContainerOptions;
#ifdef DEBUG_CONFIG
bool mLogKeys;
bool mIsMain;
#endif // DEBUG_CONFIG
};
#define valTest(num) mStatsRe##num
/**
* Configuration handler for reading (and writing).
*
* \ingroup CORE
*/
class Configuration final : public ConfigurationObject
{
public:
Configuration();
A_DELETE_COPY(Configuration)
~Configuration() override final;
/**
* Reads config file and parse all options into memory.
*
* @param filename path to config file
* @param useResManager Make use of the resource manager.
*/
void init(const std::string &filename,
const UseVirtFs useResManager,
const SkipError skipError);
void reInit();
void unload();
DefaultsData &getDefaultValues()
{ return mDefaultsData; }
/**
* Writes the current settings back to the config file.
*/
void write();
/**
* Adds a listener to the listen list of the specified config option.
*/
void addListener(const std::string &key,
ConfigListener *const listener);
/**
* Removes a listener from the listen list of the specified config
* option.
*/
void removeListener(const std::string &key,
ConfigListener *const listener);
void removeListeners(ConfigListener *const listener);
#ifdef ENABLE_CHECKS
void checkListeners(ConfigListener *const listener,
const char *const file,
const unsigned line);
#endif // ENABLE_CHECKS
void setValue(const std::string &key,
const std::string &value) override;
void incValue(const std::string &key);
void setSilent(const std::string &key,
const std::string &value);
inline void setValue(const std::string &key,
const char *const value)
{ if (value != nullptr) setValue(key, std::string(value)); }
inline void setSilent(const std::string &key,
const char *const value)
{ if (value != nullptr) setSilent(key, std::string(value)); }
inline void setValue(const std::string &key,
const float value)
{ setValue(key, toString(value)); }
inline void setValue(const std::string &key,
const double value)
{ setValue(key, toString(value)); }
inline void setValue(const std::string &key,
const int value)
{ setValue(key, toString(value)); }
inline void setValueInt(const std::string &key,
const int value)
{ setValue(key, toString(value)); }
inline void setValue(const std::string &key,
const unsigned value)
{ setValue(key, toString(value)); }
inline void setValue(const std::string &key,
const bool value)
{ setValue(key, value ? "1" : "0"); }
inline void setSilent(const std::string &key,
const bool value)
{ setSilent(key, value ? "1" : "0"); }
int resetIntValue(const std::string &key);
bool resetBoolValue(const std::string &key);
const std::string &getConfigPath() const noexcept2 A_WARN_UNUSED
{ return mConfigPath; }
/**
* returns a value corresponding to the given key.
* The default value returned in based on fallbacks registry.
* @see defaults.h
*/
int getIntValue(const std::string &key) const A_WARN_UNUSED_NON_TESTS;
float getFloatValue(const std::string &key) const
A_WARN_UNUSED_NON_TESTS;
std::string getStringValue(const std::string &key) const
A_WARN_UNUSED_NON_TESTS;
bool getBoolValue(const std::string &key) const
A_WARN_UNUSED_NON_TESTS;
std::string getDirectory() const noexcept2 A_WARN_UNUSED
{ return mDirectory; }
void removeOldKeys();
std::string getFileName() const noexcept2 A_WARN_UNUSED
{ return mFilename; }
void writeUpdated();
/**
* Clean up the default values member.
*/
void cleanDefaults();
private:
typedef std::list<ConfigListener*> Listeners;
typedef Listeners::iterator ListenerIterator;
typedef std::map<std::string, Listeners> ListenerMap;
typedef ListenerMap::iterator ListenerMapIterator;
ListenerMap mListenerMap;
// Location of config file
std::string mConfigPath;
/// Defaults of value for a given key
DefaultsData mDefaultsData;
std::string mDirectory;
std::string mFilename;
UseVirtFs mUseResManager;
bool mUpdated;
};
extern Configuration branding;
extern Configuration config;
extern Configuration serverConfig;
extern Configuration paths;
extern Configuration features;
#endif // CONFIGURATION_H