Remove no virtual dtor warnings, make MapgenParams contain actual NoiseParams
[oweals/minetest.git] / src / settings.h
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #ifndef SETTINGS_HEADER
21 #define SETTINGS_HEADER
22
23 #include "irrlichttypes_bloated.h"
24 #include <string>
25 #include <jthread.h>
26 #include <jmutex.h>
27 #include <jmutexautolock.h>
28 #include "strfnd.h"
29 #include <iostream>
30 #include <fstream>
31 #include <sstream>
32 #include "debug.h"
33 #include "log.h"
34 #include "util/string.h"
35 #include "porting.h"
36 #include <list>
37 #include <map>
38 #include <set>
39
40 enum ValueType
41 {
42         VALUETYPE_STRING,
43         VALUETYPE_FLAG // Doesn't take any arguments
44 };
45
46 struct ValueSpec
47 {
48         ValueSpec(ValueType a_type, const char *a_help=NULL)
49         {
50                 type = a_type;
51                 help = a_help;
52         }
53         ValueType type;
54         const char *help;
55 };
56
57 class Settings
58 {
59 public:
60         Settings()
61         {
62                 m_mutex.Init();
63         }
64
65         void writeLines(std::ostream &os)
66         {
67                 JMutexAutoLock lock(m_mutex);
68
69                 for(std::map<std::string, std::string>::iterator
70                                 i = m_settings.begin();
71                                 i != m_settings.end(); ++i)
72                 {
73                         std::string name = i->first;
74                         std::string value = i->second;
75                         os<<name<<" = "<<value<<"\n";
76                 }
77         }
78   
79         // return all keys used 
80         std::vector<std::string> getNames(){
81                 std::vector<std::string> names;
82                 for(std::map<std::string, std::string>::iterator
83                                 i = m_settings.begin();
84                                 i != m_settings.end(); ++i)
85                 {
86                         names.push_back(i->first);
87                 }
88                 return names;  
89         }
90
91         // remove a setting
92         bool remove(const std::string& name)
93         {
94                 return m_settings.erase(name);
95         }
96
97
98         bool parseConfigLine(const std::string &line)
99         {
100                 JMutexAutoLock lock(m_mutex);
101
102                 std::string trimmedline = trim(line);
103
104                 // Ignore empty lines and comments
105                 if(trimmedline.size() == 0 || trimmedline[0] == '#')
106                         return true;
107
108                 //infostream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
109
110                 Strfnd sf(trim(line));
111
112                 std::string name = sf.next("=");
113                 name = trim(name);
114
115                 if(name == "")
116                         return true;
117
118                 std::string value = sf.next("\n");
119                 value = trim(value);
120
121                 /*infostream<<"Config name=\""<<name<<"\" value=\""
122                                 <<value<<"\""<<std::endl;*/
123
124                 m_settings[name] = value;
125
126                 return true;
127         }
128
129         void parseConfigLines(std::istream &is, const std::string &endstring)
130         {
131                 for(;;){
132                         if(is.eof())
133                                 break;
134                         std::string line;
135                         std::getline(is, line);
136                         std::string trimmedline = trim(line);
137                         if(endstring != ""){
138                                 if(trimmedline == endstring)
139                                         break;
140                         }
141                         parseConfigLine(line);
142                 }
143         }
144
145         // Returns false on EOF
146         bool parseConfigObject(std::istream &is)
147         {
148                 if(is.eof())
149                         return false;
150
151                 /*
152                         NOTE: This function might be expanded to allow multi-line
153                               settings.
154                 */
155                 std::string line;
156                 std::getline(is, line);
157                 //infostream<<"got line: \""<<line<<"\""<<std::endl;
158
159                 return parseConfigLine(line);
160         }
161
162         /*
163                 Read configuration file
164
165                 Returns true on success
166         */
167         bool readConfigFile(const char *filename)
168         {
169                 std::ifstream is(filename);
170                 if(is.good() == false)
171                         return false;
172
173                 /*infostream<<"Parsing configuration file: \""
174                                 <<filename<<"\""<<std::endl;*/
175
176                 while(parseConfigObject(is));
177
178                 return true;
179         }
180
181         /*
182                 Reads a configuration object from stream (usually a single line)
183                 and adds it to dst.
184
185                 Preserves comments and empty lines.
186
187                 Settings that were added to dst are also added to updated.
188                 key of updated is setting name, value of updated is dummy.
189
190                 Returns false on EOF
191         */
192         bool getUpdatedConfigObject(std::istream &is,
193                         std::list<std::string> &dst,
194                         std::set<std::string> &updated,
195                         bool &value_changed)
196         {
197                 JMutexAutoLock lock(m_mutex);
198
199                 if(is.eof())
200                         return false;
201
202                 // NOTE: This function will be expanded to allow multi-line settings
203                 std::string line;
204                 std::getline(is, line);
205
206                 std::string trimmedline = trim(line);
207
208                 std::string line_end = "";
209                 if(is.eof() == false)
210                         line_end = "\n";
211
212                 // Ignore empty lines and comments
213                 if(trimmedline.size() == 0 || trimmedline[0] == '#')
214                 {
215                         dst.push_back(line+line_end);
216                         return true;
217                 }
218
219                 Strfnd sf(trim(line));
220
221                 std::string name = sf.next("=");
222                 name = trim(name);
223
224                 if(name == "")
225                 {
226                         dst.push_back(line+line_end);
227                         return true;
228                 }
229
230                 std::string value = sf.next("\n");
231                 value = trim(value);
232
233                 if(m_settings.find(name) != m_settings.end())
234                 {
235                         std::string newvalue = m_settings[name];
236
237                         if(newvalue != value)
238                         {
239                                 infostream<<"Changing value of \""<<name<<"\" = \""
240                                                 <<value<<"\" -> \""<<newvalue<<"\""
241                                                 <<std::endl;
242                                 value_changed = true;
243                         }
244
245                         dst.push_back(name + " = " + newvalue + line_end);
246
247                         updated.insert(name);
248                 }
249                 else //file contains a setting which is not in m_settings
250                         value_changed=true;
251                         
252                 return true;
253         }
254
255         /*
256                 Updates configuration file
257
258                 Returns true on success
259         */
260         bool updateConfigFile(const char *filename)
261         {
262                 infostream<<"Updating configuration file: \""
263                                 <<filename<<"\""<<std::endl;
264
265                 std::list<std::string> objects;
266                 std::set<std::string> updated;
267                 bool something_actually_changed = false;
268
269                 // Read and modify stuff
270                 {
271                         std::ifstream is(filename);
272                         if(is.good() == false)
273                         {
274                                 infostream<<"updateConfigFile():"
275                                                 " Error opening configuration file"
276                                                 " for reading: \""
277                                                 <<filename<<"\""<<std::endl;
278                         }
279                         else
280                         {
281                                 while(getUpdatedConfigObject(is, objects, updated,
282                                                 something_actually_changed));
283                         }
284                 }
285
286                 JMutexAutoLock lock(m_mutex);
287
288                 // If something not yet determined to have been changed, check if
289                 // any new stuff was added
290                 if(!something_actually_changed){
291                         for(std::map<std::string, std::string>::iterator
292                                         i = m_settings.begin();
293                                         i != m_settings.end(); ++i)
294                         {
295                                 if(updated.find(i->first) != updated.end())
296                                         continue;
297                                 something_actually_changed = true;
298                                 break;
299                         }
300                 }
301
302                 // If nothing was actually changed, skip writing the file
303                 if(!something_actually_changed){
304                         infostream<<"Skipping writing of "<<filename
305                                         <<" because content wouldn't be modified"<<std::endl;
306                         return true;
307                 }
308
309                 // Write stuff back
310                 {
311                         std::ofstream os(filename);
312                         if(os.good() == false)
313                         {
314                                 errorstream<<"Error opening configuration file"
315                                                 " for writing: \""
316                                                 <<filename<<"\""<<std::endl;
317                                 return false;
318                         }
319
320                         /*
321                                 Write updated stuff
322                         */
323                         for(std::list<std::string>::iterator
324                                         i = objects.begin();
325                                         i != objects.end(); ++i)
326                         {
327                                 os<<(*i);
328                         }
329
330                         /*
331                                 Write stuff that was not already in the file
332                         */
333                         for(std::map<std::string, std::string>::iterator
334                                         i = m_settings.begin();
335                                         i != m_settings.end(); ++i)
336                         {
337                                 if(updated.find(i->first) != updated.end())
338                                         continue;
339                                 std::string name = i->first;
340                                 std::string value = i->second;
341                                 infostream<<"Adding \""<<name<<"\" = \""<<value<<"\""
342                                                 <<std::endl;
343                                 os<<name<<" = "<<value<<"\n";
344                         }
345                 }
346
347                 return true;
348         }
349
350         /*
351                 NOTE: Types of allowed_options are ignored
352
353                 returns true on success
354         */
355         bool parseCommandLine(int argc, char *argv[],
356                         std::map<std::string, ValueSpec> &allowed_options)
357         {
358                 int nonopt_index = 0;
359                 int i=1;
360                 for(;;)
361                 {
362                         if(i >= argc)
363                                 break;
364                         std::string argname = argv[i];
365                         if(argname.substr(0, 2) != "--")
366                         {
367                                 // If option doesn't start with -, read it in as nonoptX
368                                 if(argname[0] != '-'){
369                                         std::string name = "nonopt";
370                                         name += itos(nonopt_index);
371                                         set(name, argname);
372                                         nonopt_index++;
373                                         i++;
374                                         continue;
375                                 }
376                                 errorstream<<"Invalid command-line parameter \""
377                                                 <<argname<<"\": --<option> expected."<<std::endl;
378                                 return false;
379                         }
380                         i++;
381
382                         std::string name = argname.substr(2);
383
384                         std::map<std::string, ValueSpec>::iterator n;
385                         n = allowed_options.find(name);
386                         if(n == allowed_options.end())
387                         {
388                                 errorstream<<"Unknown command-line parameter \""
389                                                 <<argname<<"\""<<std::endl;
390                                 return false;
391                         }
392
393                         ValueType type = n->second.type;
394
395                         std::string value = "";
396
397                         if(type == VALUETYPE_FLAG)
398                         {
399                                 value = "true";
400                         }
401                         else
402                         {
403                                 if(i >= argc)
404                                 {
405                                         errorstream<<"Invalid command-line parameter \""
406                                                         <<name<<"\": missing value"<<std::endl;
407                                         return false;
408                                 }
409                                 value = argv[i];
410                                 i++;
411                         }
412
413
414                         infostream<<"Valid command-line parameter: \""
415                                         <<name<<"\" = \""<<value<<"\""
416                                         <<std::endl;
417                         set(name, value);
418                 }
419
420                 return true;
421         }
422
423         void set(std::string name, std::string value)
424         {
425                 JMutexAutoLock lock(m_mutex);
426
427                 m_settings[name] = value;
428         }
429
430         void set(std::string name, const char *value)
431         {
432                 JMutexAutoLock lock(m_mutex);
433
434                 m_settings[name] = value;
435         }
436
437
438         void setDefault(std::string name, std::string value)
439         {
440                 JMutexAutoLock lock(m_mutex);
441
442                 m_defaults[name] = value;
443         }
444
445         bool exists(std::string name)
446         {
447                 JMutexAutoLock lock(m_mutex);
448
449                 return (m_settings.find(name) != m_settings.end() || m_defaults.find(name) != m_defaults.end());
450         }
451
452         std::string get(std::string name)
453         {
454                 JMutexAutoLock lock(m_mutex);
455
456                 std::map<std::string, std::string>::iterator n;
457                 n = m_settings.find(name);
458                 if(n == m_settings.end())
459                 {
460                         n = m_defaults.find(name);
461                         if(n == m_defaults.end())
462                         {
463                                 throw SettingNotFoundException(("Setting [" + name + "] not found ").c_str());
464                         }
465                 }
466
467                 return n->second;
468         }
469
470         bool getBool(std::string name)
471         {
472                 return is_yes(get(name));
473         }
474
475         bool getFlag(std::string name)
476         {
477                 try
478                 {
479                         return getBool(name);
480                 }
481                 catch(SettingNotFoundException &e)
482                 {
483                         return false;
484                 }
485         }
486
487         // Asks if empty
488         bool getBoolAsk(std::string name, std::string question, bool def)
489         {
490                 // If it is in settings
491                 if(exists(name))
492                         return getBool(name);
493
494                 std::string s;
495                 char templine[10];
496                 std::cout<<question<<" [y/N]: ";
497                 std::cin.getline(templine, 10);
498                 s = templine;
499
500                 if(s == "")
501                         return def;
502
503                 return is_yes(s);
504         }
505
506         float getFloat(std::string name)
507         {
508                 return stof(get(name));
509         }
510
511         u16 getU16(std::string name)
512         {
513                 return stoi(get(name), 0, 65535);
514         }
515
516         u16 getU16Ask(std::string name, std::string question, u16 def)
517         {
518                 // If it is in settings
519                 if(exists(name))
520                         return getU16(name);
521
522                 std::string s;
523                 char templine[10];
524                 std::cout<<question<<" ["<<def<<"]: ";
525                 std::cin.getline(templine, 10);
526                 s = templine;
527
528                 if(s == "")
529                         return def;
530
531                 return stoi(s, 0, 65535);
532         }
533
534         s16 getS16(std::string name)
535         {
536                 return stoi(get(name), -32768, 32767);
537         }
538
539         s32 getS32(std::string name)
540         {
541                 return stoi(get(name));
542         }
543
544         v3f getV3F(std::string name)
545         {
546                 v3f value;
547                 Strfnd f(get(name));
548                 f.next("(");
549                 value.X = stof(f.next(","));
550                 value.Y = stof(f.next(","));
551                 value.Z = stof(f.next(")"));
552                 return value;
553         }
554
555         v2f getV2F(std::string name)
556         {
557                 v2f value;
558                 Strfnd f(get(name));
559                 f.next("(");
560                 value.X = stof(f.next(","));
561                 value.Y = stof(f.next(")"));
562                 return value;
563         }
564
565         u64 getU64(std::string name)
566         {
567                 u64 value = 0;
568                 std::string s = get(name);
569                 std::istringstream ss(s);
570                 ss>>value;
571                 return value;
572         }
573
574         u32 getFlagStr(std::string name, FlagDesc *flagdesc)
575         {
576                 std::string val = get(name);
577                 return (isdigit(val[0])) ? stoi(val) : readFlagString(val, flagdesc);
578         }
579
580         bool getStruct(std::string name, std::string format, void *out, size_t olen)
581         {
582                 size_t len = olen;
583                 std::vector<std::string *> strs_alloced;
584                 std::string *str;
585                 std::string valstr = get(name);
586                 char *s = &valstr[0];
587                 char *buf = new char[len];
588                 char *bufpos = buf;
589                 char *f, *snext;
590                 size_t pos;
591
592                 char *fmtpos, *fmt = &format[0];
593                 while ((f = strtok_r(fmt, ",", &fmtpos)) && s) {
594                         fmt = NULL;
595
596                         bool is_unsigned = false;
597                         int width = 0;
598                         char valtype = *f;
599
600                         width = (int)strtol(f + 1, &f, 10);
601                         if (width && valtype == 's')
602                                 valtype = 'i';
603
604                         switch (valtype) {
605                                 case 'u':
606                                         is_unsigned = true;
607                                         /* FALLTHROUGH */
608                                 case 'i':
609                                         if (width == 16) {
610                                                 bufpos += PADDING(bufpos, u16);
611                                                 if ((bufpos - buf) + sizeof(u16) <= len) {
612                                                         if (is_unsigned)
613                                                                 *(u16 *)bufpos = (u16)strtoul(s, &s, 10);
614                                                         else
615                                                                 *(s16 *)bufpos = (s16)strtol(s, &s, 10);
616                                                 }
617                                                 bufpos += sizeof(u16);
618                                         } else if (width == 32) {
619                                                 bufpos += PADDING(bufpos, u32);
620                                                 if ((bufpos - buf) + sizeof(u32) <= len) {
621                                                         if (is_unsigned)
622                                                                 *(u32 *)bufpos = (u32)strtoul(s, &s, 10);
623                                                         else
624                                                                 *(s32 *)bufpos = (s32)strtol(s, &s, 10);
625                                                 }
626                                                 bufpos += sizeof(u32);
627                                         } else if (width == 64) {
628                                                 bufpos += PADDING(bufpos, u64);
629                                                 if ((bufpos - buf) + sizeof(u64) <= len) {
630                                                         if (is_unsigned)
631                                                                 *(u64 *)bufpos = (u64)strtoull(s, &s, 10);
632                                                         else
633                                                                 *(s64 *)bufpos = (s64)strtoll(s, &s, 10);
634                                                 }
635                                                 bufpos += sizeof(u64);
636                                         }
637                                         s = strchr(s, ',');
638                                         break;
639                                 case 'b':
640                                         snext = strchr(s, ',');
641                                         if (snext)
642                                                 *snext++ = 0;
643
644                                         bufpos += PADDING(bufpos, bool);
645                                         if ((bufpos - buf) + sizeof(bool) <= len)
646                                                 *(bool *)bufpos = is_yes(std::string(s));
647                                         bufpos += sizeof(bool);
648
649                                         s = snext;
650                                         break;
651                                 case 'f':
652                                         bufpos += PADDING(bufpos, float);
653                                         if ((bufpos - buf) + sizeof(float) <= len)
654                                                 *(float *)bufpos = strtof(s, &s);
655                                         bufpos += sizeof(float);
656
657                                         s = strchr(s, ',');
658                                         break;
659                                 case 's':
660                                         while (*s == ' ' || *s == '\t')
661                                                 s++;
662                                         if (*s++ != '"') //error, expected string
663                                                 goto fail;
664                                         snext = s;
665
666                                         while (snext[0] && !(snext[-1] != '\\' && snext[0] == '"'))
667                                                 snext++;
668                                         *snext++ = 0;
669
670                                         bufpos += PADDING(bufpos, std::string *);
671
672                                         str = new std::string(s);
673                                         pos = 0;
674                                         while ((pos = str->find("\\\"", pos)) != std::string::npos)
675                                                 str->erase(pos, 1);
676
677                                         if ((bufpos - buf) + sizeof(std::string *) <= len)
678                                                 *(std::string **)bufpos = str;
679                                         bufpos += sizeof(std::string *);
680                                         strs_alloced.push_back(str);
681
682                                         s = *snext ? snext + 1 : NULL;
683                                         break;
684                                 case 'v':
685                                         while (*s == ' ' || *s == '\t')
686                                                 s++;
687                                         if (*s++ != '(') //error, expected vector
688                                                 goto fail;
689
690                                         if (width == 2) {
691                                                 bufpos += PADDING(bufpos, v2f);
692
693                                                 if ((bufpos - buf) + sizeof(v2f) <= len) {
694                                                 v2f *v = (v2f *)bufpos;
695                                                         v->X = strtof(s, &s);
696                                                         s++;
697                                                         v->Y = strtof(s, &s);
698                                                 }
699
700                                                 bufpos += sizeof(v2f);
701                                         } else if (width == 3) {
702                                                 bufpos += PADDING(bufpos, v3f);
703                                                 if ((bufpos - buf) + sizeof(v3f) <= len) {
704                                                         v3f *v = (v3f *)bufpos;
705                                                         v->X = strtof(s, &s);
706                                                         s++;
707                                                         v->Y = strtof(s, &s);
708                                                         s++;
709                                                         v->Z = strtof(s, &s);
710                                                 }
711
712                                                 bufpos += sizeof(v3f);
713                                         }
714                                         s = strchr(s, ',');
715                                         break;
716                                 default: //error, invalid format specifier
717                                         goto fail;
718                         }
719
720                         if (s && *s == ',')
721                                 s++;
722
723                         if ((size_t)(bufpos - buf) > len) //error, buffer too small
724                                 goto fail;
725                 }
726
727                 if (f && *f) { //error, mismatched number of fields and values
728 fail:
729                         for (size_t i = 0; i != strs_alloced.size(); i++)
730                                 delete strs_alloced[i];
731                         delete[] buf;
732                         return false;
733                 }
734
735                 memcpy(out, buf, olen);
736                 delete[] buf;
737                 return true;
738         }
739
740         bool setStruct(std::string name, std::string format, void *value)
741         {
742                 char sbuf[2048];
743                 int sbuflen = sizeof(sbuf) - 1;
744                 sbuf[sbuflen] = 0;
745                 std::string str;
746                 int pos = 0;
747                 size_t fpos;
748                 char *f;
749
750                 char *bufpos = (char *)value;
751                 char *fmtpos, *fmt = &format[0];
752                 while ((f = strtok_r(fmt, ",", &fmtpos))) {
753                         fmt = NULL;
754                         bool is_unsigned = false;
755                         int width = 0, nprinted = 0;
756                         char valtype = *f;
757
758                         width = (int)strtol(f + 1, &f, 10);
759                         if (width && valtype == 's')
760                                 valtype = 'i';
761
762                         switch (valtype) {
763                                 case 'u':
764                                         is_unsigned = true;
765                                         /* FALLTHROUGH */
766                                 case 'i':
767                                         if (width == 16) {
768                                                 bufpos += PADDING(bufpos, u16);
769                                                 nprinted = snprintf(sbuf + pos, sbuflen,
770                                                                         is_unsigned ? "%u, " : "%d, ",
771                                                                         *((u16 *)bufpos));
772                                                 bufpos += sizeof(u16);
773                                         } else if (width == 32) {
774                                                 bufpos += PADDING(bufpos, u32);
775                                                 nprinted = snprintf(sbuf + pos, sbuflen,
776                                                                         is_unsigned ? "%u, " : "%d, ",
777                                                                         *((u32 *)bufpos));
778                                                 bufpos += sizeof(u32);
779                                         } else if (width == 64) {
780                                                 bufpos += PADDING(bufpos, u64);
781                                                 nprinted = snprintf(sbuf + pos, sbuflen,
782                                                                         is_unsigned ? "%llu, " : "%lli, ",
783                                                                         (unsigned long long)*((u64 *)bufpos));
784                                                 bufpos += sizeof(u64);
785                                         }
786                                         break;
787                                 case 'b':
788                                         bufpos += PADDING(bufpos, bool);
789                                         nprinted = snprintf(sbuf + pos, sbuflen, "%s, ",
790                                                                                 *((bool *)bufpos) ? "true" : "false");
791                                         bufpos += sizeof(bool);
792                                         break;
793                                 case 'f':
794                                         bufpos += PADDING(bufpos, float);
795                                         nprinted = snprintf(sbuf + pos, sbuflen, "%f, ",
796                                                                                 *((float *)bufpos));
797                                         bufpos += sizeof(float);
798                                         break;
799                                 case 's':
800                                         bufpos += PADDING(bufpos, std::string *);
801                                         str = **((std::string **)bufpos);
802
803                                         fpos = 0;
804                                         while ((fpos = str.find('"', fpos)) != std::string::npos) {
805                                                 str.insert(fpos, 1, '\\');
806                                                 fpos += 2;
807                                         }
808
809                                         nprinted = snprintf(sbuf + pos, sbuflen, "\"%s\", ",
810                                                                                 (*((std::string **)bufpos))->c_str());
811                                         bufpos += sizeof(std::string *);
812                                         break;
813                                 case 'v':
814                                         if (width == 2) {
815                                                 bufpos += PADDING(bufpos, v2f);
816                                                 v2f *v = (v2f *)bufpos;
817                                                 nprinted = snprintf(sbuf + pos, sbuflen,
818                                                                                         "(%f, %f), ", v->X, v->Y);
819                                                 bufpos += sizeof(v2f);
820                                         } else {
821                                                 bufpos += PADDING(bufpos, v3f);
822                                                 v3f *v = (v3f *)bufpos;
823                                                 nprinted = snprintf(sbuf + pos, sbuflen,
824                                                                                         "(%f, %f, %f), ", v->X, v->Y, v->Z);
825                                                 bufpos += sizeof(v3f);
826                                         }
827                                         break;
828                                 default:
829                                         return false;
830                         }
831                         if (nprinted < 0) //error, buffer too small
832                                 return false;
833                         pos     += nprinted;
834                         sbuflen -= nprinted;
835                 }
836
837                 if (pos >= 2)
838                         sbuf[pos - 2] = 0;
839
840                 set(name, std::string(sbuf));
841                 return true;
842         }
843         
844         void setFlagStr(std::string name, u32 flags, FlagDesc *flagdesc)
845         {
846                 set(name, writeFlagString(flags, flagdesc));
847         }
848
849         void setBool(std::string name, bool value)
850         {
851                 if(value)
852                         set(name, "true");
853                 else
854                         set(name, "false");
855         }
856
857         void setFloat(std::string name, float value)
858         {
859                 set(name, ftos(value));
860         }
861
862         void setV3F(std::string name, v3f value)
863         {
864                 std::ostringstream os;
865                 os<<"("<<value.X<<","<<value.Y<<","<<value.Z<<")";
866                 set(name, os.str());
867         }
868
869         void setV2F(std::string name, v2f value)
870         {
871                 std::ostringstream os;
872                 os<<"("<<value.X<<","<<value.Y<<")";
873                 set(name, os.str());
874         }
875
876         void setS16(std::string name, s16 value)
877         {
878                 set(name, itos(value));
879         }
880
881         void setS32(std::string name, s32 value)
882         {
883                 set(name, itos(value));
884         }
885
886         void setU64(std::string name, u64 value)
887         {
888                 std::ostringstream os;
889                 os<<value;
890                 set(name, os.str());
891         }
892
893         void clear()
894         {
895                 JMutexAutoLock lock(m_mutex);
896
897                 m_settings.clear();
898                 m_defaults.clear();
899         }
900
901         void updateValue(Settings &other, const std::string &name)
902         {
903                 JMutexAutoLock lock(m_mutex);
904
905                 if(&other == this)
906                         return;
907
908                 try{
909                         std::string val = other.get(name);
910                         m_settings[name] = val;
911                 } catch(SettingNotFoundException &e){
912                 }
913
914                 return;
915         }
916
917         void update(Settings &other)
918         {
919                 JMutexAutoLock lock(m_mutex);
920                 JMutexAutoLock lock2(other.m_mutex);
921
922                 if(&other == this)
923                         return;
924
925                 m_settings.insert(other.m_settings.begin(), other.m_settings.end());
926                 m_defaults.insert(other.m_defaults.begin(), other.m_defaults.end());
927
928                 return;
929         }
930
931         Settings & operator+=(Settings &other)
932         {
933                 JMutexAutoLock lock(m_mutex);
934                 JMutexAutoLock lock2(other.m_mutex);
935
936                 if(&other == this)
937                         return *this;
938
939                 update(other);
940
941                 return *this;
942
943         }
944
945         Settings & operator=(Settings &other)
946         {
947                 JMutexAutoLock lock(m_mutex);
948                 JMutexAutoLock lock2(other.m_mutex);
949
950                 if(&other == this)
951                         return *this;
952
953                 clear();
954                 (*this) += other;
955
956                 return *this;
957         }
958
959 private:
960         std::map<std::string, std::string> m_settings;
961         std::map<std::string, std::string> m_defaults;
962         // All methods that access m_settings/m_defaults directly should lock this.
963         JMutex m_mutex;
964 };
965
966 #endif
967