Fixed settings lookup if the section/key contains dots, second try
authorMartin Willi <martin@revosec.ch>
Thu, 29 Jul 2010 10:00:21 +0000 (12:00 +0200)
committerMartin Willi <martin@revosec.ch>
Mon, 9 Aug 2010 12:30:16 +0000 (14:30 +0200)
src/libstrongswan/settings.c
src/libstrongswan/settings.h

index 610e2b8..d85abb1 100644 (file)
@@ -88,11 +88,60 @@ struct kv_t {
 };
 
 /**
- * find a section by a given key
+ * Print a format key, but consume already processed arguments
  */
-static section_t *find_section(section_t *section, char *key, va_list args)
+static bool print_key(char *buf, int len, char *start, char *key, va_list args)
 {
-       char name[512], *pos;
+       va_list copy;
+       bool res;
+       char *pos;
+
+       va_copy(copy, args);
+       while (start < key)
+       {
+               pos = strchr(start, '%');
+               if (!pos)
+               {
+                       start += strlen(start) + 1;
+                       continue;
+               }
+               pos++;
+               switch (*pos)
+               {
+                       case 'd':
+                               va_arg(copy, int);
+                               break;
+                       case 's':
+                               va_arg(copy, char*);
+                               break;
+                       case 'N':
+                               va_arg(copy, enum_name_t*);
+                               va_arg(copy, int);
+                               break;
+                       case '%':
+                               break;
+                       default:
+                               DBG1(DBG_CFG, "settings with %%%c not supported!", *pos);
+                               break;
+               }
+               start = pos;
+               if (*start)
+               {
+                       start++;
+               }
+       }
+       res = vsnprintf(buf, len, key, copy) < len;
+       va_end(copy);
+       return res;
+}
+
+/**
+ * find a section by a given key, using buffered key, reusable buffer
+ */
+static section_t *find_section_buffered(section_t *section,
+                                       char *start, char *key, va_list args, char *buf, int len)
+{
+       char *pos;
        enumerator_t *enumerator;
        section_t *current, *found = NULL;
 
@@ -100,21 +149,20 @@ static section_t *find_section(section_t *section, char *key, va_list args)
        {
                return NULL;
        }
-       if (vsnprintf(name, sizeof(name), key, args) >= sizeof(name))
-       {
-               return NULL;
-       }
-
-       pos = strchr(name, '.');
+       pos = strchr(key, '.');
        if (pos)
        {
                *pos = '\0';
                pos++;
        }
+       if (!print_key(buf, len, start, key, args))
+       {
+               return NULL;
+       }
        enumerator = section->sections->create_enumerator(section->sections);
        while (enumerator->enumerate(enumerator, &current))
        {
-               if (streq(current->name, name))
+               if (streq(current->name, buf))
                {
                        found = current;
                        break;
@@ -123,37 +171,55 @@ static section_t *find_section(section_t *section, char *key, va_list args)
        enumerator->destroy(enumerator);
        if (found && pos)
        {
-               return find_section(found, pos, args);
+               return find_section_buffered(found, start, pos, args, buf, len);
        }
        return found;
 }
 
-static char *find_value(section_t *section, char *key, va_list args)
+/**
+ * find a section by a given key
+ */
+static section_t *find_section(section_t *section, char *key, va_list args)
 {
-       char name[512], *pos, *value = NULL;
-       enumerator_t *enumerator;
-       kv_t *kv;
-       section_t *current, *found = NULL;
+       char buf[128], keybuf[512];
 
-       if (section == NULL)
+       if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
        {
                return NULL;
        }
+       return find_section_buffered(section, keybuf, keybuf, args, buf, sizeof(buf));
+}
+
+/**
+ * Find the string value for a key, using buffered key, reusable buffer
+ */
+static char *find_value_buffered(section_t *section,
+                                       char *start, char *key, va_list args, char *buf, int len)
+{
+       char *pos, *value = NULL;
+       enumerator_t *enumerator;
+       kv_t *kv;
+       section_t *current, *found = NULL;
 
-       if (vsnprintf(name, sizeof(name), key, args) >= sizeof(name))
+       if (section == NULL)
        {
                return NULL;
        }
 
-       pos = strchr(name, '.');
+       pos = strchr(key, '.');
        if (pos)
        {
                *pos = '\0';
                pos++;
+
+               if (!print_key(buf, len, start, key, args))
+               {
+                       return NULL;
+               }
                enumerator = section->sections->create_enumerator(section->sections);
                while (enumerator->enumerate(enumerator, &current))
                {
-                       if (streq(current->name, name))
+                       if (streq(current->name, buf))
                        {
                                found = current;
                                break;
@@ -162,15 +228,19 @@ static char *find_value(section_t *section, char *key, va_list args)
                enumerator->destroy(enumerator);
                if (found)
                {
-                       return find_value(found, pos, args);
+                       return find_value_buffered(found, start, pos, args, buf, len);
                }
        }
        else
        {
+               if (!print_key(buf, len, start, key, args))
+               {
+                       return NULL;
+               }
                enumerator = section->kv->create_enumerator(section->kv);
                while (enumerator->enumerate(enumerator, &kv))
                {
-                       if (streq(kv->key, name))
+                       if (streq(kv->key, buf))
                        {
                                value = kv->value;
                                break;
@@ -182,6 +252,20 @@ static char *find_value(section_t *section, char *key, va_list args)
 }
 
 /**
+ * Find the string value for a key
+ */
+static char *find_value(section_t *section, char *key, va_list args)
+{
+       char buf[128], keybuf[512];
+
+       if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
+       {
+               return NULL;
+       }
+       return find_value_buffered(section, keybuf, keybuf, args, buf, sizeof(buf));
+}
+
+/**
  * Implementation of settings_t.get.
  */
 static char* get_str(private_settings_t *this, char *key, char *def, ...)
index f274fb3..486de8d 100644 (file)
@@ -49,8 +49,11 @@ typedef struct settings_t settings_t;
        }
        @endcode
  *
- * The values are accesses using the get() functions using dotted keys, e.g.
+ * The values are accessed using the get() functions using dotted keys, e.g.
  *   section-one.subsection.othervalue
+ *
+ * Currently only a limited set of printf format specifiers are supported
+ * (namely %s, %d and %N, see implementation for details).
  */
 struct settings_t {