enum: Add helper to parse enum flags from strings

Individual flag names are separated by |.
This commit is contained in:
Tobias Brunner
2022-04-14 18:42:01 +02:00
parent 4f4d4021b4
commit 7137fd96c2
3 changed files with 149 additions and 9 deletions
+67 -6
View File
@@ -20,13 +20,13 @@
/******************************************************************************* /*******************************************************************************
* continuous enum * continuous enum
*/ */
enum { enum test_enum_cont {
CONT1, CONT1,
CONT2, CONT2,
CONT3, CONT3,
CONT4, CONT4,
CONT5, CONT5,
} test_enum_cont; };
ENUM_BEGIN(test_enum_cont_names, CONT1, CONT5, ENUM_BEGIN(test_enum_cont_names, CONT1, CONT5,
"CONT1", "CONT2", "CONT3", "CONT4", "CONT5"); "CONT1", "CONT2", "CONT3", "CONT4", "CONT5");
@@ -35,13 +35,13 @@ ENUM_END(test_enum_cont_names, CONT5);
/******************************************************************************* /*******************************************************************************
* split enum * split enum
*/ */
enum { enum test_enum_split {
SPLIT1 = 1, SPLIT1 = 1,
SPLIT2, SPLIT2,
SPLIT3 = 5, SPLIT3 = 5,
SPLIT4, SPLIT4,
SPLIT5 = 255, SPLIT5 = 255,
} test_enum_split; };
ENUM_BEGIN(test_enum_split_names, SPLIT1, SPLIT2, ENUM_BEGIN(test_enum_split_names, SPLIT1, SPLIT2,
"SPLIT1", "SPLIT2"); "SPLIT1", "SPLIT2");
@@ -54,7 +54,7 @@ ENUM_END(test_enum_split_names, SPLIT5);
/******************************************************************************* /*******************************************************************************
* enum flags * enum flags
*/ */
enum { enum test_enum_flags {
FLAG1 = (1 << 0), FLAG1 = (1 << 0),
FLAG2 = (1 << 1), FLAG2 = (1 << 1),
FLAG3 = (1 << 2), FLAG3 = (1 << 2),
@@ -67,7 +67,7 @@ enum {
FLAG10 = (1 << 9), FLAG10 = (1 << 9),
FLAG11 = (1 << 10), FLAG11 = (1 << 10),
FLAG12 = (1 << 11), FLAG12 = (1 << 11),
} test_enum_flags; };
ENUM_FLAGS(test_enum_flags_names, FLAG1, FLAG5, ENUM_FLAGS(test_enum_flags_names, FLAG1, FLAG5,
"(unset)", "FLAG1", "FLAG2", "FLAG3", "FLAG4", "FLAG5"); "(unset)", "FLAG1", "FLAG2", "FLAG3", "FLAG4", "FLAG5");
@@ -263,6 +263,30 @@ static struct {
}, enum_flags_to_string_tests[] = { }, enum_flags_to_string_tests[] = {
{-1, NULL}, {-1, NULL},
{6435, 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) START_TEST(test_enum_printf_hook_cont)
@@ -371,6 +395,38 @@ START_TEST(test_enum_flags_to_string_noflagenum)
} }
END_TEST 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) START_TEST(test_enum_printf_hook_width)
{ {
char buf[128]; 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)); tcase_add_loop_test(tc, test_enum_flags_to_string_noflagenum, 0, countof(printf_tests_flags_noflagenum));
suite_add_tcase(s, tc); 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"); 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_cont, 0, countof(printf_tests_cont));
tcase_add_loop_test(tc, test_enum_printf_hook_split, 0, countof(printf_tests_split)); tcase_add_loop_test(tc, test_enum_printf_hook_split, 0, countof(printf_tests_split));
+49
View File
@@ -17,6 +17,7 @@
#include <stdio.h> #include <stdio.h>
#include <library.h> #include <library.h>
#include <collections/enumerator.h>
#include <utils/utils.h> #include <utils/utils.h>
#include "enum.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; 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. * See header.
*/ */
+33 -3
View File
@@ -158,7 +158,7 @@ char *enum_to_name(enum_name_t *e, int val);
*/ */
#define enum_from_name(e, name, valp) ({ \ #define enum_from_name(e, name, valp) ({ \
int _val; \ int _val; \
int _found = enum_from_name_as_int(e, name, &_val); \ bool _found = enum_from_name_as_int(e, name, &_val); \
if (_found) \ if (_found) \
{ \ { \
*(valp) = _val; \ *(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. * 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. * enum type pointers for the result.
* *
* @param e enum names for this enum value * @param e enum names for this enum value
* @param name name to get enum value for * @param name name to get enum value for
* @param val integer pointer receiving value * @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); 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); 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. * printf hook function for enum_names_t.
* *