3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #ifndef SETTINGS_HEADER
21 #define SETTINGS_HEADER
23 #include "common_irrlicht.h"
27 #include <jmutexautolock.h>
38 VALUETYPE_FLAG // Doesn't take any arguments
43 ValueSpec(ValueType a_type, const char *a_help=NULL)
60 void writeLines(std::ostream &os)
62 JMutexAutoLock lock(m_mutex);
64 for(core::map<std::string, std::string>::Iterator
65 i = m_settings.getIterator();
66 i.atEnd() == false; i++)
68 std::string name = i.getNode()->getKey();
69 std::string value = i.getNode()->getValue();
70 os<<name<<" = "<<value<<"\n";
74 bool parseConfigLine(const std::string &line)
76 JMutexAutoLock lock(m_mutex);
78 std::string trimmedline = trim(line);
81 if(trimmedline[0] == '#')
84 //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
86 Strfnd sf(trim(line));
88 std::string name = sf.next("=");
94 std::string value = sf.next("\n");
97 /*dstream<<"Config name=\""<<name<<"\" value=\""
98 <<value<<"\""<<std::endl;*/
100 m_settings[name] = value;
105 // Returns false on EOF
106 bool parseConfigObject(std::istream &is)
112 NOTE: This function might be expanded to allow multi-line
116 std::getline(is, line);
117 //dstream<<"got line: \""<<line<<"\""<<std::endl;
119 return parseConfigLine(line);
123 Read configuration file
125 Returns true on success
127 bool readConfigFile(const char *filename)
129 std::ifstream is(filename);
130 if(is.good() == false)
132 dstream<<"Error opening configuration file \""
133 <<filename<<"\""<<std::endl;
137 dstream<<"Parsing configuration file: \""
138 <<filename<<"\""<<std::endl;
140 while(parseConfigObject(is));
146 Reads a configuration object from stream (usually a single line)
149 Preserves comments and empty lines.
151 Settings that were added to dst are also added to updated.
152 key of updated is setting name, value of updated is dummy.
156 bool getUpdatedConfigObject(std::istream &is,
157 core::list<std::string> &dst,
158 core::map<std::string, bool> &updated)
160 JMutexAutoLock lock(m_mutex);
165 // NOTE: This function will be expanded to allow multi-line settings
167 std::getline(is, line);
169 std::string trimmedline = trim(line);
171 std::string line_end = "";
172 if(is.eof() == false)
176 if(trimmedline[0] == '#')
178 dst.push_back(line+line_end);
182 Strfnd sf(trim(line));
184 std::string name = sf.next("=");
189 dst.push_back(line+line_end);
193 std::string value = sf.next("\n");
196 if(m_settings.find(name))
198 std::string newvalue = m_settings[name];
200 if(newvalue != value)
202 dstream<<"Changing value of \""<<name<<"\" = \""
203 <<value<<"\" -> \""<<newvalue<<"\""
207 dst.push_back(name + " = " + newvalue + line_end);
209 updated[name] = true;
216 Updates configuration file
218 Returns true on success
220 bool updateConfigFile(const char *filename)
222 dstream<<"Updating configuration file: \""
223 <<filename<<"\""<<std::endl;
225 core::list<std::string> objects;
226 core::map<std::string, bool> updated;
228 // Read and modify stuff
230 std::ifstream is(filename);
231 if(is.good() == false)
233 dstream<<"INFO: updateConfigFile():"
234 " Error opening configuration file"
236 <<filename<<"\""<<std::endl;
240 while(getUpdatedConfigObject(is, objects, updated));
244 JMutexAutoLock lock(m_mutex);
248 std::ofstream os(filename);
249 if(os.good() == false)
251 dstream<<"Error opening configuration file"
253 <<filename<<"\""<<std::endl;
260 for(core::list<std::string>::Iterator
262 i != objects.end(); i++)
268 Write stuff that was not already in the file
270 for(core::map<std::string, std::string>::Iterator
271 i = m_settings.getIterator();
272 i.atEnd() == false; i++)
274 if(updated.find(i.getNode()->getKey()))
276 std::string name = i.getNode()->getKey();
277 std::string value = i.getNode()->getValue();
278 dstream<<"Adding \""<<name<<"\" = \""<<value<<"\""
280 os<<name<<" = "<<value<<"\n";
288 NOTE: Types of allowed_options are ignored
290 returns true on success
292 bool parseCommandLine(int argc, char *argv[],
293 core::map<std::string, ValueSpec> &allowed_options)
300 std::string argname = argv[i];
301 if(argname.substr(0, 2) != "--")
303 dstream<<"Invalid command-line parameter \""
304 <<argname<<"\": --<option> expected."<<std::endl;
309 std::string name = argname.substr(2);
311 core::map<std::string, ValueSpec>::Node *n;
312 n = allowed_options.find(name);
315 dstream<<"Unknown command-line parameter \""
316 <<argname<<"\""<<std::endl;
320 ValueType type = n->getValue().type;
322 std::string value = "";
324 if(type == VALUETYPE_FLAG)
332 dstream<<"Invalid command-line parameter \""
333 <<name<<"\": missing value"<<std::endl;
341 dstream<<"Valid command-line parameter: \""
342 <<name<<"\" = \""<<value<<"\""
350 void set(std::string name, std::string value)
352 JMutexAutoLock lock(m_mutex);
354 m_settings[name] = value;
357 void set(std::string name, const char *value)
359 JMutexAutoLock lock(m_mutex);
361 m_settings[name] = value;
365 void setDefault(std::string name, std::string value)
367 JMutexAutoLock lock(m_mutex);
369 m_defaults[name] = value;
372 bool exists(std::string name)
374 JMutexAutoLock lock(m_mutex);
376 return (m_settings.find(name) || m_defaults.find(name));
379 std::string get(std::string name)
381 JMutexAutoLock lock(m_mutex);
383 core::map<std::string, std::string>::Node *n;
384 n = m_settings.find(name);
387 n = m_defaults.find(name);
390 dstream<<"INFO: Settings: Setting not found: \""
391 <<name<<"\""<<std::endl;
392 throw SettingNotFoundException("Setting not found");
396 return n->getValue();
399 bool getBool(std::string name)
401 return is_yes(get(name));
404 bool getFlag(std::string name)
408 return getBool(name);
410 catch(SettingNotFoundException &e)
417 bool getBoolAsk(std::string name, std::string question, bool def)
419 // If it is in settings
421 return getBool(name);
425 std::cout<<question<<" [y/N]: ";
426 std::cin.getline(templine, 10);
435 float getFloat(std::string name)
437 return stof(get(name));
440 u16 getU16(std::string name)
442 return stoi(get(name), 0, 65535);
445 u16 getU16Ask(std::string name, std::string question, u16 def)
447 // If it is in settings
453 std::cout<<question<<" ["<<def<<"]: ";
454 std::cin.getline(templine, 10);
460 return stoi(s, 0, 65535);
463 s16 getS16(std::string name)
465 return stoi(get(name), -32768, 32767);
468 s32 getS32(std::string name)
470 return stoi(get(name));
473 v3f getV3F(std::string name)
478 value.X = stof(f.next(","));
479 value.Y = stof(f.next(","));
480 value.Z = stof(f.next(")"));
484 u64 getU64(std::string name)
487 std::string s = get(name);
488 std::istringstream ss(s);
493 void setBool(std::string name, bool value)
501 void setS32(std::string name, s32 value)
503 set(name, itos(value));
506 void setFloat(std::string name, float value)
508 set(name, ftos(value));
511 void setV3F(std::string name, v3f value)
513 std::ostringstream os;
514 os<<"("<<value.X<<","<<value.Y<<","<<value.Z<<")";
518 void setU64(std::string name, u64 value)
520 std::ostringstream os;
527 JMutexAutoLock lock(m_mutex);
533 Settings & operator+=(Settings &other)
535 JMutexAutoLock lock(m_mutex);
536 JMutexAutoLock lock2(other.m_mutex);
541 for(core::map<std::string, std::string>::Iterator
542 i = other.m_settings.getIterator();
543 i.atEnd() == false; i++)
545 m_settings.insert(i.getNode()->getKey(),
546 i.getNode()->getValue());
549 for(core::map<std::string, std::string>::Iterator
550 i = other.m_defaults.getIterator();
551 i.atEnd() == false; i++)
553 m_defaults.insert(i.getNode()->getKey(),
554 i.getNode()->getValue());
561 Settings & operator=(Settings &other)
563 JMutexAutoLock lock(m_mutex);
564 JMutexAutoLock lock2(other.m_mutex);
576 core::map<std::string, std::string> m_settings;
577 core::map<std::string, std::string> m_defaults;
578 // All methods that access m_settings/m_defaults directly should lock this.