]> git.lizzy.rs Git - dragonfireclient.git/blob - src/settings.cpp
Trigger on_rightclick regardless on the formspec meta field
[dragonfireclient.git] / src / settings.cpp
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 #include "settings.h"
21 #include "irrlichttypes_bloated.h"
22 #include "exceptions.h"
23 #include "threading/mutex_auto_lock.h"
24 #include "util/strfnd.h"
25 #include <iostream>
26 #include <fstream>
27 #include <sstream>
28 #include "debug.h"
29 #include "log.h"
30 #include "util/serialize.h"
31 #include "filesys.h"
32 #include "noise.h"
33 #include <cctype>
34 #include <algorithm>
35
36 static Settings main_settings;
37 Settings *g_settings = &main_settings;
38 std::string g_settings_path;
39
40 Settings::~Settings()
41 {
42         clear();
43 }
44
45
46 Settings & Settings::operator += (const Settings &other)
47 {
48         update(other);
49
50         return *this;
51 }
52
53
54 Settings & Settings::operator = (const Settings &other)
55 {
56         if (&other == this)
57                 return *this;
58
59         MutexAutoLock lock(m_mutex);
60         MutexAutoLock lock2(other.m_mutex);
61
62         clearNoLock();
63         updateNoLock(other);
64
65         return *this;
66 }
67
68
69 bool Settings::checkNameValid(const std::string &name)
70 {
71         bool valid = name.find_first_of("=\"{}#") == std::string::npos;
72         if (valid) valid = trim(name) == name;
73         if (!valid) {
74                 errorstream << "Invalid setting name \"" << name << "\""
75                         << std::endl;
76                 return false;
77         }
78         return true;
79 }
80
81
82 bool Settings::checkValueValid(const std::string &value)
83 {
84         if (value.substr(0, 3) == "\"\"\"" ||
85                 value.find("\n\"\"\"") != std::string::npos) {
86                 errorstream << "Invalid character sequence '\"\"\"' found in"
87                         " setting value!" << std::endl;
88                 return false;
89         }
90         return true;
91 }
92
93 std::string Settings::getMultiline(std::istream &is, size_t *num_lines)
94 {
95         size_t lines = 1;
96         std::string value;
97         std::string line;
98
99         while (is.good()) {
100                 lines++;
101                 std::getline(is, line);
102                 if (line == "\"\"\"")
103                         break;
104                 value += line;
105                 value.push_back('\n');
106         }
107
108         size_t len = value.size();
109         if (len)
110                 value.erase(len - 1);
111
112         if (num_lines)
113                 *num_lines = lines;
114
115         return value;
116 }
117
118
119 bool Settings::readConfigFile(const char *filename)
120 {
121         std::ifstream is(filename);
122         if (!is.good())
123                 return false;
124
125         return parseConfigLines(is, "");
126 }
127
128
129 bool Settings::parseConfigLines(std::istream &is, const std::string &end)
130 {
131         MutexAutoLock lock(m_mutex);
132
133         std::string line, name, value;
134
135         while (is.good()) {
136                 std::getline(is, line);
137                 SettingsParseEvent event = parseConfigObject(line, end, name, value);
138
139                 switch (event) {
140                 case SPE_NONE:
141                 case SPE_INVALID:
142                 case SPE_COMMENT:
143                         break;
144                 case SPE_KVPAIR:
145                         m_settings[name] = SettingsEntry(value);
146                         break;
147                 case SPE_END:
148                         return true;
149                 case SPE_GROUP: {
150                         Settings *group = new Settings;
151                         if (!group->parseConfigLines(is, "}")) {
152                                 delete group;
153                                 return false;
154                         }
155                         m_settings[name] = SettingsEntry(group);
156                         break;
157                 }
158                 case SPE_MULTILINE:
159                         m_settings[name] = SettingsEntry(getMultiline(is));
160                         break;
161                 }
162         }
163
164         return end.empty();
165 }
166
167
168 void Settings::writeLines(std::ostream &os, u32 tab_depth) const
169 {
170         MutexAutoLock lock(m_mutex);
171
172         for (SettingEntries::const_iterator it = m_settings.begin();
173                         it != m_settings.end(); ++it)
174                 printEntry(os, it->first, it->second, tab_depth);
175 }
176
177
178 void Settings::printEntry(std::ostream &os, const std::string &name,
179         const SettingsEntry &entry, u32 tab_depth)
180 {
181         for (u32 i = 0; i != tab_depth; i++)
182                 os << "\t";
183
184         if (entry.is_group) {
185                 os << name << " = {\n";
186
187                 entry.group->writeLines(os, tab_depth + 1);
188
189                 for (u32 i = 0; i != tab_depth; i++)
190                         os << "\t";
191                 os << "}\n";
192         } else {
193                 os << name << " = ";
194
195                 if (entry.value.find('\n') != std::string::npos)
196                         os << "\"\"\"\n" << entry.value << "\n\"\"\"\n";
197                 else
198                         os << entry.value << "\n";
199         }
200 }
201
202
203 bool Settings::updateConfigObject(std::istream &is, std::ostream &os,
204         const std::string &end, u32 tab_depth)
205 {
206         SettingEntries::const_iterator it;
207         std::set<std::string> present_entries;
208         std::string line, name, value;
209         bool was_modified = false;
210         bool end_found = false;
211
212         // Add any settings that exist in the config file with the current value
213         // in the object if existing
214         while (is.good() && !end_found) {
215                 std::getline(is, line);
216                 SettingsParseEvent event = parseConfigObject(line, end, name, value);
217
218                 switch (event) {
219                 case SPE_END:
220                         os << line << (is.eof() ? "" : "\n");
221                         end_found = true;
222                         break;
223                 case SPE_MULTILINE:
224                         value = getMultiline(is);
225                         /* FALLTHROUGH */
226                 case SPE_KVPAIR:
227                         it = m_settings.find(name);
228                         if (it != m_settings.end() &&
229                                 (it->second.is_group || it->second.value != value)) {
230                                 printEntry(os, name, it->second, tab_depth);
231                                 was_modified = true;
232                         } else {
233                                 os << line << "\n";
234                                 if (event == SPE_MULTILINE)
235                                         os << value << "\n\"\"\"\n";
236                         }
237                         present_entries.insert(name);
238                         break;
239                 case SPE_GROUP:
240                         it = m_settings.find(name);
241                         if (it != m_settings.end() && it->second.is_group) {
242                                 os << line << "\n";
243                                 sanity_check(it->second.group != NULL);
244                                 was_modified |= it->second.group->updateConfigObject(is, os,
245                                         "}", tab_depth + 1);
246                         } else {
247                                 printEntry(os, name, it->second, tab_depth);
248                                 was_modified = true;
249                         }
250                         present_entries.insert(name);
251                         break;
252                 default:
253                         os << line << (is.eof() ? "" : "\n");
254                         break;
255                 }
256         }
257
258         // Add any settings in the object that don't exist in the config file yet
259         for (it = m_settings.begin(); it != m_settings.end(); ++it) {
260                 if (present_entries.find(it->first) != present_entries.end())
261                         continue;
262
263                 printEntry(os, it->first, it->second, tab_depth);
264                 was_modified = true;
265         }
266
267         return was_modified;
268 }
269
270
271 bool Settings::updateConfigFile(const char *filename)
272 {
273         MutexAutoLock lock(m_mutex);
274
275         std::ifstream is(filename);
276         std::ostringstream os(std::ios_base::binary);
277
278         bool was_modified = updateConfigObject(is, os, "");
279         is.close();
280
281         if (!was_modified)
282                 return true;
283
284         if (!fs::safeWriteToFile(filename, os.str())) {
285                 errorstream << "Error writing configuration file: \""
286                         << filename << "\"" << std::endl;
287                 return false;
288         }
289
290         return true;
291 }
292
293
294 bool Settings::parseCommandLine(int argc, char *argv[],
295                 std::map<std::string, ValueSpec> &allowed_options)
296 {
297         int nonopt_index = 0;
298         for (int i = 1; i < argc; i++) {
299                 std::string arg_name = argv[i];
300                 if (arg_name.substr(0, 2) != "--") {
301                         // If option doesn't start with -, read it in as nonoptX
302                         if (arg_name[0] != '-'){
303                                 std::string name = "nonopt";
304                                 name += itos(nonopt_index);
305                                 set(name, arg_name);
306                                 nonopt_index++;
307                                 continue;
308                         }
309                         errorstream << "Invalid command-line parameter \""
310                                         << arg_name << "\": --<option> expected." << std::endl;
311                         return false;
312                 }
313
314                 std::string name = arg_name.substr(2);
315
316                 std::map<std::string, ValueSpec>::iterator n;
317                 n = allowed_options.find(name);
318                 if (n == allowed_options.end()) {
319                         errorstream << "Unknown command-line parameter \""
320                                         << arg_name << "\"" << std::endl;
321                         return false;
322                 }
323
324                 ValueType type = n->second.type;
325
326                 std::string value = "";
327
328                 if (type == VALUETYPE_FLAG) {
329                         value = "true";
330                 } else {
331                         if ((i + 1) >= argc) {
332                                 errorstream << "Invalid command-line parameter \""
333                                                 << name << "\": missing value" << std::endl;
334                                 return false;
335                         }
336                         value = argv[++i];
337                 }
338
339                 set(name, value);
340         }
341
342         return true;
343 }
344
345
346
347 /***********
348  * Getters *
349  ***********/
350
351
352 const SettingsEntry &Settings::getEntry(const std::string &name) const
353 {
354         MutexAutoLock lock(m_mutex);
355
356         SettingEntries::const_iterator n;
357         if ((n = m_settings.find(name)) == m_settings.end()) {
358                 if ((n = m_defaults.find(name)) == m_defaults.end())
359                         throw SettingNotFoundException("Setting [" + name + "] not found.");
360         }
361         return n->second;
362 }
363
364
365 Settings *Settings::getGroup(const std::string &name) const
366 {
367         const SettingsEntry &entry = getEntry(name);
368         if (!entry.is_group)
369                 throw SettingNotFoundException("Setting [" + name + "] is not a group.");
370         return entry.group;
371 }
372
373
374 const std::string &Settings::get(const std::string &name) const
375 {
376         const SettingsEntry &entry = getEntry(name);
377         if (entry.is_group)
378                 throw SettingNotFoundException("Setting [" + name + "] is a group.");
379         return entry.value;
380 }
381
382
383 bool Settings::getBool(const std::string &name) const
384 {
385         return is_yes(get(name));
386 }
387
388
389 u16 Settings::getU16(const std::string &name) const
390 {
391         return stoi(get(name), 0, 65535);
392 }
393
394
395 s16 Settings::getS16(const std::string &name) const
396 {
397         return stoi(get(name), -32768, 32767);
398 }
399
400
401 u32 Settings::getU32(const std::string &name) const
402 {
403         return (u32) stoi(get(name));
404 }
405
406 s32 Settings::getS32(const std::string &name) const
407 {
408         return stoi(get(name));
409 }
410
411
412 float Settings::getFloat(const std::string &name) const
413 {
414         return stof(get(name));
415 }
416
417
418 u64 Settings::getU64(const std::string &name) const
419 {
420         u64 value = 0;
421         std::string s = get(name);
422         std::istringstream ss(s);
423         ss >> value;
424         return value;
425 }
426
427
428 v2f Settings::getV2F(const std::string &name) const
429 {
430         v2f value;
431         Strfnd f(get(name));
432         f.next("(");
433         value.X = stof(f.next(","));
434         value.Y = stof(f.next(")"));
435         return value;
436 }
437
438
439 v3f Settings::getV3F(const std::string &name) const
440 {
441         v3f value;
442         Strfnd f(get(name));
443         f.next("(");
444         value.X = stof(f.next(","));
445         value.Y = stof(f.next(","));
446         value.Z = stof(f.next(")"));
447         return value;
448 }
449
450
451 u32 Settings::getFlagStr(const std::string &name, const FlagDesc *flagdesc,
452         u32 *flagmask) const
453 {
454         std::string val = get(name);
455         return std::isdigit(val[0])
456                 ? stoi(val)
457                 : readFlagString(val, flagdesc, flagmask);
458 }
459
460
461 // N.B. if getStruct() is used to read a non-POD aggregate type,
462 // the behavior is undefined.
463 bool Settings::getStruct(const std::string &name, const std::string &format,
464         void *out, size_t olen) const
465 {
466         std::string valstr;
467
468         try {
469                 valstr = get(name);
470         } catch (SettingNotFoundException &e) {
471                 return false;
472         }
473
474         if (!deSerializeStringToStruct(valstr, format, out, olen))
475                 return false;
476
477         return true;
478 }
479
480
481 bool Settings::getNoiseParams(const std::string &name, NoiseParams &np) const
482 {
483         return getNoiseParamsFromGroup(name, np) || getNoiseParamsFromValue(name, np);
484 }
485
486
487 bool Settings::getNoiseParamsFromValue(const std::string &name,
488         NoiseParams &np) const
489 {
490         std::string value;
491
492         if (!getNoEx(name, value))
493                 return false;
494
495         Strfnd f(value);
496
497         np.offset   = stof(f.next(","));
498         np.scale    = stof(f.next(","));
499         f.next("(");
500         np.spread.X = stof(f.next(","));
501         np.spread.Y = stof(f.next(","));
502         np.spread.Z = stof(f.next(")"));
503         f.next(",");
504         np.seed     = stoi(f.next(","));
505         np.octaves  = stoi(f.next(","));
506         np.persist  = stof(f.next(","));
507
508         std::string optional_params = f.next("");
509         if (optional_params != "")
510                 np.lacunarity = stof(optional_params);
511
512         return true;
513 }
514
515
516 bool Settings::getNoiseParamsFromGroup(const std::string &name,
517         NoiseParams &np) const
518 {
519         Settings *group = NULL;
520
521         if (!getGroupNoEx(name, group))
522                 return false;
523
524         group->getFloatNoEx("offset",      np.offset);
525         group->getFloatNoEx("scale",       np.scale);
526         group->getV3FNoEx("spread",        np.spread);
527         group->getS32NoEx("seed",          np.seed);
528         group->getU16NoEx("octaves",       np.octaves);
529         group->getFloatNoEx("persistence", np.persist);
530         group->getFloatNoEx("lacunarity",  np.lacunarity);
531
532         np.flags = 0;
533         if (!group->getFlagStrNoEx("flags", np.flags, flagdesc_noiseparams))
534                 np.flags = NOISE_FLAG_DEFAULTS;
535
536         return true;
537 }
538
539
540 bool Settings::exists(const std::string &name) const
541 {
542         MutexAutoLock lock(m_mutex);
543
544         return (m_settings.find(name) != m_settings.end() ||
545                 m_defaults.find(name) != m_defaults.end());
546 }
547
548
549 std::vector<std::string> Settings::getNames() const
550 {
551         std::vector<std::string> names;
552         for (SettingEntries::const_iterator i = m_settings.begin();
553                         i != m_settings.end(); ++i) {
554                 names.push_back(i->first);
555         }
556         return names;
557 }
558
559
560
561 /***************************************
562  * Getters that don't throw exceptions *
563  ***************************************/
564
565 bool Settings::getEntryNoEx(const std::string &name, SettingsEntry &val) const
566 {
567         try {
568                 val = getEntry(name);
569                 return true;
570         } catch (SettingNotFoundException &e) {
571                 return false;
572         }
573 }
574
575
576 bool Settings::getGroupNoEx(const std::string &name, Settings *&val) const
577 {
578         try {
579                 val = getGroup(name);
580                 return true;
581         } catch (SettingNotFoundException &e) {
582                 return false;
583         }
584 }
585
586
587 bool Settings::getNoEx(const std::string &name, std::string &val) const
588 {
589         try {
590                 val = get(name);
591                 return true;
592         } catch (SettingNotFoundException &e) {
593                 return false;
594         }
595 }
596
597
598 bool Settings::getFlag(const std::string &name) const
599 {
600         try {
601                 return getBool(name);
602         } catch(SettingNotFoundException &e) {
603                 return false;
604         }
605 }
606
607
608 bool Settings::getFloatNoEx(const std::string &name, float &val) const
609 {
610         try {
611                 val = getFloat(name);
612                 return true;
613         } catch (SettingNotFoundException &e) {
614                 return false;
615         }
616 }
617
618
619 bool Settings::getU16NoEx(const std::string &name, u16 &val) const
620 {
621         try {
622                 val = getU16(name);
623                 return true;
624         } catch (SettingNotFoundException &e) {
625                 return false;
626         }
627 }
628
629
630 bool Settings::getS16NoEx(const std::string &name, s16 &val) const
631 {
632         try {
633                 val = getS16(name);
634                 return true;
635         } catch (SettingNotFoundException &e) {
636                 return false;
637         }
638 }
639
640
641 bool Settings::getS32NoEx(const std::string &name, s32 &val) const
642 {
643         try {
644                 val = getS32(name);
645                 return true;
646         } catch (SettingNotFoundException &e) {
647                 return false;
648         }
649 }
650
651
652 bool Settings::getU64NoEx(const std::string &name, u64 &val) const
653 {
654         try {
655                 val = getU64(name);
656                 return true;
657         } catch (SettingNotFoundException &e) {
658                 return false;
659         }
660 }
661
662
663 bool Settings::getV2FNoEx(const std::string &name, v2f &val) const
664 {
665         try {
666                 val = getV2F(name);
667                 return true;
668         } catch (SettingNotFoundException &e) {
669                 return false;
670         }
671 }
672
673
674 bool Settings::getV3FNoEx(const std::string &name, v3f &val) const
675 {
676         try {
677                 val = getV3F(name);
678                 return true;
679         } catch (SettingNotFoundException &e) {
680                 return false;
681         }
682 }
683
684
685 // N.B. getFlagStrNoEx() does not set val, but merely modifies it.  Thus,
686 // val must be initialized before using getFlagStrNoEx().  The intention of
687 // this is to simplify modifying a flags field from a default value.
688 bool Settings::getFlagStrNoEx(const std::string &name, u32 &val,
689         FlagDesc *flagdesc) const
690 {
691         try {
692                 u32 flags, flagmask;
693
694                 flags = getFlagStr(name, flagdesc, &flagmask);
695
696                 val &= ~flagmask;
697                 val |=  flags;
698
699                 return true;
700         } catch (SettingNotFoundException &e) {
701                 return false;
702         }
703 }
704
705
706 /***********
707  * Setters *
708  ***********/
709
710 bool Settings::setEntry(const std::string &name, const void *data,
711         bool set_group, bool set_default)
712 {
713         Settings *old_group = NULL;
714
715         if (!checkNameValid(name))
716                 return false;
717         if (!set_group && !checkValueValid(*(const std::string *)data))
718                 return false;
719
720         {
721                 MutexAutoLock lock(m_mutex);
722
723                 SettingsEntry &entry = set_default ? m_defaults[name] : m_settings[name];
724                 old_group = entry.group;
725
726                 entry.value    = set_group ? "" : *(const std::string *)data;
727                 entry.group    = set_group ? *(Settings **)data : NULL;
728                 entry.is_group = set_group;
729         }
730
731         delete old_group;
732
733         return true;
734 }
735
736
737 bool Settings::set(const std::string &name, const std::string &value)
738 {
739         if (!setEntry(name, &value, false, false))
740                 return false;
741
742         doCallbacks(name);
743         return true;
744 }
745
746
747 bool Settings::setDefault(const std::string &name, const std::string &value)
748 {
749         return setEntry(name, &value, false, true);
750 }
751
752
753 bool Settings::setGroup(const std::string &name, Settings *group)
754 {
755         return setEntry(name, &group, true, false);
756 }
757
758
759 bool Settings::setGroupDefault(const std::string &name, Settings *group)
760 {
761         return setEntry(name, &group, true, true);
762 }
763
764
765 bool Settings::setBool(const std::string &name, bool value)
766 {
767         return set(name, value ? "true" : "false");
768 }
769
770
771 bool Settings::setS16(const std::string &name, s16 value)
772 {
773         return set(name, itos(value));
774 }
775
776
777 bool Settings::setU16(const std::string &name, u16 value)
778 {
779         return set(name, itos(value));
780 }
781
782
783 bool Settings::setS32(const std::string &name, s32 value)
784 {
785         return set(name, itos(value));
786 }
787
788
789 bool Settings::setU64(const std::string &name, u64 value)
790 {
791         std::ostringstream os;
792         os << value;
793         return set(name, os.str());
794 }
795
796
797 bool Settings::setFloat(const std::string &name, float value)
798 {
799         return set(name, ftos(value));
800 }
801
802
803 bool Settings::setV2F(const std::string &name, v2f value)
804 {
805         std::ostringstream os;
806         os << "(" << value.X << "," << value.Y << ")";
807         return set(name, os.str());
808 }
809
810
811 bool Settings::setV3F(const std::string &name, v3f value)
812 {
813         std::ostringstream os;
814         os << "(" << value.X << "," << value.Y << "," << value.Z << ")";
815         return set(name, os.str());
816 }
817
818
819 bool Settings::setFlagStr(const std::string &name, u32 flags,
820         const FlagDesc *flagdesc, u32 flagmask)
821 {
822         return set(name, writeFlagString(flags, flagdesc, flagmask));
823 }
824
825
826 bool Settings::setStruct(const std::string &name, const std::string &format,
827         void *value)
828 {
829         std::string structstr;
830         if (!serializeStructToString(&structstr, format, value))
831                 return false;
832
833         return set(name, structstr);
834 }
835
836
837 bool Settings::setNoiseParams(const std::string &name,
838         const NoiseParams &np, bool set_default)
839 {
840         Settings *group = new Settings;
841
842         group->setFloat("offset",      np.offset);
843         group->setFloat("scale",       np.scale);
844         group->setV3F("spread",        np.spread);
845         group->setS32("seed",          np.seed);
846         group->setU16("octaves",       np.octaves);
847         group->setFloat("persistence", np.persist);
848         group->setFloat("lacunarity",  np.lacunarity);
849         group->setFlagStr("flags",     np.flags, flagdesc_noiseparams, np.flags);
850
851         return setEntry(name, &group, true, set_default);
852 }
853
854
855 bool Settings::remove(const std::string &name)
856 {
857         MutexAutoLock lock(m_mutex);
858
859         SettingEntries::iterator it = m_settings.find(name);
860         if (it != m_settings.end()) {
861                 delete it->second.group;
862                 m_settings.erase(it);
863                 return true;
864         } else {
865                 return false;
866         }
867 }
868
869
870 void Settings::clear()
871 {
872         MutexAutoLock lock(m_mutex);
873         clearNoLock();
874 }
875
876 void Settings::clearDefaults()
877 {
878         MutexAutoLock lock(m_mutex);
879         clearDefaultsNoLock();
880 }
881
882 void Settings::updateValue(const Settings &other, const std::string &name)
883 {
884         if (&other == this)
885                 return;
886
887         MutexAutoLock lock(m_mutex);
888
889         try {
890                 std::string val = other.get(name);
891                 m_settings[name] = val;
892         } catch (SettingNotFoundException &e) {
893         }
894 }
895
896
897 void Settings::update(const Settings &other)
898 {
899         if (&other == this)
900                 return;
901
902         MutexAutoLock lock(m_mutex);
903         MutexAutoLock lock2(other.m_mutex);
904
905         updateNoLock(other);
906 }
907
908
909 SettingsParseEvent Settings::parseConfigObject(const std::string &line,
910         const std::string &end, std::string &name, std::string &value)
911 {
912         std::string trimmed_line = trim(line);
913
914         if (trimmed_line.empty())
915                 return SPE_NONE;
916         if (trimmed_line[0] == '#')
917                 return SPE_COMMENT;
918         if (trimmed_line == end)
919                 return SPE_END;
920
921         size_t pos = trimmed_line.find('=');
922         if (pos == std::string::npos)
923                 return SPE_INVALID;
924
925         name  = trim(trimmed_line.substr(0, pos));
926         value = trim(trimmed_line.substr(pos + 1));
927
928         if (value == "{")
929                 return SPE_GROUP;
930         if (value == "\"\"\"")
931                 return SPE_MULTILINE;
932
933         return SPE_KVPAIR;
934 }
935
936
937 void Settings::updateNoLock(const Settings &other)
938 {
939         m_settings.insert(other.m_settings.begin(), other.m_settings.end());
940         m_defaults.insert(other.m_defaults.begin(), other.m_defaults.end());
941 }
942
943
944 void Settings::clearNoLock()
945 {
946
947         for (SettingEntries::const_iterator it = m_settings.begin();
948                         it != m_settings.end(); ++it)
949                 delete it->second.group;
950         m_settings.clear();
951
952         clearDefaultsNoLock();
953 }
954
955 void Settings::clearDefaultsNoLock()
956 {
957         for (SettingEntries::const_iterator it = m_defaults.begin();
958                         it != m_defaults.end(); ++it)
959                 delete it->second.group;
960         m_defaults.clear();
961 }
962
963
964 void Settings::registerChangedCallback(const std::string &name,
965         SettingsChangedCallback cbf, void *userdata)
966 {
967         MutexAutoLock lock(m_callback_mutex);
968         m_callbacks[name].push_back(std::make_pair(cbf, userdata));
969 }
970
971 void Settings::deregisterChangedCallback(const std::string &name,
972         SettingsChangedCallback cbf, void *userdata)
973 {
974         MutexAutoLock lock(m_callback_mutex);
975         SettingsCallbackMap::iterator it_cbks = m_callbacks.find(name);
976
977         if (it_cbks != m_callbacks.end()) {
978                 SettingsCallbackList &cbks = it_cbks->second;
979
980                 SettingsCallbackList::iterator position =
981                         std::find(cbks.begin(), cbks.end(), std::make_pair(cbf, userdata));
982
983                 if (position != cbks.end())
984                         cbks.erase(position);
985         }
986 }
987
988 void Settings::doCallbacks(const std::string &name) const
989 {
990         MutexAutoLock lock(m_callback_mutex);
991
992         SettingsCallbackMap::const_iterator it_cbks = m_callbacks.find(name);
993         if (it_cbks != m_callbacks.end()) {
994                 SettingsCallbackList::const_iterator it;
995                 for (it = it_cbks->second.begin(); it != it_cbks->second.end(); ++it)
996                         (it->first)(name, it->second);
997         }
998 }