Refactor configuration API and add config option for space separated tokens as value
authorHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Tue, 24 Oct 2017 05:52:16 +0000 (07:52 +0200)
committerHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Tue, 24 Oct 2017 05:52:16 +0000 (07:52 +0200)
12 files changed:
src-api/config/CMakeLists.txt
src-api/config/cfg.c
src-api/config/cfg.h
src-api/config/cfg_cmd.c
src-api/config/cfg_help.c
src-api/config/cfg_help.h
src-api/config/cfg_schema.c
src-api/config/cfg_schema.h
src-api/config/cfg_tobin.c [new file with mode: 0644]
src-api/config/cfg_tobin.h [new file with mode: 0644]
src-api/config/cfg_validate.c
src-api/config/cfg_validate.h

index 549139d..9c1d6ee 100644 (file)
@@ -3,6 +3,7 @@ SET(OONF_CONFIG_SRCS cfg_cmd.c
                       cfg_help.c
                       cfg_io.c
                       cfg_schema.c
+                      cfg_tobin.c
                       cfg_validate.c
                       cfg.c)
 
@@ -11,6 +12,7 @@ SET(OONF_CONFIG_INCLUDES cfg_cmd.h
                          cfg_help.h
                          cfg_io.h
                          cfg_schema.h
+                         cfg_tobin.h
                          cfg_validate.h
                          cfg.h)
 
index 98d22e5..eff415a 100644 (file)
@@ -160,19 +160,38 @@ cfg_avlcmp_keys(const void *p1, const void *p2) {
   return strcasecmp(str1, str2);
 }
 
+/**
+ * Returns an element of a string array for the CHOICE schema entry
+ * @param idx index of the array
+ * @param ptr pointer to the string array
+ * @return element of the string array at the index
+ */
+const char *
+cfg_get_choice_array_value(size_t idx, const void *ptr) {
+  const char * const *string_array;
+
+  string_array = ptr;
+
+  return string_array[idx];
+}
+
+
 /**
  * Looks up the index of a string within a string array
  * @param key pointer to string to be looked up in the array
- * @param array pointer to string pointer array
- * @param array_size number of strings in array
+ * @param callback pointer to the callback that returns choice options
+ * @param choice_count number of choices
+ * @param ptr (optional) pointer for choice callback
  * @return index of the string inside the array, -1 if not found
  */
 int
-cfg_get_choice_index(const char *key, const char **array, size_t array_size) {
+cfg_get_choice_index(const char *key,
+    const char *(*callback)(size_t idx, const void *ptr),
+    size_t choices_count, const void *ptr) {
   size_t i;
 
-  for (i=0; i<array_size; i++) {
-    if (strcasecmp(key, array[i]) == 0) {
+  for (i=0; i<choices_count; i++) {
+    if (strcasecmp(key, callback(i, ptr)) == 0) {
       return (int) i;
     }
   }
index f8bbfae..d9531d6 100644 (file)
@@ -78,7 +78,10 @@ EXPORT void cfg_remove(struct cfg_instance *);
 EXPORT int cfg_append_printable_line(struct autobuf *autobuf, const char *fmt, ...)
   __attribute__ ((format(printf, 2, 3)));
 EXPORT bool cfg_is_allowed_key(const char *key);
-EXPORT int cfg_get_choice_index(const char *value, const char **array, size_t array_size);
+EXPORT const char *cfg_get_choice_array_value(size_t idx, const void *ptr);
+EXPORT int cfg_get_choice_index(const char *key,
+    const char *(*callback)(size_t idx, const void *ptr),
+    size_t choices_count, const void *ptr);
 
 EXPORT int cfg_avlcmp_keys(const void *p1, const void *p2);
 
@@ -104,7 +107,8 @@ cfg_cmp_keys(const char *str1, const char *str2) {
  */
 static INLINE bool
 cfg_get_bool(const char *value) {
-  return cfg_get_choice_index(value, CFGLIST_BOOL_TRUE, ARRAYSIZE(CFGLIST_BOOL_TRUE)) >= 0;
+  return cfg_get_choice_index(value, cfg_get_choice_array_value,
+      ARRAYSIZE(CFGLIST_BOOL_TRUE), CFGLIST_BOOL_TRUE) >= 0;
 }
 
 /**
@@ -114,7 +118,8 @@ cfg_get_bool(const char *value) {
  */
 static INLINE bool
 cfg_is_bool(const char *value) {
-  return cfg_get_choice_index(value, CFGLIST_BOOL, ARRAYSIZE(CFGLIST_BOOL)) >= 0;
+  return cfg_get_choice_index(value, cfg_get_choice_array_value,
+      ARRAYSIZE(CFGLIST_BOOL), CFGLIST_BOOL) >= 0;
 }
 
 /**
index a6099b1..22ef7e9 100644 (file)
@@ -51,6 +51,7 @@
 #include "common/common_types.h"
 #include "config/cfg_io.h"
 #include "config/cfg_cmd.h"
+#include "config/cfg_help.h"
 
 /**
  *  contains data parsing logic */
@@ -347,14 +348,15 @@ cfg_cmd_handle_schema(struct cfg_db *db,
         "(use this command with the types as parameter for more information)\n");
     avl_for_each_element(&db->schema->sections, s_section, _section_node) {
       if (!s_section->_section_node.follower) {
-        cfg_append_printable_line(log, "    %s (%s)%s%s",
+        cfg_append_printable_line(log, CFG_HELP_INDENT_PREFIX "%s (%s)%s%s",
             s_section->type,
             CFG_SCHEMA_SECTIONMODE[s_section->mode],
             s_section->help ? ": " : "",
             s_section->help ? s_section->help : "");
       }
       else if (s_section->help) {
-        cfg_append_printable_line(log, "        %s", s_section->help);
+        cfg_append_printable_line(log,
+            CFG_HELP_INDENT_PREFIX CFG_HELP_INDENT_PREFIX "%s", s_section->help);
       }
     }
     return 0;
@@ -431,14 +433,15 @@ _print_schema_section(struct autobuf *log, struct cfg_db *db, const char *sectio
     }
 
     if (!s_entry_it->_node.follower) {
-      cfg_append_printable_line(log, "    %s%s%s",
+      cfg_append_printable_line(log, CFG_HELP_INDENT_PREFIX "%s%s%s",
           s_entry_it->key.entry,
           strarray_is_empty_c(&s_entry_it->def) ? " (mandatory)" : "",
               s_entry_it->list ? " (list)" : "");
     }
 #if !defined(REMOVE_HELPTEXT)
     if (s_entry_it->help) {
-      cfg_append_printable_line(log, "        %s", s_entry_it->help);
+      cfg_append_printable_line(log,
+          CFG_HELP_INDENT_PREFIX CFG_HELP_INDENT_PREFIX "%s", s_entry_it->help);
     }
 #endif
   }
@@ -461,16 +464,17 @@ _print_schema_entry(struct autobuf *log, struct cfg_db *db,
   avl_for_each_elements_with_key(&db->schema->entries, s_entry_it, _node, s_entry_first, &key) {
     if (s_entry_it == s_entry_first) {
       /* print type/parameter */
-      cfg_append_printable_line(log, "    %s%s%s",
+      cfg_append_printable_line(log, CFG_HELP_INDENT_PREFIX "%s%s%s",
           s_entry_it->key.entry,
           strarray_is_empty_c(&s_entry_it->def) ? " (mandatory)" : "",
               s_entry_it->list ? " (list)" : "");
 
       /* print defaults */
       if (!strarray_is_empty_c(&s_entry_it->def)) {
-        cfg_append_printable_line(log, "    Default value:");
+        cfg_append_printable_line(log, CFG_HELP_INDENT_PREFIX "Default value:");
         strarray_for_each_element(&s_entry_it->def, c_ptr) {
-          cfg_append_printable_line(log, "        '%s'", c_ptr);
+          cfg_append_printable_line(log,
+              CFG_HELP_INDENT_PREFIX CFG_HELP_INDENT_PREFIX "'%s'", c_ptr);
         }
       }
     }
@@ -491,9 +495,10 @@ _print_schema_entry(struct autobuf *log, struct cfg_db *db,
     /* print help text */
     if (s_entry_it->help) {
       if (s_entry_it == s_entry_first) {
-        abuf_puts(log, "    Description:\n");
+        abuf_puts(log, CFG_HELP_INDENT_PREFIX "Description:\n");
       }
-      cfg_append_printable_line(log, "        %s", s_entry_it->help);
+      cfg_append_printable_line(log,
+          CFG_HELP_INDENT_PREFIX CFG_HELP_INDENT_PREFIX "%s", s_entry_it->help);
     }
   }
 #endif
index aa4bfc0..5773f90 100644 (file)
@@ -43,6 +43,8 @@
  * @file
  */
 
+#include <stdio.h>
+
 #include "common/common_types.h"
 #include "common/autobuf.h"
 #include "common/bitmap256.h"
 #include "common/netaddr.h"
 #include "common/netaddr_acl.h"
 
-#include "config/cfg_help.h"
 #include "config/cfg.h"
+#include "config/cfg_help.h"
 
-/*! prefix before help text parameter explanation */
-#define _PREFIX "    "
+static const char *_get_enumerator(char *buffer, size_t length, size_t idx);
 
 /**
  * Produce help text for string with maximum length
@@ -63,7 +64,7 @@
  */
 void
 cfg_help_strlen(struct autobuf *out, size_t len) {
-  cfg_append_printable_line(out, _PREFIX "Parameter must have a maximum"
+  cfg_append_printable_line(out, CFG_HELP_INDENT_PREFIX "Parameter must have a maximum"
       " length of %"PRINTF_SIZE_T_SPECIFIER" characters", len);
 }
 
@@ -75,29 +76,30 @@ cfg_help_strlen(struct autobuf *out, size_t len) {
 void
 cfg_help_printable(struct autobuf *out, size_t len) {
   cfg_help_strlen(out, len);
-  cfg_append_printable_line(out, _PREFIX "Parameter must only contain printable characters.");
+  cfg_append_printable_line(out, CFG_HELP_INDENT_PREFIX "Parameter must only contain printable characters.");
 }
 
 /**
  * Produce help text for a choice of multiple constants
  * @param out output buffer
  * @param preamble true if preamble should be printed
- * @param choices array of string pointers with available choices
- * @param choice_count number of choices in array
+ * @param choices function pointer to retriev text choices
+ * @param choice_count number of choices
  */
 void
 cfg_help_choice(struct autobuf *out, bool preamble,
-    const char **choices, size_t choice_count) {
+    const char *(*callback)(size_t idx, const void *ptr),
+    size_t choice_count, const void *ptr) {
   size_t i;
 
   if (preamble) {
-    cfg_append_printable_line(out, _PREFIX "Parameter must be on of the following list:");
+    cfg_append_printable_line(out, CFG_HELP_INDENT_PREFIX "Parameter must be on of the following list:");
   }
 
   abuf_puts(out, "    ");
   for (i=0; i < choice_count; i++) {
     abuf_appendf(out, "%s'%s'",
-        i==0 ? "" : ", ", choices[i]);
+        i==0 ? "" : ", ", callback(i, ptr));
   }
   abuf_puts(out, "\n");
 }
@@ -125,24 +127,24 @@ cfg_help_int(struct autobuf *out,
 
   if (min > min64) {
     if (max < max64) {
-      cfg_append_printable_line(out, _PREFIX "Parameter must be a %d-byte fractional integer"
+      cfg_append_printable_line(out, CFG_HELP_INDENT_PREFIX "Parameter must be a %d-byte fractional integer"
           " between %s and %s with a maximum of %d fractional digits",
           bytelen, hbuf1.buf, hbuf2.buf, fraction);
     }
     else {
-      cfg_append_printable_line(out, _PREFIX "Parameter must be a %d-byte fractional integer"
+      cfg_append_printable_line(out, CFG_HELP_INDENT_PREFIX "Parameter must be a %d-byte fractional integer"
           " larger or equal than %s with a maximum of %d fractional digits",
           bytelen, hbuf1.buf, fraction);
     }
   }
   else {
     if (max < max64) {
-      cfg_append_printable_line(out, _PREFIX "Parameter must be a %d-byte fractional integer"
+      cfg_append_printable_line(out, CFG_HELP_INDENT_PREFIX "Parameter must be a %d-byte fractional integer"
           " smaller or equal than %s with a maximum of %d fractional digits",
           bytelen, hbuf2.buf, fraction);
     }
     else {
-      cfg_append_printable_line(out, _PREFIX "Parameter must be a %d-byte signed integer"
+      cfg_append_printable_line(out, CFG_HELP_INDENT_PREFIX "Parameter must be a %d-byte signed integer"
           " with a maximum of %d fractional digits",
           bytelen, fraction);
     }
@@ -165,7 +167,7 @@ cfg_help_netaddr(struct autobuf *out, bool preamble,
   size_t i;
 
   if (preamble) {
-    abuf_puts(out, _PREFIX "Parameter must be an address of the following type: ");
+    abuf_puts(out, CFG_HELP_INDENT_PREFIX "Parameter must be an address of the following type: ");
   }
 
   first = true;
@@ -203,7 +205,7 @@ cfg_help_netaddr(struct autobuf *out, bool preamble,
   }
 
   if (prefix) {
-    abuf_puts(out, "\n" _PREFIX "    (the address can have an optional prefix)");
+    abuf_puts(out, "\n" CFG_HELP_INDENT_PREFIX "    (the address can have an optional prefix)");
   }
   abuf_puts(out, "\n");
 }
@@ -220,21 +222,21 @@ void
 cfg_help_acl(struct autobuf *out, bool preamble,
     bool prefix, const int8_t *af_types, size_t af_types_count) {
   if (preamble) {
-    abuf_puts(out, _PREFIX "Parameter is an apache2 style access control list made from a list of network addresses of the following types:\n");
+    abuf_puts(out, CFG_HELP_INDENT_PREFIX "Parameter is an apache2 style access control list made from a list of network addresses of the following types:\n");
   }
 
   cfg_help_netaddr(out, false, prefix, af_types, af_types_count);
 
   abuf_puts(out,
-      _PREFIX "    Each of the addresses/prefixes can start with a"
+      CFG_HELP_INDENT_PREFIX "    Each of the addresses/prefixes can start with a"
               " '+' to add them to the whitelist and '-' to add it to the blacklist"
               " (default is the whitelist).\n"
-      _PREFIX "    In addition to this there are four keywords to configure the ACL:\n"
-      _PREFIX "    - '" ACL_FIRST_ACCEPT "' to parse the whitelist first\n"
-      _PREFIX "    - '" ACL_FIRST_REJECT "' to parse the blacklist first\n"
-      _PREFIX "    - '" ACL_DEFAULT_ACCEPT "' to accept input if it doesn't match either list\n"
-      _PREFIX "    - '" ACL_DEFAULT_REJECT "' to not accept it if it doesn't match either list\n"
-      _PREFIX "    (default mode is '" ACL_FIRST_ACCEPT "' and '" ACL_DEFAULT_REJECT "')\n");
+      CFG_HELP_INDENT_PREFIX "    In addition to this there are four keywords to configure the ACL:\n"
+      CFG_HELP_INDENT_PREFIX "    - '" ACL_FIRST_ACCEPT "' to parse the whitelist first\n"
+      CFG_HELP_INDENT_PREFIX "    - '" ACL_FIRST_REJECT "' to parse the blacklist first\n"
+      CFG_HELP_INDENT_PREFIX "    - '" ACL_DEFAULT_ACCEPT "' to accept input if it doesn't match either list\n"
+      CFG_HELP_INDENT_PREFIX "    - '" ACL_DEFAULT_REJECT "' to not accept it if it doesn't match either list\n"
+      CFG_HELP_INDENT_PREFIX "    (default mode is '" ACL_FIRST_ACCEPT "' and '" ACL_DEFAULT_REJECT "')\n");
 }
 
 /**
@@ -245,11 +247,87 @@ cfg_help_acl(struct autobuf *out, bool preamble,
 void
 cfg_help_bitmap256(struct autobuf *out, bool preamble) {
   if (preamble) {
-    abuf_puts(out, _PREFIX "Parameter is a list of bit-numbers to define a bit-array.");
+    abuf_puts(out, CFG_HELP_INDENT_PREFIX "Parameter is a list of bit-numbers to define a bit-array.");
+  }
+
+  abuf_puts(out, CFG_HELP_INDENT_PREFIX "    Each of the bit-numbers must be between 0 and 255\n"
+      CFG_HELP_INDENT_PREFIX "    In addition to this there are two keywords to configure the bit-array:\n"
+      CFG_HELP_INDENT_PREFIX "    - '" BITMAP256_ALL "' to set all bits in the bit-array\n"
+      CFG_HELP_INDENT_PREFIX "    - '" BITMAP256_NONE "' to reset all bits in the bit-array\n");
+}
+
+/**
+ * Generate help text for space separated token config option
+ * @param out output buffer for help text
+ * @param preamble true if preamble should be printed
+ * @param token_entry token entry
+ * @param sub_entries sub entries that define the tokens elements
+ * @param entry_count number of sub entries
+ * @param customizer callbacks for customizing validation,
+ *    binary conversion or help text, NULL, if none
+ */
+void
+cfg_help_token(struct autobuf *out, bool preamble,
+    const struct cfg_schema_entry *token_entry,
+    const struct cfg_schema_entry *sub_entries, size_t entry_count,
+    const struct cfg_schema_token_customizer *customizer) {
+  char enum_buffer[10];
+  size_t i;
+
+  if (preamble) {
+    abuf_appendf(out, CFG_HELP_INDENT_PREFIX
+        "Parameter is a list of"
+        " %"PRINTF_SIZE_T_SPECIFIER" whitespace separater tokens (",
+        entry_count);
+    for (i=0; i<entry_count; i++) {
+      abuf_appendf(out, "%s%s", i==0 ? "" : ", ", sub_entries[i].key.entry);
+    }
+    abuf_puts(out, ").\n"
+        CFG_HELP_INDENT_PREFIX
+        "The last token gets the rest of the string, regardless of"
+        " the number of whitespaces used.\n\n");
+  }
+  if (customizer && customizer->cb_valhelp) {
+    customizer->cb_valhelp(token_entry, out);
+  }
+
+  for (i=0; i<entry_count; i++) {
+    abuf_appendf(out, CFG_HELP_INDENT_PREFIX
+        "Description of the %s token '%s':\n",
+        _get_enumerator(enum_buffer, sizeof(enum_buffer), i),
+        sub_entries[i].key.entry);
+
+    if (sub_entries[i].help) {
+      abuf_appendf(out,
+          CFG_HELP_INDENT_PREFIX CFG_HELP_INDENT_PREFIX "%s\n",
+          sub_entries[i].help);
+    }
+    if (sub_entries[i].cb_valhelp) {
+      sub_entries[i].cb_valhelp(&sub_entries[i], out);
+    }
+    abuf_puts(out, "\n");
   }
+}
+
+/**
+ * Get enumeration word for a certain index (first, second, ...)
+ * @param buffer target buffer to copy word into
+ * @param length length of buffer
+ * @param idx index of word, starting with zero
+ * @return pointer to buffer
+ */
+static const char *
+_get_enumerator(char *buffer, size_t length, size_t idx) {
+  static const char *_ENUMERATIONS[] = {
+    "first", "second", "third", "fourth", "fifth",
+    "sixth", "seventh", "eight", "ninth", "tenth"
+  };
 
-  abuf_puts(out, _PREFIX "    Each of the bit-numbers must be between 0 and 255\n"
-      _PREFIX "    In addition to this there are two keywords to configure the bit-array:\n"
-      _PREFIX "    - '" BITMAP256_ALL "' to set all bits in the bit-array\n"
-      _PREFIX "    - '" BITMAP256_NONE "' to reset all bits in the bit-array\n");
+  if (idx < ARRAYSIZE(_ENUMERATIONS)) {
+    strscpy(buffer, _ENUMERATIONS[idx], length);
+  }
+  else {
+    snprintf(buffer, length, "%"PRINTF_SIZE_T_SPECIFIER".", idx+1);
+  }
+  return buffer;
 }
index 0c7b279..01f424b 100644 (file)
 
 #include "common/autobuf.h"
 #include "common/common_types.h"
+#include "config/cfg_schema.h"
+
+/*! prefix before help text parameter explanation */
+#define CFG_HELP_INDENT_PREFIX "    "
 
 EXPORT void cfg_help_printable(struct autobuf *out, size_t len);
 EXPORT void cfg_help_strlen(struct autobuf *out, size_t len);
 EXPORT void cfg_help_choice(struct autobuf *out, bool preamble,
-    const char **choices, size_t choice_count);
+    const char *(*callback)(size_t idx, const void *ptr),
+    size_t choice_count, const void *ptr);
 EXPORT void cfg_help_int(struct autobuf *out,
     int64_t min, int64_t max, uint16_t bytelen, uint16_t fraction);
 EXPORT void cfg_help_netaddr(struct autobuf *out, bool preamble,
@@ -60,5 +65,9 @@ EXPORT void cfg_help_netaddr(struct autobuf *out, bool preamble,
 EXPORT void cfg_help_acl(struct autobuf *out, bool preamble,
     bool prefix, const int8_t *af_types, size_t af_types_count);
 EXPORT void cfg_help_bitmap256(struct autobuf *out, bool preamble);
+EXPORT void cfg_help_token(struct autobuf *out, bool preamble,
+    const struct cfg_schema_entry *token_entry,
+    const struct cfg_schema_entry *sub_entries, size_t entry_count,
+    const struct cfg_schema_token_customizer *customizer);
 
 #endif /* CFG_HELP_H_ */
index 36968cf..6af4e6b 100644 (file)
@@ -61,8 +61,9 @@
 #include "config/cfg.h"
 #include "config/cfg_db.h"
 #include "config/cfg_help.h"
-#include "config/cfg_schema.h"
+#include "config/cfg_tobin.h"
 #include "config/cfg_validate.h"
+#include "config/cfg_schema.h"
 
 static bool _validate_cfg_entry(
     struct cfg_db *db, struct cfg_section_type *section,
@@ -457,6 +458,20 @@ cfg_avlcmp_schemaentries(const void *p1, const void *p2) {
   return cfg_avlcmp_keys(key1->entry, key2->entry);
 }
 
+/**
+ * Helper function to get a value from an string array.
+ * Used by the CFG_xxx_CHOICE macro
+ * @param idx index to be retrieved from the string array
+ * @param ptr pointer to string array
+ * @return array element
+ */
+const char *
+cfg_schema_get_choice_value(size_t idx, const void *ptr) {
+  const char* const *array = ptr;
+
+  return array[idx];
+}
+
 /**
  * Schema entry validator for string maximum length.
  * See CFG_VALIDATE_STRING_LEN() macro in cfg_schema.h
@@ -504,9 +519,12 @@ int
 cfg_schema_validate_choice(const struct cfg_schema_entry *entry,
     const char *section_name, const char *value, struct autobuf *out) {
   return cfg_validate_choice(out, section_name, entry->key.entry, value,
-      entry->validate_param[0].ptr, entry->validate_param[1].s);
+      entry->validate_param[0].ptr, entry->validate_param[1].s,
+      entry->validate_param[2].ptr);
 }
 
+
+
 /**
  * Schema entry validator for integers.
  * See CFG_VALIDATE_INT*() and CFG_VALIDATE_FRACTIONAL*() macros in cfg_schema.h
@@ -572,6 +590,22 @@ cfg_schema_validate_bitmap256(const struct cfg_schema_entry *entry,
   return cfg_validate_bitmap256(out, section_name, entry->key.entry, value);
 }
 
+/**
+ * Schema entry validator for a Token of space separated
+ * entries of a "sub"-schema.
+ * @param entry pointer to schema entry
+ * @param section_name name of section type and name
+ * @param value value of schema entry
+ * @param out pointer to autobuffer for validator output
+ * @return 0 if validation found no problems, -1 otherwise
+ */
+int
+cfg_schema_validate_tokens(const struct cfg_schema_entry *entry,
+    const char *section_name, const char *value, struct autobuf *out) {
+  return cfg_validate_tokens(out, section_name, entry->key.entry, value,
+      entry->validate_param[0].ptr, entry->validate_param[1].s,
+      entry->validate_param[2].ptr);
+}
 /**
  * Help generator for string maximum length validator.
  * See CFG_VALIDATE_STRING_LEN() macro in cfg_schema.h
@@ -608,7 +642,7 @@ void
 cfg_schema_help_choice(
     const struct cfg_schema_entry *entry, struct autobuf *out) {
   cfg_help_choice(out, true, entry->validate_param[0].ptr,
-      entry->validate_param[1].s);
+      entry->validate_param[1].s, entry->validate_param[2].ptr);
 }
 
 /**
@@ -663,6 +697,21 @@ cfg_schema_help_bitmap256(
   cfg_help_bitmap256(out, true);
 }
 
+/**
+ * Help generator for token validator.
+ * See CFG_VALIDATE_TOKEN() macro in cfg_schema.h
+ * @param entry pointer to schema entry
+ * @param out pointer to autobuffer for help output
+ */
+void
+cfg_schema_help_token(
+    const struct cfg_schema_entry *entry, struct autobuf *out) {
+  cfg_help_token(out, true, entry,
+      entry->validate_param[0].ptr, entry->validate_param[1].s,
+      entry->validate_param[2].ptr);
+}
+
+
 /**
  * Binary converter for string pointers. This validator will
  * allocate additional memory for the string.
@@ -674,21 +723,13 @@ cfg_schema_help_bitmap256(
  * @return 0 if conversion succeeded, -1 otherwise.
  */
 int
-cfg_schema_tobin_strptr(const struct cfg_schema_entry *s_entry __attribute__((unused)),
+cfg_schema_tobin_strptr(const struct cfg_schema_entry *s_entry,
     const struct const_strarray *value, void *reference) {
-  char **ptr;
-
-  if (s_entry->bin_size != sizeof(*ptr)) {
+  if (s_entry->list) {
+    /* we don't support direct list conversion to binary */
     return -1;
   }
-
-  ptr = (char **)reference;
-  if (*ptr) {
-    free(*ptr);
-  }
-
-  *ptr = strdup(strarray_get_first_c(value));
-  return *ptr == NULL ? -1 : 0;
+  return cfg_tobin_strptr(reference, s_entry->bin_size, value);
 }
 
 /**
@@ -702,16 +743,12 @@ cfg_schema_tobin_strptr(const struct cfg_schema_entry *s_entry __attribute__((un
 int
 cfg_schema_tobin_strarray(const struct cfg_schema_entry *s_entry,
     const struct const_strarray *value, void *reference) {
-  char *ptr;
-
-  if (s_entry->bin_size < s_entry->validate_param[0].s) {
+  if (s_entry->list) {
+    /* we don't support direct list conversion to binary */
     return -1;
   }
-
-  ptr = (char *)reference;
-
-  strscpy(ptr, strarray_get_first_c(value), s_entry->validate_param[0].s);
-  return 0;
+  return cfg_tobin_strarray(reference, s_entry->bin_size, value,
+      s_entry->validate_param[0].s);
 }
 
 /**
@@ -726,17 +763,13 @@ cfg_schema_tobin_strarray(const struct cfg_schema_entry *s_entry,
 int
 cfg_schema_tobin_choice(const struct cfg_schema_entry *s_entry,
     const struct const_strarray *value, void *reference) {
-  int *ptr;
-
-  if (s_entry->bin_size != sizeof(int)) {
+  if (s_entry->list) {
+    /* we don't support direct list conversion to binary */
     return -1;
   }
-
-  ptr = (int *)reference;
-
-  *ptr = cfg_get_choice_index(strarray_get_first_c(value),
-      s_entry->validate_param[0].ptr, s_entry->validate_param[1].s);
-  return 0;
+  return cfg_tobin_choice(reference, s_entry->bin_size, value,
+      s_entry->validate_param[0].ptr, s_entry->validate_param[1].s,
+      s_entry->validate_param[2].ptr);
 }
 
 /**
@@ -750,28 +783,12 @@ cfg_schema_tobin_choice(const struct cfg_schema_entry *s_entry,
 int
 cfg_schema_tobin_int(const struct cfg_schema_entry *s_entry,
     const struct const_strarray *value, void *reference) {
-  int64_t i;
-  int result;
-
-  if (s_entry->bin_size != s_entry->validate_param[2].u16[0]) {
+  if (s_entry->list) {
+    /* we don't support direct list conversion to binary */
     return -1;
   }
-
-  result = isonumber_to_s64(&i, strarray_get_first_c(value),
-      s_entry->validate_param[2].u16[1]);
-  if (result == 0) {
-    switch (s_entry->validate_param[2].u16[0]) {
-      case 4:
-        *((int32_t *)reference) = i;
-        break;
-      case 8:
-        *((int64_t *)reference) = i;
-        break;
-      default:
-        return -1;
-    }
-  }
-  return result;
+  return cfg_tobin_int(reference, s_entry->bin_size, value,
+      s_entry->validate_param[2].u16[1], s_entry->validate_param[2].u16[0]);
 }
 
 /**
@@ -782,17 +799,13 @@ cfg_schema_tobin_int(const struct cfg_schema_entry *s_entry,
  * @param reference pointer to binary output buffer.
  * @return 0 if conversion succeeded, -1 otherwise.
  */int
-cfg_schema_tobin_netaddr(const struct cfg_schema_entry *s_entry __attribute__((unused)),
+cfg_schema_tobin_netaddr(const struct cfg_schema_entry *s_entry,
     const struct const_strarray *value, void *reference) {
-  struct netaddr *ptr;
-
-  if (s_entry->bin_size != sizeof(*ptr)) {
+  if (s_entry->list) {
+    /* we don't support direct list conversion to binary */
     return -1;
   }
-
-  ptr = (struct netaddr *)reference;
-
-  return netaddr_from_string(ptr, strarray_get_first_c(value));
+  return cfg_tobin_netaddr(reference, s_entry->bin_size, value);
 }
 
 /**
@@ -804,18 +817,9 @@ cfg_schema_tobin_netaddr(const struct cfg_schema_entry *s_entry __attribute__((u
  * @return -1 if an error happened, 0 otherwise
  */
 int
-cfg_schema_tobin_acl(const struct cfg_schema_entry *s_entry __attribute__((unused)),
+cfg_schema_tobin_acl(const struct cfg_schema_entry *s_entry,
      const struct const_strarray *value, void *reference) {
-  struct netaddr_acl *ptr;
-
-  if (s_entry->bin_size != sizeof(*ptr)) {
-    return -1;
-  }
-
-  ptr = (struct netaddr_acl *)reference;
-  netaddr_acl_remove(ptr);
-
-  return netaddr_acl_from_strarray(ptr, value);
+  return cfg_tobin_acl(reference, s_entry->bin_size, value);
 }
 
 /**
@@ -827,41 +831,9 @@ cfg_schema_tobin_acl(const struct cfg_schema_entry *s_entry __attribute__((unuse
  * @return -1 if an error happened, 0 otherwise
  */
 int
-cfg_schema_tobin_bitmap256(const struct cfg_schema_entry *s_entry __attribute__((unused)),
+cfg_schema_tobin_bitmap256(const struct cfg_schema_entry *s_entry,
      const struct const_strarray *value, void *reference) {
-  struct bitmap256 *bitmap;
-  const char *ptr;
-  int idx;
-
-  if (s_entry->bin_size != sizeof(*bitmap)) {
-    return -1;
-  }
-
-  bitmap = (struct bitmap256 *)reference;
-  memset(bitmap, 0, sizeof(*bitmap));
-
-  strarray_for_each_element(value, ptr) {
-    errno = 0;
-    if (strcasecmp(ptr, BITMAP256_ALL) == 0) {
-      memset(bitmap, 255, sizeof(*bitmap));
-    }
-    else if (strcasecmp(ptr, BITMAP256_NONE) == 0) {
-      memset(bitmap, 0, sizeof(*bitmap));
-    }
-    else if (*ptr == '-') {
-      idx = strtol(&ptr[1], NULL, 10);
-      if (!errno) {
-        bitmap256_reset(bitmap, idx);
-      }
-    }
-    else {
-      idx = strtol(ptr, NULL, 10);
-      if (!errno) {
-        bitmap256_set(bitmap, idx);
-      }
-    }
-  }
-  return 0;
+  return cfg_tobin_bitmap256(reference, s_entry->bin_size, value);
 }
 
  /**
@@ -873,18 +845,13 @@ cfg_schema_tobin_bitmap256(const struct cfg_schema_entry *s_entry __attribute__(
   * @return 0 if conversion succeeded, -1 otherwise.
   */
 int
-cfg_schema_tobin_bool(const struct cfg_schema_entry *s_entry __attribute__((unused)),
+cfg_schema_tobin_bool(const struct cfg_schema_entry *s_entry,
     const struct const_strarray *value, void *reference) {
-  bool *ptr;
-
-  if (s_entry->bin_size != sizeof(*ptr)) {
+  if (s_entry->list) {
+    /* we don't support direct list conversion to binary */
     return -1;
   }
-
-  ptr = (bool *)reference;
-
-  *ptr = cfg_get_bool(strarray_get_first_c(value));
-  return 0;
+  return cfg_tobin_bool(reference, s_entry->bin_size, value);
 }
 
 /**
@@ -896,21 +863,30 @@ cfg_schema_tobin_bool(const struct cfg_schema_entry *s_entry __attribute__((unus
  * @return 0 if conversion succeeded, -1 otherwise.
  */
 int
-cfg_schema_tobin_stringlist(const struct cfg_schema_entry *s_entry __attribute__((unused)),
+cfg_schema_tobin_stringlist(const struct cfg_schema_entry *s_entry,
     const struct const_strarray *value, void *reference) {
-  struct strarray *array;
+  return cfg_tobin_stringlist(reference, s_entry->bin_size, value);
+}
 
-  if (s_entry->bin_size != sizeof(*array)) {
+/**
+ * Binary converter for tokenized list of parameters.
+ * See CFG_MAP_TOKENS() macro in cfg_schema.h
+ * @param s_entry pointer to configuration entry schema.
+ * @param value pointer to value of configuration entry.
+ * @param reference pointer to binary output buffer.
+ * @return 0 if conversion succeeded, -1 otherwise.
+ */
+int
+cfg_schema_tobin_tokens(const struct cfg_schema_entry *s_entry,
+    const struct const_strarray *value, void *reference) {
+  if (s_entry->list) {
+    /* we don't support direct list conversion to binary */
     return -1;
   }
-
-  array = (struct strarray *)reference;
-
-  if (!value->value[0]) {
-    strarray_init(array);
-    return 0;
-  }
-  return strarray_copy_c(array, value);
+  return cfg_tobin_tokens(reference,
+      strarray_get_first_c(value),
+      s_entry->validate_param[0].ptr, s_entry->validate_param[1].s,
+      s_entry->validate_param[2].ptr);
 }
 
 /**
index 5c808e6..f0718e7 100644 (file)
@@ -154,6 +154,22 @@ struct cfg_schema_entry;
  */
 #define CFG_VALIDATE_PRINTABLE_LEN(p_name, p_def, p_help, maxlen, args...)                   _CFG_VALIDATE(p_name, p_def, p_help, .cb_validate = cfg_schema_validate_printable, .cb_valhelp = cfg_schema_help_printable, .validate_param = {{.s = (maxlen) }}, ##args )
 
+/**
+ * Creates a cfg_schema_entry for a parameter that can be choosen
+ * from a fixed list defined by a callback.
+ * @param p_name parameter name
+ * @param p_def parameter default value
+ * @param p_help help text for configuration entry
+ * @param p_choice_cb reference a function with a size_t argument and a
+ *   const void pointer argument stored in the schema entry
+ *   that returns a const char pointer, the choice with the given index.
+ *   see cfg_schema_get_choice_value() function as an example
+ * @param p_choice_count number of elements in the list
+ * @param p_choice_arg argument for choice callback function
+ * @param args variable list of additional arguments
+ */
+#define CFG_VALIDATE_CHOICE_CB_ARG(p_name, p_def, p_help, p_choice_cb, p_choice_count, p_choice_arg, args...)   _CFG_VALIDATE(p_name, p_def, p_help, .cb_validate = cfg_schema_validate_choice, .cb_valhelp = cfg_schema_help_choice, .validate_param = {{.ptr = (p_choice_cb)}, {.s = (p_choice_count)}, {.ptr = (p_choice_arg)}}, ##args )
+
 /**
  * Creates a cfg_schema_entry for a parameter that can be choosen
  * from a fixed list.
@@ -164,7 +180,22 @@ struct cfg_schema_entry;
  *   (not a pointer to the array, ARRAYSIZE() would not work)
  * @param args variable list of additional arguments
  */
-#define CFG_VALIDATE_CHOICE(p_name, p_def, p_help, p_list, args...)                          _CFG_VALIDATE(p_name, p_def, p_help, .cb_validate = cfg_schema_validate_choice, .cb_valhelp = cfg_schema_help_choice, .validate_param = {{.ptr = (p_list)}, { .s = ARRAYSIZE(p_list)}}, ##args )
+#define CFG_VALIDATE_CHOICE(p_name, p_def, p_help, p_list, args...)                           CFG_VALIDATE_CHOICE_CB_ARG(p_name, p_def, p_help, cfg_schema_get_choice_value, ARRAYSIZE(p_list), p_list, ##args )
+
+/**
+ * Creates a cfg_schema_entry for a parameter that can be choosen
+ * from a fixed list defined by a callback.
+ * @param p_name parameter name
+ * @param p_def parameter default value
+ * @param p_help help text for configuration entry
+ * @param p_choice_cb reference a function with a size_t argument and a
+ *   const void pointer argument stored in the schema entry
+ *   that returns a const char pointer, the choice with the given index.
+ *   see cfg_schema_get_choice_value() function as an example
+ * @param p_choice_count number of elements in the list
+ * @param args variable list of additional arguments
+ */
+#define CFG_VALIDATE_CHOICE_CB(p_name, p_def, p_help, p_choice_cb, p_choice_count, args...)   CFG_VALIDATE_CHOICE_CB_ARG(p_name, p_def, p_help, p_choice_cb, p_choice_count, NULL, ##args )
 
 /**
  * Creates a cfg_schema_entry for a 32 bit signed integer parameter
@@ -379,6 +410,28 @@ struct cfg_schema_entry;
  */
 #define CFG_VALIDATE_BOOL(p_name, p_def, p_help, args...)                                    CFG_VALIDATE_CHOICE(p_name, p_def, p_help, CFGLIST_BOOL, ##args)
 
+/**
+ * Creates a cfg_schema_entry for a list of parameters, split by spaces
+ * @param p_name parameter name
+ * @param p_def parameter default value
+ * @param p_help help text for configuration entry
+ * @param schema_entries array of schema entries for tokens
+ * @param args variable list of additional arguments
+ */
+#define CFG_VALIDATE_TOKENS(p_name, p_def, p_help, schema_entries, args...)                  _CFG_VALIDATE(p_name, p_def, p_help, .cb_validate = cfg_schema_validate_tokens, .cb_valhelp = cfg_schema_help_token, .validate_param = {{.ptr = (schema_entries)}, {.s = ARRAYSIZE(schema_entries)}}, ##args)
+
+/**
+ * Creates a cfg_schema_entry for a list of parameters, split by spaces.
+ * Contains a pointer to a customizer for validation, binary conversion
+ * and help output.
+ * @param p_help help text for configuration entry
+ * @param schema_entries array of schema entries for tokens
+ * @param custom pointer to customizer for tokens
+ * @param args variable list of additional arguments
+ */
+#define CFG_VALIDATE_TOKENS_CUSTOM(p_name, p_def, p_help, schema_entries, custom, args...)   _CFG_VALIDATE(p_name, p_def, p_help, .cb_validate = cfg_schema_validate_tokens, .cb_valhelp = cfg_schema_help_token, .validate_param = {{.ptr = (schema_entries)}, {.s = ARRAYSIZE(schema_entries)}, {.ptr = &(custom)}}, ##args)
+
+
 /*
  * Example of a section schema definition with binary mapping
  *
@@ -513,8 +566,43 @@ struct cfg_schema_entry;
  */
 #define CFG_MAP_PRINTABLE_ARRAY(p_reference, p_field, p_name, p_def, p_help, maxlen, args...)                 CFG_VALIDATE_PRINTABLE_LEN(p_name, p_def, p_help, maxlen, .cb_to_binary = cfg_schema_tobin_strarray, .bin_size = calculate_size(p_reference, p_field), .bin_offset = offsetof(struct p_reference, p_field), ##args)
 
+/**
+ * Creates a cfg_schema_entry for a parameter that can be chosen
+ * from a fixed list defined by a callback.
+ * @param p_reference reference to instance of struct
+ * @param p_field name of field in the struct for the parameter,
+ * @param p_name parameter name
+ * @param p_def parameter default value
+ * @param p_help help text for configuration entry
+ * @param p_choice_cb reference a function with a size_t argument and a
+ *   const void pointer argument stored in the schema entry
+ *   that returns a const char pointer, the choice with the given index.
+ *   see cfg_schema_get_choice_value() function as an example
+ * @param p_choice_count number of elements in the list
+ * @param p_choice_arg argument for choice callback function
+ * @param args variable list of additional arguments
+ */
+#define CFG_MAP_CHOICE_CB_ARG(p_reference, p_field, p_name, p_def, p_help, p_choice_cb, p_choice_count, p_choice_arg, args...)   CFG_VALIDATE_CHOICE_CB_ARG(p_name, p_def, p_help, p_choice_cb, p_choice_count, p_choice_arg, .cb_to_binary = cfg_schema_tobin_choice, .bin_size = calculate_size(p_reference, p_field), .bin_offset = offsetof(struct p_reference, p_field), ##args )
+
+/**
+ * Creates a cfg_schema_entry for a parameter that can be choosen
+ * from a fixed list.
+ * @param p_reference reference to instance of struct
+ * @param p_field name of field in the struct for the parameter,
+ *   it must be an integer for the index of the selected choice
+ * @param p_name parameter name
+ * from a fixed list and can be mapped into a binary struct
+ * @param p_def parameter default value
+ * @param p_help help text for configuration entry
+ * @param p_list reference to an array of string pointers with the options
+ *   (not a pointer to the array, ARRAYSIZE() would not work)
+ * @param args variable list of additional arguments
+ */
+#define CFG_MAP_CHOICE_CB(p_reference, p_field, p_name, p_def, p_help, p_choice_cb, p_choice_count, args...)                          CFG_MAP_CHOICE_CB_ARG(p_reference, p_field, p_name, p_def, p_help, p_choice_cb, p_choice_count, NULL, ##args)
+
 /**
  * Creates a cfg_schema_entry for a parameter that can be choosen
+ * from a fixed list.
  * @param p_reference reference to instance of struct
  * @param p_field name of field in the struct for the parameter,
  *   it must be an integer for the index of the selected choice
@@ -526,7 +614,7 @@ struct cfg_schema_entry;
  *   (not a pointer to the array, ARRAYSIZE() would not work)
  * @param args variable list of additional arguments
  */
-#define CFG_MAP_CHOICE(p_reference, p_field, p_name, p_def, p_help, p_list, args...)                          CFG_VALIDATE_CHOICE(p_name, p_def, p_help, p_list, .cb_to_binary = cfg_schema_tobin_choice, .bin_size = calculate_size(p_reference, p_field), .bin_offset = offsetof(struct p_reference, p_field), ##args)
+#define CFG_MAP_CHOICE(p_reference, p_field, p_name, p_def, p_help, p_list, args...)                          CFG_MAP_CHOICE_CB_ARG(p_reference, p_field, p_name, p_def, p_help, cfg_schema_get_choice_value, ARRAYSIZE(p_list), p_list, ##args)
 
 /**
  * Creates a cfg_schema_entry for a 32 bit signed integer parameter
@@ -829,6 +917,28 @@ struct cfg_schema_entry;
  */
 #define CFG_MAP_STRINGLIST(p_reference, p_field, p_name, p_def, p_help, args...)                              _CFG_VALIDATE(p_name, p_def, p_help, .cb_to_binary = cfg_schema_tobin_stringlist, .bin_size = calculate_size(p_reference, p_field), .bin_offset = offsetof(struct p_reference, p_field), .list = true, ##args )
 
+/**
+ * Creates a cfg_schema_entry for a list of parameters, split by spaces
+ * that can be mapped into a binary struct
+ * @param p_name parameter name
+ * @param p_def parameter default value
+ * @param p_help help text for configuration entry
+ * @param schema_entries array of schema entries for tokens
+ * @param args variable list of additional arguments
+ */
+#define CFG_MAP_TOKENS(p_name, p_def, p_help, schema_entries, args...)                                        CFG_VALIDATE_TOKENS(p_name, p_def, p_help, schema_entries, .cb_to_binary = cfg_schema_tobin_tokens, ##args)
+/**
+ * Creates a cfg_schema_entry for a list of parameters, split by spaces
+ * that can be mapped into a binary struct. Contains a pointer to
+ * a customizer for validation, binary conversion and help output.
+ * @param p_name parameter name
+ * @param p_def parameter default value
+ * @param p_help help text for configuration entry
+ * @param schema_entries array of schema entries for tokens
+ * @param custom pointer to customizer for tokens
+ * @param args variable list of additional arguments
+ */
+#define CFG_MAP_TOKENS_CUSTOM(p_name, p_def, p_help, schema_entries, custom, args...)                         CFG_VALIDATE_TOKENS(p_name, p_def, p_help, schema_entries, custom, .cb_to_binary = cfg_schema_tobin_tokens, ##args)
 
 /*! convenience definition for configuration that only allows access from loopback */
 #define ACL_LOCALHOST_ONLY "+127.0.0.1/8\0+::1/128\0" ACL_DEFAULT_REJECT
@@ -1038,6 +1148,48 @@ struct cfg_schema_entry {
   bool delta_changed;
 };
 
+/**
+ * Callback table to customize the behavior of a TOKEN configuration
+ * entry, which might be necessary if the tokens depend on each other
+ * for validation and conversion to binary.
+ */
+struct cfg_schema_token_customizer {
+  /**
+   * Additional validator, will be called after all schema entries have
+   * been successfully validated with their own validator.
+   * @param out buffer for text output of validation
+   * @param section_name name of configuration section
+   * @param entry_name name of configuration entry
+   * @param value complete token string defined by the user
+   * @param entries pointer to array of schema entries for token
+   * @param entry_count number of schema entries for token
+   * @return -1 if validation failed, 0 otherwise
+   */
+  int (*cb_validator)(struct autobuf *out,
+      const char *section_name, const char *entry_name,
+      const char *value, struct cfg_schema_entry *entries, size_t entry_count);
+
+  /**
+   * Additional binary converter for TOKENs
+   * @param entries pointer to array of schema entries for token
+   * @param entry_count number of schema entries for token
+   * @param value string array of values specified by the user, use only first
+   *   string if converter does not need multiple entries
+   * @param ptr pointer to the beginning of the data structure used for
+   *   placing the content of the tokens
+   * @return -1 if an error happened, 0 otherwise
+   */
+  int (*cb_tobin)(struct cfg_schema_entry *entries, size_t entry_count,
+      const char *value, void *ptr);
+
+  /**
+   * Additional help output generator for TOKENs
+   * @param entry token schema entry
+   * @param out buffer for help text output
+   */
+  void (*cb_valhelp)(const struct cfg_schema_entry *entry, struct autobuf *out);
+};
+
 /*! List of strings that are considered valid boolean options */
 #define CFGLIST_BOOL_VALUES "true", "1", "on", "yes", "false", "0", "off", "no"
 
@@ -1064,6 +1216,8 @@ EXPORT int cfg_schema_handle_db_startup_changes(struct cfg_db *db);
 
 EXPORT int cfg_avlcmp_schemaentries(const void *p1, const void *p2);
 
+EXPORT const char *cfg_schema_get_choice_value(size_t idx, const void *ptr);
+
 EXPORT int cfg_schema_validate_printable(const struct cfg_schema_entry *entry,
     const char *section_name, const char *value, struct autobuf *out);
 EXPORT int cfg_schema_validate_strlen(const struct cfg_schema_entry *entry,
@@ -1078,6 +1232,8 @@ EXPORT int cfg_schema_validate_acl(const struct cfg_schema_entry *entry,
     const char *section_name, const char *value, struct autobuf *out);
 EXPORT int cfg_schema_validate_bitmap256(const struct cfg_schema_entry *entry,
     const char *section_name, const char *value, struct autobuf *out);
+EXPORT int cfg_schema_validate_tokens(const struct cfg_schema_entry *entry,
+    const char *section_name, const char *value, struct autobuf *out);
 
 EXPORT void cfg_schema_help_printable(
     const struct cfg_schema_entry *entry, struct autobuf *out);
@@ -1093,6 +1249,8 @@ EXPORT void cfg_schema_help_acl(
     const struct cfg_schema_entry *entry, struct autobuf *out);
 EXPORT void cfg_schema_help_bitmap256(
     const struct cfg_schema_entry *entry, struct autobuf *out);
+EXPORT void cfg_schema_help_token(
+    const struct cfg_schema_entry *entry, struct autobuf *out);
 
 EXPORT int cfg_schema_tobin_strptr(const struct cfg_schema_entry *s_entry,
     const struct const_strarray *value, void *reference);
@@ -1112,6 +1270,8 @@ EXPORT int cfg_schema_tobin_acl(const struct cfg_schema_entry *s_entry,
     const struct const_strarray *value, void *reference);
 EXPORT int cfg_schema_tobin_bitmap256(const struct cfg_schema_entry *s_entry,
      const struct const_strarray *value, void *reference);
+EXPORT int cfg_schema_tobin_tokens(const struct cfg_schema_entry *s_entry,
+    const struct const_strarray *value, void *reference);
 
 /**
  * Finds a section in a schema
diff --git a/src-api/config/cfg_tobin.c b/src-api/config/cfg_tobin.c
new file mode 100644 (file)
index 0000000..7a6b082
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * cfg_tobin.c
+ *
+ *  Created on: 05.10.2017
+ *      Author: rogge
+ */
+
+#include <errno.h>
+
+#include "common/common_types.h"
+#include "common/bitmap256.h"
+#include "common/isonumber.h"
+#include "common/netaddr.h"
+#include "common/netaddr_acl.h"
+#include "common/string.h"
+
+#include "config/cfg.h"
+#include "config/cfg_tobin.h"
+
+/**
+ * Binary converter for string pointers. It will
+ * allocate additional memory for the string.
+ * See CFG_MAP_STRING() and CFG_MAP_STRING_LEN() macro
+ * in cfg_schema.h
+ * @param reference pointer to binary output buffer.
+ * @param bin_size size of reference memory
+ * @param value pointer to value of configuration entry.
+ * @return 0 if conversion succeeded, -1 otherwise.
+ */
+int
+cfg_tobin_strptr(void *reference, size_t bin_size, const struct const_strarray *value) {
+  char **ptr;
+
+  if (bin_size != sizeof(*ptr)) {
+    return -1;
+  }
+
+  ptr = (char **)reference;
+  if (*ptr) {
+    free(*ptr);
+  }
+
+  *ptr = strdup(strarray_get_first_c(value));
+  return *ptr == NULL ? -1 : 0;
+}
+
+/**
+ * Binary converter for string arrays.
+ * See CFG_MAP_STRING_ARRAY() macro in cfg_schema.h
+ * @param reference pointer to binary output buffer.
+ * @param bin_size size of reference memory
+ * @param value pointer to value of configuration entry.
+ * @param array_size size of the target array
+ * @return 0 if conversion succeeded, -1 otherwise.
+ */
+int
+cfg_tobin_strarray(void *reference, size_t bin_size,
+    const struct const_strarray *value, size_t array_size) {
+  char *ptr;
+
+  if (bin_size < array_size) {
+    return -1;
+  }
+
+  ptr = (char *)reference;
+
+  strscpy(ptr, strarray_get_first_c(value), array_size);
+  return 0;
+}
+
+/**
+ * Binary converter for integers chosen as an index in a predefined
+ * string list.
+ * See CFG_MAP_CHOICE() macro in cfg_schema.h
+ * @param reference pointer to binary output buffer.
+ * @param bin_size size of reference memory
+ * @param value pointer to value of configuration entry.
+ * @param choices array of strings to choose from
+ * @param choice_count number of strings to choose from
+ * @return 0 if conversion succeeded, -1 otherwise.
+ */
+int
+cfg_tobin_choice(void *reference, size_t bin_size,
+    const struct const_strarray *value,
+    const char *(*callback)(size_t idx, const void *ptr),
+    size_t choices_count, const void *ptr) {
+  int *result;
+
+  if (bin_size != sizeof(int)) {
+    return -1;
+  }
+
+  result = (int *)reference;
+
+  *result = cfg_get_choice_index(strarray_get_first_c(value),
+      callback, choices_count, ptr);
+  return 0;
+}
+
+/**
+ * Binary converter for integers.
+ * See CFG_VALIDATE_INT*() macro in cfg_schema.h
+ * @param reference pointer to binary output buffer.
+ * @param bin_size size of reference memory
+ * @param value pointer to value of configuration entry.
+ * @param fractions number of fractional digits
+ * @param int_size size of signed integer to read
+ * @return 0 if conversion succeeded, -1 otherwise.
+ */
+int
+cfg_tobin_int(void *reference, size_t bin_size,
+    const struct const_strarray *value, int fractions, size_t int_size) {
+  int64_t i;
+  int result;
+
+  if (bin_size != int_size) {
+    return -1;
+  }
+
+  result = isonumber_to_s64(&i, strarray_get_first_c(value), fractions);
+  if (result == 0) {
+    switch (int_size) {
+      case 4:
+        *((int32_t *)reference) = i;
+        break;
+      case 8:
+        *((int64_t *)reference) = i;
+        break;
+      default:
+        return -1;
+    }
+  }
+  return result;
+}
+
+/**
+ * Binary converter for netaddr objects.
+ * See CFG_MAP_NETADDR*() macros in cfg_schema.h
+ * @param reference pointer to binary output buffer.
+ * @param bin_size size of reference memory
+ * @param value pointer to value of configuration entry.
+ * @return 0 if conversion succeeded, -1 otherwise.
+ */
+int
+cfg_tobin_netaddr(void *reference, size_t bin_size,
+    const struct const_strarray *value) {
+  struct netaddr *ptr;
+
+  if (bin_size != sizeof(*ptr)) {
+    return -1;
+  }
+
+  ptr = (struct netaddr *)reference;
+
+  return netaddr_from_string(ptr, strarray_get_first_c(value));
+}
+
+/**
+ * Schema entry binary converter for ACL entries.
+ * See CFG_MAP_ACL_*() macros.
+ * @param reference pointer to binary output buffer.
+ * @param bin_size size of reference memory
+ * @param value pointer to value of configuration entry.
+ * @return -1 if an error happened, 0 otherwise
+ */
+int
+cfg_tobin_acl(void *reference, size_t bin_size,
+     const struct const_strarray *value) {
+  struct netaddr_acl *ptr;
+
+  if (bin_size != sizeof(*ptr)) {
+    return -1;
+  }
+
+  ptr = (struct netaddr_acl *)reference;
+  netaddr_acl_remove(ptr);
+
+  return netaddr_acl_from_strarray(ptr, value);
+}
+
+/**
+ * Schema entry binary converter for bitmap256 entries.
+ * See CFG_MAP_BITMAP256() macros.
+ * @param reference pointer to binary output buffer.
+ * @param bin_size size of reference memory
+ * @param value pointer to value of configuration entry.
+ * @return -1 if an error happened, 0 otherwise
+ */
+int
+cfg_tobin_bitmap256(void *reference, size_t bin_size,
+     const struct const_strarray *value) {
+  struct bitmap256 *bitmap;
+  const char *ptr;
+  int idx;
+
+  if (bin_size != sizeof(*bitmap)) {
+    return -1;
+  }
+
+  bitmap = (struct bitmap256 *)reference;
+  memset(bitmap, 0, sizeof(*bitmap));
+
+  strarray_for_each_element(value, ptr) {
+    errno = 0;
+    if (strcasecmp(ptr, BITMAP256_ALL) == 0) {
+      memset(bitmap, 255, sizeof(*bitmap));
+    }
+    else if (strcasecmp(ptr, BITMAP256_NONE) == 0) {
+      memset(bitmap, 0, sizeof(*bitmap));
+    }
+    else if (*ptr == '-') {
+      idx = strtol(&ptr[1], NULL, 10);
+      if (!errno) {
+        bitmap256_reset(bitmap, idx);
+      }
+    }
+    else {
+      idx = strtol(ptr, NULL, 10);
+      if (!errno) {
+        bitmap256_set(bitmap, idx);
+      }
+    }
+  }
+  return 0;
+}
+
+/**
+ * Binary converter for booleans.
+ * See CFG_MAP_BOOL() macro in cfg_schema.h
+ * @param reference pointer to binary output buffer.
+ * @param bin_size size of reference memory
+ * @param value pointer to value of configuration entry.
+ * @return 0 if conversion succeeded, -1 otherwise.
+ */
+int
+cfg_tobin_bool(void *reference, size_t bin_size,
+    const struct const_strarray *value) {
+  bool *ptr;
+
+  if (bin_size != sizeof(*ptr)) {
+    return -1;
+  }
+
+  ptr = (bool *)reference;
+
+  *ptr = cfg_get_bool(strarray_get_first_c(value));
+  return 0;
+}
+
+/**
+ * Binary converter for list of strings.
+ * See CFG_MAP_STRINGLIST() macro in cfg_schema.h
+ * @param reference pointer to binary output buffer.
+ * @param bin_size size of reference memory
+ * @param value pointer to value of configuration entry.
+ * @return 0 if conversion succeeded, -1 otherwise.
+ */
+int
+cfg_tobin_stringlist(void *reference, size_t bin_size,
+    const struct const_strarray *value) {
+  struct strarray *array;
+
+  if (bin_size != sizeof(*array)) {
+    return -1;
+  }
+
+  array = (struct strarray *)reference;
+
+  if (!value->value[0]) {
+    strarray_init(array);
+    return 0;
+  }
+  return strarray_copy_c(array, value);
+}
+
+/**
+ * Binary converter for list of space separated tokens.
+ * See CFG_MAP_STRINGLIST() macro in cfg_schema.h
+ * @param reference pointer to binary output buffer.
+ * @param bin_size size of reference memory
+ * @param value pointer to value of configuration entry.
+ * @param entries pointer to array of configuration entries
+ * @param entry_count number of configuration entries
+ * @return 0 if conversion succeeded, -1 otherwise.
+ */
+int
+cfg_tobin_tokens(void *reference,
+    const char *value,
+    struct cfg_schema_entry *entries, size_t entry_count,
+    struct cfg_schema_token_customizer *custom) {
+  struct const_strarray parameter;
+  const char *next_token;
+  char buffer[256];
+  char *dst;
+  size_t i;
+
+  dst = reference;
+  next_token = value;
+
+  parameter.value = buffer;
+  for (i=0; i<entry_count-1; i++) {
+    if (!next_token) {
+      return -1;
+    }
+    next_token = str_cpynextword(buffer, next_token, sizeof(buffer));
+    parameter.length = strlen(parameter.value) + 1;
+
+    if (entries[i].cb_to_binary) {
+      if (entries[i].cb_to_binary(&entries[i], &parameter, dst + entries[i].bin_offset)) {
+        return -1;
+      }
+    }
+  }
+
+  if (next_token) {
+    /* we have data for the last entry left */
+    i = entry_count-1;
+
+    parameter.value = next_token;
+    parameter.length = strlen(next_token) + 1;
+
+    if (entries[i].cb_to_binary) {
+      if (entries[i].cb_to_binary(&entries[i], &parameter, dst + entries[i].bin_offset)) {
+        return -1;
+      }
+    }
+  }
+
+  if (custom && custom->cb_tobin) {
+    return custom->cb_tobin(entries, entry_count, value, dst);
+  }
+  return 0;
+}
+
diff --git a/src-api/config/cfg_tobin.h b/src-api/config/cfg_tobin.h
new file mode 100644 (file)
index 0000000..e886c46
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * cfg_tobin.h
+ *
+ *  Created on: 05.10.2017
+ *      Author: rogge
+ */
+
+#ifndef CFG_TOBIN_H_
+#define CFG_TOBIN_H_
+
+#include "common/common_types.h"
+#include "common/string.h"
+
+EXPORT int cfg_tobin_strptr(
+    void *reference, size_t bin_size, const struct const_strarray *value);
+EXPORT int cfg_tobin_strarray(void *reference, size_t bin_size,
+    const struct const_strarray *value, size_t array_size);
+EXPORT int cfg_tobin_choice(void *reference, size_t bin_size,
+    const struct const_strarray *value,
+    const char *(*callback)(size_t idx, const void *ptr),
+    size_t choices_count, const void *ptr);
+EXPORT int cfg_tobin_int(void *reference, size_t bin_size,
+    const struct const_strarray *value, int fractions, size_t int_size);
+EXPORT int cfg_tobin_netaddr(void *reference, size_t bin_size,
+    const struct const_strarray *value);
+EXPORT int cfg_tobin_acl(void *reference, size_t bin_size,
+     const struct const_strarray *value);
+EXPORT int cfg_tobin_bitmap256(void *reference, size_t bin_size,
+     const struct const_strarray *value);
+EXPORT int cfg_tobin_bool(void *reference, size_t bin_size,
+    const struct const_strarray *value);
+EXPORT int cfg_tobin_stringlist(void *reference, size_t bin_size,
+    const struct const_strarray *value);
+EXPORT int cfg_tobin_tokens(void *reference, const char *value,
+    struct cfg_schema_entry *entries, size_t entry_count,
+    struct cfg_schema_token_customizer *custom);
+
+#endif /* CFG_TOBIN_H_ */
index 7fa9e5a..2f8c46e 100644 (file)
@@ -44,6 +44,7 @@
  */
 
 #include <errno.h>
+#include <stdio.h>
 
 #include "common/common_types.h"
 #include "common/autobuf.h"
@@ -113,10 +114,11 @@ cfg_validate_strlen(struct autobuf *out, const char *section_name,
  */
 int
 cfg_validate_choice(struct autobuf *out, const char *section_name,
-    const char *entry_name, const char *value, const char **choices,
-    size_t choices_count) {
+    const char *entry_name, const char *value,
+    const char *(*callback)(size_t idx, const void *ptr),
+    size_t choices_count, const void *ptr) {
   int i;
-  i = cfg_get_choice_index(value, choices, choices_count);
+  i = cfg_get_choice_index(value, callback, choices_count, ptr);
   if (i >= 0) {
     return 0;
   }
@@ -306,3 +308,59 @@ cfg_validate_bitmap256(struct autobuf *out,
   }
   return 0;
 }
+
+/**
+ * Validates if a value is defined as in a list of configuration
+ * entries split by whitespaces.
+ * @param out output buffer for error messages
+ * @param section_name name of configuration section
+ * @param entry_name name of configuration entry
+ * @param value value that needs to be validated
+ * @param entries pointer to array of configuration entries
+ * @param entry_count number of configuration entries
+ * @return 0 if value is valid, -1 otherwise
+ */
+int
+cfg_validate_tokens(struct autobuf *out,
+    const char *section_name, const char *entry_name, const char *value,
+    struct cfg_schema_entry *entries, size_t entry_count,
+    struct cfg_schema_token_customizer *custom) {
+  char buffer[256];
+  char section_name_entry[32];
+  const char *ptr;
+  size_t i;
+
+  if (str_countwords(value) < entry_count) {
+    cfg_append_printable_line(out, "Missing token for entry '%s'"
+        " in section %s. At least %"PRINTF_SIZE_T_SPECIFIER" tokens"
+        " expected. Tokens must be separated by whitespaces.",
+        entry_name, section_name, entry_count);
+    return -1;
+  }
+  snprintf(section_name_entry, sizeof(section_name_entry), "%s.%s",
+      section_name, entry_name);
+
+  /* check each token */
+  ptr = value;
+  for (i=0; i<entry_count-1; i++) {
+    ptr = str_cpynextword(buffer, ptr, sizeof(buffer));
+
+    /* see if token is valid */
+    if (entries[i].cb_validate(&entries[i], section_name_entry,
+        buffer, out)) {
+      return -1;
+    }
+  }
+
+  /* see if the rest of the value is a valid "last" token */
+  if (entries[i].cb_validate(&entries[entry_count-1],
+      section_name_entry, ptr, out)) {
+    return -1;
+  }
+
+  if (custom && custom->cb_validator) {
+    return custom->cb_validator(out, section_name, entry_name,
+        value, entries, entry_count);
+  }
+  return 0;
+}
index 8673aa9..b14f09f 100644 (file)
@@ -48,6 +48,7 @@
 
 #include "common/autobuf.h"
 #include "common/common_types.h"
+#include "config/cfg_schema.h"
 
 EXPORT int cfg_validate_printable(struct autobuf *out,
     const char *section_name, const char *entry_name, const char *value,
@@ -55,9 +56,10 @@ EXPORT int cfg_validate_printable(struct autobuf *out,
 EXPORT int cfg_validate_strlen(struct autobuf *out,
     const char *section_name, const char *entry_name, const char *value,
     size_t len);
-EXPORT int cfg_validate_choice(struct autobuf *out,
-    const char *section_name, const char *entry_name, const char *value,
-    const char **choices, size_t choice_count);
+EXPORT int cfg_validate_choice(struct autobuf *out, const char *section_name,
+    const char *entry_name, const char *value,
+    const char *(*callback)(size_t idx, const void *ptr),
+    size_t choices_count, const void *ptr);
 EXPORT int cfg_validate_int(struct autobuf *out,
     const char *section_name, const char *entry_name, const char *value,
     int64_t min, int64_t max, uint16_t bytelen, uint16_t fraction);
@@ -69,5 +71,9 @@ EXPORT int cfg_validate_acl(struct autobuf *out,
     bool prefix, const int8_t *af_types, size_t af_types_count);
 EXPORT int cfg_validate_bitmap256(struct autobuf *out,
     const char *section_name, const char *entry_name, const char *value);
+EXPORT int cfg_validate_tokens(struct autobuf *out,
+    const char *section_name, const char *entry_name, const char *value,
+    struct cfg_schema_entry *entries, size_t entry_count,
+    struct cfg_schema_token_customizer *custom);
 
 #endif /* CFG_VALIDATE_H_ */