From c6f8c0632c3209e4db0e79f073f23e28597f04fc Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 19 Nov 2018 12:16:05 +0100 Subject: [PATCH] shared: allow optional trailing comma in NM_MAKE_STRV() Supporting a trailing comma in NM_MAKE_STRV() can be desirable, because it allows to extend the code with less noise in the diff. Now, there may or may not be a trailing comma at the end. There is a downside to this: the following no longer work: const char *const v1[] = NM_MAKE_STRV ("a", "b"); const char *const v2[3] = NM_MAKE_STRV ("a", "b"); but then, above can be written more simply already as: const char *const v1[] = { "a", "b", NULL }; const char *const v2[3] = { "a", "b" }; so the fact that the macro won't work in that case may be preferable, because it forces you to use the already existing better variant. --- shared/nm-utils/nm-macros-internal.h | 5 ++- shared/nm-utils/tests/test-shared-general.c | 41 +++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h index 40e2dd0bc..82e1e02b4 100644 --- a/shared/nm-utils/nm-macros-internal.h +++ b/shared/nm-utils/nm-macros-internal.h @@ -639,8 +639,11 @@ NM_G_ERROR_MSG (GError *error) #define NM_PROPAGATE_CONST(test_expr, ptr) (ptr) #endif +/* with the way it is implemented, the caller may or may not pass a trailing + * ',' and it will work. However, this makes the macro unsuitable for initializing + * an array. */ #define NM_MAKE_STRV(...) \ - ((const char *const[]) { __VA_ARGS__, NULL }) + ((const char *const[(sizeof (((const char *const[]) { __VA_ARGS__ })) / sizeof (const char *)) + 1]) { __VA_ARGS__ }) /*****************************************************************************/ diff --git a/shared/nm-utils/tests/test-shared-general.c b/shared/nm-utils/tests/test-shared-general.c index f186e423b..ecc138748 100644 --- a/shared/nm-utils/tests/test-shared-general.c +++ b/shared/nm-utils/tests/test-shared-general.c @@ -62,6 +62,46 @@ test_nmhash (void) /*****************************************************************************/ +static const char * +_make_strv_foo (void) +{ + return "foo"; +} + +static const char *const*const _tst_make_strv_1 = NM_MAKE_STRV ("1", "2"); + +static void +test_make_strv (void) +{ + const char *const*v1a = NM_MAKE_STRV ("a"); + const char *const*v1b = NM_MAKE_STRV ("a", ); + const char *const*v2a = NM_MAKE_STRV ("a", "b"); + const char *const*v2b = NM_MAKE_STRV ("a", "b", ); + const char *const v3[] = { "a", "b", }; + const char *const*v4b = NM_MAKE_STRV ("a", _make_strv_foo (), ); + + g_assert (NM_PTRARRAY_LEN (v1a) == 1); + g_assert (NM_PTRARRAY_LEN (v1b) == 1); + g_assert (NM_PTRARRAY_LEN (v2a) == 2); + g_assert (NM_PTRARRAY_LEN (v2b) == 2); + + g_assert (NM_PTRARRAY_LEN (_tst_make_strv_1) == 2); + g_assert_cmpstr (_tst_make_strv_1[0], ==, "1"); + g_assert_cmpstr (_tst_make_strv_1[1], ==, "2"); + /* writing the static read-only variable leads to crash .*/ + //((char **) _tst_make_strv_1)[0] = NULL; + //((char **) _tst_make_strv_1)[2] = "c"; + + G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (v3) == 2); + + g_assert (NM_PTRARRAY_LEN (v4b) == 2); + + G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (NM_MAKE_STRV ("a", "b" )) == 3); + G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (NM_MAKE_STRV ("a", "b", )) == 3); +} + +/*****************************************************************************/ + NMTST_DEFINE (); int main (int argc, char **argv) @@ -70,6 +110,7 @@ int main (int argc, char **argv) g_test_add_func ("/general/test_monotonic_timestamp", test_monotonic_timestamp); g_test_add_func ("/general/test_nmhash", test_nmhash); + g_test_add_func ("/general/test_nm_make_strv", test_make_strv); return g_test_run (); }