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