Change Minetest-c55 to Minetest
[oweals/minetest.git] / src / settings.h
1 /*
2 Minetest
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         u32 getFlagStr(std::string name, FlagDesc *flagdesc)
573         {
574                 std::string val = get(name);
575                 return (isdigit(val[0])) ? stoi(val) : readFlagString(val, flagdesc);
576         }
577
578         template <class T> T *getStruct(std::string name, std::string format)
579         {
580                 size_t len = sizeof(T);
581                 std::vector<std::string *> strs_alloced;
582                 std::string *str;
583                 std::string valstr = get(name);
584                 char *s = &valstr[0];
585                 T *buf = new T;
586                 char *bufpos = (char *)buf;
587                 char *f, *snext;
588                 size_t pos;
589
590                 char *fmtpos, *fmt = &format[0];
591                 while ((f = strtok_r(fmt, ",", &fmtpos)) && s) {
592                         fmt = NULL;
593
594                         bool is_unsigned = false;
595                         int width = 0;
596                         char valtype = *f;
597
598                         width = (int)strtol(f + 1, &f, 10);
599                         if (width && valtype == 's')
600                                 valtype = 'i';
601
602                         switch (valtype) {
603                                 case 'u':
604                                         is_unsigned = true;
605                                         /* FALLTHROUGH */
606                                 case 'i':
607                                         if (width == 16) {
608                                                 bufpos += PADDING(bufpos, u16);
609                                                 if ((bufpos - (char *)buf) + sizeof(u16) <= len) {
610                                                         if (is_unsigned)
611                                                                 *(u16 *)bufpos = (u16)strtoul(s, &s, 10);
612                                                         else
613                                                                 *(s16 *)bufpos = (s16)strtol(s, &s, 10);
614                                                 }
615                                                 bufpos += sizeof(u16);
616                                         } else if (width == 32) {
617                                                 bufpos += PADDING(bufpos, u32);
618                                                 if ((bufpos - (char *)buf) + sizeof(u32) <= len) {
619                                                         if (is_unsigned)
620                                                                 *(u32 *)bufpos = (u32)strtoul(s, &s, 10);
621                                                         else
622                                                                 *(s32 *)bufpos = (s32)strtol(s, &s, 10);
623                                                 }
624                                                 bufpos += sizeof(u32);
625                                         } else if (width == 64) {
626                                                 bufpos += PADDING(bufpos, u64);
627                                                 if ((bufpos - (char *)buf) + sizeof(u64) <= len) {
628                                                         if (is_unsigned)
629                                                                 *(u64 *)bufpos = (u64)strtoull(s, &s, 10);
630                                                         else
631                                                                 *(s64 *)bufpos = (s64)strtoll(s, &s, 10);
632                                                 }
633                                                 bufpos += sizeof(u64);
634                                         }
635                                         s = strchr(s, ',');
636                                         break;
637                                 case 'b':
638                                         snext = strchr(s, ',');
639                                         if (snext)
640                                                 *snext++ = 0;
641
642                                         bufpos += PADDING(bufpos, bool);
643                                         if ((bufpos - (char *)buf) + sizeof(bool) <= len)
644                                                 *(bool *)bufpos = is_yes(std::string(s));
645                                         bufpos += sizeof(bool);
646
647                                         s = snext;
648                                         break;
649                                 case 'f':
650                                         bufpos += PADDING(bufpos, float);
651                                         if ((bufpos - (char *)buf) + sizeof(float) <= len)
652                                                 *(float *)bufpos = strtof(s, &s);
653                                         bufpos += sizeof(float);
654
655                                         s = strchr(s, ',');
656                                         break;
657                                 case 's':
658                                         while (*s == ' ' || *s == '\t')
659                                                 s++;
660                                         if (*s++ != '"') //error, expected string
661                                                 goto fail;
662                                         snext = s;
663
664                                         while (snext[0] && !(snext[-1] != '\\' && snext[0] == '"'))
665                                                 snext++;
666                                         *snext++ = 0;
667
668                                         bufpos += PADDING(bufpos, std::string *);
669
670                                         str = new std::string(s);
671                                         pos = 0;
672                                         while ((pos = str->find("\\\"", pos)) != std::string::npos)
673                                                 str->erase(pos, 1);
674
675                                         if ((bufpos - (char *)buf) + sizeof(std::string *) <= len)
676                                                 *(std::string **)bufpos = str;
677                                         bufpos += sizeof(std::string *);
678                                         strs_alloced.push_back(str);
679
680                                         s = *snext ? snext + 1 : NULL;
681                                         break;
682                                 case 'v':
683                                         while (*s == ' ' || *s == '\t')
684                                                 s++;
685                                         if (*s++ != '(') //error, expected vector
686                                                 goto fail;
687
688                                         if (width == 2) {
689                                                 bufpos += PADDING(bufpos, v2f);
690
691                                                 if ((bufpos - (char *)buf) + sizeof(v2f) <= len) {
692                                                 v2f *v = (v2f *)bufpos;
693                                                         v->X = strtof(s, &s);
694                                                         s++;
695                                                         v->Y = strtof(s, &s);
696                                                 }
697
698                                                 bufpos += sizeof(v2f);
699                                         } else if (width == 3) {
700                                                 bufpos += PADDING(bufpos, v3f);
701                                                 if ((bufpos - (char *)buf) + sizeof(v3f) <= len) {
702                                                         v3f *v = (v3f *)bufpos;
703                                                         v->X = strtof(s, &s);
704                                                         s++;
705                                                         v->Y = strtof(s, &s);
706                                                         s++;
707                                                         v->Z = strtof(s, &s);
708                                                 }
709
710                                                 bufpos += sizeof(v3f);
711                                         }
712                                         s = strchr(s, ',');
713                                         break;
714                                 default: //error, invalid format specifier
715                                         goto fail;
716                         }
717
718                         if (s && *s == ',')
719                                 s++;
720
721                         if ((size_t)(bufpos - (char *)buf) > len) //error, buffer too small
722                                 goto fail;
723                 }
724
725                 if (f && *f) { //error, mismatched number of fields and values
726 fail:
727                         for (unsigned int i = 0; i != strs_alloced.size(); i++)
728                                 delete strs_alloced[i];
729                         delete buf;
730                         //delete[] buf;
731                         buf = NULL;
732                 }
733
734                 return buf;
735         }
736
737         bool setStruct(std::string name, std::string format, void *value)
738         {
739                 char sbuf[2048];
740                 int sbuflen = sizeof(sbuf) - 1;
741                 sbuf[sbuflen] = 0;
742                 std::string str;
743                 int pos = 0;
744                 size_t fpos;
745                 char *f;
746
747                 char *bufpos = (char *)value;
748                 char *fmtpos, *fmt = &format[0];
749                 while ((f = strtok_r(fmt, ",", &fmtpos))) {
750                         fmt = NULL;
751                         bool is_unsigned = false;
752                         int width = 0, nprinted = 0;
753                         char valtype = *f;
754
755                         width = (int)strtol(f + 1, &f, 10);
756                         if (width && valtype == 's')
757                                 valtype = 'i';
758
759                         switch (valtype) {
760                                 case 'u':
761                                         is_unsigned = true;
762                                         /* FALLTHROUGH */
763                                 case 'i':
764                                         if (width == 16) {
765                                                 bufpos += PADDING(bufpos, u16);
766                                                 nprinted = snprintf(sbuf + pos, sbuflen,
767                                                                         is_unsigned ? "%u, " : "%d, ",
768                                                                         *((u16 *)bufpos));
769                                                 bufpos += sizeof(u16);
770                                         } else if (width == 32) {
771                                                 bufpos += PADDING(bufpos, u32);
772                                                 nprinted = snprintf(sbuf + pos, sbuflen,
773                                                                         is_unsigned ? "%u, " : "%d, ",
774                                                                         *((u32 *)bufpos));
775                                                 bufpos += sizeof(u32);
776                                         } else if (width == 64) {
777                                                 bufpos += PADDING(bufpos, u64);
778                                                 nprinted = snprintf(sbuf + pos, sbuflen,
779                                                                         is_unsigned ? "%llu, " : "%lli, ",
780                                                                         (unsigned long long)*((u64 *)bufpos));
781                                                 bufpos += sizeof(u64);
782                                         }
783                                         break;
784                                 case 'b':
785                                         bufpos += PADDING(bufpos, bool);
786                                         nprinted = snprintf(sbuf + pos, sbuflen, "%s, ",
787                                                                                 *((bool *)bufpos) ? "true" : "false");
788                                         bufpos += sizeof(bool);
789                                         break;
790                                 case 'f':
791                                         bufpos += PADDING(bufpos, float);
792                                         nprinted = snprintf(sbuf + pos, sbuflen, "%f, ",
793                                                                                 *((float *)bufpos));
794                                         bufpos += sizeof(float);
795                                         break;
796                                 case 's':
797                                         bufpos += PADDING(bufpos, std::string *);
798                                         str = **((std::string **)bufpos);
799
800                                         fpos = 0;
801                                         while ((fpos = str.find('"', fpos)) != std::string::npos) {
802                                                 str.insert(fpos, 1, '\\');
803                                                 fpos += 2;
804                                         }
805
806                                         nprinted = snprintf(sbuf + pos, sbuflen, "\"%s\", ",
807                                                                                 (*((std::string **)bufpos))->c_str());
808                                         bufpos += sizeof(std::string *);
809                                         break;
810                                 case 'v':
811                                         if (width == 2) {
812                                                 bufpos += PADDING(bufpos, v2f);
813                                                 v2f *v = (v2f *)bufpos;
814                                                 nprinted = snprintf(sbuf + pos, sbuflen,
815                                                                                         "(%f, %f), ", v->X, v->Y);
816                                                 bufpos += sizeof(v2f);
817                                         } else {
818                                                 bufpos += PADDING(bufpos, v3f);
819                                                 v3f *v = (v3f *)bufpos;
820                                                 nprinted = snprintf(sbuf + pos, sbuflen,
821                                                                                         "(%f, %f, %f), ", v->X, v->Y, v->Z);
822                                                 bufpos += sizeof(v3f);
823                                         }
824                                         break;
825                                 default:
826                                         return false;
827                         }
828                         if (nprinted < 0) //error, buffer too small
829                                 return false;
830                         pos     += nprinted;
831                         sbuflen -= nprinted;
832                 }
833
834                 if (pos >= 2)
835                         sbuf[pos - 2] = 0;
836
837                 set(name, std::string(sbuf));
838                 return true;
839         }
840         
841         void setFlagStr(std::string name, u32 flags, FlagDesc *flagdesc)
842         {
843                 set(name, writeFlagString(flags, flagdesc));
844         }
845
846         void setBool(std::string name, bool value)
847         {
848                 if(value)
849                         set(name, "true");
850                 else
851                         set(name, "false");
852         }
853
854         void setFloat(std::string name, float value)
855         {
856                 set(name, ftos(value));
857         }
858
859         void setV3F(std::string name, v3f value)
860         {
861                 std::ostringstream os;
862                 os<<"("<<value.X<<","<<value.Y<<","<<value.Z<<")";
863                 set(name, os.str());
864         }
865
866         void setV2F(std::string name, v2f value)
867         {
868                 std::ostringstream os;
869                 os<<"("<<value.X<<","<<value.Y<<")";
870                 set(name, os.str());
871         }
872
873         void setS16(std::string name, s16 value)
874         {
875                 set(name, itos(value));
876         }
877
878         void setS32(std::string name, s32 value)
879         {
880                 set(name, itos(value));
881         }
882
883         void setU64(std::string name, u64 value)
884         {
885                 std::ostringstream os;
886                 os<<value;
887                 set(name, os.str());
888         }
889
890         void clear()
891         {
892                 JMutexAutoLock lock(m_mutex);
893
894                 m_settings.clear();
895                 m_defaults.clear();
896         }
897
898         void updateValue(Settings &other, const std::string &name)
899         {
900                 JMutexAutoLock lock(m_mutex);
901
902                 if(&other == this)
903                         return;
904
905                 try{
906                         std::string val = other.get(name);
907                         m_settings[name] = val;
908                 } catch(SettingNotFoundException &e){
909                 }
910
911                 return;
912         }
913
914         void update(Settings &other)
915         {
916                 JMutexAutoLock lock(m_mutex);
917                 JMutexAutoLock lock2(other.m_mutex);
918
919                 if(&other == this)
920                         return;
921
922                 for(core::map<std::string, std::string>::Iterator
923                                 i = other.m_settings.getIterator();
924                                 i.atEnd() == false; i++)
925                 {
926                         m_settings[i.getNode()->getKey()] = i.getNode()->getValue();
927                 }
928
929                 for(core::map<std::string, std::string>::Iterator
930                                 i = other.m_defaults.getIterator();
931                                 i.atEnd() == false; i++)
932                 {
933                         m_defaults[i.getNode()->getKey()] = i.getNode()->getValue();
934                 }
935
936                 return;
937         }
938
939         Settings & operator+=(Settings &other)
940         {
941                 JMutexAutoLock lock(m_mutex);
942                 JMutexAutoLock lock2(other.m_mutex);
943
944                 if(&other == this)
945                         return *this;
946
947                 for(core::map<std::string, std::string>::Iterator
948                                 i = other.m_settings.getIterator();
949                                 i.atEnd() == false; i++)
950                 {
951                         m_settings.insert(i.getNode()->getKey(),
952                                         i.getNode()->getValue());
953                 }
954
955                 for(core::map<std::string, std::string>::Iterator
956                                 i = other.m_defaults.getIterator();
957                                 i.atEnd() == false; i++)
958                 {
959                         m_defaults.insert(i.getNode()->getKey(),
960                                         i.getNode()->getValue());
961                 }
962
963                 return *this;
964
965         }
966
967         Settings & operator=(Settings &other)
968         {
969                 JMutexAutoLock lock(m_mutex);
970                 JMutexAutoLock lock2(other.m_mutex);
971
972                 if(&other == this)
973                         return *this;
974
975                 clear();
976                 (*this) += other;
977
978                 return *this;
979         }
980
981 private:
982         core::map<std::string, std::string> m_settings;
983         core::map<std::string, std::string> m_defaults;
984         // All methods that access m_settings/m_defaults directly should lock this.
985         JMutex m_mutex;
986 };
987
988 #endif
989