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