enum: Add functions to add and remove mappings from enum names

Co-authored-by: Thomas Egerer <thomas.egerer@secunet.com>
This commit is contained in:
Tobias Brunner 2023-02-16 17:04:40 +01:00
parent 3cf5653640
commit 0de42047a9
3 changed files with 160 additions and 1 deletions

View File

@ -85,6 +85,13 @@ ENUM_FLAGS(test_enum_flags_overflow_names, FLAG1, FLAG12, "(unset)",
"OVERFLOWFLAGLONGNAME7", "OVERFLOWFLAGLONGNAME8", "OVERFLOWFLAGLONGNAME9", "OVERFLOWFLAGLONGNAME7", "OVERFLOWFLAGLONGNAME8", "OVERFLOWFLAGLONGNAME9",
"OVERFLOWFLAGLONGNAME10", "OVERFLOWFLAGLONGNAME11", "OVERFLOWFLAGLONGNAME12"); "OVERFLOWFLAGLONGNAME10", "OVERFLOWFLAGLONGNAME11", "OVERFLOWFLAGLONGNAME12");
/*******************************************************************************
* add_enum_names
*/
ENUM_EXT(e1, 65000, 65001, "CONT65000", "CONT65001");
ENUM_EXT(e2, 62000, 62001, "CONT62000", "CONT62001");
/******************************************************************************* /*******************************************************************************
* enum_to_name * enum_to_name
*/ */
@ -172,6 +179,15 @@ static struct {
{FALSE, 0, "asdf"}, {FALSE, 0, "asdf"},
{FALSE, 0, ""}, {FALSE, 0, ""},
{FALSE, 0, NULL}, {FALSE, 0, NULL},
}, enum_tests_ext[] = {
{TRUE, CONT1, "CONT1"},
{TRUE, 62000, "CONT62000"},
{TRUE, 62001, "CONT62001"},
{TRUE, 65000, "CONT65000"},
{TRUE, 65001, "CONT65001"},
{FALSE, 0, "CONT64000"},
{FALSE, 0, ""},
{FALSE, 0, NULL},
}; };
START_TEST(test_enum_from_name_cont) START_TEST(test_enum_from_name_cont)
@ -196,6 +212,23 @@ START_TEST(test_enum_from_name_split)
} }
END_TEST END_TEST
START_TEST(test_enum_from_name_ext)
{
int val = 0;
bool found;
enum_add_enum_names(test_enum_cont_names, e1);
enum_add_enum_names(test_enum_cont_names, e2);
found = enum_from_name(test_enum_cont_names, enum_tests_ext[_i].str, &val);
ck_assert(enum_tests_ext[_i].found == found);
ck_assert_int_eq(val, enum_tests_ext[_i].val);
enum_remove_enum_names(test_enum_cont_names, e1);
enum_remove_enum_names(test_enum_cont_names, e2);
}
END_TEST
/******************************************************************************* /*******************************************************************************
* enum_printf_hook * enum_printf_hook
*/ */
@ -441,6 +474,51 @@ START_TEST(test_enum_printf_hook_width)
} }
END_TEST END_TEST
START_TEST(test_enum_printf_hook_add_enum_names)
{
char buf[128];
enum_add_enum_names(test_enum_cont_names, e1);
snprintf(buf, sizeof(buf), "%N", test_enum_cont_names, 65001);
ck_assert_str_eq("CONT65001", buf);
enum_add_enum_names(test_enum_cont_names, e2);
snprintf(buf, sizeof(buf), "%N", test_enum_cont_names, 62001);
ck_assert_str_eq("CONT62001", buf);
/* adding the same list repeatedly should not result in an infinite loop */
enum_add_enum_names(test_enum_cont_names, e2);
snprintf(buf, sizeof(buf), "%N", test_enum_cont_names, 62001);
ck_assert_str_eq("CONT62001", buf);
/* can also be defined inside a function as long as the same function is
* adding and removing it */
ENUM_EXT(e3, 64000, 64001, "CONT64000", "CONT64001");
enum_add_enum_names(test_enum_cont_names, e3);
snprintf(buf, sizeof(buf), "%N", test_enum_cont_names, 64000);
ck_assert_str_eq("CONT64000", buf);
snprintf(buf, sizeof(buf), "%N, %N, %N", test_enum_cont_names, 62001,
test_enum_cont_names, 65000, test_enum_cont_names, 64000);
ck_assert_str_eq("CONT62001, CONT65000, CONT64000", buf);
enum_remove_enum_names(test_enum_cont_names, e2);
snprintf(buf, sizeof(buf), "%N, %N, %N", test_enum_cont_names, 62001,
test_enum_cont_names, 65000, test_enum_cont_names, 64000);
ck_assert_str_eq("(62001), CONT65000, CONT64000", buf);
enum_remove_enum_names(test_enum_cont_names, e3);
snprintf(buf, sizeof(buf), "%N, %N, %N", test_enum_cont_names, 62001,
test_enum_cont_names, 65000, test_enum_cont_names, 64000);
ck_assert_str_eq("(62001), CONT65000, (64000)", buf);
enum_remove_enum_names(test_enum_cont_names, e1);
snprintf(buf, sizeof(buf), "%N, %N, %N", test_enum_cont_names, 62001,
test_enum_cont_names, 65000, test_enum_cont_names, 64000);
ck_assert_str_eq("(62001), (65000), (64000)", buf);
}
END_TEST
Suite *enum_suite_create() Suite *enum_suite_create()
{ {
Suite *s; Suite *s;
@ -456,6 +534,7 @@ Suite *enum_suite_create()
tc = tcase_create("enum_from_name"); tc = tcase_create("enum_from_name");
tcase_add_loop_test(tc, test_enum_from_name_cont, 0, countof(enum_tests_cont)); tcase_add_loop_test(tc, test_enum_from_name_cont, 0, countof(enum_tests_cont));
tcase_add_loop_test(tc, test_enum_from_name_split, 0, countof(enum_tests_split)); tcase_add_loop_test(tc, test_enum_from_name_split, 0, countof(enum_tests_split));
tcase_add_loop_test(tc, test_enum_from_name_ext, 0, countof(enum_tests_ext));
suite_add_tcase(s, tc); suite_add_tcase(s, tc);
tc = tcase_create("enum_flags_to_string"); tc = tcase_create("enum_flags_to_string");
@ -478,6 +557,7 @@ Suite *enum_suite_create()
tcase_add_loop_test(tc, test_enum_printf_hook_flags_overflow, 0, countof(printf_tests_flags_overflow)); tcase_add_loop_test(tc, test_enum_printf_hook_flags_overflow, 0, countof(printf_tests_flags_overflow));
tcase_add_loop_test(tc, test_enum_printf_hook_flags_noflagenum, 0, countof(printf_tests_flags_noflagenum)); tcase_add_loop_test(tc, test_enum_printf_hook_flags_noflagenum, 0, countof(printf_tests_flags_noflagenum));
tcase_add_test(tc, test_enum_printf_hook_width); tcase_add_test(tc, test_enum_printf_hook_width);
tcase_add_test(tc, test_enum_printf_hook_add_enum_names);
suite_add_tcase(s, tc); suite_add_tcase(s, tc);
return s; return s;

View File

@ -1,4 +1,5 @@
/* /*
* Copyright (C) 2023 Tobias Brunner
* Copyright (C) 2006 Martin Willi * Copyright (C) 2006 Martin Willi
* *
* Copyright (C) secunet Security Networks AG * Copyright (C) secunet Security Networks AG
@ -23,6 +24,49 @@
#include "enum.h" #include "enum.h"
/*
* Described in header
*/
void enum_add_enum_names(enum_name_t *e, enum_name_t *names)
{
if (e)
{
do
{
if (!e->next)
{
e->next = names;
break;
}
else if (e->next == names)
{
break;
}
}
while ((e = e->next));
}
}
/*
* Described in header
*/
void enum_remove_enum_names(enum_name_t *e, enum_name_t *names)
{
if (e)
{
do
{
if (e->next == names)
{
e->next = names->next;
names->next = NULL;
break;
}
}
while ((e = e->next));
}
}
/** /**
* See header. * See header.
*/ */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2009-2019 Tobias Brunner * Copyright (C) 2009-2023 Tobias Brunner
* Copyright (C) 2006-2008 Martin Willi * Copyright (C) 2006-2008 Martin Willi
* *
* Copyright (C) secunet Security Networks AG * Copyright (C) secunet Security Networks AG
@ -140,6 +140,41 @@ struct enum_name_t {
countof(((char*[]){__VA_ARGS__}))), \ countof(((char*[]){__VA_ARGS__}))), \
ENUM_FLAG_MAGIC, { unset, __VA_ARGS__ }}; ENUM_END(name, last) ENUM_FLAG_MAGIC, { unset, __VA_ARGS__ }}; ENUM_END(name, last)
/**
* Define a static enum name that can be added and removed to an existing list
* via enum_add_enum_names() and enum_remove_enum_names(), respectively.
*
* @param name name of the static enum_name element
* @param first enum value of the first enum string
* @param last enum value of the last enum string
* @param ... a list of strings
*/
#define ENUM_EXT(name, first, last, ...) \
ENUM_BEGIN(name, first, last, __VA_ARGS__); static ENUM_END(name, last)
/**
* Register enum names for additional enum values with an existing enum name.
*
* @note Must be called while running single-threaded, e.g. when plugins and
* their features are loaded. Use enum_remove_enum_names() to remove the names
* during deinitialization.
*
* @param e enum names to add new names to
* @param names additional enum names
*/
void enum_add_enum_names(enum_name_t *e, enum_name_t *names);
/**
* Remove previously registered enum names.
*
* @note Must be called while running single-threaded, e.g. when plugins and
* their features are unloaded.
*
* @param e enum names to remove previously added names from
* @param names additional enum names to remove
*/
void enum_remove_enum_names(enum_name_t *e, enum_name_t *names);
/** /**
* Convert a enum value to its string representation. * Convert a enum value to its string representation.
* *