From: Tobias Brunner Date: Fri, 17 Dec 2021 14:19:02 +0000 (+0100) Subject: enum: Add helper to parse enum flags from strings X-Git-Tag: 5.9.6rc1~3^2~38 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7137fd96c25bd73af7ba50441994fdcffe7b5ac0;p=thirdparty%2Fstrongswan.git enum: Add helper to parse enum flags from strings Individual flag names are separated by |. --- diff --git a/src/libstrongswan/tests/suites/test_enum.c b/src/libstrongswan/tests/suites/test_enum.c index 613043e6de..83ff14be83 100644 --- a/src/libstrongswan/tests/suites/test_enum.c +++ b/src/libstrongswan/tests/suites/test_enum.c @@ -20,13 +20,13 @@ /******************************************************************************* * 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)); diff --git a/src/libstrongswan/utils/enum.c b/src/libstrongswan/utils/enum.c index e62c75f913..79da450f0c 100644 --- a/src/libstrongswan/utils/enum.c +++ b/src/libstrongswan/utils/enum.c @@ -17,6 +17,7 @@ #include #include +#include #include #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. */ diff --git a/src/libstrongswan/utils/enum.h b/src/libstrongswan/utils/enum.h index 1e723a220e..d6f909e15b 100644 --- a/src/libstrongswan/utils/enum.h +++ b/src/libstrongswan/utils/enum.h @@ -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. *