829e784820adb4866b0867f0aaefd1c01855ba2c
[strongswan.git] / src / libstrongswan / settings / settings.c
1 /*
2 * Copyright (C) 2010-2014 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * 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, bool def, ...)
498 {
499 char *value;
500 va_list args;
501
502 va_start(args, def);
503 value = find_value(this, this->top, key, args);
504 va_end(args);
505 return settings_value_as_bool(value, def);
506 }
507
508 /**
509 * Described in header
510 */
511 inline int settings_value_as_int(char *value, int def)
512 {
513 int intval;
514 char *end;
515
516 if (value)
517 {
518 errno = 0;
519 intval = strtol(value, &end, 10);
520 if (errno == 0 && *end == 0 && end != value)
521 {
522 return intval;
523 }
524 }
525 return def;
526 }
527
528 METHOD(settings_t, get_int, int,
529 private_settings_t *this, char *key, int def, ...)
530 {
531 char *value;
532 va_list args;
533
534 va_start(args, def);
535 value = find_value(this, this->top, key, args);
536 va_end(args);
537 return settings_value_as_int(value, def);
538 }
539
540 /**
541 * Described in header
542 */
543 inline uint64_t settings_value_as_uint64(char *value, uint64_t def)
544 {
545 uint64_t intval;
546 char *end;
547 int base = 10;
548
549 if (value)
550 {
551 errno = 0;
552 if (value[0] == '0' && value[1] == 'x')
553 { /* manually detect 0x prefix as we want to avoid octal encoding */
554 base = 16;
555 }
556 intval = strtoull(value, &end, base);
557 if (errno == 0 && *end == 0 && end != value)
558 {
559 return intval;
560 }
561 }
562 return def;
563 }
564
565 /**
566 * Described in header
567 */
568 inline double settings_value_as_double(char *value, double def)
569 {
570 double dval;
571 char *end;
572
573 if (value)
574 {
575 errno = 0;
576 dval = strtod(value, &end);
577 if (errno == 0 && *end == 0 && end != value)
578 {
579 return dval;
580 }
581 }
582 return def;
583 }
584
585 METHOD(settings_t, get_double, double,
586 private_settings_t *this, char *key, double def, ...)
587 {
588 char *value;
589 va_list args;
590
591 va_start(args, def);
592 value = find_value(this, this->top, key, args);
593 va_end(args);
594 return settings_value_as_double(value, def);
595 }
596
597 /**
598 * Described in header
599 */
600 inline uint32_t settings_value_as_time(char *value, uint32_t def)
601 {
602 char *endptr;
603 uint32_t timeval;
604 if (value)
605 {
606 errno = 0;
607 timeval = strtoul(value, &endptr, 10);
608 if (endptr == value)
609 {
610 return def;
611 }
612 if (errno == 0)
613 {
614 while (isspace(*endptr))
615 {
616 endptr++;
617 }
618 switch (*endptr)
619 {
620 case 'd': /* time in days */
621 timeval *= 24 * 3600;
622 break;
623 case 'h': /* time in hours */
624 timeval *= 3600;
625 break;
626 case 'm': /* time in minutes */
627 timeval *= 60;
628 break;
629 case 's': /* time in seconds */
630 case '\0':
631 break;
632 default:
633 return def;
634 }
635 return timeval;
636 }
637 }
638 return def;
639 }
640
641 METHOD(settings_t, get_time, uint32_t,
642 private_settings_t *this, char *key, uint32_t def, ...)
643 {
644 char *value;
645 va_list args;
646
647 va_start(args, def);
648 value = find_value(this, this->top, key, args);
649 va_end(args);
650 return settings_value_as_time(value, def);
651 }
652
653 METHOD(settings_t, set_str, void,
654 private_settings_t *this, char *key, char *value, ...)
655 {
656 va_list args;
657 va_start(args, value);
658 set_value(this, this->top, key, args, value);
659 va_end(args);
660 }
661
662 METHOD(settings_t, set_bool, void,
663 private_settings_t *this, char *key, bool value, ...)
664 {
665 va_list args;
666 va_start(args, value);
667 set_value(this, this->top, key, args, value ? "1" : "0");
668 va_end(args);
669 }
670
671 METHOD(settings_t, set_int, void,
672 private_settings_t *this, char *key, int value, ...)
673 {
674 char val[16];
675 va_list args;
676 va_start(args, value);
677 if (snprintf(val, sizeof(val), "%d", value) < sizeof(val))
678 {
679 set_value(this, this->top, key, args, val);
680 }
681 va_end(args);
682 }
683
684 METHOD(settings_t, set_double, void,
685 private_settings_t *this, char *key, double value, ...)
686 {
687 char val[64];
688 va_list args;
689 va_start(args, value);
690 if (snprintf(val, sizeof(val), "%f", value) < sizeof(val))
691 {
692 set_value(this, this->top, key, args, val);
693 }
694 va_end(args);
695 }
696
697 METHOD(settings_t, set_time, void,
698 private_settings_t *this, char *key, uint32_t value, ...)
699 {
700 char val[16];
701 va_list args;
702 va_start(args, value);
703 if (snprintf(val, sizeof(val), "%u", value) < sizeof(val))
704 {
705 set_value(this, this->top, key, args, val);
706 }
707 va_end(args);
708 }
709
710 METHOD(settings_t, set_default_str, bool,
711 private_settings_t *this, char *key, char *value, ...)
712 {
713 char *old;
714 va_list args;
715
716 va_start(args, value);
717 old = find_value(this, this->top, key, args);
718 va_end(args);
719
720 if (!old)
721 {
722 va_start(args, value);
723 set_value(this, this->top, key, args, value);
724 va_end(args);
725 return TRUE;
726 }
727 return FALSE;
728 }
729
730 /**
731 * Data for enumerators
732 */
733 typedef struct {
734 /** settings_t instance */
735 private_settings_t *settings;
736 /** sections to enumerate */
737 array_t *sections;
738 /** sections/keys that were already enumerated */
739 hashtable_t *seen;
740 } enumerator_data_t;
741
742 /**
743 * Destroy enumerator data
744 */
745 static void enumerator_destroy(enumerator_data_t *this)
746 {
747 this->settings->lock->unlock(this->settings->lock);
748 this->seen->destroy(this->seen);
749 array_destroy(this->sections);
750 free(this);
751 }
752
753 /**
754 * Enumerate section names, not sections
755 */
756 static bool section_filter(hashtable_t *seen, section_t **in, char **out)
757 {
758 *out = (*in)->name;
759 if (seen->get(seen, *out))
760 {
761 return FALSE;
762 }
763 seen->put(seen, *out, *out);
764 return TRUE;
765 }
766
767 /**
768 * Enumerate sections of the given section
769 */
770 static enumerator_t *section_enumerator(section_t *section,
771 enumerator_data_t *data)
772 {
773 return enumerator_create_filter(
774 array_create_enumerator(section->sections_order),
775 (void*)section_filter, data->seen, NULL);
776 }
777
778 METHOD(settings_t, create_section_enumerator, enumerator_t*,
779 private_settings_t *this, char *key, ...)
780 {
781 enumerator_data_t *data;
782 array_t *sections;
783 va_list args;
784
785 this->lock->read_lock(this->lock);
786 va_start(args, key);
787 sections = find_sections(this, this->top, key, args);
788 va_end(args);
789
790 if (!sections)
791 {
792 this->lock->unlock(this->lock);
793 return enumerator_create_empty();
794 }
795 INIT(data,
796 .settings = this,
797 .sections = sections,
798 .seen = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
799 );
800 return enumerator_create_nested(array_create_enumerator(sections),
801 (void*)section_enumerator, data, (void*)enumerator_destroy);
802 }
803
804 /**
805 * Enumerate key and values, not kv_t entries
806 */
807 static bool kv_filter(hashtable_t *seen, kv_t **in, char **key,
808 void *none, char **value)
809 {
810 *key = (*in)->key;
811 if (seen->get(seen, *key) || !(*in)->value)
812 {
813 return FALSE;
814 }
815 *value = (*in)->value;
816 seen->put(seen, *key, *key);
817 return TRUE;
818 }
819
820 /**
821 * Enumerate key/value pairs of the given section
822 */
823 static enumerator_t *kv_enumerator(section_t *section, enumerator_data_t *data)
824 {
825 return enumerator_create_filter(array_create_enumerator(section->kv_order),
826 (void*)kv_filter, data->seen, NULL);
827 }
828
829 METHOD(settings_t, create_key_value_enumerator, enumerator_t*,
830 private_settings_t *this, char *key, ...)
831 {
832 enumerator_data_t *data;
833 array_t *sections;
834 va_list args;
835
836 this->lock->read_lock(this->lock);
837 va_start(args, key);
838 sections = find_sections(this, this->top, key, args);
839 va_end(args);
840
841 if (!sections)
842 {
843 this->lock->unlock(this->lock);
844 return enumerator_create_empty();
845 }
846 INIT(data,
847 .settings = this,
848 .sections = sections,
849 .seen = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
850 );
851 return enumerator_create_nested(array_create_enumerator(sections),
852 (void*)kv_enumerator, data, (void*)enumerator_destroy);
853 }
854
855 METHOD(settings_t, add_fallback, void,
856 private_settings_t *this, const char *key, const char *fallback, ...)
857 {
858 section_t *section;
859 va_list args;
860
861 /* find/create the fallback */
862 va_start(args, fallback);
863 section = ensure_section(this, this->top, fallback, args);
864 va_end(args);
865
866 va_start(args, fallback);
867 add_fallback_to_section(this, this->top, key, args, section);
868 va_end(args);
869 }
870
871 /**
872 * Load settings from files matching the given file pattern or from a string.
873 * All sections and values are added relative to "parent".
874 * All files (even included ones) have to be loaded successfully.
875 * If merge is FALSE the contents of parent are replaced with the parsed
876 * contents, otherwise they are merged together.
877 */
878 static bool load_internal(private_settings_t *this, section_t *parent,
879 char *pattern, bool merge, bool string)
880 {
881 section_t *section;
882 bool loaded;
883
884 if (pattern == NULL || !pattern[0])
885 { /* TODO: Clear parent if merge is FALSE? */
886 return TRUE;
887 }
888
889 section = settings_section_create(NULL);
890 loaded = string ? settings_parser_parse_string(section, pattern) :
891 settings_parser_parse_file(section, pattern);
892 if (!loaded)
893 {
894 settings_section_destroy(section, NULL);
895 return FALSE;
896 }
897
898 this->lock->write_lock(this->lock);
899 settings_section_extend(parent, section, this->contents, !merge);
900 this->lock->unlock(this->lock);
901
902 settings_section_destroy(section, NULL);
903 return TRUE;
904 }
905
906 METHOD(settings_t, load_files, bool,
907 private_settings_t *this, char *pattern, bool merge)
908 {
909 return load_internal(this, this->top, pattern, merge, FALSE);
910 }
911
912 METHOD(settings_t, load_files_section, bool,
913 private_settings_t *this, char *pattern, bool merge, char *key, ...)
914 {
915 section_t *section;
916 va_list args;
917
918 va_start(args, key);
919 section = ensure_section(this, this->top, key, args);
920 va_end(args);
921
922 if (!section)
923 {
924 return FALSE;
925 }
926 return load_internal(this, section, pattern, merge, FALSE);
927 }
928
929 METHOD(settings_t, load_string, bool,
930 private_settings_t *this, char *settings, bool merge)
931 {
932 return load_internal(this, this->top, settings, merge, TRUE);
933 }
934
935 METHOD(settings_t, load_string_section, bool,
936 private_settings_t *this, char *settings, bool merge, char *key, ...)
937 {
938 section_t *section;
939 va_list args;
940
941 va_start(args, key);
942 section = ensure_section(this, this->top, key, args);
943 va_end(args);
944
945 if (!section)
946 {
947 return FALSE;
948 }
949 return load_internal(this, section, settings, merge, TRUE);
950 }
951
952 METHOD(settings_t, destroy, void,
953 private_settings_t *this)
954 {
955 settings_section_destroy(this->top, NULL);
956 array_destroy_function(this->contents, (void*)free, NULL);
957 this->lock->destroy(this->lock);
958 free(this);
959 }
960
961 static private_settings_t *settings_create_base()
962 {
963 private_settings_t *this;
964
965 INIT(this,
966 .public = {
967 .get_str = _get_str,
968 .get_int = _get_int,
969 .get_double = _get_double,
970 .get_time = _get_time,
971 .get_bool = _get_bool,
972 .set_str = _set_str,
973 .set_int = _set_int,
974 .set_double = _set_double,
975 .set_time = _set_time,
976 .set_bool = _set_bool,
977 .set_default_str = _set_default_str,
978 .create_section_enumerator = _create_section_enumerator,
979 .create_key_value_enumerator = _create_key_value_enumerator,
980 .add_fallback = _add_fallback,
981 .load_files = _load_files,
982 .load_files_section = _load_files_section,
983 .load_string = _load_string,
984 .load_string_section = _load_string_section,
985 .destroy = _destroy,
986 },
987 .top = settings_section_create(NULL),
988 .contents = array_create(0, 0),
989 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
990 );
991 return this;
992 }
993
994 /*
995 * see header file
996 */
997 settings_t *settings_create(char *file)
998 {
999 private_settings_t *this = settings_create_base();
1000
1001 load_files(this, file, FALSE);
1002
1003 return &this->public;
1004 }
1005
1006 /*
1007 * see header file
1008 */
1009 settings_t *settings_create_string(char *settings)
1010 {
1011 private_settings_t *this = settings_create_base();
1012
1013 load_string(this, settings, FALSE);
1014
1015 return &this->public;
1016 }