diff options
author | Thomas Haller <thaller@redhat.com> | 2020-08-24 19:09:53 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2020-08-25 09:54:11 +0200 |
commit | 2e0cd52474da9998b187b8aa3ba65f3686ad4d7e (patch) | |
tree | 81a41879a92c6930c1d408aa60791163afe94dc8 | |
parent | c25f4d947a46a2b96afab25e023bbf2611edde59 (diff) | |
download | NetworkManager-2e0cd52474da9998b187b8aa3ba65f3686ad4d7e.tar.gz |
shared: add nm_utils_strv_dup_packed() util
-rw-r--r-- | shared/nm-glib-aux/nm-shared-utils.c | 68 | ||||
-rw-r--r-- | shared/nm-glib-aux/nm-shared-utils.h | 5 | ||||
-rw-r--r-- | shared/nm-glib-aux/tests/test-shared-general.c | 46 |
3 files changed, 119 insertions, 0 deletions
diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index 704ee089a9..be7b1cd9c7 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -3422,6 +3422,74 @@ _nm_utils_strv_dup (const char *const*strv, return v; } +const char ** +_nm_utils_strv_dup_packed (const char *const*strv, + gssize len) + +{ + const char **result; + gsize mem_len; + gsize pre_len; + gsize len2; + char *sbuf; + gsize i; + + nm_assert (len >= -1); + + mem_len = 0; + if (G_LIKELY (len < 0)) { + if ( !strv + || !strv[0]) { + /* This function never returns an empty strv array. If you need that, handle it + * yourself. */ + return NULL; + } + for (i = 0; strv[i]; i++) + mem_len += strlen (strv[i]); + len2 = i; + } else { + if (len == 0) + return NULL; + len2 = len; + for (i = 0; i < len; i++) { + if (G_LIKELY (strv[i])) + mem_len += strlen (strv[i]); + } + } + mem_len += len2; + + pre_len = sizeof (const char *) * (len2 + 1u); + + result = g_malloc (pre_len + mem_len); + sbuf = &(((char *) result)[pre_len]); + for (i = 0; i < len2; i++) { + gsize l; + + if (G_UNLIKELY (!strv[i])) { + /* Technically there is no problem with accepting NULL strings. But that + * does not really result in a strv array, and likely this only happens due + * to a bug. We want to catch such bugs by asserting. + * + * We clear the remainder of the buffer and fail with an assertion. */ + len2++; + for (; i < len2; i++) + result[i] = NULL; + g_return_val_if_reached (result);; + } + + result[i] = sbuf; + + l = strlen (strv[i]) + 1u; + memcpy (sbuf, strv[i], l); + sbuf += l; + } + result[i] = NULL; + nm_assert (i == len2); + nm_assert (sbuf == (&((const char *) result)[pre_len]) + mem_len); + + return result; +} + /*****************************************************************************/ gssize diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index f7788d9c08..a1e142d3ff 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -1533,6 +1533,11 @@ char **_nm_utils_strv_dup (const char *const*strv, #define nm_utils_strv_dup(strv, len, deep_copied) _nm_utils_strv_dup (NM_CAST_STRV_CC (strv), (len), (deep_copied)) +const char **_nm_utils_strv_dup_packed (const char *const*strv, + gssize len); + +#define nm_utils_strv_dup_packed(strv, len) _nm_utils_strv_dup_packed (NM_CAST_STRV_CC (strv), (len)) + /*****************************************************************************/ GSList *nm_utils_g_slist_find_str (const GSList *list, diff --git a/shared/nm-glib-aux/tests/test-shared-general.c b/shared/nm-glib-aux/tests/test-shared-general.c index b4b958c503..2d5bbd2220 100644 --- a/shared/nm-glib-aux/tests/test-shared-general.c +++ b/shared/nm-glib-aux/tests/test-shared-general.c @@ -941,6 +941,51 @@ test_is_specific_hostname (void) /*****************************************************************************/ +static void +test_strv_dup_packed (void) +{ + gs_unref_ptrarray GPtrArray *src = NULL; + int i_run; + + + src = g_ptr_array_new_with_free_func (g_free); + + for (i_run = 0; i_run < 500; i_run++) { + const int strv_len = nmtst_get_rand_word_length (NULL); + gs_free const char **strv_cpy = NULL; + const char *const*strv_src; + int i, j; + + g_ptr_array_set_size (src, 0); + for (i = 0; i < strv_len; i++) { + const int word_len = nmtst_get_rand_word_length (NULL); + NMStrBuf sbuf = NM_STR_BUF_INIT (0, nmtst_get_rand_bool ()); + + for (j = 0; j < word_len; j++) + nm_str_buf_append_c (&sbuf, 'a' + (nmtst_get_rand_uint32 () % 20)); + + g_ptr_array_add (src, nm_str_buf_finalize (&sbuf, NULL) ?: g_new0 (char, 1)); + } + g_ptr_array_add (src, NULL); + + strv_src = (const char *const*) src->pdata; + g_assert (strv_src); + g_assert (NM_PTRARRAY_LEN (strv_src) == strv_len); + + strv_cpy = nm_utils_strv_dup_packed (strv_src, + nmtst_get_rand_bool () ? (gssize) strv_len : (gssize) -1); + if (strv_len == 0) + g_assert (!strv_cpy); + else + g_assert (strv_cpy); + g_assert (NM_PTRARRAY_LEN (strv_cpy) == strv_len); + if (strv_cpy) + g_assert (_nm_utils_strv_equal ((char **) strv_cpy, (char **) strv_src)); + } +} + +/*****************************************************************************/ + NMTST_DEFINE (); int main (int argc, char **argv) @@ -965,6 +1010,7 @@ int main (int argc, char **argv) g_test_add_func ("/general/test_nm_utils_parse_next_line", test_nm_utils_parse_next_line); g_test_add_func ("/general/test_in_strset_ascii_case", test_in_strset_ascii_case); g_test_add_func ("/general/test_is_specific_hostname", test_is_specific_hostname); + g_test_add_func ("/general/test_strv_dup_packed", test_strv_dup_packed); return g_test_run (); } |