settings: Fix compilation with newer versions of Clang
[strongswan.git] / src / libstrongswan / settings / settings.c
1 /*
2 * Copyright (C) 2010-2018 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 * Note that key and start point into the same string
77 */
78 static bool print_key(char *buf, int len, char *start, char *key, va_list args)
79 {
80 va_list copy;
81 char *pos = start;
82 bool res;
83
84 va_copy(copy, args);
85 while (TRUE)
86 {
87 pos = memchr(pos, '%', key - pos);
88 if (!pos)
89 {
90 break;
91 }
92 pos++;
93 switch (*pos)
94 {
95 case 'd':
96 va_arg(copy, int);
97 break;
98 case 's':
99 va_arg(copy, char*);
100 break;
101 case 'N':
102 va_arg(copy, enum_name_t*);
103 va_arg(copy, int);
104 break;
105 case '%':
106 break;
107 default:
108 DBG1(DBG_CFG, "settings with %%%c not supported!", *pos);
109 break;
110 }
111 pos++;
112 }
113 res = vsnprintf(buf, len, key, copy) < len;
114 va_end(copy);
115 return res;
116 }
117
118 /**
119 * Check if the given section is contained in the given array.
120 */
121 static bool has_section(array_t *array, section_t *section)
122 {
123 section_t *current;
124 int i;
125
126 for (i = 0; i < array_count(array); i++)
127 {
128 array_get(array, i, &current);
129 if (current == section)
130 {
131 return TRUE;
132 }
133 }
134 return FALSE;
135 }
136
137 /**
138 * Find a section by a given key, using buffered key, reusable buffer.
139 * If "ensure" is TRUE, the sections are created if they don't exist.
140 */
141 static section_t *find_section_buffered(section_t *section,
142 char *start, char *key, va_list args, char *buf, int len,
143 bool ensure)
144 {
145 char *pos;
146 section_t *found = NULL;
147
148 if (section == NULL)
149 {
150 return NULL;
151 }
152 pos = strchr(key, '.');
153 if (pos)
154 {
155 *pos = '\0';
156 pos++;
157 }
158 if (!print_key(buf, len, start, key, args))
159 {
160 return NULL;
161 }
162 if (!strlen(buf))
163 {
164 found = section;
165 }
166 else if (array_bsearch(section->sections, buf, settings_section_find,
167 &found) == -1)
168 {
169 if (ensure)
170 {
171 found = settings_section_create(strdup(buf));
172 settings_section_add(section, found, NULL);
173 }
174 }
175 if (found && pos)
176 {
177 return find_section_buffered(found, start, pos, args, buf, len, ensure);
178 }
179 return found;
180 }
181
182 /**
183 * Forward declaration
184 */
185 static array_t *find_sections(private_settings_t *this, section_t *section,
186 char *key, va_list args, array_t **sections);
187
188 /**
189 * Resolve the given reference. Not thread-safe.
190 * Only a vararg function to get an empty va_list.
191 */
192 static void resolve_reference(private_settings_t *this, section_ref_t *ref,
193 array_t **sections, ...)
194 {
195 va_list args;
196
197 va_start(args, sections);
198 find_sections(this, this->top, ref->name, args, sections);
199 va_end(args);
200 }
201
202 /**
203 * Find all sections via a given key considering references, using buffered key,
204 * reusable buffer.
205 */
206 static void find_sections_buffered(private_settings_t *this, section_t *section,
207 char *start, char *key, va_list args,
208 char *buf, int len, bool ignore_refs,
209 array_t **sections)
210 {
211 section_t *found = NULL, *reference;
212 array_t *references;
213 section_ref_t *ref;
214 char *pos;
215 int i, j;
216
217 if (!section)
218 {
219 return;
220 }
221 pos = strchr(key, '.');
222 if (pos)
223 {
224 *pos = '\0';
225 }
226 if (!print_key(buf, len, start, key, args))
227 {
228 return;
229 }
230 if (pos)
231 { /* restore so we can follow references */
232 *pos = '.';
233 }
234 if (!strlen(buf))
235 {
236 found = section;
237 }
238 else
239 {
240 array_bsearch(section->sections, buf, settings_section_find, &found);
241 }
242 if (found)
243 {
244 if (pos)
245 {
246 find_sections_buffered(this, found, start, pos+1, args, buf, len,
247 FALSE, sections);
248 }
249 else if (!has_section(*sections, found))
250 {
251 /* ignore if already added to avoid loops */
252 array_insert_create(sections, ARRAY_TAIL, found);
253 /* add all sections that are referenced here (also resolves
254 * references in parent sections of the referenced section) */
255 for (i = 0; i < array_count(found->references); i++)
256 {
257 array_get(found->references, i, &ref);
258 resolve_reference(this, ref, sections);
259 }
260 }
261 }
262 if (!ignore_refs && section != found && section->references)
263 {
264 /* find matching sub-sections relative to the referenced sections */
265 for (i = 0; i < array_count(section->references); i++)
266 {
267 array_get(section->references, i, &ref);
268 references = NULL;
269 resolve_reference(this, ref, &references);
270 for (j = 0; j < array_count(references); j++)
271 {
272 array_get(references, j, &reference);
273 /* ignore references in this referenced section, they were
274 * resolved via resolve_reference() */
275 find_sections_buffered(this, reference, start, key, args,
276 buf, len, TRUE, sections);
277 }
278 array_destroy(references);
279 }
280 }
281 }
282
283 /**
284 * Ensure that the section with the given key exists (not thread-safe).
285 */
286 static section_t *ensure_section(private_settings_t *this, section_t *section,
287 const char *key, va_list args)
288 {
289 char buf[128], keybuf[512];
290
291 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
292 {
293 return NULL;
294 }
295 return find_section_buffered(section, keybuf, keybuf, args, buf,
296 sizeof(buf), TRUE);
297 }
298
299 /**
300 * Find a section by a given key with resolved references (not thread-safe!).
301 * The array is allocated. NULL is returned if no sections are found.
302 */
303 static array_t *find_sections(private_settings_t *this, section_t *section,
304 char *key, va_list args, array_t **sections)
305 {
306 char buf[128], keybuf[512];
307
308 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
309 {
310 return NULL;
311 }
312 find_sections_buffered(this, section, keybuf, keybuf, args, buf,
313 sizeof(buf), FALSE, sections);
314 return *sections;
315 }
316
317 /**
318 * Find the key/value pair for a key, using buffered key, reusable buffer
319 * There are two modes: 1. To find a key at an exact location and create the
320 * sections (and key/value pair) if necessary, don't pass an array for sections.
321 * 2. To find a key and follow references pass a pointer to an array to store
322 * visited sections. NULL is returned in this case if the key is not found.
323 */
324 static kv_t *find_value_buffered(private_settings_t *this, section_t *section,
325 char *start, char *key, va_list args,
326 char *buf, int len, bool ignore_refs,
327 array_t **sections)
328 {
329 section_t *found = NULL;
330 kv_t *kv = NULL;
331 section_ref_t *ref;
332 array_t *references;
333 char *pos;
334 int i, j;
335
336 if (!section)
337 {
338 return NULL;
339 }
340 pos = strchr(key, '.');
341 if (pos)
342 {
343 *pos = '\0';
344 if (!print_key(buf, len, start, key, args))
345 {
346 return NULL;
347 }
348 /* restore so we can follow references */
349 *pos = '.';
350 if (!strlen(buf))
351 {
352 found = section;
353 }
354 else if (array_bsearch(section->sections, buf, settings_section_find,
355 &found) == -1)
356 {
357 if (!sections)
358 {
359 found = settings_section_create(strdup(buf));
360 settings_section_add(section, found, NULL);
361 }
362 }
363 if (found)
364 {
365 kv = find_value_buffered(this, found, start, pos+1, args, buf, len,
366 FALSE, sections);
367 }
368 }
369 else
370 {
371 if (sections)
372 {
373 array_insert_create(sections, ARRAY_TAIL, section);
374 }
375 if (!print_key(buf, len, start, key, args))
376 {
377 return NULL;
378 }
379 if (array_bsearch(section->kv, buf, settings_kv_find, &kv) == -1)
380 {
381 if (!sections)
382 {
383 kv = settings_kv_create(strdup(buf), NULL);
384 settings_kv_add(section, kv, NULL);
385 }
386 }
387 }
388 if (!kv && !ignore_refs && sections && section->references)
389 {
390 /* find key relative to the referenced sections */
391 for (i = 0; !kv && i < array_count(section->references); i++)
392 {
393 array_get(section->references, i, &ref);
394 references = NULL;
395 resolve_reference(this, ref, &references);
396 for (j = 0; !kv && j < array_count(references); j++)
397 {
398 array_get(references, j, &found);
399 /* ignore if already added to avoid loops */
400 if (!has_section(*sections, found))
401 {
402 /* ignore references in this referenced section, they were
403 * resolved via resolve_reference() */
404 kv = find_value_buffered(this, found, start, key, args,
405 buf, len, TRUE, sections);
406 }
407 }
408 array_destroy(references);
409 }
410 }
411 return kv;
412 }
413
414 /**
415 * Remove the key/value pair for a key, using buffered key, reusable buffer
416 */
417 static void remove_value_buffered(private_settings_t *this, section_t *section,
418 char *start, char *key, va_list args,
419 char *buf, int len)
420 {
421 section_t *found = NULL;
422 kv_t *kv = NULL, *ordered = NULL;
423 char *pos;
424 int idx, i;
425
426 if (!section)
427 {
428 return;
429 }
430 pos = strchr(key, '.');
431 if (pos)
432 {
433 *pos = '\0';
434 pos++;
435 }
436 if (!print_key(buf, len, start, key, args))
437 {
438 return;
439 }
440 if (!strlen(buf))
441 {
442 found = section;
443 }
444 if (pos)
445 {
446 if (array_bsearch(section->sections, buf, settings_section_find,
447 &found) != -1)
448 {
449 remove_value_buffered(this, found, start, pos, args, buf, len);
450 }
451 }
452 else
453 {
454 idx = array_bsearch(section->kv, buf, settings_kv_find, &kv);
455 if (idx != -1)
456 {
457 array_remove(section->kv, idx, NULL);
458 for (i = 0; i < array_count(section->kv_order); i++)
459 {
460 array_get(section->kv_order, i, &ordered);
461 if (kv == ordered)
462 {
463 array_remove(section->kv_order, i, NULL);
464 settings_kv_destroy(kv, this->contents);
465 }
466 }
467 }
468 }
469 }
470
471 /*
472 * Described in header
473 */
474 void settings_remove_value(settings_t *settings, char *key, ...)
475 {
476 private_settings_t *this = (private_settings_t*)settings;
477 char buf[128], keybuf[512];
478 va_list args;
479
480 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
481 {
482 return;
483 }
484 va_start(args, key);
485
486 this->lock->read_lock(this->lock);
487 remove_value_buffered(this, this->top, keybuf, keybuf, args, buf,
488 sizeof(buf));
489 this->lock->unlock(this->lock);
490
491 va_end(args);
492 }
493
494 /**
495 * Find the string value for a key (thread-safe).
496 */
497 static char *find_value(private_settings_t *this, section_t *section,
498 char *key, va_list args)
499 {
500 char buf[128], keybuf[512], *value = NULL;
501 array_t *sections = NULL;
502 kv_t *kv;
503
504 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
505 {
506 return NULL;
507 }
508 this->lock->read_lock(this->lock);
509 kv = find_value_buffered(this, section, keybuf, keybuf, args,
510 buf, sizeof(buf), FALSE, &sections);
511 if (kv)
512 {
513 value = kv->value;
514 }
515 this->lock->unlock(this->lock);
516 array_destroy(sections);
517 return value;
518 }
519
520 /**
521 * Set a value to a copy of the given string (thread-safe).
522 */
523 static void set_value(private_settings_t *this, section_t *section,
524 char *key, va_list args, char *value)
525 {
526 char buf[128], keybuf[512];
527 kv_t *kv;
528
529 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
530 {
531 return;
532 }
533 this->lock->write_lock(this->lock);
534 kv = find_value_buffered(this, section, keybuf, keybuf, args,
535 buf, sizeof(buf), FALSE, NULL);
536 if (kv)
537 {
538 settings_kv_set(kv, strdupnull(value), this->contents);
539 }
540 this->lock->unlock(this->lock);
541 }
542
543 METHOD(settings_t, get_str, char*,
544 private_settings_t *this, char *key, char *def, ...)
545 {
546 char *value;
547 va_list args;
548
549 va_start(args, def);
550 value = find_value(this, this->top, key, args);
551 va_end(args);
552 if (value)
553 {
554 return value;
555 }
556 return def;
557 }
558
559 /**
560 * Described in header
561 */
562 inline bool settings_value_as_bool(char *value, bool def)
563 {
564 if (value)
565 {
566 if (strcaseeq(value, "1") ||
567 strcaseeq(value, "yes") ||
568 strcaseeq(value, "true") ||
569 strcaseeq(value, "enabled"))
570 {
571 return TRUE;
572 }
573 else if (strcaseeq(value, "0") ||
574 strcaseeq(value, "no") ||
575 strcaseeq(value, "false") ||
576 strcaseeq(value, "disabled"))
577 {
578 return FALSE;
579 }
580 }
581 return def;
582 }
583
584 METHOD(settings_t, get_bool, bool,
585 private_settings_t *this, char *key, int def, ...)
586 {
587 char *value;
588 va_list args;
589
590 /* we can't use bool for def due to this call */
591 va_start(args, def);
592 value = find_value(this, this->top, key, args);
593 va_end(args);
594 return settings_value_as_bool(value, def);
595 }
596
597 /**
598 * Described in header
599 */
600 inline int settings_value_as_int(char *value, int def)
601 {
602 int intval;
603 char *end;
604 int base = 10;
605
606 if (value)
607 {
608 errno = 0;
609 if (value[0] == '0' && value[1] == 'x')
610 { /* manually detect 0x prefix as we want to avoid octal encoding */
611 base = 16;
612 }
613 intval = strtol(value, &end, base);
614 if (errno == 0 && *end == 0 && end != value)
615 {
616 return intval;
617 }
618 }
619 return def;
620 }
621
622 METHOD(settings_t, get_int, int,
623 private_settings_t *this, char *key, int def, ...)
624 {
625 char *value;
626 va_list args;
627
628 va_start(args, def);
629 value = find_value(this, this->top, key, args);
630 va_end(args);
631 return settings_value_as_int(value, def);
632 }
633
634 /**
635 * Described in header
636 */
637 inline uint64_t settings_value_as_uint64(char *value, uint64_t def)
638 {
639 uint64_t intval;
640 char *end;
641 int base = 10;
642
643 if (value)
644 {
645 errno = 0;
646 if (value[0] == '0' && value[1] == 'x')
647 { /* manually detect 0x prefix as we want to avoid octal encoding */
648 base = 16;
649 }
650 intval = strtoull(value, &end, base);
651 if (errno == 0 && *end == 0 && end != value)
652 {
653 return intval;
654 }
655 }
656 return def;
657 }
658
659 /**
660 * Described in header
661 */
662 inline double settings_value_as_double(char *value, double def)
663 {
664 double dval;
665 char *end;
666
667 if (value)
668 {
669 errno = 0;
670 dval = strtod(value, &end);
671 if (errno == 0 && *end == 0 && end != value)
672 {
673 return dval;
674 }
675 }
676 return def;
677 }
678
679 METHOD(settings_t, get_double, double,
680 private_settings_t *this, char *key, double def, ...)
681 {
682 char *value;
683 va_list args;
684
685 va_start(args, def);
686 value = find_value(this, this->top, key, args);
687 va_end(args);
688 return settings_value_as_double(value, def);
689 }
690
691 /**
692 * Described in header
693 */
694 inline uint32_t settings_value_as_time(char *value, uint32_t def)
695 {
696 time_t val;
697
698 if (timespan_from_string(value, NULL, &val))
699 {
700 return val;
701 }
702 return def;
703 }
704
705 METHOD(settings_t, get_time, uint32_t,
706 private_settings_t *this, char *key, uint32_t def, ...)
707 {
708 char *value;
709 va_list args;
710
711 va_start(args, def);
712 value = find_value(this, this->top, key, args);
713 va_end(args);
714 return settings_value_as_time(value, def);
715 }
716
717 METHOD(settings_t, set_str, void,
718 private_settings_t *this, char *key, char *value, ...)
719 {
720 va_list args;
721 va_start(args, value);
722 set_value(this, this->top, key, args, value);
723 va_end(args);
724 }
725
726 METHOD(settings_t, set_bool, void,
727 private_settings_t *this, char *key, int value, ...)
728 {
729 va_list args;
730 /* we can't use bool for value due to this call */
731 va_start(args, value);
732 set_value(this, this->top, key, args, value ? "1" : "0");
733 va_end(args);
734 }
735
736 METHOD(settings_t, set_int, void,
737 private_settings_t *this, char *key, int value, ...)
738 {
739 char val[16];
740 va_list args;
741 va_start(args, value);
742 if (snprintf(val, sizeof(val), "%d", value) < sizeof(val))
743 {
744 set_value(this, this->top, key, args, val);
745 }
746 va_end(args);
747 }
748
749 METHOD(settings_t, set_double, void,
750 private_settings_t *this, char *key, double value, ...)
751 {
752 char val[64];
753 va_list args;
754 va_start(args, value);
755 if (snprintf(val, sizeof(val), "%f", value) < sizeof(val))
756 {
757 set_value(this, this->top, key, args, val);
758 }
759 va_end(args);
760 }
761
762 METHOD(settings_t, set_time, void,
763 private_settings_t *this, char *key, uint32_t value, ...)
764 {
765 char val[16];
766 va_list args;
767 va_start(args, value);
768 if (snprintf(val, sizeof(val), "%u", value) < sizeof(val))
769 {
770 set_value(this, this->top, key, args, val);
771 }
772 va_end(args);
773 }
774
775 METHOD(settings_t, set_default_str, bool,
776 private_settings_t *this, char *key, char *value, ...)
777 {
778 char *old;
779 va_list args;
780
781 va_start(args, value);
782 old = find_value(this, this->top, key, args);
783 va_end(args);
784
785 if (!old)
786 {
787 va_start(args, value);
788 set_value(this, this->top, key, args, value);
789 va_end(args);
790 return TRUE;
791 }
792 return FALSE;
793 }
794
795 /**
796 * Data for enumerators
797 */
798 typedef struct {
799 /** settings_t instance */
800 private_settings_t *settings;
801 /** sections to enumerate */
802 array_t *sections;
803 /** sections/keys that were already enumerated */
804 hashtable_t *seen;
805 } enumerator_data_t;
806
807 CALLBACK(enumerator_destroy, void,
808 enumerator_data_t *this)
809 {
810 this->settings->lock->unlock(this->settings->lock);
811 this->seen->destroy(this->seen);
812 array_destroy(this->sections);
813 free(this);
814 }
815
816 CALLBACK(section_filter, bool,
817 hashtable_t *seen, enumerator_t *orig, va_list args)
818 {
819 section_t *section;
820 char **out;
821
822 VA_ARGS_VGET(args, out);
823
824 while (orig->enumerate(orig, &section))
825 {
826 if (seen->get(seen, section->name))
827 {
828 continue;
829 }
830 *out = section->name;
831 seen->put(seen, section->name, section->name);
832 return TRUE;
833 }
834 return FALSE;
835 }
836
837 /**
838 * Enumerate sections of the given section
839 */
840 static enumerator_t *section_enumerator(section_t *section,
841 enumerator_data_t *data)
842 {
843 return enumerator_create_filter(
844 array_create_enumerator(section->sections_order),
845 section_filter, data->seen, NULL);
846 }
847
848 METHOD(settings_t, create_section_enumerator, enumerator_t*,
849 private_settings_t *this, char *key, ...)
850 {
851 enumerator_data_t *data;
852 array_t *sections = NULL;
853 va_list args;
854
855 this->lock->read_lock(this->lock);
856 va_start(args, key);
857 sections = find_sections(this, this->top, key, args, &sections);
858 va_end(args);
859
860 if (!sections)
861 {
862 this->lock->unlock(this->lock);
863 return enumerator_create_empty();
864 }
865 INIT(data,
866 .settings = this,
867 .sections = sections,
868 .seen = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
869 );
870 return enumerator_create_nested(array_create_enumerator(sections),
871 (void*)section_enumerator, data, enumerator_destroy);
872 }
873
874 CALLBACK(kv_filter, bool,
875 hashtable_t *seen, enumerator_t *orig, va_list args)
876 {
877 kv_t *kv;
878 char **key, **value;
879
880 VA_ARGS_VGET(args, key, value);
881
882 while (orig->enumerate(orig, &kv))
883 {
884 if (seen->get(seen, kv->key))
885 {
886 continue;
887 }
888 seen->put(seen, kv->key, kv->key);
889 if (!kv->value)
890 {
891 continue;
892 }
893 *key = kv->key;
894 *value = kv->value;
895 return TRUE;
896 }
897 return FALSE;
898 }
899
900 /**
901 * Enumerate key/value pairs of the given section
902 */
903 static enumerator_t *kv_enumerator(section_t *section, enumerator_data_t *data)
904 {
905 return enumerator_create_filter(array_create_enumerator(section->kv_order),
906 kv_filter, data->seen, NULL);
907 }
908
909 METHOD(settings_t, create_key_value_enumerator, enumerator_t*,
910 private_settings_t *this, char *key, ...)
911 {
912 enumerator_data_t *data;
913 array_t *sections = NULL;
914 va_list args;
915
916 this->lock->read_lock(this->lock);
917 va_start(args, key);
918 sections = find_sections(this, this->top, key, args, &sections);
919 va_end(args);
920
921 if (!sections)
922 {
923 this->lock->unlock(this->lock);
924 return enumerator_create_empty();
925 }
926 INIT(data,
927 .settings = this,
928 .sections = sections,
929 .seen = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
930 );
931 return enumerator_create_nested(array_create_enumerator(sections),
932 (void*)kv_enumerator, data, (void*)enumerator_destroy);
933 }
934
935 METHOD(settings_t, add_fallback, void,
936 private_settings_t *this, const char *key, const char *fallback, ...)
937 {
938 section_t *section;
939 va_list args;
940 char buf[512];
941
942 this->lock->write_lock(this->lock);
943 va_start(args, fallback);
944 section = ensure_section(this, this->top, key, args);
945 va_end(args);
946
947 va_start(args, fallback);
948 if (section && vsnprintf(buf, sizeof(buf), fallback, args) < sizeof(buf))
949 {
950 settings_reference_add(section, strdup(buf), TRUE);
951 }
952 va_end(args);
953 this->lock->unlock(this->lock);
954 }
955
956 /**
957 * Load settings from files matching the given file pattern or from a string.
958 * All files (even included ones) have to be loaded successfully.
959 */
960 static section_t *load_internal(char *pattern, bool string)
961 {
962 section_t *section;
963 bool loaded;
964
965 if (pattern == NULL || !pattern[0])
966 {
967 return settings_section_create(NULL);
968 }
969
970 section = settings_section_create(NULL);
971 loaded = string ? settings_parser_parse_string(section, pattern) :
972 settings_parser_parse_file(section, pattern);
973 if (!loaded)
974 {
975 settings_section_destroy(section, NULL);
976 section = NULL;
977 }
978 return section;
979 }
980
981 /**
982 * Add sections and values in "section" relative to "parent".
983 * If merge is FALSE the contents of parent are replaced with the parsed
984 * contents, otherwise they are merged together.
985 *
986 * Releases the write lock and destroys the given section.
987 * If parent is NULL this is all that happens.
988 */
989 static bool extend_section(private_settings_t *this, section_t *parent,
990 section_t *section, bool merge)
991 {
992 if (parent)
993 {
994 settings_section_extend(parent, section, this->contents, !merge);
995 }
996 this->lock->unlock(this->lock);
997 settings_section_destroy(section, NULL);
998 return parent != NULL;
999 }
1000
1001 METHOD(settings_t, load_files, bool,
1002 private_settings_t *this, char *pattern, bool merge)
1003 {
1004 section_t *section;
1005
1006 section = load_internal(pattern, FALSE);
1007 if (!section)
1008 {
1009 return FALSE;
1010 }
1011
1012 this->lock->write_lock(this->lock);
1013 return extend_section(this, this->top, section, merge);
1014 }
1015
1016 METHOD(settings_t, load_files_section, bool,
1017 private_settings_t *this, char *pattern, bool merge, char *key, ...)
1018 {
1019 section_t *section, *parent;
1020 va_list args;
1021
1022 section = load_internal(pattern, FALSE);
1023 if (!section)
1024 {
1025 return FALSE;
1026 }
1027
1028 this->lock->write_lock(this->lock);
1029
1030 va_start(args, key);
1031 parent = ensure_section(this, this->top, key, args);
1032 va_end(args);
1033
1034 return extend_section(this, parent, section, merge);
1035 }
1036
1037 METHOD(settings_t, load_string, bool,
1038 private_settings_t *this, char *settings, bool merge)
1039 {
1040 section_t *section;
1041
1042 section = load_internal(settings, TRUE);
1043 if (!section)
1044 {
1045 return FALSE;
1046 }
1047
1048 this->lock->write_lock(this->lock);
1049 return extend_section(this, this->top, section, merge);
1050 }
1051
1052 METHOD(settings_t, load_string_section, bool,
1053 private_settings_t *this, char *settings, bool merge, char *key, ...)
1054 {
1055 section_t *section, *parent;
1056 va_list args;
1057
1058 section = load_internal(settings, TRUE);
1059 if (!section)
1060 {
1061 return FALSE;
1062 }
1063
1064 this->lock->write_lock(this->lock);
1065
1066 va_start(args, key);
1067 parent = ensure_section(this, this->top, key, args);
1068 va_end(args);
1069
1070 return extend_section(this, parent, section, merge);
1071 }
1072
1073 METHOD(settings_t, destroy, void,
1074 private_settings_t *this)
1075 {
1076 settings_section_destroy(this->top, NULL);
1077 array_destroy_function(this->contents, (void*)free, NULL);
1078 this->lock->destroy(this->lock);
1079 free(this);
1080 }
1081
1082 static private_settings_t *settings_create_base()
1083 {
1084 private_settings_t *this;
1085
1086 INIT(this,
1087 .public = {
1088 .get_str = _get_str,
1089 .get_int = _get_int,
1090 .get_double = _get_double,
1091 .get_time = _get_time,
1092 .get_bool = _get_bool,
1093 .set_str = _set_str,
1094 .set_int = _set_int,
1095 .set_double = _set_double,
1096 .set_time = _set_time,
1097 .set_bool = _set_bool,
1098 .set_default_str = _set_default_str,
1099 .create_section_enumerator = _create_section_enumerator,
1100 .create_key_value_enumerator = _create_key_value_enumerator,
1101 .add_fallback = _add_fallback,
1102 .load_files = _load_files,
1103 .load_files_section = _load_files_section,
1104 .load_string = _load_string,
1105 .load_string_section = _load_string_section,
1106 .destroy = _destroy,
1107 },
1108 .top = settings_section_create(NULL),
1109 .contents = array_create(0, 0),
1110 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
1111 );
1112 return this;
1113 }
1114
1115 /*
1116 * see header file
1117 */
1118 settings_t *settings_create(char *file)
1119 {
1120 private_settings_t *this = settings_create_base();
1121
1122 load_files(this, file, FALSE);
1123
1124 return &this->public;
1125 }
1126
1127 /*
1128 * see header file
1129 */
1130 settings_t *settings_create_string(char *settings)
1131 {
1132 private_settings_t *this = settings_create_base();
1133
1134 load_string(this, settings, FALSE);
1135
1136 return &this->public;
1137 }