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