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>
39 VALUETYPE_FLAG // Doesn't take any arguments
44 ValueSpec(ValueType a_type, const char *a_help=NULL)
61 void writeLines(std::ostream &os)
63 JMutexAutoLock lock(m_mutex);
65 for(core::map<std::string, std::string>::Iterator
66 i = m_settings.getIterator();
67 i.atEnd() == false; i++)
69 std::string name = i.getNode()->getKey();
70 std::string value = i.getNode()->getValue();
71 os<<name<<" = "<<value<<"\n";
75 bool parseConfigLine(const std::string &line)
77 JMutexAutoLock lock(m_mutex);
79 std::string trimmedline = trim(line);
82 if(trimmedline[0] == '#')
85 //infostream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
87 Strfnd sf(trim(line));
89 std::string name = sf.next("=");
95 std::string value = sf.next("\n");
98 /*infostream<<"Config name=\""<<name<<"\" value=\""
99 <<value<<"\""<<std::endl;*/
101 m_settings[name] = value;
106 void parseConfigLines(std::istream &is, const std::string &endstring)
112 std::getline(is, line);
113 std::string trimmedline = trim(line);
115 if(trimmedline == endstring)
118 parseConfigLine(line);
122 // Returns false on EOF
123 bool parseConfigObject(std::istream &is)
129 NOTE: This function might be expanded to allow multi-line
133 std::getline(is, line);
134 //infostream<<"got line: \""<<line<<"\""<<std::endl;
136 return parseConfigLine(line);
140 Read configuration file
142 Returns true on success
144 bool readConfigFile(const char *filename)
146 std::ifstream is(filename);
147 if(is.good() == false)
149 errorstream<<"Error opening configuration file \""
150 <<filename<<"\""<<std::endl;
154 infostream<<"Parsing configuration file: \""
155 <<filename<<"\""<<std::endl;
157 while(parseConfigObject(is));
163 Reads a configuration object from stream (usually a single line)
166 Preserves comments and empty lines.
168 Settings that were added to dst are also added to updated.
169 key of updated is setting name, value of updated is dummy.
173 bool getUpdatedConfigObject(std::istream &is,
174 core::list<std::string> &dst,
175 core::map<std::string, bool> &updated)
177 JMutexAutoLock lock(m_mutex);
182 // NOTE: This function will be expanded to allow multi-line settings
184 std::getline(is, line);
186 std::string trimmedline = trim(line);
188 std::string line_end = "";
189 if(is.eof() == false)
193 if(trimmedline[0] == '#')
195 dst.push_back(line+line_end);
199 Strfnd sf(trim(line));
201 std::string name = sf.next("=");
206 dst.push_back(line+line_end);
210 std::string value = sf.next("\n");
213 if(m_settings.find(name))
215 std::string newvalue = m_settings[name];
217 if(newvalue != value)
219 infostream<<"Changing value of \""<<name<<"\" = \""
220 <<value<<"\" -> \""<<newvalue<<"\""
224 dst.push_back(name + " = " + newvalue + line_end);
226 updated[name] = true;
233 Updates configuration file
235 Returns true on success
237 bool updateConfigFile(const char *filename)
239 infostream<<"Updating configuration file: \""
240 <<filename<<"\""<<std::endl;
242 core::list<std::string> objects;
243 core::map<std::string, bool> updated;
245 // Read and modify stuff
247 std::ifstream is(filename);
248 if(is.good() == false)
250 infostream<<"updateConfigFile():"
251 " Error opening configuration file"
253 <<filename<<"\""<<std::endl;
257 while(getUpdatedConfigObject(is, objects, updated));
261 JMutexAutoLock lock(m_mutex);
265 std::ofstream os(filename);
266 if(os.good() == false)
268 errorstream<<"Error opening configuration file"
270 <<filename<<"\""<<std::endl;
277 for(core::list<std::string>::Iterator
279 i != objects.end(); i++)
285 Write stuff that was not already in the file
287 for(core::map<std::string, std::string>::Iterator
288 i = m_settings.getIterator();
289 i.atEnd() == false; i++)
291 if(updated.find(i.getNode()->getKey()))
293 std::string name = i.getNode()->getKey();
294 std::string value = i.getNode()->getValue();
295 infostream<<"Adding \""<<name<<"\" = \""<<value<<"\""
297 os<<name<<" = "<<value<<"\n";
305 NOTE: Types of allowed_options are ignored
307 returns true on success
309 bool parseCommandLine(int argc, char *argv[],
310 core::map<std::string, ValueSpec> &allowed_options)
317 std::string argname = argv[i];
318 if(argname.substr(0, 2) != "--")
320 errorstream<<"Invalid command-line parameter \""
321 <<argname<<"\": --<option> expected."<<std::endl;
326 std::string name = argname.substr(2);
328 core::map<std::string, ValueSpec>::Node *n;
329 n = allowed_options.find(name);
332 errorstream<<"Unknown command-line parameter \""
333 <<argname<<"\""<<std::endl;
337 ValueType type = n->getValue().type;
339 std::string value = "";
341 if(type == VALUETYPE_FLAG)
349 errorstream<<"Invalid command-line parameter \""
350 <<name<<"\": missing value"<<std::endl;
358 infostream<<"Valid command-line parameter: \""
359 <<name<<"\" = \""<<value<<"\""
367 void set(std::string name, std::string value)
369 JMutexAutoLock lock(m_mutex);
371 m_settings[name] = value;
374 void set(std::string name, const char *value)
376 JMutexAutoLock lock(m_mutex);
378 m_settings[name] = value;
382 void setDefault(std::string name, std::string value)
384 JMutexAutoLock lock(m_mutex);
386 m_defaults[name] = value;
389 bool exists(std::string name)
391 JMutexAutoLock lock(m_mutex);
393 return (m_settings.find(name) || m_defaults.find(name));
396 std::string get(std::string name)
398 JMutexAutoLock lock(m_mutex);
400 core::map<std::string, std::string>::Node *n;
401 n = m_settings.find(name);
404 n = m_defaults.find(name);
407 infostream<<"Settings: Setting not found: \""
408 <<name<<"\""<<std::endl;
409 throw SettingNotFoundException("Setting not found");
413 return n->getValue();
416 bool getBool(std::string name)
418 return is_yes(get(name));
421 bool getFlag(std::string name)
425 return getBool(name);
427 catch(SettingNotFoundException &e)
434 bool getBoolAsk(std::string name, std::string question, bool def)
436 // If it is in settings
438 return getBool(name);
442 std::cout<<question<<" [y/N]: ";
443 std::cin.getline(templine, 10);
452 float getFloat(std::string name)
454 return stof(get(name));
457 u16 getU16(std::string name)
459 return stoi(get(name), 0, 65535);
462 u16 getU16Ask(std::string name, std::string question, u16 def)
464 // If it is in settings
470 std::cout<<question<<" ["<<def<<"]: ";
471 std::cin.getline(templine, 10);
477 return stoi(s, 0, 65535);
480 s16 getS16(std::string name)
482 return stoi(get(name), -32768, 32767);
485 s32 getS32(std::string name)
487 return stoi(get(name));
490 v3f getV3F(std::string name)
495 value.X = stof(f.next(","));
496 value.Y = stof(f.next(","));
497 value.Z = stof(f.next(")"));
501 v2f getV2F(std::string name)
506 value.X = stof(f.next(","));
507 value.Y = stof(f.next(")"));
511 u64 getU64(std::string name)
514 std::string s = get(name);
515 std::istringstream ss(s);
520 void setBool(std::string name, bool value)
528 void setS32(std::string name, s32 value)
530 set(name, itos(value));
533 void setFloat(std::string name, float value)
535 set(name, ftos(value));
538 void setV3F(std::string name, v3f value)
540 std::ostringstream os;
541 os<<"("<<value.X<<","<<value.Y<<","<<value.Z<<")";
545 void setV2F(std::string name, v2f value)
547 std::ostringstream os;
548 os<<"("<<value.X<<","<<value.Y<<")";
552 void setU64(std::string name, u64 value)
554 std::ostringstream os;
561 JMutexAutoLock lock(m_mutex);
567 void updateValue(Settings &other, const std::string &name)
569 JMutexAutoLock lock(m_mutex);
575 std::string val = other.get(name);
576 m_settings[name] = val;
577 } catch(SettingNotFoundException &e){
583 void update(Settings &other)
585 JMutexAutoLock lock(m_mutex);
586 JMutexAutoLock lock2(other.m_mutex);
591 for(core::map<std::string, std::string>::Iterator
592 i = other.m_settings.getIterator();
593 i.atEnd() == false; i++)
595 m_settings[i.getNode()->getKey()] = i.getNode()->getValue();
598 for(core::map<std::string, std::string>::Iterator
599 i = other.m_defaults.getIterator();
600 i.atEnd() == false; i++)
602 m_defaults[i.getNode()->getKey()] = i.getNode()->getValue();
608 Settings & operator+=(Settings &other)
610 JMutexAutoLock lock(m_mutex);
611 JMutexAutoLock lock2(other.m_mutex);
616 for(core::map<std::string, std::string>::Iterator
617 i = other.m_settings.getIterator();
618 i.atEnd() == false; i++)
620 m_settings.insert(i.getNode()->getKey(),
621 i.getNode()->getValue());
624 for(core::map<std::string, std::string>::Iterator
625 i = other.m_defaults.getIterator();
626 i.atEnd() == false; i++)
628 m_defaults.insert(i.getNode()->getKey(),
629 i.getNode()->getValue());
636 Settings & operator=(Settings &other)
638 JMutexAutoLock lock(m_mutex);
639 JMutexAutoLock lock2(other.m_mutex);
651 core::map<std::string, std::string> m_settings;
652 core::map<std::string, std::string> m_defaults;
653 // All methods that access m_settings/m_defaults directly should lock this.