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 void parseConfigLines(std::istream &is, const std::string &endstring)
111 std::getline(is, line);
112 std::string trimmedline = trim(line);
114 if(trimmedline == endstring)
117 parseConfigLine(line);
121 // Returns false on EOF
122 bool parseConfigObject(std::istream &is)
128 NOTE: This function might be expanded to allow multi-line
132 std::getline(is, line);
133 //dstream<<"got line: \""<<line<<"\""<<std::endl;
135 return parseConfigLine(line);
139 Read configuration file
141 Returns true on success
143 bool readConfigFile(const char *filename)
145 std::ifstream is(filename);
146 if(is.good() == false)
148 dstream<<"Error opening configuration file \""
149 <<filename<<"\""<<std::endl;
153 dstream<<"Parsing configuration file: \""
154 <<filename<<"\""<<std::endl;
156 while(parseConfigObject(is));
162 Reads a configuration object from stream (usually a single line)
165 Preserves comments and empty lines.
167 Settings that were added to dst are also added to updated.
168 key of updated is setting name, value of updated is dummy.
172 bool getUpdatedConfigObject(std::istream &is,
173 core::list<std::string> &dst,
174 core::map<std::string, bool> &updated)
176 JMutexAutoLock lock(m_mutex);
181 // NOTE: This function will be expanded to allow multi-line settings
183 std::getline(is, line);
185 std::string trimmedline = trim(line);
187 std::string line_end = "";
188 if(is.eof() == false)
192 if(trimmedline[0] == '#')
194 dst.push_back(line+line_end);
198 Strfnd sf(trim(line));
200 std::string name = sf.next("=");
205 dst.push_back(line+line_end);
209 std::string value = sf.next("\n");
212 if(m_settings.find(name))
214 std::string newvalue = m_settings[name];
216 if(newvalue != value)
218 dstream<<"Changing value of \""<<name<<"\" = \""
219 <<value<<"\" -> \""<<newvalue<<"\""
223 dst.push_back(name + " = " + newvalue + line_end);
225 updated[name] = true;
232 Updates configuration file
234 Returns true on success
236 bool updateConfigFile(const char *filename)
238 dstream<<"Updating configuration file: \""
239 <<filename<<"\""<<std::endl;
241 core::list<std::string> objects;
242 core::map<std::string, bool> updated;
244 // Read and modify stuff
246 std::ifstream is(filename);
247 if(is.good() == false)
249 dstream<<"INFO: updateConfigFile():"
250 " Error opening configuration file"
252 <<filename<<"\""<<std::endl;
256 while(getUpdatedConfigObject(is, objects, updated));
260 JMutexAutoLock lock(m_mutex);
264 std::ofstream os(filename);
265 if(os.good() == false)
267 dstream<<"Error opening configuration file"
269 <<filename<<"\""<<std::endl;
276 for(core::list<std::string>::Iterator
278 i != objects.end(); i++)
284 Write stuff that was not already in the file
286 for(core::map<std::string, std::string>::Iterator
287 i = m_settings.getIterator();
288 i.atEnd() == false; i++)
290 if(updated.find(i.getNode()->getKey()))
292 std::string name = i.getNode()->getKey();
293 std::string value = i.getNode()->getValue();
294 dstream<<"Adding \""<<name<<"\" = \""<<value<<"\""
296 os<<name<<" = "<<value<<"\n";
304 NOTE: Types of allowed_options are ignored
306 returns true on success
308 bool parseCommandLine(int argc, char *argv[],
309 core::map<std::string, ValueSpec> &allowed_options)
316 std::string argname = argv[i];
317 if(argname.substr(0, 2) != "--")
319 dstream<<"Invalid command-line parameter \""
320 <<argname<<"\": --<option> expected."<<std::endl;
325 std::string name = argname.substr(2);
327 core::map<std::string, ValueSpec>::Node *n;
328 n = allowed_options.find(name);
331 dstream<<"Unknown command-line parameter \""
332 <<argname<<"\""<<std::endl;
336 ValueType type = n->getValue().type;
338 std::string value = "";
340 if(type == VALUETYPE_FLAG)
348 dstream<<"Invalid command-line parameter \""
349 <<name<<"\": missing value"<<std::endl;
357 dstream<<"Valid command-line parameter: \""
358 <<name<<"\" = \""<<value<<"\""
366 void set(std::string name, std::string value)
368 JMutexAutoLock lock(m_mutex);
370 m_settings[name] = value;
373 void set(std::string name, const char *value)
375 JMutexAutoLock lock(m_mutex);
377 m_settings[name] = value;
381 void setDefault(std::string name, std::string value)
383 JMutexAutoLock lock(m_mutex);
385 m_defaults[name] = value;
388 bool exists(std::string name)
390 JMutexAutoLock lock(m_mutex);
392 return (m_settings.find(name) || m_defaults.find(name));
395 std::string get(std::string name)
397 JMutexAutoLock lock(m_mutex);
399 core::map<std::string, std::string>::Node *n;
400 n = m_settings.find(name);
403 n = m_defaults.find(name);
406 dstream<<"INFO: Settings: Setting not found: \""
407 <<name<<"\""<<std::endl;
408 throw SettingNotFoundException("Setting not found");
412 return n->getValue();
415 bool getBool(std::string name)
417 return is_yes(get(name));
420 bool getFlag(std::string name)
424 return getBool(name);
426 catch(SettingNotFoundException &e)
433 bool getBoolAsk(std::string name, std::string question, bool def)
435 // If it is in settings
437 return getBool(name);
441 std::cout<<question<<" [y/N]: ";
442 std::cin.getline(templine, 10);
451 float getFloat(std::string name)
453 return stof(get(name));
456 u16 getU16(std::string name)
458 return stoi(get(name), 0, 65535);
461 u16 getU16Ask(std::string name, std::string question, u16 def)
463 // If it is in settings
469 std::cout<<question<<" ["<<def<<"]: ";
470 std::cin.getline(templine, 10);
476 return stoi(s, 0, 65535);
479 s16 getS16(std::string name)
481 return stoi(get(name), -32768, 32767);
484 s32 getS32(std::string name)
486 return stoi(get(name));
489 v3f getV3F(std::string name)
494 value.X = stof(f.next(","));
495 value.Y = stof(f.next(","));
496 value.Z = stof(f.next(")"));
500 v2f getV2F(std::string name)
505 value.X = stof(f.next(","));
506 value.Y = stof(f.next(")"));
510 u64 getU64(std::string name)
513 std::string s = get(name);
514 std::istringstream ss(s);
519 void setBool(std::string name, bool value)
527 void setS32(std::string name, s32 value)
529 set(name, itos(value));
532 void setFloat(std::string name, float value)
534 set(name, ftos(value));
537 void setV3F(std::string name, v3f value)
539 std::ostringstream os;
540 os<<"("<<value.X<<","<<value.Y<<","<<value.Z<<")";
544 void setV2F(std::string name, v2f value)
546 std::ostringstream os;
547 os<<"("<<value.X<<","<<value.Y<<")";
551 void setU64(std::string name, u64 value)
553 std::ostringstream os;
560 JMutexAutoLock lock(m_mutex);
566 void updateValue(Settings &other, const std::string &name)
568 JMutexAutoLock lock(m_mutex);
574 std::string val = other.get(name);
575 m_settings[name] = val;
576 } catch(SettingNotFoundException &e){
582 void update(Settings &other)
584 JMutexAutoLock lock(m_mutex);
585 JMutexAutoLock lock2(other.m_mutex);
590 for(core::map<std::string, std::string>::Iterator
591 i = other.m_settings.getIterator();
592 i.atEnd() == false; i++)
594 m_settings[i.getNode()->getKey()] = i.getNode()->getValue();
597 for(core::map<std::string, std::string>::Iterator
598 i = other.m_defaults.getIterator();
599 i.atEnd() == false; i++)
601 m_defaults[i.getNode()->getKey()] = i.getNode()->getValue();
607 Settings & operator+=(Settings &other)
609 JMutexAutoLock lock(m_mutex);
610 JMutexAutoLock lock2(other.m_mutex);
615 for(core::map<std::string, std::string>::Iterator
616 i = other.m_settings.getIterator();
617 i.atEnd() == false; i++)
619 m_settings.insert(i.getNode()->getKey(),
620 i.getNode()->getValue());
623 for(core::map<std::string, std::string>::Iterator
624 i = other.m_defaults.getIterator();
625 i.atEnd() == false; i++)
627 m_defaults.insert(i.getNode()->getKey(),
628 i.getNode()->getValue());
635 Settings & operator=(Settings &other)
637 JMutexAutoLock lock(m_mutex);
638 JMutexAutoLock lock2(other.m_mutex);
650 core::map<std::string, std::string> m_settings;
651 core::map<std::string, std::string> m_defaults;
652 // All methods that access m_settings/m_defaults directly should lock this.