]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
enum: Add functions to add and remove mappings from enum names
authorTobias Brunner <tobias@strongswan.org>
Thu, 16 Feb 2023 16:04:40 +0000 (17:04 +0100)
committerTobias Brunner <tobias@strongswan.org>
Fri, 17 Feb 2023 12:37:38 +0000 (13:37 +0100)
Co-authored-by: Thomas Egerer <thomas.egerer@secunet.com>
src/libstrongswan/tests/suites/test_enum.c
src/libstrongswan/utils/enum.c
src/libstrongswan/utils/enum.h

index c2329bdba4940d1054993e73728b8dd998dec63c..fdb37a8d14b79dbb284aff3b232a5993262fb77c 100644 (file)
@@ -85,6 +85,13 @@ ENUM_FLAGS(test_enum_flags_overflow_names, FLAG1, FLAG12, "(unset)",
        "OVERFLOWFLAGLONGNAME7",  "OVERFLOWFLAGLONGNAME8",  "OVERFLOWFLAGLONGNAME9",
        "OVERFLOWFLAGLONGNAME10", "OVERFLOWFLAGLONGNAME11", "OVERFLOWFLAGLONGNAME12");
 
+/*******************************************************************************
+ * add_enum_names
+ */
+
+ENUM_EXT(e1, 65000, 65001, "CONT65000", "CONT65001");
+ENUM_EXT(e2, 62000, 62001, "CONT62000", "CONT62001");
+
 /*******************************************************************************
  * enum_to_name
  */
@@ -172,6 +179,15 @@ static struct {
        {FALSE, 0, "asdf"},
        {FALSE, 0, ""},
        {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)
@@ -196,6 +212,23 @@ START_TEST(test_enum_from_name_split)
 }
 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
  */
@@ -441,6 +474,51 @@ START_TEST(test_enum_printf_hook_width)
 }
 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 *s;
@@ -456,6 +534,7 @@ Suite *enum_suite_create()
        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_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);
 
        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_noflagenum, 0, countof(printf_tests_flags_noflagenum));
        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);
 
        return s;
index 4f93e8c6d2f6c715e7bea1d6aa03e1960b5bc0bc..b6f65f2e8f7c31952c54889a7a886ea92d31e3a5 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2023 Tobias Brunner
  * Copyright (C) 2006 Martin Willi
  *
  * Copyright (C) secunet Security Networks AG
 
 #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.
  */
index 45649224ea4944fdae531bcc44151f526084114e..5b3957b268f41a1740e497aa9d74fb140abf86ec 100644 (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) secunet Security Networks AG
@@ -140,6 +140,41 @@ struct enum_name_t {
                        countof(((char*[]){__VA_ARGS__}))), \
                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.
  *