2 * Copyright (C) 2010-2014 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
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>.
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
23 #include <sys/types.h>
29 #include "settings_types.h"
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"
37 typedef struct private_settings_t private_settings_t
;
40 * Parse functions provided by the generated parser.
42 bool settings_parser_parse_file(section_t
*root
, char *name
);
43 bool settings_parser_parse_string(section_t
*root
, char *settings
);
46 * Private data of settings
48 struct private_settings_t
{
61 * Contents of replaced settings (char*)
63 * FIXME: This is required because the pointer returned by get_str()
64 * is not refcounted. Might cause ever increasing usage stats.
69 * Lock to safely access the settings
75 * Print a format key, but consume already processed arguments
77 static bool print_key(char *buf
, int len
, char *start
, char *key
, va_list args
)
86 pos
= memchr(pos
, '%', key
- pos
);
101 va_arg(copy
, enum_name_t
*);
107 DBG1(DBG_CFG
, "settings with %%%c not supported!", *pos
);
112 res
= vsnprintf(buf
, len
, key
, copy
) < len
;
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.
121 static section_t
*find_section_buffered(section_t
*section
,
122 char *start
, char *key
, va_list args
, char *buf
, int len
,
126 section_t
*found
= NULL
;
132 pos
= strchr(key
, '.');
138 if (!print_key(buf
, len
, start
, key
, args
))
146 else if (array_bsearch(section
->sections
, buf
, settings_section_find
,
151 found
= settings_section_create(strdup(buf
));
152 settings_section_add(section
, found
, NULL
);
157 return find_section_buffered(found
, start
, pos
, args
, buf
, len
, ensure
);
163 * Find all sections via a given key considering fallbacks, using buffered key,
166 static void find_sections_buffered(section_t
*section
, char *start
, char *key
,
167 va_list args
, char *buf
, int len
, array_t
**sections
)
169 section_t
*found
= NULL
, *fallback
;
177 pos
= strchr(key
, '.');
182 if (!print_key(buf
, len
, start
, key
, args
))
187 { /* restore so we can follow fallbacks */
196 array_bsearch(section
->sections
, buf
, settings_section_find
, &found
);
202 find_sections_buffered(found
, start
, pos
+1, args
, buf
, len
,
207 array_insert_create(sections
, ARRAY_TAIL
, found
);
208 for (i
= 0; i
< array_count(found
->fallbacks
); i
++)
210 array_get(found
->fallbacks
, i
, &fallback
);
211 array_insert_create(sections
, ARRAY_TAIL
, fallback
);
215 if (section
->fallbacks
)
217 for (i
= 0; i
< array_count(section
->fallbacks
); i
++)
219 array_get(section
->fallbacks
, i
, &fallback
);
220 find_sections_buffered(fallback
, start
, key
, args
, buf
, len
,
227 * Ensure that the section with the given key exists (thread-safe).
229 static section_t
*ensure_section(private_settings_t
*this, section_t
*section
,
230 const char *key
, va_list args
)
232 char buf
[128], keybuf
[512];
235 if (snprintf(keybuf
, sizeof(keybuf
), "%s", key
) >= sizeof(keybuf
))
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
,
243 this->lock
->unlock(this->lock
);
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.
252 static array_t
*find_sections(private_settings_t
*this, section_t
*section
,
253 char *key
, va_list args
)
255 char buf
[128], keybuf
[512];
256 array_t
*sections
= NULL
;
258 if (snprintf(keybuf
, sizeof(keybuf
), "%s", key
) >= sizeof(keybuf
))
262 find_sections_buffered(section
, keybuf
, keybuf
, args
, buf
,
263 sizeof(buf
), §ions
);
268 * Check if the given fallback section already exists
270 static bool fallback_exists(section_t
*section
, section_t
*fallback
)
272 if (section
== fallback
)
276 else if (section
->fallbacks
)
281 for (i
= 0; i
< array_count(section
->fallbacks
); i
++)
283 array_get(section
->fallbacks
, i
, &existing
);
284 if (existing
== fallback
)
294 * Ensure that the section with the given key exists and add the given fallback
295 * section (thread-safe).
297 static void add_fallback_to_section(private_settings_t
*this,
298 section_t
*section
, const char *key
, va_list args
,
301 char buf
[128], keybuf
[512];
304 if (snprintf(keybuf
, sizeof(keybuf
), "%s", key
) >= sizeof(keybuf
))
308 this->lock
->write_lock(this->lock
);
309 found
= find_section_buffered(section
, keybuf
, keybuf
, args
, buf
,
311 if (!fallback_exists(found
, fallback
))
313 /* to ensure sections referred to as fallback are not purged, we create
314 * the array there too */
315 if (!fallback
->fallbacks
)
317 fallback
->fallbacks
= array_create(0, 0);
319 array_insert_create(&found
->fallbacks
, ARRAY_TAIL
, fallback
);
321 this->lock
->unlock(this->lock
);
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
328 * Fallbacks are only considered if "ensure" is FALSE.
330 static kv_t
*find_value_buffered(section_t
*section
, char *start
, char *key
,
331 va_list args
, char *buf
, int len
, bool ensure
)
336 section_t
*found
= NULL
;
343 pos
= strchr(key
, '.');
347 if (!print_key(buf
, len
, start
, key
, args
))
351 /* restore so we can retry for fallbacks */
357 else if (array_bsearch(section
->sections
, buf
, settings_section_find
,
362 found
= settings_section_create(strdup(buf
));
363 settings_section_add(section
, found
, NULL
);
368 kv
= find_value_buffered(found
, start
, pos
+1, args
, buf
, len
,
371 if (!kv
&& !ensure
&& section
->fallbacks
)
373 for (i
= 0; !kv
&& i
< array_count(section
->fallbacks
); i
++)
375 array_get(section
->fallbacks
, i
, &found
);
376 kv
= find_value_buffered(found
, start
, key
, args
, buf
, len
,
383 if (!print_key(buf
, len
, start
, key
, args
))
387 if (array_bsearch(section
->kv
, buf
, settings_kv_find
, &kv
) == -1)
391 kv
= settings_kv_create(strdup(buf
), NULL
);
392 settings_kv_add(section
, kv
, NULL
);
394 else if (section
->fallbacks
)
396 for (i
= 0; !kv
&& i
< array_count(section
->fallbacks
); i
++)
398 array_get(section
->fallbacks
, i
, &found
);
399 kv
= find_value_buffered(found
, start
, key
, args
, buf
, len
,
409 * Find the string value for a key (thread-safe).
411 static char *find_value(private_settings_t
*this, section_t
*section
,
412 char *key
, va_list args
)
414 char buf
[128], keybuf
[512], *value
= NULL
;
417 if (snprintf(keybuf
, sizeof(keybuf
), "%s", key
) >= sizeof(keybuf
))
421 this->lock
->read_lock(this->lock
);
422 kv
= find_value_buffered(section
, keybuf
, keybuf
, args
, buf
, sizeof(buf
),
428 this->lock
->unlock(this->lock
);
433 * Set a value to a copy of the given string (thread-safe).
435 static void set_value(private_settings_t
*this, section_t
*section
,
436 char *key
, va_list args
, char *value
)
438 char buf
[128], keybuf
[512];
441 if (snprintf(keybuf
, sizeof(keybuf
), "%s", key
) >= sizeof(keybuf
))
445 this->lock
->write_lock(this->lock
);
446 kv
= find_value_buffered(section
, keybuf
, keybuf
, args
, buf
, sizeof(buf
),
450 settings_kv_set(kv
, strdupnull(value
), this->contents
);
452 this->lock
->unlock(this->lock
);
455 METHOD(settings_t
, get_str
, char*,
456 private_settings_t
*this, char *key
, char *def
, ...)
462 value
= find_value(this, this->top
, key
, args
);
472 * Described in header
474 inline bool settings_value_as_bool(char *value
, bool def
)
478 if (strcaseeq(value
, "1") ||
479 strcaseeq(value
, "yes") ||
480 strcaseeq(value
, "true") ||
481 strcaseeq(value
, "enabled"))
485 else if (strcaseeq(value
, "0") ||
486 strcaseeq(value
, "no") ||
487 strcaseeq(value
, "false") ||
488 strcaseeq(value
, "disabled"))
496 METHOD(settings_t
, get_bool
, bool,
497 private_settings_t
*this, char *key
, bool def
, ...)
503 value
= find_value(this, this->top
, key
, args
);
505 return settings_value_as_bool(value
, def
);
509 * Described in header
511 inline int settings_value_as_int(char *value
, int def
)
519 intval
= strtol(value
, &end
, 10);
520 if (errno
== 0 && *end
== 0 && end
!= value
)
528 METHOD(settings_t
, get_int
, int,
529 private_settings_t
*this, char *key
, int def
, ...)
535 value
= find_value(this, this->top
, key
, args
);
537 return settings_value_as_int(value
, def
);
541 * Described in header
543 inline uint64_t settings_value_as_uint64(char *value
, uint64_t def
)
552 if (value
[0] == '0' && value
[1] == 'x')
553 { /* manually detect 0x prefix as we want to avoid octal encoding */
556 intval
= strtoull(value
, &end
, base
);
557 if (errno
== 0 && *end
== 0 && end
!= value
)
566 * Described in header
568 inline double settings_value_as_double(char *value
, double def
)
576 dval
= strtod(value
, &end
);
577 if (errno
== 0 && *end
== 0 && end
!= value
)
585 METHOD(settings_t
, get_double
, double,
586 private_settings_t
*this, char *key
, double def
, ...)
592 value
= find_value(this, this->top
, key
, args
);
594 return settings_value_as_double(value
, def
);
598 * Described in header
600 inline uint32_t settings_value_as_time(char *value
, uint32_t def
)
607 timeval
= strtoul(value
, &endptr
, 10);
614 while (isspace(*endptr
))
620 case 'd': /* time in days */
621 timeval
*= 24 * 3600;
623 case 'h': /* time in hours */
626 case 'm': /* time in minutes */
629 case 's': /* time in seconds */
641 METHOD(settings_t
, get_time
, uint32_t,
642 private_settings_t
*this, char *key
, uint32_t def
, ...)
648 value
= find_value(this, this->top
, key
, args
);
650 return settings_value_as_time(value
, def
);
653 METHOD(settings_t
, set_str
, void,
654 private_settings_t
*this, char *key
, char *value
, ...)
657 va_start(args
, value
);
658 set_value(this, this->top
, key
, args
, value
);
662 METHOD(settings_t
, set_bool
, void,
663 private_settings_t
*this, char *key
, bool value
, ...)
666 va_start(args
, value
);
667 set_value(this, this->top
, key
, args
, value ?
"1" : "0");
671 METHOD(settings_t
, set_int
, void,
672 private_settings_t
*this, char *key
, int value
, ...)
676 va_start(args
, value
);
677 if (snprintf(val
, sizeof(val
), "%d", value
) < sizeof(val
))
679 set_value(this, this->top
, key
, args
, val
);
684 METHOD(settings_t
, set_double
, void,
685 private_settings_t
*this, char *key
, double value
, ...)
689 va_start(args
, value
);
690 if (snprintf(val
, sizeof(val
), "%f", value
) < sizeof(val
))
692 set_value(this, this->top
, key
, args
, val
);
697 METHOD(settings_t
, set_time
, void,
698 private_settings_t
*this, char *key
, uint32_t value
, ...)
702 va_start(args
, value
);
703 if (snprintf(val
, sizeof(val
), "%u", value
) < sizeof(val
))
705 set_value(this, this->top
, key
, args
, val
);
710 METHOD(settings_t
, set_default_str
, bool,
711 private_settings_t
*this, char *key
, char *value
, ...)
716 va_start(args
, value
);
717 old
= find_value(this, this->top
, key
, args
);
722 va_start(args
, value
);
723 set_value(this, this->top
, key
, args
, value
);
731 * Data for enumerators
734 /** settings_t instance */
735 private_settings_t
*settings
;
736 /** sections to enumerate */
738 /** sections/keys that were already enumerated */
743 * Destroy enumerator data
745 static void enumerator_destroy(enumerator_data_t
*this)
747 this->settings
->lock
->unlock(this->settings
->lock
);
748 this->seen
->destroy(this->seen
);
749 array_destroy(this->sections
);
754 * Enumerate section names, not sections
756 static bool section_filter(hashtable_t
*seen
, section_t
**in
, char **out
)
759 if (seen
->get(seen
, *out
))
763 seen
->put(seen
, *out
, *out
);
768 * Enumerate sections of the given section
770 static enumerator_t
*section_enumerator(section_t
*section
,
771 enumerator_data_t
*data
)
773 return enumerator_create_filter(
774 array_create_enumerator(section
->sections_order
),
775 (void*)section_filter
, data
->seen
, NULL
);
778 METHOD(settings_t
, create_section_enumerator
, enumerator_t
*,
779 private_settings_t
*this, char *key
, ...)
781 enumerator_data_t
*data
;
785 this->lock
->read_lock(this->lock
);
787 sections
= find_sections(this, this->top
, key
, args
);
792 this->lock
->unlock(this->lock
);
793 return enumerator_create_empty();
797 .sections
= sections
,
798 .seen
= hashtable_create(hashtable_hash_str
, hashtable_equals_str
, 8),
800 return enumerator_create_nested(array_create_enumerator(sections
),
801 (void*)section_enumerator
, data
, (void*)enumerator_destroy
);
805 * Enumerate key and values, not kv_t entries
807 static bool kv_filter(hashtable_t
*seen
, kv_t
**in
, char **key
,
808 void *none
, char **value
)
811 if (seen
->get(seen
, *key
) || !(*in
)->value
)
815 *value
= (*in
)->value
;
816 seen
->put(seen
, *key
, *key
);
821 * Enumerate key/value pairs of the given section
823 static enumerator_t
*kv_enumerator(section_t
*section
, enumerator_data_t
*data
)
825 return enumerator_create_filter(array_create_enumerator(section
->kv_order
),
826 (void*)kv_filter
, data
->seen
, NULL
);
829 METHOD(settings_t
, create_key_value_enumerator
, enumerator_t
*,
830 private_settings_t
*this, char *key
, ...)
832 enumerator_data_t
*data
;
836 this->lock
->read_lock(this->lock
);
838 sections
= find_sections(this, this->top
, key
, args
);
843 this->lock
->unlock(this->lock
);
844 return enumerator_create_empty();
848 .sections
= sections
,
849 .seen
= hashtable_create(hashtable_hash_str
, hashtable_equals_str
, 8),
851 return enumerator_create_nested(array_create_enumerator(sections
),
852 (void*)kv_enumerator
, data
, (void*)enumerator_destroy
);
855 METHOD(settings_t
, add_fallback
, void,
856 private_settings_t
*this, const char *key
, const char *fallback
, ...)
861 /* find/create the fallback */
862 va_start(args
, fallback
);
863 section
= ensure_section(this, this->top
, fallback
, args
);
866 va_start(args
, fallback
);
867 add_fallback_to_section(this, this->top
, key
, args
, section
);
872 * Load settings from files matching the given file pattern or from a string.
873 * All sections and values are added relative to "parent".
874 * All files (even included ones) have to be loaded successfully.
875 * If merge is FALSE the contents of parent are replaced with the parsed
876 * contents, otherwise they are merged together.
878 static bool load_internal(private_settings_t
*this, section_t
*parent
,
879 char *pattern
, bool merge
, bool string
)
884 if (pattern
== NULL
|| !pattern
[0])
885 { /* TODO: Clear parent if merge is FALSE? */
889 section
= settings_section_create(NULL
);
890 loaded
= string ?
settings_parser_parse_string(section
, pattern
) :
891 settings_parser_parse_file(section
, pattern
);
894 settings_section_destroy(section
, NULL
);
898 this->lock
->write_lock(this->lock
);
899 settings_section_extend(parent
, section
, this->contents
, !merge
);
900 this->lock
->unlock(this->lock
);
902 settings_section_destroy(section
, NULL
);
906 METHOD(settings_t
, load_files
, bool,
907 private_settings_t
*this, char *pattern
, bool merge
)
909 return load_internal(this, this->top
, pattern
, merge
, FALSE
);
912 METHOD(settings_t
, load_files_section
, bool,
913 private_settings_t
*this, char *pattern
, bool merge
, char *key
, ...)
919 section
= ensure_section(this, this->top
, key
, args
);
926 return load_internal(this, section
, pattern
, merge
, FALSE
);
929 METHOD(settings_t
, load_string
, bool,
930 private_settings_t
*this, char *settings
, bool merge
)
932 return load_internal(this, this->top
, settings
, merge
, TRUE
);
935 METHOD(settings_t
, load_string_section
, bool,
936 private_settings_t
*this, char *settings
, bool merge
, char *key
, ...)
942 section
= ensure_section(this, this->top
, key
, args
);
949 return load_internal(this, section
, settings
, merge
, TRUE
);
952 METHOD(settings_t
, destroy
, void,
953 private_settings_t
*this)
955 settings_section_destroy(this->top
, NULL
);
956 array_destroy_function(this->contents
, (void*)free
, NULL
);
957 this->lock
->destroy(this->lock
);
961 static private_settings_t
*settings_create_base()
963 private_settings_t
*this;
969 .get_double
= _get_double
,
970 .get_time
= _get_time
,
971 .get_bool
= _get_bool
,
974 .set_double
= _set_double
,
975 .set_time
= _set_time
,
976 .set_bool
= _set_bool
,
977 .set_default_str
= _set_default_str
,
978 .create_section_enumerator
= _create_section_enumerator
,
979 .create_key_value_enumerator
= _create_key_value_enumerator
,
980 .add_fallback
= _add_fallback
,
981 .load_files
= _load_files
,
982 .load_files_section
= _load_files_section
,
983 .load_string
= _load_string
,
984 .load_string_section
= _load_string_section
,
987 .top
= settings_section_create(NULL
),
988 .contents
= array_create(0, 0),
989 .lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
997 settings_t
*settings_create(char *file
)
999 private_settings_t
*this = settings_create_base();
1001 load_files(this, file
, FALSE
);
1003 return &this->public;
1009 settings_t
*settings_create_string(char *settings
)
1011 private_settings_t
*this = settings_create_base();
1013 load_string(this, settings
, FALSE
);
1015 return &this->public;