]> git.lizzy.rs Git - minetest.git/blobdiff - src/settings.h
Add a callback: minetest.register_on_craft(itemstack, player,
[minetest.git] / src / settings.h
index f972ce3ece1ce8528d97eb2c82514ca9e5aef550..4ee5b591322a9070f6bf7b685f034cd823b1e54c 100644 (file)
@@ -1,18 +1,18 @@
 /*
 /*
-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
 
 This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GNU Lesser General Public License for more details.
 
 
-You should have received a copy of the GNU General Public License along
+You should have received a copy of the GNU Lesser General Public License along
 with this program; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 with this program; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
@@ -20,17 +20,23 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #ifndef SETTINGS_HEADER
 #define SETTINGS_HEADER
 
 #ifndef SETTINGS_HEADER
 #define SETTINGS_HEADER
 
-#include "common_irrlicht.h"
+#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 <sstream>
 #include "debug.h"
 #include "strfnd.h"
 #include <iostream>
 #include <fstream>
 #include <sstream>
 #include "debug.h"
-#include "utility.h"
+#include "log.h"
+#include "util/string.h"
+#include "porting.h"
+#include <list>
+#include <map>
+#include <set>
+#include "filesys.h"
 
 enum ValueType
 {
 
 enum ValueType
 {
@@ -60,28 +66,47 @@ class Settings
        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 comments
-               if(trimmedline[0] == '#')
+
+               // Ignore empty lines and comments
+               if(trimmedline.size() == 0 || trimmedline[0] == '#')
                        return true;
 
                        return true;
 
-               //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
+               //infostream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
 
                Strfnd sf(trim(line));
 
 
                Strfnd sf(trim(line));
 
@@ -90,31 +115,47 @@ class Settings
 
                if(name == "")
                        return true;
 
                if(name == "")
                        return true;
-               
+
                std::string value = sf.next("\n");
                value = trim(value);
 
                std::string value = sf.next("\n");
                value = trim(value);
 
-               /*dstream<<"Config name=\""<<name<<"\" value=\""
+               /*infostream<<"Config name=\""<<name<<"\" value=\""
                                <<value<<"\""<<std::endl;*/
                                <<value<<"\""<<std::endl;*/
-               
+
                m_settings[name] = value;
                m_settings[name] = value;
-               
+
                return true;
        }
 
                return true;
        }
 
+       void parseConfigLines(std::istream &is, const std::string &endstring)
+       {
+               for(;;){
+                       if(is.eof())
+                               break;
+                       std::string line;
+                       std::getline(is, line);
+                       std::string trimmedline = trim(line);
+                       if(endstring != ""){
+                               if(trimmedline == endstring)
+                                       break;
+                       }
+                       parseConfigLine(line);
+               }
+       }
+
        // Returns false on EOF
        bool parseConfigObject(std::istream &is)
        {
                if(is.eof())
                        return false;
        // Returns false on EOF
        bool parseConfigObject(std::istream &is)
        {
                if(is.eof())
                        return false;
-               
+
                /*
                        NOTE: This function might be expanded to allow multi-line
                              settings.
                */
                std::string line;
                std::getline(is, line);
                /*
                        NOTE: This function might be expanded to allow multi-line
                              settings.
                */
                std::string line;
                std::getline(is, line);
-               //dstream<<"got line: \""<<line<<"\""<<std::endl;
+               //infostream<<"got line: \""<<line<<"\""<<std::endl;
 
                return parseConfigLine(line);
        }
 
                return parseConfigLine(line);
        }
@@ -128,24 +169,20 @@ class Settings
        {
                std::ifstream is(filename);
                if(is.good() == false)
        {
                std::ifstream is(filename);
                if(is.good() == false)
-               {
-                       dstream<<"Error opening configuration file \""
-                                       <<filename<<"\""<<std::endl;
                        return false;
                        return false;
-               }
 
 
-               dstream<<"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.
@@ -154,14 +191,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);
        {
                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);
@@ -171,9 +209,9 @@ 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 comments
-               if(trimmedline[0] == '#')
+
+               // Ignore empty lines and comments
+               if(trimmedline.size() == 0 || trimmedline[0] == '#')
                {
                        dst.push_back(line+line_end);
                        return true;
                {
                        dst.push_back(line+line_end);
                        return true;
@@ -189,26 +227,29 @@ 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)
                        {
                        if(newvalue != value)
                        {
-                               dstream<<"Changing value of \""<<name<<"\" = \""
+                               infostream<<"Changing value of \""<<name<<"\" = \""
                                                <<value<<"\" -> \""<<newvalue<<"\""
                                                <<std::endl;
                                                <<value<<"\" -> \""<<newvalue<<"\""
                                                <<std::endl;
+                               value_changed = true;
                        }
 
                        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;
        }
 
@@ -219,68 +260,91 @@ class Settings
        */
        bool updateConfigFile(const char *filename)
        {
        */
        bool updateConfigFile(const char *filename)
        {
-               dstream<<"Updating configuration file: \""
+               infostream<<"Updating configuration file: \""
                                <<filename<<"\""<<std::endl;
                                <<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;
+
                // Read and modify stuff
                {
                        std::ifstream is(filename);
                        if(is.good() == false)
                        {
                // Read and modify stuff
                {
                        std::ifstream is(filename);
                        if(is.good() == false)
                        {
-                               dstream<<"INFO: updateConfigFile():"
+                               infostream<<"updateConfigFile():"
                                                " Error opening configuration file"
                                                " for reading: \""
                                                <<filename<<"\""<<std::endl;
                        }
                        else
                        {
                                                " Error opening configuration file"
                                                " for reading: \""
                                                <<filename<<"\""<<std::endl;
                        }
                        else
                        {
-                               while(getUpdatedConfigObject(is, objects, updated));
+                               while(getUpdatedConfigObject(is, objects, updated,
+                                               something_actually_changed));
                        }
                }
                        }
                }
-               
+
                JMutexAutoLock lock(m_mutex);
                JMutexAutoLock lock(m_mutex);
-               
-               // Write stuff back
-               {
-                       std::ofstream os(filename);
-                       if(os.good() == false)
+
+               // If something not yet determined to have been changed, check if
+               // any new stuff was added
+               if(!something_actually_changed){
+                       for(std::map<std::string, std::string>::iterator
+                                       i = m_settings.begin();
+                                       i != m_settings.end(); ++i)
                        {
                        {
-                               dstream<<"Error opening configuration file"
-                                               " for writing: \""
-                                               <<filename<<"\""<<std::endl;
-                               return false;
+                               if(updated.find(i->first) != updated.end())
+                                       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;
+               }
+
+               // Write stuff back
+               {
+                       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();
-                               dstream<<"Adding \""<<name<<"\" = \""<<value<<"\""
+                               std::string name = i->first;
+                               std::string value = i->second;
+                               infostream<<"Adding \""<<name<<"\" = \""<<value<<"\""
                                                <<std::endl;
                                                <<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;
        }
 
@@ -290,8 +354,9 @@ 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;
                for(;;)
                {
                int i=1;
                for(;;)
                {
@@ -300,7 +365,16 @@ class Settings
                        std::string argname = argv[i];
                        if(argname.substr(0, 2) != "--")
                        {
                        std::string argname = argv[i];
                        if(argname.substr(0, 2) != "--")
                        {
-                               dstream<<"Invalid command-line parameter \""
+                               // If option doesn't start with -, read it in as nonoptX
+                               if(argname[0] != '-'){
+                                       std::string name = "nonopt";
+                                       name += itos(nonopt_index);
+                                       set(name, argname);
+                                       nonopt_index++;
+                                       i++;
+                                       continue;
+                               }
+                               errorstream<<"Invalid command-line parameter \""
                                                <<argname<<"\": --<option> expected."<<std::endl;
                                return false;
                        }
                                                <<argname<<"\": --<option> expected."<<std::endl;
                                return false;
                        }
@@ -308,19 +382,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())
                        {
                        {
-                               dstream<<"Unknown command-line parameter \""
+                               errorstream<<"Unknown command-line parameter \""
                                                <<argname<<"\""<<std::endl;
                                return false;
                        }
 
                                                <<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";
@@ -329,16 +403,16 @@ class Settings
                        {
                                if(i >= argc)
                                {
                        {
                                if(i >= argc)
                                {
-                                       dstream<<"Invalid command-line parameter \""
+                                       errorstream<<"Invalid command-line parameter \""
                                                        <<name<<"\": missing value"<<std::endl;
                                        return false;
                                }
                                value = argv[i];
                                i++;
                        }
                                                        <<name<<"\": missing value"<<std::endl;
                                        return false;
                                }
                                value = argv[i];
                                i++;
                        }
-                       
 
 
-                       dstream<<"Valid command-line parameter: \""
+
+                       infostream<<"Valid command-line parameter: \""
                                        <<name<<"\" = \""<<value<<"\""
                                        <<std::endl;
                        set(name, value);
                                        <<name<<"\" = \""<<value<<"\""
                                        <<std::endl;
                        set(name, value);
@@ -350,7 +424,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;
        }
 
@@ -365,42 +439,40 @@ 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())
                        {
                        {
-                               dstream<<"INFO: Settings: Setting not found: \""
-                                               <<name<<"\""<<std::endl;
-                               throw SettingNotFoundException("Setting not found");
+                               throw SettingNotFoundException(("Setting [" + name + "] not found ").c_str());
                        }
                }
 
                        }
                }
 
-               return n->getValue();
+               return n->second;
        }
 
        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
@@ -419,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]: ";
@@ -447,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<<"]: ";
@@ -481,6 +553,16 @@ class Settings
                return value;
        }
 
                return value;
        }
 
+       v2f getV2F(std::string name)
+       {
+               v2f value;
+               Strfnd f(get(name));
+               f.next("(");
+               value.X = stof(f.next(","));
+               value.Y = stof(f.next(")"));
+               return value;
+       }
+
        u64 getU64(std::string name)
        {
                u64 value = 0;
        u64 getU64(std::string name)
        {
                u64 value = 0;
@@ -490,6 +572,281 @@ class Settings
                return value;
        }
 
                return value;
        }
 
+       u32 getFlagStr(std::string name, FlagDesc *flagdesc)
+       {
+               std::string val = get(name);
+               return (isdigit(val[0])) ? stoi(val) : readFlagString(val, flagdesc);
+       }
+
+       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;
+               std::string valstr = get(name);
+               char *s = &valstr[0];
+               char *buf = new char[len];
+               char *bufpos = buf;
+               char *f, *snext;
+               size_t pos;
+
+               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;
+       }
+
+       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)
+       {
+               set(name, writeFlagString(flags, flagdesc));
+       }
+
        void setBool(std::string name, bool value)
        {
                if(value)
        void setBool(std::string name, bool value)
        {
                if(value)
@@ -498,11 +855,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));
@@ -515,6 +867,23 @@ class Settings
                set(name, os.str());
        }
 
                set(name, os.str());
        }
 
+       void setV2F(std::string name, v2f value)
+       {
+               std::ostringstream os;
+               os<<"("<<value.X<<","<<value.Y<<")";
+               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;
@@ -525,34 +894,50 @@ 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();
        }
 
+       void updateValue(Settings &other, const std::string &name)
+       {
+               JMutexAutoLock lock(m_mutex);
+
+               if(&other == this)
+                       return;
+
+               try{
+                       std::string val = other.get(name);
+                       m_settings[name] = val;
+               } catch(SettingNotFoundException &e){
+               }
+
+               return;
+       }
+
+       void update(Settings &other)
+       {
+               JMutexAutoLock lock(m_mutex);
+               JMutexAutoLock lock2(other.m_mutex);
+
+               if(&other == this)
+                       return;
+
+               m_settings.insert(other.m_settings.begin(), other.m_settings.end());
+               m_defaults.insert(other.m_defaults.begin(), other.m_defaults.end());
+
+               return;
+       }
+
        Settings & operator+=(Settings &other)
        {
                JMutexAutoLock lock(m_mutex);
                JMutexAutoLock lock2(other.m_mutex);
        Settings & operator+=(Settings &other)
        {
                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;
 
@@ -562,19 +947,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;
 };