Annotation of embedaddon/strongswan/src/libstrongswan/settings/settings.c, revision 1.1.1.1
1.1 misho 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, ¤t);
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: break;
466: }
467: }
468: }
469: }
470: }
471:
472: /*
473: * Described in header
474: */
475: void settings_remove_value(settings_t *settings, char *key, ...)
476: {
477: private_settings_t *this = (private_settings_t*)settings;
478: char buf[128], keybuf[512];
479: va_list args;
480:
481: if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
482: {
483: return;
484: }
485: va_start(args, key);
486:
487: this->lock->read_lock(this->lock);
488: remove_value_buffered(this, this->top, keybuf, keybuf, args, buf,
489: sizeof(buf));
490: this->lock->unlock(this->lock);
491:
492: va_end(args);
493: }
494:
495: /**
496: * Find the string value for a key (thread-safe).
497: */
498: static char *find_value(private_settings_t *this, section_t *section,
499: char *key, va_list args)
500: {
501: char buf[128], keybuf[512], *value = NULL;
502: array_t *sections = NULL;
503: kv_t *kv;
504:
505: if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
506: {
507: return NULL;
508: }
509: this->lock->read_lock(this->lock);
510: kv = find_value_buffered(this, section, keybuf, keybuf, args,
511: buf, sizeof(buf), FALSE, §ions);
512: if (kv)
513: {
514: value = kv->value;
515: }
516: this->lock->unlock(this->lock);
517: array_destroy(sections);
518: return value;
519: }
520:
521: /**
522: * Set a value to a copy of the given string (thread-safe).
523: */
524: static void set_value(private_settings_t *this, section_t *section,
525: char *key, va_list args, char *value)
526: {
527: char buf[128], keybuf[512];
528: kv_t *kv;
529:
530: if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
531: {
532: return;
533: }
534: this->lock->write_lock(this->lock);
535: kv = find_value_buffered(this, section, keybuf, keybuf, args,
536: buf, sizeof(buf), FALSE, NULL);
537: if (kv)
538: {
539: settings_kv_set(kv, strdupnull(value), this->contents);
540: }
541: this->lock->unlock(this->lock);
542: }
543:
544: METHOD(settings_t, get_str, char*,
545: private_settings_t *this, char *key, char *def, ...)
546: {
547: char *value;
548: va_list args;
549:
550: va_start(args, def);
551: value = find_value(this, this->top, key, args);
552: va_end(args);
553: if (value)
554: {
555: return value;
556: }
557: return def;
558: }
559:
560: /**
561: * Described in header
562: */
563: inline bool settings_value_as_bool(char *value, bool def)
564: {
565: if (value)
566: {
567: if (strcaseeq(value, "1") ||
568: strcaseeq(value, "yes") ||
569: strcaseeq(value, "true") ||
570: strcaseeq(value, "enabled"))
571: {
572: return TRUE;
573: }
574: else if (strcaseeq(value, "0") ||
575: strcaseeq(value, "no") ||
576: strcaseeq(value, "false") ||
577: strcaseeq(value, "disabled"))
578: {
579: return FALSE;
580: }
581: }
582: return def;
583: }
584:
585: METHOD(settings_t, get_bool, bool,
586: private_settings_t *this, char *key, int def, ...)
587: {
588: char *value;
589: va_list args;
590:
591: /* we can't use bool for def due to this call */
592: va_start(args, def);
593: value = find_value(this, this->top, key, args);
594: va_end(args);
595: return settings_value_as_bool(value, def);
596: }
597:
598: /**
599: * Described in header
600: */
601: inline int settings_value_as_int(char *value, int def)
602: {
603: int intval;
604: char *end;
605: int base = 10;
606:
607: if (value)
608: {
609: errno = 0;
610: if (value[0] == '0' && value[1] == 'x')
611: { /* manually detect 0x prefix as we want to avoid octal encoding */
612: base = 16;
613: }
614: intval = strtoul(value, &end, base);
615: if (errno == 0 && *end == 0 && end != value)
616: {
617: return intval;
618: }
619: }
620: return def;
621: }
622:
623: METHOD(settings_t, get_int, int,
624: private_settings_t *this, char *key, int def, ...)
625: {
626: char *value;
627: va_list args;
628:
629: va_start(args, def);
630: value = find_value(this, this->top, key, args);
631: va_end(args);
632: return settings_value_as_int(value, def);
633: }
634:
635: /**
636: * Described in header
637: */
638: inline uint64_t settings_value_as_uint64(char *value, uint64_t def)
639: {
640: uint64_t intval;
641: char *end;
642: int base = 10;
643:
644: if (value)
645: {
646: errno = 0;
647: if (value[0] == '0' && value[1] == 'x')
648: { /* manually detect 0x prefix as we want to avoid octal encoding */
649: base = 16;
650: }
651: intval = strtoull(value, &end, base);
652: if (errno == 0 && *end == 0 && end != value)
653: {
654: return intval;
655: }
656: }
657: return def;
658: }
659:
660: /**
661: * Described in header
662: */
663: inline double settings_value_as_double(char *value, double def)
664: {
665: double dval;
666: char *end;
667:
668: if (value)
669: {
670: errno = 0;
671: dval = strtod(value, &end);
672: if (errno == 0 && *end == 0 && end != value)
673: {
674: return dval;
675: }
676: }
677: return def;
678: }
679:
680: METHOD(settings_t, get_double, double,
681: private_settings_t *this, char *key, double def, ...)
682: {
683: char *value;
684: va_list args;
685:
686: va_start(args, def);
687: value = find_value(this, this->top, key, args);
688: va_end(args);
689: return settings_value_as_double(value, def);
690: }
691:
692: /**
693: * Described in header
694: */
695: inline uint32_t settings_value_as_time(char *value, uint32_t def)
696: {
697: time_t val;
698:
699: if (timespan_from_string(value, NULL, &val))
700: {
701: return val;
702: }
703: return def;
704: }
705:
706: METHOD(settings_t, get_time, uint32_t,
707: private_settings_t *this, char *key, uint32_t def, ...)
708: {
709: char *value;
710: va_list args;
711:
712: va_start(args, def);
713: value = find_value(this, this->top, key, args);
714: va_end(args);
715: return settings_value_as_time(value, def);
716: }
717:
718: METHOD(settings_t, set_str, void,
719: private_settings_t *this, char *key, char *value, ...)
720: {
721: va_list args;
722: va_start(args, value);
723: set_value(this, this->top, key, args, value);
724: va_end(args);
725: }
726:
727: METHOD(settings_t, set_bool, void,
728: private_settings_t *this, char *key, int value, ...)
729: {
730: va_list args;
731: /* we can't use bool for value due to this call */
732: va_start(args, value);
733: set_value(this, this->top, key, args, value ? "1" : "0");
734: va_end(args);
735: }
736:
737: METHOD(settings_t, set_int, void,
738: private_settings_t *this, char *key, int value, ...)
739: {
740: char val[16];
741: va_list args;
742: va_start(args, value);
743: if (snprintf(val, sizeof(val), "%d", value) < sizeof(val))
744: {
745: set_value(this, this->top, key, args, val);
746: }
747: va_end(args);
748: }
749:
750: METHOD(settings_t, set_double, void,
751: private_settings_t *this, char *key, double value, ...)
752: {
753: char val[64];
754: va_list args;
755: va_start(args, value);
756: if (snprintf(val, sizeof(val), "%f", value) < sizeof(val))
757: {
758: set_value(this, this->top, key, args, val);
759: }
760: va_end(args);
761: }
762:
763: METHOD(settings_t, set_time, void,
764: private_settings_t *this, char *key, uint32_t value, ...)
765: {
766: char val[16];
767: va_list args;
768: va_start(args, value);
769: if (snprintf(val, sizeof(val), "%u", value) < sizeof(val))
770: {
771: set_value(this, this->top, key, args, val);
772: }
773: va_end(args);
774: }
775:
776: METHOD(settings_t, set_default_str, bool,
777: private_settings_t *this, char *key, char *value, ...)
778: {
779: char *old;
780: va_list args;
781:
782: va_start(args, value);
783: old = find_value(this, this->top, key, args);
784: va_end(args);
785:
786: if (!old)
787: {
788: va_start(args, value);
789: set_value(this, this->top, key, args, value);
790: va_end(args);
791: return TRUE;
792: }
793: return FALSE;
794: }
795:
796: /**
797: * Data for enumerators
798: */
799: typedef struct {
800: /** settings_t instance */
801: private_settings_t *settings;
802: /** sections to enumerate */
803: array_t *sections;
804: /** sections/keys that were already enumerated */
805: hashtable_t *seen;
806: } enumerator_data_t;
807:
808: CALLBACK(enumerator_destroy, void,
809: enumerator_data_t *this)
810: {
811: this->settings->lock->unlock(this->settings->lock);
812: this->seen->destroy(this->seen);
813: array_destroy(this->sections);
814: free(this);
815: }
816:
817: CALLBACK(section_filter, bool,
818: hashtable_t *seen, enumerator_t *orig, va_list args)
819: {
820: section_t *section;
821: char **out;
822:
823: VA_ARGS_VGET(args, out);
824:
825: while (orig->enumerate(orig, §ion))
826: {
827: if (seen->get(seen, section->name))
828: {
829: continue;
830: }
831: *out = section->name;
832: seen->put(seen, section->name, section->name);
833: return TRUE;
834: }
835: return FALSE;
836: }
837:
838: /**
839: * Enumerate sections of the given section
840: */
841: static enumerator_t *section_enumerator(section_t *section,
842: enumerator_data_t *data)
843: {
844: return enumerator_create_filter(
845: array_create_enumerator(section->sections_order),
846: section_filter, data->seen, NULL);
847: }
848:
849: METHOD(settings_t, create_section_enumerator, enumerator_t*,
850: private_settings_t *this, char *key, ...)
851: {
852: enumerator_data_t *data;
853: array_t *sections = NULL;
854: va_list args;
855:
856: this->lock->read_lock(this->lock);
857: va_start(args, key);
858: sections = find_sections(this, this->top, key, args, §ions);
859: va_end(args);
860:
861: if (!sections)
862: {
863: this->lock->unlock(this->lock);
864: return enumerator_create_empty();
865: }
866: INIT(data,
867: .settings = this,
868: .sections = sections,
869: .seen = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
870: );
871: return enumerator_create_nested(array_create_enumerator(sections),
872: (void*)section_enumerator, data, enumerator_destroy);
873: }
874:
875: CALLBACK(kv_filter, bool,
876: hashtable_t *seen, enumerator_t *orig, va_list args)
877: {
878: kv_t *kv;
879: char **key, **value;
880:
881: VA_ARGS_VGET(args, key, value);
882:
883: while (orig->enumerate(orig, &kv))
884: {
885: if (seen->get(seen, kv->key))
886: {
887: continue;
888: }
889: seen->put(seen, kv->key, kv->key);
890: if (!kv->value)
891: {
892: continue;
893: }
894: *key = kv->key;
895: *value = kv->value;
896: return TRUE;
897: }
898: return FALSE;
899: }
900:
901: /**
902: * Enumerate key/value pairs of the given section
903: */
904: static enumerator_t *kv_enumerator(section_t *section, enumerator_data_t *data)
905: {
906: return enumerator_create_filter(array_create_enumerator(section->kv_order),
907: kv_filter, data->seen, NULL);
908: }
909:
910: METHOD(settings_t, create_key_value_enumerator, enumerator_t*,
911: private_settings_t *this, char *key, ...)
912: {
913: enumerator_data_t *data;
914: array_t *sections = NULL;
915: va_list args;
916:
917: this->lock->read_lock(this->lock);
918: va_start(args, key);
919: sections = find_sections(this, this->top, key, args, §ions);
920: va_end(args);
921:
922: if (!sections)
923: {
924: this->lock->unlock(this->lock);
925: return enumerator_create_empty();
926: }
927: INIT(data,
928: .settings = this,
929: .sections = sections,
930: .seen = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
931: );
932: return enumerator_create_nested(array_create_enumerator(sections),
933: (void*)kv_enumerator, data, (void*)enumerator_destroy);
934: }
935:
936: METHOD(settings_t, add_fallback, void,
937: private_settings_t *this, const char *key, const char *fallback, ...)
938: {
939: section_t *section;
940: va_list args;
941: char buf[512];
942:
943: this->lock->write_lock(this->lock);
944: va_start(args, fallback);
945: section = ensure_section(this, this->top, key, args);
946: va_end(args);
947:
948: va_start(args, fallback);
949: if (section && vsnprintf(buf, sizeof(buf), fallback, args) < sizeof(buf))
950: {
951: settings_reference_add(section, strdup(buf), TRUE);
952: }
953: va_end(args);
954: this->lock->unlock(this->lock);
955: }
956:
957: /**
958: * Load settings from files matching the given file pattern or from a string.
959: * All files (even included ones) have to be loaded successfully.
960: */
961: static section_t *load_internal(char *pattern, bool string)
962: {
963: section_t *section;
964: bool loaded;
965:
966: if (pattern == NULL || !pattern[0])
967: {
968: return settings_section_create(NULL);
969: }
970:
971: section = settings_section_create(NULL);
972: loaded = string ? settings_parser_parse_string(section, pattern) :
973: settings_parser_parse_file(section, pattern);
974: if (!loaded)
975: {
976: settings_section_destroy(section, NULL);
977: section = NULL;
978: }
979: return section;
980: }
981:
982: /**
983: * Add sections and values in "section" relative to "parent".
984: * If merge is FALSE the contents of parent are replaced with the parsed
985: * contents, otherwise they are merged together.
986: *
987: * Releases the write lock and destroys the given section.
988: * If parent is NULL this is all that happens.
989: */
990: static bool extend_section(private_settings_t *this, section_t *parent,
991: section_t *section, bool merge)
992: {
993: if (parent)
994: {
995: settings_section_extend(parent, section, this->contents, !merge);
996: }
997: this->lock->unlock(this->lock);
998: settings_section_destroy(section, NULL);
999: return parent != NULL;
1000: }
1001:
1002: METHOD(settings_t, load_files, bool,
1003: private_settings_t *this, char *pattern, bool merge)
1004: {
1005: section_t *section;
1006:
1007: section = load_internal(pattern, FALSE);
1008: if (!section)
1009: {
1010: return FALSE;
1011: }
1012:
1013: this->lock->write_lock(this->lock);
1014: return extend_section(this, this->top, section, merge);
1015: }
1016:
1017: METHOD(settings_t, load_files_section, bool,
1018: private_settings_t *this, char *pattern, bool merge, char *key, ...)
1019: {
1020: section_t *section, *parent;
1021: va_list args;
1022:
1023: section = load_internal(pattern, FALSE);
1024: if (!section)
1025: {
1026: return FALSE;
1027: }
1028:
1029: this->lock->write_lock(this->lock);
1030:
1031: va_start(args, key);
1032: parent = ensure_section(this, this->top, key, args);
1033: va_end(args);
1034:
1035: return extend_section(this, parent, section, merge);
1036: }
1037:
1038: METHOD(settings_t, load_string, bool,
1039: private_settings_t *this, char *settings, bool merge)
1040: {
1041: section_t *section;
1042:
1043: section = load_internal(settings, TRUE);
1044: if (!section)
1045: {
1046: return FALSE;
1047: }
1048:
1049: this->lock->write_lock(this->lock);
1050: return extend_section(this, this->top, section, merge);
1051: }
1052:
1053: METHOD(settings_t, load_string_section, bool,
1054: private_settings_t *this, char *settings, bool merge, char *key, ...)
1055: {
1056: section_t *section, *parent;
1057: va_list args;
1058:
1059: section = load_internal(settings, TRUE);
1060: if (!section)
1061: {
1062: return FALSE;
1063: }
1064:
1065: this->lock->write_lock(this->lock);
1066:
1067: va_start(args, key);
1068: parent = ensure_section(this, this->top, key, args);
1069: va_end(args);
1070:
1071: return extend_section(this, parent, section, merge);
1072: }
1073:
1074: METHOD(settings_t, destroy, void,
1075: private_settings_t *this)
1076: {
1077: settings_section_destroy(this->top, NULL);
1078: array_destroy_function(this->contents, (void*)free, NULL);
1079: this->lock->destroy(this->lock);
1080: free(this);
1081: }
1082:
1083: static private_settings_t *settings_create_base()
1084: {
1085: private_settings_t *this;
1086:
1087: INIT(this,
1088: .public = {
1089: .get_str = _get_str,
1090: .get_int = _get_int,
1091: .get_double = _get_double,
1092: .get_time = _get_time,
1093: .get_bool = _get_bool,
1094: .set_str = _set_str,
1095: .set_int = _set_int,
1096: .set_double = _set_double,
1097: .set_time = _set_time,
1098: .set_bool = _set_bool,
1099: .set_default_str = _set_default_str,
1100: .create_section_enumerator = _create_section_enumerator,
1101: .create_key_value_enumerator = _create_key_value_enumerator,
1102: .add_fallback = _add_fallback,
1103: .load_files = _load_files,
1104: .load_files_section = _load_files_section,
1105: .load_string = _load_string,
1106: .load_string_section = _load_string_section,
1107: .destroy = _destroy,
1108: },
1109: .top = settings_section_create(NULL),
1110: .contents = array_create(0, 0),
1111: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
1112: );
1113: return this;
1114: }
1115:
1116: /*
1117: * see header file
1118: */
1119: settings_t *settings_create(char *file)
1120: {
1121: private_settings_t *this = settings_create_base();
1122:
1123: load_files(this, file, FALSE);
1124:
1125: return &this->public;
1126: }
1127:
1128: /*
1129: * see header file
1130: */
1131: settings_t *settings_create_string(char *settings)
1132: {
1133: private_settings_t *this = settings_create_base();
1134:
1135: load_string(this, settings, FALSE);
1136:
1137: return &this->public;
1138: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>