Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ConfigDB.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2012 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "precompiled.h"
19 
20 #include <boost/algorithm/string.hpp>
21 
22 #include "Pyrogenesis.h"
23 #include "Parser.h"
24 #include "ConfigDB.h"
25 #include "CLogger.h"
26 #include "Filesystem.h"
28 
29 typedef std::map <CStr, CConfigValueSet> TConfigMap;
32 
34 {
35 }
36 
38 {
39  CConfigValueSet* values = GetValues(ns, name);
40  if (!values)
41  return NULL;
42  return &((*values)[0]);
43 }
44 
46 {
47  if (ns < 0 || ns >= CFG_LAST)
48  {
49  debug_warn(L"CConfigDB: Invalid ns value");
50  return NULL;
51  }
52 
53  TConfigMap::iterator it = m_Map[CFG_COMMAND].find(name);
54  if (it != m_Map[CFG_COMMAND].end())
55  return &(it->second);
56 
57  for (int search_ns = ns; search_ns >= 0; search_ns--)
58  {
59  TConfigMap::iterator it = m_Map[search_ns].find(name);
60  if (it != m_Map[search_ns].end())
61  return &(it->second);
62  }
63 
64  return NULL;
65 }
66 
68 {
69  if (ns < 0 || ns >= CFG_LAST)
70  {
71  debug_warn(L"CConfigDB: Invalid ns value");
72  return CFG_LAST;
73  }
74 
75  TConfigMap::iterator it = m_Map[CFG_COMMAND].find(name);
76  if (it != m_Map[CFG_COMMAND].end())
77  return CFG_COMMAND;
78 
79  for (int search_ns = ns; search_ns >= 0; search_ns--)
80  {
81  TConfigMap::iterator it = m_Map[search_ns].find(name);
82  if (it != m_Map[search_ns].end())
83  return (EConfigNamespace)search_ns;
84  }
85 
86  return CFG_LAST;
87 }
88 
89 std::map<CStr, CConfigValueSet> CConfigDB::GetValuesWithPrefix(EConfigNamespace ns, const CStr& prefix)
90 {
91  std::map<CStr, CConfigValueSet> ret;
92 
93  if (ns < 0 || ns >= CFG_LAST)
94  {
95  debug_warn(L"CConfigDB: Invalid ns value");
96  return ret;
97  }
98 
99  // Loop upwards so that values in later namespaces can override
100  // values in earlier namespaces
101  for (int search_ns = 0; search_ns <= ns; search_ns++)
102  {
103  for (TConfigMap::iterator it = m_Map[search_ns].begin(); it != m_Map[search_ns].end(); ++it)
104  {
105  if (boost::algorithm::starts_with(it->first, prefix))
106  ret[it->first] = it->second;
107  }
108  }
109 
110  return ret;
111 }
112 
114 {
115  if (ns < 0 || ns >= CFG_LAST)
116  {
117  debug_warn(L"CConfigDB: Invalid ns value");
118  return NULL;
119  }
120 
121  TConfigMap::iterator it = m_Map[ns].find(name);
122  if (it != m_Map[ns].end())
123  return &(it->second[0]);
124 
125  it=m_Map[ns].insert(m_Map[ns].begin(), make_pair(name, CConfigValueSet(1)));
126  return &(it->second[0]);
127 }
128 
130 {
131  if (ns < 0 || ns >= CFG_LAST)
132  {
133  debug_warn(L"CConfigDB: Invalid ns value");
134  return;
135  }
136 
137  m_ConfigFile[ns]=path;
138 }
139 
141 {
142  if (ns < 0 || ns >= CFG_LAST)
143  {
144  debug_warn(L"CConfigDB: Invalid ns value");
145  return false;
146  }
147 
148  // Set up CParser
149  CParser parser;
150  CParserLine parserLine;
151  parser.InputTaskType("Assignment", "_$ident_=<_[-$arg(_minus)]_$value_,>_[-$arg(_minus)]_$value[[;]$rest]");
152  parser.InputTaskType("CommentOrBlank", "_[;[$rest]]");
153 
154  // Open file with VFS
155  shared_ptr<u8> buffer; size_t buflen;
156  {
157  // Handle missing files quietly
158  if (g_VFS->GetFileInfo(m_ConfigFile[ns], NULL) < 0)
159  {
160  LOGMESSAGE(L"Cannot find config file \"%ls\" - ignoring", m_ConfigFile[ns].string().c_str());
161  return false;
162  }
163  else
164  {
165  LOGMESSAGE(L"Loading config file \"%ls\"", m_ConfigFile[ns].string().c_str());
166  Status ret = g_VFS->LoadFile(m_ConfigFile[ns], buffer, buflen);
167  if (ret != INFO::OK)
168  {
169  LOGERROR(L"CConfigDB::Reload(): vfs_load for \"%ls\" failed: return was %lld", m_ConfigFile[ns].string().c_str(), (long long)ret);
170  return false;
171  }
172  }
173  }
174 
175  TConfigMap newMap;
176 
177  char *filebuf=(char *)buffer.get();
178  char *filebufend=filebuf+buflen;
179 
180  // Read file line by line
181  char *next=filebuf-1;
182  do
183  {
184  char *pos=next+1;
185  next=(char *)memchr(pos, '\n', filebufend-pos);
186  if (!next) next=filebufend;
187 
188  char *lend=next;
189  if (lend > filebuf && *(lend-1) == '\r') lend--;
190 
191  // Send line to parser
192  bool parseOk=parserLine.ParseString(parser, std::string(pos, lend));
193  // Get name and value from parser
194  std::string name;
195  std::string value;
196 
197  if (parseOk &&
198  parserLine.GetArgCount()>=2 &&
199  parserLine.GetArgString(0, name) &&
200  parserLine.GetArgString(1, value))
201  {
202  // Add name and value to the map
203  size_t argCount = parserLine.GetArgCount();
204 
205  newMap[name].clear();
206 
207  for( size_t t = 0; t < argCount; t++ )
208  {
209  if( !parserLine.GetArgString( (int)t + 1, value ) )
210  continue;
211  CConfigValue argument;
212  argument.m_String = value;
213  newMap[name].push_back( argument );
214  LOGMESSAGE(L"Loaded config string \"%hs\" = \"%hs\"", name.c_str(), value.c_str());
215  }
216  }
217  }
218  while (next < filebufend);
219 
220  m_Map[ns].swap(newMap);
221 
222  return true;
223 }
224 
226 {
227  if (ns < 0 || ns >= CFG_LAST)
228  {
229  debug_warn(L"CConfigDB: Invalid ns value");
230  return false;
231  }
232 
233  return WriteFile(ns, m_ConfigFile[ns]);
234 }
235 
237 {
238  if (ns < 0 || ns >= CFG_LAST)
239  {
240  debug_warn(L"CConfigDB: Invalid ns value");
241  return false;
242  }
243 
244  shared_ptr<u8> buf;
246  char* pos = (char*)buf.get();
247  TConfigMap &map=m_Map[ns];
248  for(TConfigMap::const_iterator it = map.begin(); it != map.end(); ++it)
249  {
250  pos += sprintf(pos, "%s = \"%s\"\n", it->first.c_str(), it->second[0].m_String.c_str());
251  }
252  const size_t len = pos - (char*)buf.get();
253 
254  Status ret = g_VFS->CreateFile(path, buf, len);
255  if(ret < 0)
256  {
257  LOGERROR(L"CConfigDB::WriteFile(): CreateFile \"%ls\" failed (error: %d)", path.string().c_str(), (int)ret);
258  return false;
259  }
260 
261  return true;
262 }
std::vector< CParserValue > CConfigValueSet
Definition: ConfigDB.h:50
std::map< CStr, CConfigValueSet > GetValuesWithPrefix(EConfigNamespace ns, const CStr &prefix)
Retrieve a map of values corresponding to settings whose names begin with the given prefix; will sear...
Definition: ConfigDB.cpp:89
const Status OK
Definition: status.h:386
#define LOGERROR
Definition: CLogger.h:35
std::string m_String
Definition: Parser.h:112
static const uintptr_t maxSectorSize
Definition: alignment.h:82
#define LOGMESSAGE
Definition: CLogger.h:32
static CStr prefix
Definition: DllLoader.cpp:47
static VfsPath m_ConfigFile[]
Definition: ConfigDB.h:57
EConfigNamespace GetValueNamespace(EConfigNamespace ns, const CStr &name)
Returns the namespace that the value returned by GetValues was defined in, or CFG_LAST if it wasn&#39;t d...
Definition: ConfigDB.cpp:67
Definition: path.h:75
bool Reload(EConfigNamespace)
Reload the config file associated with the specified config namespace (the last config file path set ...
Definition: ConfigDB.cpp:140
const String & string() const
Definition: path.h:123
static const size_t MiB
Definition: alignment.h:72
bool WriteFile(EConfigNamespace ns, const VfsPath &path)
Write the current state of the specified config namespace to the file specified by &#39;path&#39;...
Definition: ConfigDB.cpp:236
std::map< CStr, CConfigValueSet > TConfigMap
Definition: ConfigDB.cpp:29
i64 Status
Error handling system.
Definition: status.h:171
bool ParseString(const CParser &parser, const std::string &line)
Definition: Parser.cpp:325
CConfigValueSet * GetValues(EConfigNamespace ns, const CStr &name)
Attempt to retrieve a vector of values corresponding to the given setting; will search CFG_COMMAND fi...
Definition: ConfigDB.cpp:45
bool GetArgString(size_t arg, std::string &ret)
static Status AllocateAligned(shared_ptr< T > &p, size_t size, size_t alignment=cacheLineSize)
Definition: shared_ptr.h:66
size_t GetArgCount() const
Definition: Parser.h:219
CConfigValue * GetValue(EConfigNamespace ns, const CStr &name)
Attempt to find a config variable with the given name; will search CFG_COMMAND first, and then all namespaces from the specified namespace down to system.
Definition: ConfigDB.cpp:37
static std::map< CStr, CConfigValueSet > m_Map[]
Definition: ConfigDB.h:56
bool InputTaskType(const std::string &strName, const std::string &strSyntax)
Definition: Parser.cpp:816
EConfigNamespace
Definition: ConfigDB.h:39
void SetConfigFile(EConfigNamespace ns, const VfsPath &path)
Set the path to the config file used to populate the specified namespace Note that this function does...
Definition: ConfigDB.cpp:129
#define debug_warn(expr)
display the error dialog with the given text.
Definition: debug.h:324
CConfigValue * CreateValue(EConfigNamespace ns, const CStr &name)
Create a new config value in the specified namespace.
Definition: ConfigDB.cpp:113
PIVFS g_VFS
Definition: Filesystem.cpp:30