settings: Add support for hex integers (0x prefix) via get_int()
[strongswan.git] / src / libstrongswan / settings / settings.c
index c6ebe89..b00e819 100644 (file)
@@ -23,6 +23,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <ctype.h>
 
 #include "settings.h"
 #include "settings_types.h"
 typedef struct private_settings_t private_settings_t;
 
 /**
- * Parse function provided by the generated parser.
+ * Parse functions provided by the generated parser.
  */
 bool settings_parser_parse_file(section_t *root, char *name);
+bool settings_parser_parse_string(section_t *root, char *settings);
 
 /**
  * Private data of settings
@@ -69,40 +71,6 @@ struct private_settings_t {
        rwlock_t *lock;
 };
 
-static void kv_destroy(kv_t *kv, int idx, array_t *contents)
-{
-       settings_kv_destroy(kv, contents);
-}
-
-/**
- * Purge contents of a section, returns if section can be safely removed.
- */
-static bool section_purge(section_t *this, array_t *contents)
-{
-       section_t *current;
-       int i, idx;
-
-       array_destroy_function(this->kv, (void*)kv_destroy, contents);
-       this->kv = NULL;
-       array_destroy(this->kv_order);
-       this->kv_order = NULL;
-       /* we ensure sections used as fallback, or configured with fallbacks (or
-        * having any such subsections) are not removed */
-       for (i = array_count(this->sections_order) - 1; i >= 0; i--)
-       {
-               array_get(this->sections, i, &current);
-               if (section_purge(current, contents))
-               {
-                       array_remove(this->sections_order, i, NULL);
-                       idx = array_bsearch(this->sections, current->name,
-                                                               settings_section_find, NULL);
-                       array_remove(this->sections, idx, NULL);
-                       settings_section_destroy(current, contents);
-               }
-       }
-       return !this->fallbacks && !array_count(this->sections);
-}
-
 /**
  * Print a format key, but consume already processed arguments
  */
@@ -543,11 +511,18 @@ METHOD(settings_t, get_bool, bool,
 inline int settings_value_as_int(char *value, int def)
 {
        int intval;
+       char *end;
+       int base = 10;
+
        if (value)
        {
                errno = 0;
-               intval = strtol(value, NULL, 10);
-               if (errno == 0)
+               if (value[0] == '0' && value[1] == 'x')
+               {       /* manually detect 0x prefix as we want to avoid octal encoding */
+                       base = 16;
+               }
+               intval = strtol(value, &end, base);
+               if (errno == 0 && *end == 0 && end != value)
                {
                        return intval;
                }
@@ -570,14 +545,41 @@ METHOD(settings_t, get_int, int,
 /**
  * Described in header
  */
+inline uint64_t settings_value_as_uint64(char *value, uint64_t def)
+{
+       uint64_t intval;
+       char *end;
+       int base = 10;
+
+       if (value)
+       {
+               errno = 0;
+               if (value[0] == '0' && value[1] == 'x')
+               {       /* manually detect 0x prefix as we want to avoid octal encoding */
+                       base = 16;
+               }
+               intval = strtoull(value, &end, base);
+               if (errno == 0 && *end == 0 && end != value)
+               {
+                       return intval;
+               }
+       }
+       return def;
+}
+
+/**
+ * Described in header
+ */
 inline double settings_value_as_double(char *value, double def)
 {
        double dval;
+       char *end;
+
        if (value)
        {
                errno = 0;
-               dval = strtod(value, NULL);
-               if (errno == 0)
+               dval = strtod(value, &end);
+               if (errno == 0 && *end == 0 && end != value)
                {
                        return dval;
                }
@@ -600,16 +602,24 @@ METHOD(settings_t, get_double, double,
 /**
  * Described in header
  */
-inline u_int32_t settings_value_as_time(char *value, u_int32_t def)
+inline uint32_t settings_value_as_time(char *value, uint32_t def)
 {
        char *endptr;
-       u_int32_t timeval;
+       uint32_t timeval;
        if (value)
        {
                errno = 0;
                timeval = strtoul(value, &endptr, 10);
+               if (endptr == value)
+               {
+                       return def;
+               }
                if (errno == 0)
                {
+                       while (isspace(*endptr))
+                       {
+                               endptr++;
+                       }
                        switch (*endptr)
                        {
                                case 'd':               /* time in days */
@@ -622,8 +632,10 @@ inline u_int32_t settings_value_as_time(char *value, u_int32_t def)
                                        timeval *= 60;
                                        break;
                                case 's':               /* time in seconds */
-                               default:
+                               case '\0':
                                        break;
+                               default:
+                                       return def;
                        }
                        return timeval;
                }
@@ -631,8 +643,8 @@ inline u_int32_t settings_value_as_time(char *value, u_int32_t def)
        return def;
 }
 
-METHOD(settings_t, get_time, u_int32_t,
-       private_settings_t *this, char *key, u_int32_t def, ...)
+METHOD(settings_t, get_time, uint32_t,
+       private_settings_t *this, char *key, uint32_t def, ...)
 {
        char *value;
        va_list args;
@@ -688,7 +700,7 @@ METHOD(settings_t, set_double, void,
 }
 
 METHOD(settings_t, set_time, void,
-       private_settings_t *this, char *key, u_int32_t value, ...)
+       private_settings_t *this, char *key, uint32_t value, ...)
 {
        char val[16];
        va_list args;
@@ -862,40 +874,34 @@ METHOD(settings_t, add_fallback, void,
 }
 
 /**
- * Load settings from files matching the given file pattern.
+ * Load settings from files matching the given file pattern or from a string.
  * All sections and values are added relative to "parent".
  * All files (even included ones) have to be loaded successfully.
  * If merge is FALSE the contents of parent are replaced with the parsed
  * contents, otherwise they are merged together.
  */
-static bool load_files_internal(private_settings_t *this, section_t *parent,
-                                                               char *pattern, bool merge)
+static bool load_internal(private_settings_t *this, section_t *parent,
+                                                 char *pattern, bool merge, bool string)
 {
        section_t *section;
+       bool loaded;
 
-       if (pattern == NULL)
-       {
-#ifdef STRONGSWAN_CONF
-               pattern = STRONGSWAN_CONF;
-#else
-               return FALSE;
-#endif
+       if (pattern == NULL || !pattern[0])
+       {       /* TODO: Clear parent if merge is FALSE? */
+               return TRUE;
        }
 
        section = settings_section_create(NULL);
-       if (!settings_parser_parse_file(section, pattern))
+       loaded = string ? settings_parser_parse_string(section, pattern) :
+                                         settings_parser_parse_file(section, pattern);
+       if (!loaded)
        {
                settings_section_destroy(section, NULL);
                return FALSE;
        }
 
        this->lock->write_lock(this->lock);
-       if (!merge)
-       {
-               section_purge(parent, this->contents);
-       }
-       /* extend parent section */
-       settings_section_extend(parent, section, this->contents);
+       settings_section_extend(parent, section, this->contents, !merge);
        this->lock->unlock(this->lock);
 
        settings_section_destroy(section, NULL);
@@ -905,7 +911,7 @@ static bool load_files_internal(private_settings_t *this, section_t *parent,
 METHOD(settings_t, load_files, bool,
        private_settings_t *this, char *pattern, bool merge)
 {
-       return load_files_internal(this, this->top, pattern, merge);
+       return load_internal(this, this->top, pattern, merge, FALSE);
 }
 
 METHOD(settings_t, load_files_section, bool,
@@ -922,7 +928,30 @@ METHOD(settings_t, load_files_section, bool,
        {
                return FALSE;
        }
-       return load_files_internal(this, section, pattern, merge);
+       return load_internal(this, section, pattern, merge, FALSE);
+}
+
+METHOD(settings_t, load_string, bool,
+       private_settings_t *this, char *settings, bool merge)
+{
+       return load_internal(this, this->top, settings, merge, TRUE);
+}
+
+METHOD(settings_t, load_string_section, bool,
+       private_settings_t *this, char *settings, bool merge, char *key, ...)
+{
+       section_t *section;
+       va_list args;
+
+       va_start(args, key);
+       section = ensure_section(this, this->top, key, args);
+       va_end(args);
+
+       if (!section)
+       {
+               return FALSE;
+       }
+       return load_internal(this, section, settings, merge, TRUE);
 }
 
 METHOD(settings_t, destroy, void,
@@ -934,10 +963,7 @@ METHOD(settings_t, destroy, void,
        free(this);
 }
 
-/*
- * see header file
- */
-settings_t *settings_create(char *file)
+static private_settings_t *settings_create_base()
 {
        private_settings_t *this;
 
@@ -959,14 +985,37 @@ settings_t *settings_create(char *file)
                        .add_fallback = _add_fallback,
                        .load_files = _load_files,
                        .load_files_section = _load_files_section,
+                       .load_string = _load_string,
+                       .load_string_section = _load_string_section,
                        .destroy = _destroy,
                },
                .top = settings_section_create(NULL),
                .contents = array_create(0, 0),
                .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
        );
+       return this;
+}
+
+/*
+ * see header file
+ */
+settings_t *settings_create(char *file)
+{
+       private_settings_t *this = settings_create_base();
 
        load_files(this, file, FALSE);
 
        return &this->public;
 }
+
+/*
+ * see header file
+ */
+settings_t *settings_create_string(char *settings)
+{
+       private_settings_t *this = settings_create_base();
+
+       load_string(this, settings, FALSE);
+
+       return &this->public;
+}