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