]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
enum: Add helper to parse enum flags from strings
authorTobias Brunner <tobias@strongswan.org>
Fri, 17 Dec 2021 14:19:02 +0000 (15:19 +0100)
committerTobias Brunner <tobias@strongswan.org>
Thu, 14 Apr 2022 16:42:01 +0000 (18:42 +0200)
Individual flag names are separated by |.

src/libstrongswan/tests/suites/test_enum.c
src/libstrongswan/utils/enum.c
src/libstrongswan/utils/enum.h

index 613043e6deea0b8937a16a99fb00920ffd547e04..83ff14be832026221447e7e4b17ef1b619c1ade9 100644 (file)
 /*******************************************************************************
  * continuous enum
  */
-enum {
+enum test_enum_cont {
        CONT1,
        CONT2,
        CONT3,
        CONT4,
        CONT5,
-} test_enum_cont;
+};
 
 ENUM_BEGIN(test_enum_cont_names, CONT1, CONT5,
        "CONT1", "CONT2", "CONT3", "CONT4", "CONT5");
@@ -35,13 +35,13 @@ ENUM_END(test_enum_cont_names, CONT5);
 /*******************************************************************************
  * split enum
  */
-enum {
+enum test_enum_split {
        SPLIT1 = 1,
        SPLIT2,
        SPLIT3 = 5,
        SPLIT4,
        SPLIT5 = 255,
-} test_enum_split;
+};
 
 ENUM_BEGIN(test_enum_split_names, SPLIT1, SPLIT2,
        "SPLIT1", "SPLIT2");
@@ -54,7 +54,7 @@ ENUM_END(test_enum_split_names, SPLIT5);
 /*******************************************************************************
  * enum flags
  */
-enum {
+enum test_enum_flags {
        FLAG1 = (1 << 0),
        FLAG2 = (1 << 1),
        FLAG3 = (1 << 2),
@@ -67,7 +67,7 @@ enum {
        FLAG10 = (1 << 9),
        FLAG11 = (1 << 10),
        FLAG12 = (1 << 11),
-} test_enum_flags;
+};
 
 ENUM_FLAGS(test_enum_flags_names, FLAG1, FLAG5,
        "(unset)", "FLAG1", "FLAG2", "FLAG3", "FLAG4", "FLAG5");
@@ -263,6 +263,30 @@ static struct {
 }, enum_flags_to_string_tests[] = {
        {-1, NULL},
        {6435, NULL},
+}, enum_flags_from_string_tests[] = {
+       {0, NULL},
+       {0, ""},
+       {0, "(unset)"},
+       {FLAG1, "FLAG1"},
+       {FLAG2, "flag2"},
+       {FLAG3, "fLaG3"},
+       {FLAG4, "FLAG4"},
+       {FLAG5, "FLAG5"},
+       {FLAG1 | FLAG3, "FLAG1 | FLAG3"},
+       {FLAG1 | FLAG3, "flag3|flag1"},
+       {FLAG1 | FLAG3, "flag1|flag3 | (unset)"},
+       {FLAG1 | FLAG2 | FLAG3 | FLAG4 | FLAG5, "flag1|flag2|flag3|flag4|flag5"},
+       {FLAG1 | FLAG2 | FLAG3 | FLAG4 | FLAG5, "flag3|flag4|flag5|flag2|flag1"},
+       {FLAG5, "(unset)|flag5"},
+       {FLAG1, "FLAG1 | flag1 | flAg1"},
+       {-1, "FLAG6"},
+       {-1, "flag1 | asdf"},
+}, enum_flags_from_string_noflagenum_tests[] = {
+       {0, NULL},
+       {0, ""},
+       {CONT2, "CONT2"},
+       {CONT5, "CONT5"},
+       {-1, "asdf"},
 };
 
 START_TEST(test_enum_printf_hook_cont)
@@ -371,6 +395,38 @@ START_TEST(test_enum_flags_to_string_noflagenum)
 }
 END_TEST
 
+START_TEST(test_enum_flags_from_string)
+{
+       enum test_enum_flags val;
+
+       if (enum_flags_from_string(test_enum_flags_names,
+                                                          enum_flags_from_string_tests[_i].str, &val))
+       {
+               ck_assert_int_eq(enum_flags_from_string_tests[_i].val, val);
+       }
+       else
+       {
+               ck_assert_int_eq(enum_flags_from_string_tests[_i].val, -1);
+       }
+}
+END_TEST
+
+START_TEST(test_enum_flags_from_string_noflagenum)
+{
+       enum test_enum_cont val;
+
+       if (enum_flags_from_string(test_enum_cont_names,
+                                               enum_flags_from_string_noflagenum_tests[_i].str, &val))
+       {
+               ck_assert_int_eq(enum_flags_from_string_noflagenum_tests[_i].val, val);
+       }
+       else
+       {
+               ck_assert_int_eq(enum_flags_from_string_noflagenum_tests[_i].val, -1);
+       }
+}
+END_TEST
+
 START_TEST(test_enum_printf_hook_width)
 {
        char buf[128];
@@ -406,6 +462,11 @@ Suite *enum_suite_create()
        tcase_add_loop_test(tc, test_enum_flags_to_string_noflagenum, 0, countof(printf_tests_flags_noflagenum));
        suite_add_tcase(s, tc);
 
+       tc = tcase_create("enum_flags_from_string");
+       tcase_add_loop_test(tc, test_enum_flags_from_string, 0, countof(enum_flags_from_string_tests));
+       tcase_add_loop_test(tc, test_enum_flags_from_string_noflagenum, 0, countof(enum_flags_from_string_noflagenum_tests));
+       suite_add_tcase(s, tc);
+
        tc = tcase_create("enum_printf_hook");
        tcase_add_loop_test(tc, test_enum_printf_hook_cont, 0, countof(printf_tests_cont));
        tcase_add_loop_test(tc, test_enum_printf_hook_split, 0, countof(printf_tests_split));
index e62c75f913b2c8e50716e844eab1f8cd8852e363..79da450f0cee2735fe079c81f57cd72b30f3dfa2 100644 (file)
@@ -17,6 +17,7 @@
 #include <stdio.h>
 
 #include <library.h>
+#include <collections/enumerator.h>
 #include <utils/utils.h>
 
 #include "enum.h"
@@ -135,6 +136,54 @@ char *enum_flags_to_string(enum_name_t *e, u_int val, char *buf, size_t len)
        return buf;
 }
 
+/*
+ * Described in header
+ */
+bool enum_flags_from_string_as_int(enum_name_t *e, const char *str, u_int *val)
+{
+       enumerator_t *enumerator;
+       char *name;
+
+       *val = 0;
+
+       if (!str || !*str)
+       {
+               return TRUE;
+       }
+       else if (e->next != ENUM_FLAG_MAGIC)
+       {
+               return enum_from_name_as_int(e, str, val);
+       }
+
+       enumerator = enumerator_create_token(str, "|", " ");
+       while (enumerator->enumerate(enumerator, &name))
+       {
+               u_int flag, i;
+               bool found = FALSE;
+
+               if (strcaseeq(name, e->names[0]))
+               {       /* accept name used if no flags are set */
+                       continue;
+               }
+               for (i = 1, flag = e->first; flag <= e->last; i++, flag <<= 1)
+               {
+                       if (e->names[i] && strcaseeq(name, e->names[i]))
+                       {
+                               *val |= flag;
+                               found = TRUE;
+                               break;
+                       }
+               }
+               if (!found)
+               {
+                       enumerator->destroy(enumerator);
+                       return FALSE;
+               }
+       }
+       enumerator->destroy(enumerator);
+       return TRUE;
+}
+
 /**
  * See header.
  */
index 1e723a220e4519f77d1138adcfa6f6e61ee88a3a..d6f909e15b0426a0cf7c2c7e6f9e9b069990b7b5 100644 (file)
@@ -158,7 +158,7 @@ char *enum_to_name(enum_name_t *e, int val);
  */
 #define enum_from_name(e, name, valp) ({ \
        int _val; \
-       int _found = enum_from_name_as_int(e, name, &_val); \
+       bool _found = enum_from_name_as_int(e, name, &_val); \
        if (_found) \
        { \
                *(valp) = _val; \
@@ -168,13 +168,13 @@ char *enum_to_name(enum_name_t *e, int val);
 /**
  * Convert a enum string back to its enum value, integer pointer variant.
  *
- * This variant takes integer pointer only, use enum_from_name() to pass
+ * This variant takes an integer pointer, use enum_from_name() to pass
  * enum type pointers for the result.
  *
  * @param e            enum names for this enum value
  * @param name name to get enum value for
  * @param val  integer pointer receiving value
- * @return             TRUE if enum name found, FALSE otherwise
+ * @return             TRUE if all names found, FALSE otherwise
  */
 bool enum_from_name_as_int(enum_name_t *e, const char *name, int *val);
 
@@ -189,6 +189,36 @@ bool enum_from_name_as_int(enum_name_t *e, const char *name, int *val);
  */
 char *enum_flags_to_string(enum_name_t *e, u_int val, char *buf, size_t len);
 
+/**
+ * Convert a string of flags separated by | to their combined value
+ *
+ * @param e            enum names for this enum value
+ * @param str  string to get enum value for
+ * @param valp variable sized pointer receiving value
+ * @return             TRUE if all names found, FALSE otherwise
+ */
+#define enum_flags_from_string(e, str, valp) ({ \
+       u_int _val; \
+       bool _found = enum_flags_from_string_as_int(e, str, &_val); \
+       if (_found) \
+       { \
+               *(valp) = _val; \
+       } \
+       _found; })
+
+/**
+ * Convert a string of flags separated by | to their combined value.
+ *
+ * This variant takes an unsigned integer pointer, use enum_flags_from_names()
+ * to pass enum type pointers for the result.
+ *
+ * @param e            enum names for this enum value
+ * @param str  string to get enum value for
+ * @param val  integer pointer receiving value
+ * @return             TRUE if enum name found, FALSE otherwise
+ */
+bool enum_flags_from_string_as_int(enum_name_t *e, const char *str, u_int *val);
+
 /**
  * printf hook function for enum_names_t.
  *