diff --git a/source/ps/ConfigDB.cpp b/source/ps/ConfigDB.cpp new file mode 100755 index 0000000000..a0ccaadb01 --- /dev/null +++ b/source/ps/ConfigDB.cpp @@ -0,0 +1,130 @@ +#include "Prometheus.h" +#include "Parser.h" +#include "ConfigDB.h" +#include "CLogger.h" +#include "res/vfs.h" +#include "res/file.h" + +using namespace std; + +typedef map TConfigMap; +TConfigMap CConfigDB::m_Map[CFG_LAST]; +CStr CConfigDB::m_ConfigFile[CFG_LAST]; +bool CConfigDB::m_UseVFS[CFG_LAST]; + +CConfigValue *CConfigDB::GetValue(EConfigNamespace ns, CStr name) +{ + assert(ns < CFG_LAST && ns >= 0); + + TConfigMap::iterator it=m_Map[ns].find(name); + if (it == m_Map[ns].end()) + return NULL; + else + return &(it->second); +} + +CConfigValue *CConfigDB::CreateValue(EConfigNamespace ns, CStr name) +{ + assert(ns < CFG_LAST && ns >= 0); + + CConfigValue *ret=GetValue(ns, name); + if (ret) return ret; + + TConfigMap::iterator it=m_Map[ns].insert(m_Map[ns].begin(), make_pair(name, CConfigValue())); + return &(it->second); +} + +void CConfigDB::SetConfigFile(EConfigNamespace ns, bool useVFS, CStr path) +{ + assert(ns < CFG_LAST && ns >= 0); + + m_ConfigFile[ns]=path; + m_UseVFS[ns]=useVFS; +} + +bool CConfigDB::Reload(EConfigNamespace ns) +{ + // Set up CParser + CParser parser; + CParserLine parserLine; + parser.InputTaskType("Assignment", "_$ident_=_[-$arg(_minus)]_$value_[;$rest]"); + parser.InputTaskType("Comment", "_;$rest"); + + void *buffer; + uint buflen; + File f; + Handle fh; + if (m_UseVFS[ns]) + { + // Open file with VFS + fh=vfs_load(m_ConfigFile[ns], buffer, buflen); + if (fh <= 0) + { + LOG(ERROR, "vfs_load for \"%s\" failed: return was %lld", m_ConfigFile[ns].c_str(), fh); + return false; + } + } + else + { + if (file_open(m_ConfigFile[ns].c_str(), 0, &f)!=0) + { + LOG(ERROR, "file_open for \"%s\" failed", m_ConfigFile[ns].c_str()); + return false; + } + if (file_map(&f, buffer, buflen) != 0) + { + LOG(ERROR, "file_map for \"%s\" failed", m_ConfigFile[ns].c_str()); + return false; + } + } + + TConfigMap newMap; + + char *filebuf=(char *)malloc(buflen+1); + memcpy(filebuf, buffer, buflen); + filebuf[buflen]=0; + + // Read file line by line + char *ctxt=NULL; + // strtok is defined to skip empty tokens, so this neatly takes care of + // unix/windows file endings + const char *delim="\r\n"; + char *line=strtok_r((char *)filebuf, delim, &ctxt); + do + { + // Send line to parser + parserLine.ParseString(parser, line); + // Get name and value from parser + string name; + string value; + + if (parserLine.GetArgCount()>=2 && + parserLine.GetArgString(0, name) && + parserLine.GetArgString(1, value)) + { + // Add name and value to the map + newMap[name].m_String=value; + LOG(NORMAL, "Loaded config string \"%s\" = \"%s\"", name.c_str(), value.c_str()); + } + } + while (line = strtok_r(NULL, delim, &ctxt)); + + m_Map[ns].swap(newMap); + + free(filebuf); + // Close the correct file handle + if (m_UseVFS[ns]) + { + vfs_close(fh); + } + else + { + file_unmap(&f); + file_close(&f); + } +} + +void CConfigDB::WriteFile(EConfigNamespace ns, bool useVFS, CStr path) +{ + // TODO Implement this function +} diff --git a/source/ps/ConfigDB.h b/source/ps/ConfigDB.h new file mode 100755 index 0000000000..bf7cf5b30d --- /dev/null +++ b/source/ps/ConfigDB.h @@ -0,0 +1,80 @@ +/* + CConfigDB - Load, access and store configuration variables + + TDD : http://forums.wildfiregames.com/0ad/index.php?showtopic=1125 + AUTHOR : Simon Brenner , + OVERVIEW: +*/ + +#ifndef _ps_ConfigDB_H +#define _ps_ConfigDB_H + +#include "Prometheus.h" +#include "Parser.h" +#include "CStr.h" +#include "Singleton.h" + +enum EConfigNamespace +{ + CFG_SYSTEM, + CFG_MOD, + CFG_USER, + CFG_LAST +}; + +typedef CParserValue CConfigValue; +#define g_ConfigDB CConfigDB::GetSingleton() + +class CConfigDB: public Singleton +{ + static std::map m_Map[]; + static CStr m_ConfigFile[]; + static bool m_UseVFS[]; + +public: + // GetValue() + // Attempt to find a config variable with the given name in the specified + // namespace. + // + // Returns a pointer to the config value structure for the variable, or + // NULL if such a variable could not be found + CConfigValue *GetValue(EConfigNamespace ns, CStr name); + + // CreateValue() + // Create a new config value in the specified namespace. If such a + // variable already exists, the old value is returned and the effect is + // exactly the same as that of GetValue() + // + // Returns a pointer to the value of the newly created config variable, or + // that of the already existing config variable. + CConfigValue *CreateValue(EConfigNamespace ns, CStr name); + + // SetConfigFile() + // Set the path to the config file used to populate the specified namespace + // Note that this function does not actually load the config file. Use + // the Reload() method if you want to read the config file at the same time. + // + // 'path': The path to the config file. + // VFS: relative to VFS root + // non-VFS: relative to current working directory (binaries/data/) + // 'useVFS': true if the path is a VFS path, false if it is a real path + void SetConfigFile(EConfigNamespace ns, bool useVFS, CStr path); + + // Reload() + // Reload the config file associated with the specified config namespace + // (the last config file path set with SetConfigFile) + // + // Returns: + // true: if the reload succeeded, + // false: if the reload failed + bool Reload(EConfigNamespace); + + // WriteFile() + // Write the current state of the specified config namespace to the file + // specified by 'path' + // + // This function can also + void WriteFile(EConfigNamespace ns, bool useVFS, CStr path); +}; + +#endif