]> git.lizzy.rs Git - minetest.git/blobdiff - src/settings.h
Fix lost pause support in singleplayer
[minetest.git] / src / settings.h
index e7b49b6d7798497cc3d25f8bda08a596abe4acf9..13c8e1e65e6a7d42b61933629d624560bca05e97 100644 (file)
@@ -21,10 +21,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define SETTINGS_HEADER
 
 #include "irrlichttypes_bloated.h"
+#include "exceptions.h"
 #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>
@@ -32,10 +32,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "debug.h"
 #include "log.h"
 #include "util/string.h"
-#include "porting.h"
+#include "util/serialize.h"
 #include <list>
 #include <map>
 #include <set>
+#include "filesys.h"
+#include <cctype>
 
 enum ValueType
 {
@@ -59,7 +61,6 @@ class Settings
 public:
        Settings()
        {
-               m_mutex.Init();
        }
 
        void writeLines(std::ostream &os)
@@ -76,7 +77,7 @@ class Settings
                }
        }
   
-       // return all keys used 
+       // return all keys used
        std::vector<std::string> getNames(){
                std::vector<std::string> names;
                for(std::map<std::string, std::string>::iterator
@@ -85,7 +86,7 @@ class Settings
                {
                        names.push_back(i->first);
                }
-               return names;  
+               return names;
        }
 
        // remove a setting
@@ -308,14 +309,7 @@ class Settings
 
                // 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
@@ -324,7 +318,7 @@ class Settings
                                        i = objects.begin();
                                        i != objects.end(); ++i)
                        {
-                               os<<(*i);
+                               ss<<(*i);
                        }
 
                        /*
@@ -340,7 +334,14 @@ class Settings
                                std::string value = i->second;
                                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;
                        }
                }
 
@@ -467,6 +468,7 @@ class Settings
                return n->second;
        }
 
+       //////////// Get setting
        bool getBool(std::string name)
        {
                return is_yes(get(name));
@@ -571,279 +573,169 @@ class Settings
                return value;
        }
 
-       u32 getFlagStr(std::string name, FlagDesc *flagdesc)
+       u32 getFlagStr(std::string name, FlagDesc *flagdesc, u32 *flagmask)
        {
                std::string val = get(name);
-               return (isdigit(val[0])) ? stoi(val) : readFlagString(val, flagdesc);
+               return (std::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;
-               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;
+               std::string valstr;
 
-                                       bufpos += PADDING(bufpos, bool);
-                                       if ((bufpos - buf) + sizeof(bool) <= len)
-                                               *(bool *)bufpos = is_yes(std::string(s));
-                                       bufpos += sizeof(bool);
+               try {
+                       valstr = get(name);
+               } catch (SettingNotFoundException &e) {
+                       return false;
+               }
 
-                                       s = snext;
-                                       break;
-                               case 'f':
-                                       bufpos += PADDING(bufpos, float);
-                                       if ((bufpos - buf) + sizeof(float) <= len)
-                                               *(float *)bufpos = strtof(s, &s);
-                                       bufpos += sizeof(float);
+               if (!deSerializeStringToStruct(valstr, format, out, olen))
+                       return false;
 
-                                       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;
-                       }
+               return true;
+       }
 
-                       if (s && *s == ',')
-                               s++;
+       //////////// 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;
 
-                       if ((size_t)(bufpos - buf) > len) //error, buffer too small
-                               goto fail;
+                       flags = getFlagStr(name, flagdesc, &flagmask);
+
+                       val &= ~flagmask;
+                       val |=  flags;
+
+                       return true;
+               } catch (SettingNotFoundException &e) {
+                       return false;
                }
+       }
 
-               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;
+       bool getFloatNoEx(std::string name, float &val)
+       {
+               try {
+                       val = getFloat(name);
+                       return true;
+               } catch (SettingNotFoundException &e) {
                        return false;
                }
+       }
 
-               memcpy(out, buf, olen);
-               delete[] buf;
-               return true;
+       bool getU16NoEx(std::string name, int &val)
+       {
+               try {
+                       val = getU16(name);
+                       return true;
+               } catch (SettingNotFoundException &e) {
+                       return false;
+               }
        }
 
-       bool setStruct(std::string name, std::string format, void *value)
+       bool getU16NoEx(std::string name, u16 &val)
        {
-               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;
+               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;
                }
+       }
 
-               if (pos >= 2)
-                       sbuf[pos - 2] = 0;
+       bool getV2FNoEx(std::string name, v2f &val)
+       {
+               try {
+                       val = getV2F(name);
+                       return true;
+               } catch (SettingNotFoundException &e) {
+                       return false;
+               }
+       }
 
-               set(name, std::string(sbuf));
+       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)
+       {
+               std::string structstr;
+               if (!serializeStructToString(&structstr, format, value))
+                       return false;
+
+               set(name, structstr);
                return true;
        }
-       
-       void setFlagStr(std::string name, u32 flags, FlagDesc *flagdesc)
+
+       void setFlagStr(std::string name, u32 flags,
+               FlagDesc *flagdesc, u32 flagmask)
        {
-               set(name, writeFlagString(flags, flagdesc));
+               set(name, writeFlagString(flags, flagdesc, flagmask));
        }
 
        void setBool(std::string name, bool value)