]> git.lizzy.rs Git - minetest.git/blobdiff - src/settings.h
Make flag strings clear specified flag with 'no' prefix
[minetest.git] / src / settings.h
index 1ab6fcc6b550740181ed3eb888a5770144f14361..2aa03074b7d6bebec053b5927ad4663dc715442a 100644 (file)
@@ -1,6 +1,6 @@
 /*
 /*
-Minetest-c55
-Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+Minetest
+Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as published by
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as published by
@@ -21,10 +21,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define SETTINGS_HEADER
 
 #include "irrlichttypes_bloated.h"
 #define SETTINGS_HEADER
 
 #include "irrlichttypes_bloated.h"
+#include "exceptions.h"
 #include <string>
 #include <string>
-#include <jthread.h>
-#include <jmutex.h>
-#include <jmutexautolock.h>
+#include "jthread/jmutex.h"
+#include "jthread/jmutexautolock.h"
 #include "strfnd.h"
 #include <iostream>
 #include <fstream>
 #include "strfnd.h"
 #include <iostream>
 #include <fstream>
@@ -32,6 +32,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "debug.h"
 #include "log.h"
 #include "util/string.h"
 #include "debug.h"
 #include "log.h"
 #include "util/string.h"
+#include "porting.h"
+#include <list>
+#include <map>
+#include <set>
+#include "filesys.h"
 
 enum ValueType
 {
 
 enum ValueType
 {
@@ -55,29 +60,47 @@ class Settings
 public:
        Settings()
        {
 public:
        Settings()
        {
-               m_mutex.Init();
        }
 
        void writeLines(std::ostream &os)
        {
                JMutexAutoLock lock(m_mutex);
        }
 
        void writeLines(std::ostream &os)
        {
                JMutexAutoLock lock(m_mutex);
-               
-               for(core::map<std::string, std::string>::Iterator
-                               i = m_settings.getIterator();
-                               i.atEnd() == false; i++)
+
+               for(std::map<std::string, std::string>::iterator
+                               i = m_settings.begin();
+                               i != m_settings.end(); ++i)
                {
                {
-                       std::string name = i.getNode()->getKey();
-                       std::string value = i.getNode()->getValue();
+                       std::string name = i->first;
+                       std::string value = i->second;
                        os<<name<<" = "<<value<<"\n";
                }
        }
                        os<<name<<" = "<<value<<"\n";
                }
        }
+  
+       // return all keys used
+       std::vector<std::string> getNames(){
+               std::vector<std::string> names;
+               for(std::map<std::string, std::string>::iterator
+                               i = m_settings.begin();
+                               i != m_settings.end(); ++i)
+               {
+                       names.push_back(i->first);
+               }
+               return names;
+       }
+
+       // remove a setting
+       bool remove(const std::string& name)
+       {
+               return m_settings.erase(name);
+       }
+
 
        bool parseConfigLine(const std::string &line)
        {
                JMutexAutoLock lock(m_mutex);
 
        bool parseConfigLine(const std::string &line)
        {
                JMutexAutoLock lock(m_mutex);
-               
+
                std::string trimmedline = trim(line);
                std::string trimmedline = trim(line);
-               
+
                // Ignore empty lines and comments
                if(trimmedline.size() == 0 || trimmedline[0] == '#')
                        return true;
                // Ignore empty lines and comments
                if(trimmedline.size() == 0 || trimmedline[0] == '#')
                        return true;
@@ -91,15 +114,15 @@ class Settings
 
                if(name == "")
                        return true;
 
                if(name == "")
                        return true;
-               
+
                std::string value = sf.next("\n");
                value = trim(value);
 
                /*infostream<<"Config name=\""<<name<<"\" value=\""
                                <<value<<"\""<<std::endl;*/
                std::string value = sf.next("\n");
                value = trim(value);
 
                /*infostream<<"Config name=\""<<name<<"\" value=\""
                                <<value<<"\""<<std::endl;*/
-               
+
                m_settings[name] = value;
                m_settings[name] = value;
-               
+
                return true;
        }
 
                return true;
        }
 
@@ -124,7 +147,7 @@ class Settings
        {
                if(is.eof())
                        return false;
        {
                if(is.eof())
                        return false;
-               
+
                /*
                        NOTE: This function might be expanded to allow multi-line
                              settings.
                /*
                        NOTE: This function might be expanded to allow multi-line
                              settings.
@@ -149,16 +172,16 @@ class Settings
 
                /*infostream<<"Parsing configuration file: \""
                                <<filename<<"\""<<std::endl;*/
 
                /*infostream<<"Parsing configuration file: \""
                                <<filename<<"\""<<std::endl;*/
-                               
+
                while(parseConfigObject(is));
                while(parseConfigObject(is));
-               
+
                return true;
        }
 
        /*
                Reads a configuration object from stream (usually a single line)
                and adds it to dst.
                return true;
        }
 
        /*
                Reads a configuration object from stream (usually a single line)
                and adds it to dst.
-               
+
                Preserves comments and empty lines.
 
                Settings that were added to dst are also added to updated.
                Preserves comments and empty lines.
 
                Settings that were added to dst are also added to updated.
@@ -167,15 +190,15 @@ class Settings
                Returns false on EOF
        */
        bool getUpdatedConfigObject(std::istream &is,
                Returns false on EOF
        */
        bool getUpdatedConfigObject(std::istream &is,
-                       core::list<std::string> &dst,
-                       core::map<std::string, bool> &updated,
+                       std::list<std::string> &dst,
+                       std::set<std::string> &updated,
                        bool &value_changed)
        {
                JMutexAutoLock lock(m_mutex);
                        bool &value_changed)
        {
                JMutexAutoLock lock(m_mutex);
-               
+
                if(is.eof())
                        return false;
                if(is.eof())
                        return false;
-               
+
                // NOTE: This function will be expanded to allow multi-line settings
                std::string line;
                std::getline(is, line);
                // NOTE: This function will be expanded to allow multi-line settings
                std::string line;
                std::getline(is, line);
@@ -185,7 +208,7 @@ class Settings
                std::string line_end = "";
                if(is.eof() == false)
                        line_end = "\n";
                std::string line_end = "";
                if(is.eof() == false)
                        line_end = "\n";
-               
+
                // Ignore empty lines and comments
                if(trimmedline.size() == 0 || trimmedline[0] == '#')
                {
                // Ignore empty lines and comments
                if(trimmedline.size() == 0 || trimmedline[0] == '#')
                {
@@ -203,14 +226,14 @@ class Settings
                        dst.push_back(line+line_end);
                        return true;
                }
                        dst.push_back(line+line_end);
                        return true;
                }
-               
+
                std::string value = sf.next("\n");
                value = trim(value);
                std::string value = sf.next("\n");
                value = trim(value);
-               
-               if(m_settings.find(name))
+
+               if(m_settings.find(name) != m_settings.end())
                {
                        std::string newvalue = m_settings[name];
                {
                        std::string newvalue = m_settings[name];
-                       
+
                        if(newvalue != value)
                        {
                                infostream<<"Changing value of \""<<name<<"\" = \""
                        if(newvalue != value)
                        {
                                infostream<<"Changing value of \""<<name<<"\" = \""
@@ -221,9 +244,11 @@ class Settings
 
                        dst.push_back(name + " = " + newvalue + line_end);
 
 
                        dst.push_back(name + " = " + newvalue + line_end);
 
-                       updated[name] = true;
+                       updated.insert(name);
                }
                }
-               
+               else //file contains a setting which is not in m_settings
+                       value_changed=true;
+                       
                return true;
        }
 
                return true;
        }
 
@@ -236,11 +261,11 @@ class Settings
        {
                infostream<<"Updating configuration file: \""
                                <<filename<<"\""<<std::endl;
        {
                infostream<<"Updating configuration file: \""
                                <<filename<<"\""<<std::endl;
-               
-               core::list<std::string> objects;
-               core::map<std::string, bool> updated;
+
+               std::list<std::string> objects;
+               std::set<std::string> updated;
                bool something_actually_changed = false;
                bool something_actually_changed = false;
-               
+
                // Read and modify stuff
                {
                        std::ifstream is(filename);
                // Read and modify stuff
                {
                        std::ifstream is(filename);
@@ -257,68 +282,68 @@ class Settings
                                                something_actually_changed));
                        }
                }
                                                something_actually_changed));
                        }
                }
-               
+
                JMutexAutoLock lock(m_mutex);
                JMutexAutoLock lock(m_mutex);
-               
+
                // If something not yet determined to have been changed, check if
                // any new stuff was added
                if(!something_actually_changed){
                // If something not yet determined to have been changed, check if
                // any new stuff was added
                if(!something_actually_changed){
-                       for(core::map<std::string, std::string>::Iterator
-                                       i = m_settings.getIterator();
-                                       i.atEnd() == false; i++)
+                       for(std::map<std::string, std::string>::iterator
+                                       i = m_settings.begin();
+                                       i != m_settings.end(); ++i)
                        {
                        {
-                               if(updated.find(i.getNode()->getKey()))
+                               if(updated.find(i->first) != updated.end())
                                        continue;
                                something_actually_changed = true;
                                break;
                        }
                }
                                        continue;
                                something_actually_changed = true;
                                break;
                        }
                }
-               
+
                // If nothing was actually changed, skip writing the file
                if(!something_actually_changed){
                        infostream<<"Skipping writing of "<<filename
                                        <<" because content wouldn't be modified"<<std::endl;
                        return true;
                }
                // If nothing was actually changed, skip writing the file
                if(!something_actually_changed){
                        infostream<<"Skipping writing of "<<filename
                                        <<" because content wouldn't be modified"<<std::endl;
                        return true;
                }
-               
+
                // Write stuff back
                {
                // Write stuff back
                {
-                       std::ofstream os(filename);
-                       if(os.good() == false)
-                       {
-                               errorstream<<"Error opening configuration file"
-                                               " for writing: \""
-                                               <<filename<<"\""<<std::endl;
-                               return false;
-                       }
-                       
+                       std::ostringstream ss(std::ios_base::binary);
+
                        /*
                                Write updated stuff
                        */
                        /*
                                Write updated stuff
                        */
-                       for(core::list<std::string>::Iterator
+                       for(std::list<std::string>::iterator
                                        i = objects.begin();
                                        i = objects.begin();
-                                       i != objects.end(); i++)
+                                       i != objects.end(); ++i)
                        {
                        {
-                               os<<(*i);
+                               ss<<(*i);
                        }
 
                        /*
                                Write stuff that was not already in the file
                        */
                        }
 
                        /*
                                Write stuff that was not already in the file
                        */
-                       for(core::map<std::string, std::string>::Iterator
-                                       i = m_settings.getIterator();
-                                       i.atEnd() == false; i++)
+                       for(std::map<std::string, std::string>::iterator
+                                       i = m_settings.begin();
+                                       i != m_settings.end(); ++i)
                        {
                        {
-                               if(updated.find(i.getNode()->getKey()))
+                               if(updated.find(i->first) != updated.end())
                                        continue;
                                        continue;
-                               std::string name = i.getNode()->getKey();
-                               std::string value = i.getNode()->getValue();
+                               std::string name = i->first;
+                               std::string value = i->second;
                                infostream<<"Adding \""<<name<<"\" = \""<<value<<"\""
                                                <<std::endl;
                                infostream<<"Adding \""<<name<<"\" = \""<<value<<"\""
                                                <<std::endl;
-                               os<<name<<" = "<<value<<"\n";
+                               ss<<name<<" = "<<value<<"\n";
+                       }
+
+                       if(!fs::safeWriteToFile(filename, ss.str()))
+                       {
+                               errorstream<<"Error writing configuration file: \""
+                                               <<filename<<"\""<<std::endl;
+                               return false;
                        }
                }
                        }
                }
-               
+
                return true;
        }
 
                return true;
        }
 
@@ -328,7 +353,7 @@ class Settings
                returns true on success
        */
        bool parseCommandLine(int argc, char *argv[],
                returns true on success
        */
        bool parseCommandLine(int argc, char *argv[],
-                       core::map<std::string, ValueSpec> &allowed_options)
+                       std::map<std::string, ValueSpec> &allowed_options)
        {
                int nonopt_index = 0;
                int i=1;
        {
                int nonopt_index = 0;
                int i=1;
@@ -356,19 +381,19 @@ class Settings
 
                        std::string name = argname.substr(2);
 
 
                        std::string name = argname.substr(2);
 
-                       core::map<std::string, ValueSpec>::Node *n;
+                       std::map<std::string, ValueSpec>::iterator n;
                        n = allowed_options.find(name);
                        n = allowed_options.find(name);
-                       if(n == NULL)
+                       if(n == allowed_options.end())
                        {
                                errorstream<<"Unknown command-line parameter \""
                                                <<argname<<"\""<<std::endl;
                                return false;
                        }
 
                        {
                                errorstream<<"Unknown command-line parameter \""
                                                <<argname<<"\""<<std::endl;
                                return false;
                        }
 
-                       ValueType type = n->getValue().type;
+                       ValueType type = n->second.type;
 
                        std::string value = "";
 
                        std::string value = "";
-                       
+
                        if(type == VALUETYPE_FLAG)
                        {
                                value = "true";
                        if(type == VALUETYPE_FLAG)
                        {
                                value = "true";
@@ -384,7 +409,7 @@ class Settings
                                value = argv[i];
                                i++;
                        }
                                value = argv[i];
                                i++;
                        }
-                       
+
 
                        infostream<<"Valid command-line parameter: \""
                                        <<name<<"\" = \""<<value<<"\""
 
                        infostream<<"Valid command-line parameter: \""
                                        <<name<<"\" = \""<<value<<"\""
@@ -398,7 +423,7 @@ class Settings
        void set(std::string name, std::string value)
        {
                JMutexAutoLock lock(m_mutex);
        void set(std::string name, std::string value)
        {
                JMutexAutoLock lock(m_mutex);
-               
+
                m_settings[name] = value;
        }
 
                m_settings[name] = value;
        }
 
@@ -413,40 +438,41 @@ class Settings
        void setDefault(std::string name, std::string value)
        {
                JMutexAutoLock lock(m_mutex);
        void setDefault(std::string name, std::string value)
        {
                JMutexAutoLock lock(m_mutex);
-               
+
                m_defaults[name] = value;
        }
 
        bool exists(std::string name)
        {
                JMutexAutoLock lock(m_mutex);
                m_defaults[name] = value;
        }
 
        bool exists(std::string name)
        {
                JMutexAutoLock lock(m_mutex);
-               
-               return (m_settings.find(name) || m_defaults.find(name));
+
+               return (m_settings.find(name) != m_settings.end() || m_defaults.find(name) != m_defaults.end());
        }
 
        std::string get(std::string name)
        {
                JMutexAutoLock lock(m_mutex);
        }
 
        std::string get(std::string name)
        {
                JMutexAutoLock lock(m_mutex);
-               
-               core::map<std::string, std::string>::Node *n;
+
+               std::map<std::string, std::string>::iterator n;
                n = m_settings.find(name);
                n = m_settings.find(name);
-               if(n == NULL)
+               if(n == m_settings.end())
                {
                        n = m_defaults.find(name);
                {
                        n = m_defaults.find(name);
-                       if(n == NULL)
+                       if(n == m_defaults.end())
                        {
                        {
-                               throw SettingNotFoundException("Setting not found");
+                               throw SettingNotFoundException(("Setting [" + name + "] not found ").c_str());
                        }
                }
 
                        }
                }
 
-               return n->getValue();
+               return n->second;
        }
 
        }
 
+       //////////// Get setting
        bool getBool(std::string name)
        {
                return is_yes(get(name));
        }
        bool getBool(std::string name)
        {
                return is_yes(get(name));
        }
-       
+
        bool getFlag(std::string name)
        {
                try
        bool getFlag(std::string name)
        {
                try
@@ -465,7 +491,7 @@ class Settings
                // If it is in settings
                if(exists(name))
                        return getBool(name);
                // If it is in settings
                if(exists(name))
                        return getBool(name);
-               
+
                std::string s;
                char templine[10];
                std::cout<<question<<" [y/N]: ";
                std::string s;
                char templine[10];
                std::cout<<question<<" [y/N]: ";
@@ -493,7 +519,7 @@ class Settings
                // If it is in settings
                if(exists(name))
                        return getU16(name);
                // If it is in settings
                if(exists(name))
                        return getU16(name);
-               
+
                std::string s;
                char templine[10];
                std::cout<<question<<" ["<<def<<"]: ";
                std::string s;
                char templine[10];
                std::cout<<question<<" ["<<def<<"]: ";
@@ -546,6 +572,415 @@ class Settings
                return value;
        }
 
                return value;
        }
 
+       u32 getFlagStr(std::string name, FlagDesc *flagdesc, u32 *flagmask)
+       {
+               std::string val = get(name);
+               return (isdigit(val[0])) ? stoi(val) :
+                       readFlagString(val, flagdesc, flagmask);
+       }
+
+       // N.B. if getStruct() is used to read a non-POD aggregate type,
+       // the behavior is undefined.
+       bool getStruct(std::string name, std::string format, void *out, size_t olen)
+       {
+               size_t len = olen;
+               std::vector<std::string *> strs_alloced;
+               std::string *str, valstr;
+               char *f, *snext;
+               size_t pos;
+
+               try {
+                       valstr = get(name);
+               } catch (SettingNotFoundException &e) {
+                       return false;
+               }
+
+               char *s = &valstr[0];
+               char *buf = new char[len];
+               char *bufpos = buf;
+
+               char *fmtpos, *fmt = &format[0];
+               while ((f = strtok_r(fmt, ",", &fmtpos)) && s) {
+                       fmt = NULL;
+
+                       bool is_unsigned = false;
+                       int width = 0;
+                       char valtype = *f;
+
+                       width = (int)strtol(f + 1, &f, 10);
+                       if (width && valtype == 's')
+                               valtype = 'i';
+
+                       switch (valtype) {
+                               case 'u':
+                                       is_unsigned = true;
+                                       /* FALLTHROUGH */
+                               case 'i':
+                                       if (width == 16) {
+                                               bufpos += PADDING(bufpos, u16);
+                                               if ((bufpos - buf) + sizeof(u16) <= len) {
+                                                       if (is_unsigned)
+                                                               *(u16 *)bufpos = (u16)strtoul(s, &s, 10);
+                                                       else
+                                                               *(s16 *)bufpos = (s16)strtol(s, &s, 10);
+                                               }
+                                               bufpos += sizeof(u16);
+                                       } else if (width == 32) {
+                                               bufpos += PADDING(bufpos, u32);
+                                               if ((bufpos - buf) + sizeof(u32) <= len) {
+                                                       if (is_unsigned)
+                                                               *(u32 *)bufpos = (u32)strtoul(s, &s, 10);
+                                                       else
+                                                               *(s32 *)bufpos = (s32)strtol(s, &s, 10);
+                                               }
+                                               bufpos += sizeof(u32);
+                                       } else if (width == 64) {
+                                               bufpos += PADDING(bufpos, u64);
+                                               if ((bufpos - buf) + sizeof(u64) <= len) {
+                                                       if (is_unsigned)
+                                                               *(u64 *)bufpos = (u64)strtoull(s, &s, 10);
+                                                       else
+                                                               *(s64 *)bufpos = (s64)strtoll(s, &s, 10);
+                                               }
+                                               bufpos += sizeof(u64);
+                                       }
+                                       s = strchr(s, ',');
+                                       break;
+                               case 'b':
+                                       snext = strchr(s, ',');
+                                       if (snext)
+                                               *snext++ = 0;
+
+                                       bufpos += PADDING(bufpos, bool);
+                                       if ((bufpos - buf) + sizeof(bool) <= len)
+                                               *(bool *)bufpos = is_yes(std::string(s));
+                                       bufpos += sizeof(bool);
+
+                                       s = snext;
+                                       break;
+                               case 'f':
+                                       bufpos += PADDING(bufpos, float);
+                                       if ((bufpos - buf) + sizeof(float) <= len)
+                                               *(float *)bufpos = strtof(s, &s);
+                                       bufpos += sizeof(float);
+
+                                       s = strchr(s, ',');
+                                       break;
+                               case 's':
+                                       while (*s == ' ' || *s == '\t')
+                                               s++;
+                                       if (*s++ != '"') //error, expected string
+                                               goto fail;
+                                       snext = s;
+
+                                       while (snext[0] && !(snext[-1] != '\\' && snext[0] == '"'))
+                                               snext++;
+                                       *snext++ = 0;
+
+                                       bufpos += PADDING(bufpos, std::string *);
+
+                                       str = new std::string(s);
+                                       pos = 0;
+                                       while ((pos = str->find("\\\"", pos)) != std::string::npos)
+                                               str->erase(pos, 1);
+
+                                       if ((bufpos - buf) + sizeof(std::string *) <= len)
+                                               *(std::string **)bufpos = str;
+                                       bufpos += sizeof(std::string *);
+                                       strs_alloced.push_back(str);
+
+                                       s = *snext ? snext + 1 : NULL;
+                                       break;
+                               case 'v':
+                                       while (*s == ' ' || *s == '\t')
+                                               s++;
+                                       if (*s++ != '(') //error, expected vector
+                                               goto fail;
+
+                                       if (width == 2) {
+                                               bufpos += PADDING(bufpos, v2f);
+
+                                               if ((bufpos - buf) + sizeof(v2f) <= len) {
+                                               v2f *v = (v2f *)bufpos;
+                                                       v->X = strtof(s, &s);
+                                                       s++;
+                                                       v->Y = strtof(s, &s);
+                                               }
+
+                                               bufpos += sizeof(v2f);
+                                       } else if (width == 3) {
+                                               bufpos += PADDING(bufpos, v3f);
+                                               if ((bufpos - buf) + sizeof(v3f) <= len) {
+                                                       v3f *v = (v3f *)bufpos;
+                                                       v->X = strtof(s, &s);
+                                                       s++;
+                                                       v->Y = strtof(s, &s);
+                                                       s++;
+                                                       v->Z = strtof(s, &s);
+                                               }
+
+                                               bufpos += sizeof(v3f);
+                                       }
+                                       s = strchr(s, ',');
+                                       break;
+                               default: //error, invalid format specifier
+                                       goto fail;
+                       }
+
+                       if (s && *s == ',')
+                               s++;
+
+                       if ((size_t)(bufpos - buf) > len) //error, buffer too small
+                               goto fail;
+               }
+
+               if (f && *f) { //error, mismatched number of fields and values
+fail:
+                       for (size_t i = 0; i != strs_alloced.size(); i++)
+                               delete strs_alloced[i];
+                       delete[] buf;
+                       return false;
+               }
+
+               memcpy(out, buf, olen);
+               delete[] buf;
+               return true;
+       }
+
+       //////////// Try to get value, no exception thrown
+       bool getNoEx(std::string name, std::string &val)
+       {
+               try {
+                       val = get(name);
+                       return true;
+               } catch (SettingNotFoundException &e) {
+                       return false;
+               }
+       }
+
+       // N.B. getFlagStrNoEx() does not set val, but merely modifies it.  Thus,
+       // val must be initialized before using getFlagStrNoEx().  The intention of
+       // this is to simplify modifying a flags field from a default value.
+       bool getFlagStrNoEx(std::string name, u32 &val, FlagDesc *flagdesc)
+       {
+               try {
+                       u32 flags, flagmask;
+
+                       flags = getFlagStr(name, flagdesc, &flagmask);
+
+                       val &= ~flagmask;
+                       val |=  flags;
+
+                       return true;
+               } catch (SettingNotFoundException &e) {
+                       return false;
+               }
+       }
+
+       bool getFloatNoEx(std::string name, float &val)
+       {
+               try {
+                       val = getFloat(name);
+                       return true;
+               } catch (SettingNotFoundException &e) {
+                       return false;
+               }
+       }
+
+       bool getU16NoEx(std::string name, int &val)
+       {
+               try {
+                       val = getU16(name);
+                       return true;
+               } catch (SettingNotFoundException &e) {
+                       return false;
+               }
+       }
+
+       bool getU16NoEx(std::string name, u16 &val)
+       {
+               try {
+                       val = getU16(name);
+                       return true;
+               } catch (SettingNotFoundException &e) {
+                       return false;
+               }
+       }
+
+       bool getS16NoEx(std::string name, int &val)
+       {
+               try {
+                       val = getU16(name);
+                       return true;
+               } catch (SettingNotFoundException &e) {
+                       return false;
+               }
+       }
+
+       bool getS16NoEx(std::string name, s16 &val)
+       {
+               try {
+                       val = getS16(name);
+                       return true;
+               } catch (SettingNotFoundException &e) {
+                       return false;
+               }
+       }
+
+       bool getS32NoEx(std::string name, s32 &val)
+       {
+               try {
+                       val = getS32(name);
+                       return true;
+               } catch (SettingNotFoundException &e) {
+                       return false;
+               }
+       }
+
+       bool getV3FNoEx(std::string name, v3f &val)
+       {
+               try {
+                       val = getV3F(name);
+                       return true;
+               } catch (SettingNotFoundException &e) {
+                       return false;
+               }
+       }
+
+       bool getV2FNoEx(std::string name, v2f &val)
+       {
+               try {
+                       val = getV2F(name);
+                       return true;
+               } catch (SettingNotFoundException &e) {
+                       return false;
+               }
+       }
+
+       bool getU64NoEx(std::string name, u64 &val)
+       {
+               try {
+                       val = getU64(name);
+                       return true;
+               } catch (SettingNotFoundException &e) {
+                       return false;
+               }
+       }
+
+       //////////// Set setting
+
+       // N.B. if setStruct() is used to write a non-POD aggregate type,
+       // the behavior is undefined.
+       bool setStruct(std::string name, std::string format, void *value)
+       {
+               char sbuf[2048];
+               int sbuflen = sizeof(sbuf) - 1;
+               sbuf[sbuflen] = 0;
+               std::string str;
+               int pos = 0;
+               size_t fpos;
+               char *f;
+
+               char *bufpos = (char *)value;
+               char *fmtpos, *fmt = &format[0];
+               while ((f = strtok_r(fmt, ",", &fmtpos))) {
+                       fmt = NULL;
+                       bool is_unsigned = false;
+                       int width = 0, nprinted = 0;
+                       char valtype = *f;
+
+                       width = (int)strtol(f + 1, &f, 10);
+                       if (width && valtype == 's')
+                               valtype = 'i';
+
+                       switch (valtype) {
+                               case 'u':
+                                       is_unsigned = true;
+                                       /* FALLTHROUGH */
+                               case 'i':
+                                       if (width == 16) {
+                                               bufpos += PADDING(bufpos, u16);
+                                               nprinted = snprintf(sbuf + pos, sbuflen,
+                                                                       is_unsigned ? "%u, " : "%d, ",
+                                                                       *((u16 *)bufpos));
+                                               bufpos += sizeof(u16);
+                                       } else if (width == 32) {
+                                               bufpos += PADDING(bufpos, u32);
+                                               nprinted = snprintf(sbuf + pos, sbuflen,
+                                                                       is_unsigned ? "%u, " : "%d, ",
+                                                                       *((u32 *)bufpos));
+                                               bufpos += sizeof(u32);
+                                       } else if (width == 64) {
+                                               bufpos += PADDING(bufpos, u64);
+                                               nprinted = snprintf(sbuf + pos, sbuflen,
+                                                                       is_unsigned ? "%llu, " : "%lli, ",
+                                                                       (unsigned long long)*((u64 *)bufpos));
+                                               bufpos += sizeof(u64);
+                                       }
+                                       break;
+                               case 'b':
+                                       bufpos += PADDING(bufpos, bool);
+                                       nprinted = snprintf(sbuf + pos, sbuflen, "%s, ",
+                                                                               *((bool *)bufpos) ? "true" : "false");
+                                       bufpos += sizeof(bool);
+                                       break;
+                               case 'f':
+                                       bufpos += PADDING(bufpos, float);
+                                       nprinted = snprintf(sbuf + pos, sbuflen, "%f, ",
+                                                                               *((float *)bufpos));
+                                       bufpos += sizeof(float);
+                                       break;
+                               case 's':
+                                       bufpos += PADDING(bufpos, std::string *);
+                                       str = **((std::string **)bufpos);
+
+                                       fpos = 0;
+                                       while ((fpos = str.find('"', fpos)) != std::string::npos) {
+                                               str.insert(fpos, 1, '\\');
+                                               fpos += 2;
+                                       }
+
+                                       nprinted = snprintf(sbuf + pos, sbuflen, "\"%s\", ",
+                                                                               (*((std::string **)bufpos))->c_str());
+                                       bufpos += sizeof(std::string *);
+                                       break;
+                               case 'v':
+                                       if (width == 2) {
+                                               bufpos += PADDING(bufpos, v2f);
+                                               v2f *v = (v2f *)bufpos;
+                                               nprinted = snprintf(sbuf + pos, sbuflen,
+                                                                                       "(%f, %f), ", v->X, v->Y);
+                                               bufpos += sizeof(v2f);
+                                       } else {
+                                               bufpos += PADDING(bufpos, v3f);
+                                               v3f *v = (v3f *)bufpos;
+                                               nprinted = snprintf(sbuf + pos, sbuflen,
+                                                                                       "(%f, %f, %f), ", v->X, v->Y, v->Z);
+                                               bufpos += sizeof(v3f);
+                                       }
+                                       break;
+                               default:
+                                       return false;
+                       }
+                       if (nprinted < 0) //error, buffer too small
+                               return false;
+                       pos     += nprinted;
+                       sbuflen -= nprinted;
+               }
+
+               if (pos >= 2)
+                       sbuf[pos - 2] = 0;
+
+               set(name, std::string(sbuf));
+               return true;
+       }
+
+       void setFlagStr(std::string name, u32 flags,
+               FlagDesc *flagdesc, u32 flagmask)
+       {
+               set(name, writeFlagString(flags, flagdesc, flagmask));
+       }
+
        void setBool(std::string name, bool value)
        {
                if(value)
        void setBool(std::string name, bool value)
        {
                if(value)
@@ -554,11 +989,6 @@ class Settings
                        set(name, "false");
        }
 
                        set(name, "false");
        }
 
-       void setS32(std::string name, s32 value)
-       {
-               set(name, itos(value));
-       }
-
        void setFloat(std::string name, float value)
        {
                set(name, ftos(value));
        void setFloat(std::string name, float value)
        {
                set(name, ftos(value));
@@ -578,6 +1008,16 @@ class Settings
                set(name, os.str());
        }
 
                set(name, os.str());
        }
 
+       void setS16(std::string name, s16 value)
+       {
+               set(name, itos(value));
+       }
+
+       void setS32(std::string name, s32 value)
+       {
+               set(name, itos(value));
+       }
+
        void setU64(std::string name, u64 value)
        {
                std::ostringstream os;
        void setU64(std::string name, u64 value)
        {
                std::ostringstream os;
@@ -588,7 +1028,7 @@ class Settings
        void clear()
        {
                JMutexAutoLock lock(m_mutex);
        void clear()
        {
                JMutexAutoLock lock(m_mutex);
-               
+
                m_settings.clear();
                m_defaults.clear();
        }
                m_settings.clear();
                m_defaults.clear();
        }
@@ -596,7 +1036,7 @@ class Settings
        void updateValue(Settings &other, const std::string &name)
        {
                JMutexAutoLock lock(m_mutex);
        void updateValue(Settings &other, const std::string &name)
        {
                JMutexAutoLock lock(m_mutex);
-               
+
                if(&other == this)
                        return;
 
                if(&other == this)
                        return;
 
@@ -613,23 +1053,12 @@ class Settings
        {
                JMutexAutoLock lock(m_mutex);
                JMutexAutoLock lock2(other.m_mutex);
        {
                JMutexAutoLock lock(m_mutex);
                JMutexAutoLock lock2(other.m_mutex);
-               
+
                if(&other == this)
                        return;
 
                if(&other == this)
                        return;
 
-               for(core::map<std::string, std::string>::Iterator
-                               i = other.m_settings.getIterator();
-                               i.atEnd() == false; i++)
-               {
-                       m_settings[i.getNode()->getKey()] = i.getNode()->getValue();
-               }
-               
-               for(core::map<std::string, std::string>::Iterator
-                               i = other.m_defaults.getIterator();
-                               i.atEnd() == false; i++)
-               {
-                       m_defaults[i.getNode()->getKey()] = i.getNode()->getValue();
-               }
+               m_settings.insert(other.m_settings.begin(), other.m_settings.end());
+               m_defaults.insert(other.m_defaults.begin(), other.m_defaults.end());
 
                return;
        }
 
                return;
        }
@@ -638,25 +1067,11 @@ class Settings
        {
                JMutexAutoLock lock(m_mutex);
                JMutexAutoLock lock2(other.m_mutex);
        {
                JMutexAutoLock lock(m_mutex);
                JMutexAutoLock lock2(other.m_mutex);
-               
+
                if(&other == this)
                        return *this;
 
                if(&other == this)
                        return *this;
 
-               for(core::map<std::string, std::string>::Iterator
-                               i = other.m_settings.getIterator();
-                               i.atEnd() == false; i++)
-               {
-                       m_settings.insert(i.getNode()->getKey(),
-                                       i.getNode()->getValue());
-               }
-               
-               for(core::map<std::string, std::string>::Iterator
-                               i = other.m_defaults.getIterator();
-                               i.atEnd() == false; i++)
-               {
-                       m_defaults.insert(i.getNode()->getKey(),
-                                       i.getNode()->getValue());
-               }
+               update(other);
 
                return *this;
 
 
                return *this;
 
@@ -666,19 +1081,19 @@ class Settings
        {
                JMutexAutoLock lock(m_mutex);
                JMutexAutoLock lock2(other.m_mutex);
        {
                JMutexAutoLock lock(m_mutex);
                JMutexAutoLock lock2(other.m_mutex);
-               
+
                if(&other == this)
                        return *this;
 
                clear();
                (*this) += other;
                if(&other == this)
                        return *this;
 
                clear();
                (*this) += other;
-               
+
                return *this;
        }
 
 private:
                return *this;
        }
 
 private:
-       core::map<std::string, std::string> m_settings;
-       core::map<std::string, std::string> m_defaults;
+       std::map<std::string, std::string> m_settings;
+       std::map<std::string, std::string> m_defaults;
        // All methods that access m_settings/m_defaults directly should lock this.
        JMutex m_mutex;
 };
        // All methods that access m_settings/m_defaults directly should lock this.
        JMutex m_mutex;
 };