a4c5060fae431de2f57fe2c1a7cb8d52cd848e8f
[strongswan.git] / src / libstrongswan / settings / settings.c
1 /*
2 * Copyright (C) 2010-2014 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * HSR Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #define _GNU_SOURCE
18 #include <string.h>
19 #include <stdarg.h>
20 #include <stdio.h>
21 #include <errno.h>
22 #include <limits.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <ctype.h>
27
28 #include "settings.h"
29 #include "settings_types.h"
30
31 #include "collections/array.h"
32 #include "collections/hashtable.h"
33 #include "collections/linked_list.h"
34 #include "threading/rwlock.h"
35 #include "utils/debug.h"
36
37 typedef struct private_settings_t private_settings_t;
38
39 /**
40 * Parse functions provided by the generated parser.
41 */
42 bool settings_parser_parse_file(section_t *root, char *name);
43 bool settings_parser_parse_string(section_t *root, char *settings);
44
45 /**
46 * Private data of settings
47 */
48 struct private_settings_t {
49
50 /**
51 * Public interface
52 */
53 settings_t public;
54
55 /**
56 * Top level section
57 */
58 section_t *top;
59
60 /**
61 * Contents of replaced settings (char*)
62 *
63 * FIXME: This is required because the pointer returned by get_str()
64 * is not refcounted. Might cause ever increasing usage stats.
65 */
66 array_t *contents;
67
68 /**
69 * Lock to safely access the settings
70 */
71 rwlock_t *lock;
72 };
73
74 /**
75 * Print a format key, but consume already processed arguments
76 */
77 static bool print_key(char *buf, int len, char *start, char *key, va_list args)
78 {
79 va_list copy;
80 char *pos = start;
81 bool res;
82
83 va_copy(copy, args);
84 while (TRUE)
85 {
86 pos = memchr(pos, '%', key - pos);
87 if (!pos)
88 {
89 break;
90 }
91 pos++;
92 switch (*pos)
93 {
94 case 'd':
95 va_arg(copy, int);
96 break;
97 case 's':
98 va_arg(copy, char*);
99 break;
100 case 'N':
101 va_arg(copy, enum_name_t*);
102 va_arg(copy, int);
103 break;
104 case '%':
105 break;
106 default:
107 DBG1(DBG_CFG, "settings with %%%c not supported!", *pos);
108 break;
109 }
110 pos++;
111 }
112 res = vsnprintf(buf, len, key, copy) < len;
113 va_end(copy);
114 return res;
115 }
116
117 /**
118 * Find a section by a given key, using buffered key, reusable buffer.
119 * If "ensure" is TRUE, the sections are created if they don't exist.
120 */
121 static section_t *find_section_buffered(section_t *section,
122 char *start, char *key, va_list args, char *buf, int len,
123 bool ensure)
124 {
125 char *pos;
126 section_t *found = NULL;
127
128 if (section == NULL)
129 {
130 return NULL;
131 }
132 pos = strchr(key, '.');
133 if (pos)
134 {
135 *pos = '\0';
136 pos++;
137 }
138 if (!print_key(buf, len, start, key, args))
139 {
140 return NULL;
141 }
142 if (!strlen(buf))
143 {
144 found = section;
145 }
146 else if (array_bsearch(section->sections, buf, settings_section_find,
147 &found) == -1)
148 {
149 if (ensure)
150 {
151 found = settings_section_create(strdup(buf));
152 settings_section_add(section, found, NULL);
153 }
154 }
155 if (found && pos)
156 {
157 return find_section_buffered(found, start, pos, args, buf, len, ensure);
158 }
159 return found;
160 }
161
162 /**
163 * Find all sections via a given key considering fallbacks, using buffered key,
164 * reusable buffer.
165 */
166 static void find_sections_buffered(section_t *section, char *start, char *key,
167 va_list args, char *buf, int len, array_t **sections)
168 {
169 section_t *found = NULL, *fallback;
170 char *pos;
171 int i;
172
173 if (!section)
174 {
175 return;
176 }
177 pos = strchr(key, '.');
178 if (pos)
179 {
180 *pos = '\0';
181 }
182 if (!print_key(buf, len, start, key, args))
183 {
184 return;
185 }
186 if (pos)
187 { /* restore so we can follow fallbacks */
188 *pos = '.';
189 }
190 if (!strlen(buf))
191 {
192 found = section;
193 }
194 else
195 {
196 array_bsearch(section->sections, buf, settings_section_find, &found);
197 }
198 if (found)
199 {
200 if (pos)
201 {
202 find_sections_buffered(found, start, pos+1, args, buf, len,
203 sections);
204 }
205 else
206 {
207 array_insert_create(sections, ARRAY_TAIL, found);
208 for (i = 0; i < array_count(found->fallbacks); i++)
209 {
210 array_get(found->fallbacks, i, &fallback);
211 array_insert_create(sections, ARRAY_TAIL, fallback);
212 }
213 }
214 }
215 if (section->fallbacks)
216 {
217 for (i = 0; i < array_count(section->fallbacks); i++)
218 {
219 array_get(section->fallbacks, i, &fallback);
220 find_sections_buffered(fallback, start, key, args, buf, len,
221 sections);
222 }
223 }
224 }
225
226 /**
227 * Ensure that the section with the given key exists (thread-safe).
228 */
229 static section_t *ensure_section(private_settings_t *this, section_t *section,
230 const char *key, va_list args)
231 {
232 char buf[128], keybuf[512];
233 section_t *found;
234
235 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
236 {
237 return NULL;
238 }
239 /* we might have to change the tree */
240 this->lock->write_lock(this->lock);
241 found = find_section_buffered(section, keybuf, keybuf, args, buf,
242 sizeof(buf), TRUE);
243 this->lock->unlock(this->lock);
244 return found;
245 }
246
247 /**
248 * Find a section by a given key with its fallbacks (not thread-safe!).
249 * Sections are returned in depth-first order (array is allocated). NULL is
250 * returned if no sections are found.
251 */
252 static array_t *find_sections(private_settings_t *this, section_t *section,
253 char *key, va_list args)
254 {
255 char buf[128], keybuf[512];
256 array_t *sections = NULL;
257
258 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
259 {
260 return NULL;
261 }
262 find_sections_buffered(section, keybuf, keybuf, args, buf,
263 sizeof(buf), &sections);
264 return sections;
265 }
266
267 /**
268 * Check if the given fallback section already exists
269 */
270 static bool fallback_exists(section_t *section, section_t *fallback)
271 {
272 if (section == fallback)
273 {
274 return TRUE;
275 }
276 else if (section->fallbacks)
277 {
278 section_t *existing;
279 int i;
280
281 for (i = 0; i < array_count(section->fallbacks); i++)
282 {
283 array_get(section->fallbacks, i, &existing);
284 if (existing == fallback)
285 {
286 return TRUE;
287 }
288 }
289 }
290 return FALSE;
291 }
292
293 /**
294 * Ensure that the section with the given key exists and add the given fallback
295 * section (thread-safe).
296 */
297 static void add_fallback_to_section(private_settings_t *this,
298 section_t *section, const char *key, va_list args,
299 section_t *fallback)
300 {
301 char buf[128], keybuf[512];
302 section_t *found;
303
304 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
305 {
306 return;
307 }
308 this->lock->write_lock(this->lock);
309 found = find_section_buffered(section, keybuf, keybuf, args, buf,
310 sizeof(buf), TRUE);
311 if (!fallback_exists(found, fallback))
312 {
313 /* to ensure sections referred to as fallback are not purged, we create
314 * the array there too */
315 if (!fallback->fallbacks)
316 {
317 fallback->fallbacks = array_create(0, 0);
318 }
319 array_insert_create(&found->fallbacks, ARRAY_TAIL, fallback);
320 }
321 this->lock->unlock(this->lock);
322 }
323
324 /**
325 * Find the key/value pair for a key, using buffered key, reusable buffer
326 * If "ensure" is TRUE, the sections (and key/value pair) are created if they
327 * don't exist.
328 * Fallbacks are only considered if "ensure" is FALSE.
329 */
330 static kv_t *find_value_buffered(section_t *section, char *start, char *key,
331 va_list args, char *buf, int len, bool ensure)
332 {
333 int i;
334 char *pos;
335 kv_t *kv = NULL;
336 section_t *found = NULL;
337
338 if (section == NULL)
339 {
340 return NULL;
341 }
342
343 pos = strchr(key, '.');
344 if (pos)
345 {
346 *pos = '\0';
347 if (!print_key(buf, len, start, key, args))
348 {
349 return NULL;
350 }
351 /* restore so we can retry for fallbacks */
352 *pos = '.';
353 if (!strlen(buf))
354 {
355 found = section;
356 }
357 else if (array_bsearch(section->sections, buf, settings_section_find,
358 &found) == -1)
359 {
360 if (ensure)
361 {
362 found = settings_section_create(strdup(buf));
363 settings_section_add(section, found, NULL);
364 }
365 }
366 if (found)
367 {
368 kv = find_value_buffered(found, start, pos+1, args, buf, len,
369 ensure);
370 }
371 if (!kv && !ensure && section->fallbacks)
372 {
373 for (i = 0; !kv && i < array_count(section->fallbacks); i++)
374 {
375 array_get(section->fallbacks, i, &found);
376 kv = find_value_buffered(found, start, key, args, buf, len,
377 ensure);
378 }
379 }
380 }
381 else
382 {
383 if (!print_key(buf, len, start, key, args))
384 {
385 return NULL;
386 }
387 if (array_bsearch(section->kv, buf, settings_kv_find, &kv) == -1)
388 {
389 if (ensure)
390 {
391 kv = settings_kv_create(strdup(buf), NULL);
392 settings_kv_add(section, kv, NULL);
393 }
394 else if (section->fallbacks)
395 {
396 for (i = 0; !kv && i < array_count(section->fallbacks); i++)
397 {
398 array_get(section->fallbacks, i, &found);
399 kv = find_value_buffered(found, start, key, args, buf, len,
400 ensure);
401 }
402 }
403 }
404 }
405 return kv;
406 }
407
408 /**
409 * Find the string value for a key (thread-safe).
410 */
411 static char *find_value(private_settings_t *this, section_t *section,
412 char *key, va_list args)
413 {
414 char buf[128], keybuf[512], *value = NULL;
415 kv_t *kv;
416
417 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
418 {
419 return NULL;
420 }
421 this->lock->read_lock(this->lock);
422 kv = find_value_buffered(section, keybuf, keybuf, args, buf, sizeof(buf),
423 FALSE);
424 if (kv)
425 {
426 value = kv->value;
427 }
428 this->lock->unlock(this->lock);
429 return value;
430 }
431
432 /**
433 * Set a value to a copy of the given string (thread-safe).
434 */
435 static void set_value(private_settings_t *this, section_t *section,
436 char *key, va_list args, char *value)
437 {
438 char buf[128], keybuf[512];
439 kv_t *kv;
440
441 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
442 {
443 return;
444 }
445 this->lock->write_lock(this->lock);
446 kv = find_value_buffered(section, keybuf, keybuf, args, buf, sizeof(buf),
447 TRUE);
448 if (kv)
449 {
450 settings_kv_set(kv, strdupnull(value), this->contents);
451 }
452 this->lock->unlock(this->lock);
453 }
454
455 METHOD(settings_t, get_str, char*,
456 private_settings_t *this, char *key, char *def, ...)
457 {
458 char *value;
459 va_list args;
460
461 va_start(args, def);
462 value = find_value(this, this->top, key, args);
463 va_end(args);
464 if (value)
465 {
466 return value;
467 }
468 return def;
469 }
470
471 /**
472 * Described in header
473 */
474 inline bool settings_value_as_bool(char *value, bool def)
475 {
476 if (value)
477 {
478 if (strcaseeq(value, "1") ||
479 strcaseeq(value, "yes") ||
480 strcaseeq(value, "true") ||
481 strcaseeq(value, "enabled"))
482 {
483 return TRUE;
484 }
485 else if (strcaseeq(value, "0") ||
486 strcaseeq(value, "no") ||
487 strcaseeq(value, "false") ||
488 strcaseeq(value, "disabled"))
489 {
490 return FALSE;
491 }
492 }
493 return def;
494 }
495
496 METHOD(settings_t, get_bool, bool,
497 private_settings_t *this, char *key, int def, ...)
498 {
499 char *value;
500 va_list args;
501
502 /* we can't use bool for def due to this call */
503 va_start(args, def);
504 value = find_value(this, this->top, key, args);
505 va_end(args);
506 return settings_value_as_bool(value, def);
507 }
508
509 /**
510 * Described in header
511 */
512 inline int settings_value_as_int(char *value, int def)
513 {
514 int intval;
515 char *end;
516 int base = 10;
517
518 if (value)
519 {
520 errno = 0;
521 if (value[0] == '0' && value[1] == 'x')
522 { /* manually detect 0x prefix as we want to avoid octal encoding */
523 base = 16;
524 }
525 intval = strtol(value, &end, base);
526 if (errno == 0 && *end == 0 && end != value)
527 {
528 return intval;
529 }
530 }
531 return def;
532 }
533
534 METHOD(settings_t, get_int, int,
535 private_settings_t *this, char *key, int def, ...)
536 {
537 char *value;
538 va_list args;
539
540 va_start(args, def);
541 value = find_value(this, this->top, key, args);
542 va_end(args);
543 return settings_value_as_int(value, def);
544 }
545
546 /**
547 * Described in header
548 */
549 inline uint64_t settings_value_as_uint64(char *value, uint64_t def)
550 {
551 uint64_t intval;
552 char *end;
553 int base = 10;
554
555 if (value)
556 {
557 errno = 0;
558 if (value[0] == '0' && value[1] == 'x')
559 { /* manually detect 0x prefix as we want to avoid octal encoding */
560 base = 16;
561 }
562 intval = strtoull(value, &end, base);
563 if (errno == 0 && *end == 0 && end != value)
564 {
565 return intval;
566 }
567 }
568 return def;
569 }
570
571 /**
572 * Described in header
573 */
574 inline double settings_value_as_double(char *value, double def)
575 {
576 double dval;
577 char *end;
578
579 if (value)
580 {
581 errno = 0;
582 dval = strtod(value, &end);
583 if (errno == 0 && *end == 0 && end != value)
584 {
585 return dval;
586 }
587 }
588 return def;
589 }
590
591 METHOD(settings_t, get_double, double,
592 private_settings_t *this, char *key, double def, ...)
593 {
594 char *value;
595 va_list args;
596
597 va_start(args, def);
598 value = find_value(this, this->top, key, args);
599 va_end(args);
600 return settings_value_as_double(value, def);
601 }
602
603 /**
604 * Described in header
605 */
606 inline uint32_t settings_value_as_time(char *value, uint32_t def)
607 {
608 time_t val;
609
610 if (timespan_from_string(value, NULL, &val))
611 {
612 return val;
613 }
614 return def;
615 }
616
617 METHOD(settings_t, get_time, uint32_t,
618 private_settings_t *this, char *key, uint32_t def, ...)
619 {
620 char *value;
621 va_list args;
622
623 va_start(args, def);
624 value = find_value(this, this->top, key, args);
625 va_end(args);
626 return settings_value_as_time(value, def);
627 }
628
629 METHOD(settings_t, set_str, void,
630 private_settings_t *this, char *key, char *value, ...)
631 {
632 va_list args;
633 va_start(args, value);
634 set_value(this, this->top, key, args, value);
635 va_end(args);
636 }
637
638 METHOD(settings_t, set_bool, void,
639 private_settings_t *this, char *key, int value, ...)
640 {
641 va_list args;
642 /* we can't use bool for value due to this call */
643 va_start(args, value);
644 set_value(this, this->top, key, args, value ? "1" : "0");
645 va_end(args);
646 }
647
648 METHOD(settings_t, set_int, void,
649 private_settings_t *this, char *key, int value, ...)
650 {
651 char val[16];
652 va_list args;
653 va_start(args, value);
654 if (snprintf(val, sizeof(val), "%d", value) < sizeof(val))
655 {
656 set_value(this, this->top, key, args, val);
657 }
658 va_end(args);
659 }
660
661 METHOD(settings_t, set_double, void,
662 private_settings_t *this, char *key, double value, ...)
663 {
664 char val[64];
665 va_list args;
666 va_start(args, value);
667 if (snprintf(val, sizeof(val), "%f", value) < sizeof(val))
668 {
669 set_value(this, this->top, key, args, val);
670 }
671 va_end(args);
672 }
673
674 METHOD(settings_t, set_time, void,
675 private_settings_t *this, char *key, uint32_t value, ...)
676 {
677 char val[16];
678 va_list args;
679 va_start(args, value);
680 if (snprintf(val, sizeof(val), "%u", value) < sizeof(val))
681 {
682 set_value(this, this->top, key, args, val);
683 }
684 va_end(args);
685 }
686
687 METHOD(settings_t, set_default_str, bool,
688 private_settings_t *this, char *key, char *value, ...)
689 {
690 char *old;
691 va_list args;
692
693 va_start(args, value);
694 old = find_value(this, this->top, key, args);
695 va_end(args);
696
697 if (!old)
698 {
699 va_start(args, value);
700 set_value(this, this->top, key, args, value);
701 va_end(args);
702 return TRUE;
703 }
704 return FALSE;
705 }
706
707 /**
708 * Data for enumerators
709 */
710 typedef struct {
711 /** settings_t instance */
712 private_settings_t *settings;
713 /** sections to enumerate */
714 array_t *sections;
715 /** sections/keys that were already enumerated */
716 hashtable_t *seen;
717 } enumerator_data_t;
718
719 CALLBACK(enumerator_destroy, void,
720 enumerator_data_t *this)
721 {
722 this->settings->lock->unlock(this->settings->lock);
723 this->seen->destroy(this->seen);
724 array_destroy(this->sections);
725 free(this);
726 }
727
728 CALLBACK(section_filter, bool,
729 hashtable_t *seen, enumerator_t *orig, va_list args)
730 {
731 section_t *section;
732 char **out;
733
734 VA_ARGS_VGET(args, out);
735
736 while (orig->enumerate(orig, &section))
737 {
738 if (seen->get(seen, section->name))
739 {
740 continue;
741 }
742 *out = section->name;
743 seen->put(seen, section->name, section->name);
744 return TRUE;
745 }
746 return FALSE;
747 }
748
749 /**
750 * Enumerate sections of the given section
751 */
752 static enumerator_t *section_enumerator(section_t *section,
753 enumerator_data_t *data)
754 {
755 return enumerator_create_filter(
756 array_create_enumerator(section->sections_order),
757 section_filter, data->seen, NULL);
758 }
759
760 METHOD(settings_t, create_section_enumerator, enumerator_t*,
761 private_settings_t *this, char *key, ...)
762 {
763 enumerator_data_t *data;
764 array_t *sections;
765 va_list args;
766
767 this->lock->read_lock(this->lock);
768 va_start(args, key);
769 sections = find_sections(this, this->top, key, args);
770 va_end(args);
771
772 if (!sections)
773 {
774 this->lock->unlock(this->lock);
775 return enumerator_create_empty();
776 }
777 INIT(data,
778 .settings = this,
779 .sections = sections,
780 .seen = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
781 );
782 return enumerator_create_nested(array_create_enumerator(sections),
783 (void*)section_enumerator, data, enumerator_destroy);
784 }
785
786 CALLBACK(kv_filter, bool,
787 hashtable_t *seen, enumerator_t *orig, va_list args)
788 {
789 kv_t *kv;
790 char **key, **value;
791
792 VA_ARGS_VGET(args, key, value);
793
794 while (orig->enumerate(orig, &kv))
795 {
796 if (seen->get(seen, kv->key) || !kv->value)
797 {
798 continue;
799 }
800 *key = kv->key;
801 *value = kv->value;
802 seen->put(seen, kv->key, kv->key);
803 return TRUE;
804 }
805 return FALSE;
806 }
807
808 /**
809 * Enumerate key/value pairs of the given section
810 */
811 static enumerator_t *kv_enumerator(section_t *section, enumerator_data_t *data)
812 {
813 return enumerator_create_filter(array_create_enumerator(section->kv_order),
814 kv_filter, data->seen, NULL);
815 }
816
817 METHOD(settings_t, create_key_value_enumerator, enumerator_t*,
818 private_settings_t *this, char *key, ...)
819 {
820 enumerator_data_t *data;
821 array_t *sections;
822 va_list args;
823
824 this->lock->read_lock(this->lock);
825 va_start(args, key);
826 sections = find_sections(this, this->top, key, args);
827 va_end(args);
828
829 if (!sections)
830 {
831 this->lock->unlock(this->lock);
832 return enumerator_create_empty();
833 }
834 INIT(data,
835 .settings = this,
836 .sections = sections,
837 .seen = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
838 );
839 return enumerator_create_nested(array_create_enumerator(sections),
840 (void*)kv_enumerator, data, (void*)enumerator_destroy);
841 }
842
843 METHOD(settings_t, add_fallback, void,
844 private_settings_t *this, const char *key, const char *fallback, ...)
845 {
846 section_t *section;
847 va_list args;
848
849 /* find/create the fallback */
850 va_start(args, fallback);
851 section = ensure_section(this, this->top, fallback, args);
852 va_end(args);
853
854 va_start(args, fallback);
855 add_fallback_to_section(this, this->top, key, args, section);
856 va_end(args);
857 }
858
859 /**
860 * Load settings from files matching the given file pattern or from a string.
861 * All sections and values are added relative to "parent".
862 * All files (even included ones) have to be loaded successfully.
863 * If merge is FALSE the contents of parent are replaced with the parsed
864 * contents, otherwise they are merged together.
865 */
866 static bool load_internal(private_settings_t *this, section_t *parent,
867 char *pattern, bool merge, bool string)
868 {
869 section_t *section;
870 bool loaded;
871
872 if (pattern == NULL || !pattern[0])
873 { /* TODO: Clear parent if merge is FALSE? */
874 return TRUE;
875 }
876
877 section = settings_section_create(NULL);
878 loaded = string ? settings_parser_parse_string(section, pattern) :
879 settings_parser_parse_file(section, pattern);
880 if (!loaded)
881 {
882 settings_section_destroy(section, NULL);
883 return FALSE;
884 }
885
886 this->lock->write_lock(this->lock);
887 settings_section_extend(parent, section, this->contents, !merge);
888 this->lock->unlock(this->lock);
889
890 settings_section_destroy(section, NULL);
891 return TRUE;
892 }
893
894 METHOD(settings_t, load_files, bool,
895 private_settings_t *this, char *pattern, bool merge)
896 {
897 return load_internal(this, this->top, pattern, merge, FALSE);
898 }
899
900 METHOD(settings_t, load_files_section, bool,
901 private_settings_t *this, char *pattern, bool merge, char *key, ...)
902 {
903 section_t *section;
904 va_list args;
905
906 va_start(args, key);
907 section = ensure_section(this, this->top, key, args);
908 va_end(args);
909
910 if (!section)
911 {
912 return FALSE;
913 }
914 return load_internal(this, section, pattern, merge, FALSE);
915 }
916
917 METHOD(settings_t, load_string, bool,
918 private_settings_t *this, char *settings, bool merge)
919 {
920 return load_internal(this, this->top, settings, merge, TRUE);
921 }
922
923 METHOD(settings_t, load_string_section, bool,
924 private_settings_t *this, char *settings, bool merge, char *key, ...)
925 {
926 section_t *section;
927 va_list args;
928
929 va_start(args, key);
930 section = ensure_section(this, this->top, key, args);
931 va_end(args);
932
933 if (!section)
934 {
935 return FALSE;
936 }
937 return load_internal(this, section, settings, merge, TRUE);
938 }
939
940 METHOD(settings_t, destroy, void,
941 private_settings_t *this)
942 {
943 settings_section_destroy(this->top, NULL);
944 array_destroy_function(this->contents, (void*)free, NULL);
945 this->lock->destroy(this->lock);
946 free(this);
947 }
948
949 static private_settings_t *settings_create_base()
950 {
951 private_settings_t *this;
952
953 INIT(this,
954 .public = {
955 .get_str = _get_str,
956 .get_int = _get_int,
957 .get_double = _get_double,
958 .get_time = _get_time,
959 .get_bool = _get_bool,
960 .set_str = _set_str,
961 .set_int = _set_int,
962 .set_double = _set_double,
963 .set_time = _set_time,
964 .set_bool = _set_bool,
965 .set_default_str = _set_default_str,
966 .create_section_enumerator = _create_section_enumerator,
967 .create_key_value_enumerator = _create_key_value_enumerator,
968 .add_fallback = _add_fallback,
969 .load_files = _load_files,
970 .load_files_section = _load_files_section,
971 .load_string = _load_string,
972 .load_string_section = _load_string_section,
973 .destroy = _destroy,
974 },
975 .top = settings_section_create(NULL),
976 .contents = array_create(0, 0),
977 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
978 );
979 return this;
980 }
981
982 /*
983 * see header file
984 */
985 settings_t *settings_create(char *file)
986 {
987 private_settings_t *this = settings_create_base();
988
989 load_files(this, file, FALSE);
990
991 return &this->public;
992 }
993
994 /*
995 * see header file
996 */
997 settings_t *settings_create_string(char *settings)
998 {
999 private_settings_t *this = settings_create_base();
1000
1001 load_string(this, settings, FALSE);
1002
1003 return &this->public;
1004 }