summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-08-24 19:09:53 +0200
committerThomas Haller <thaller@redhat.com>2020-08-25 09:54:11 +0200
commit2e0cd52474da9998b187b8aa3ba65f3686ad4d7e (patch)
tree81a41879a92c6930c1d408aa60791163afe94dc8
parentc25f4d947a46a2b96afab25e023bbf2611edde59 (diff)
downloadNetworkManager-2e0cd52474da9998b187b8aa3ba65f3686ad4d7e.tar.gz
shared: add nm_utils_strv_dup_packed() util
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.c68
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.h5
-rw-r--r--shared/nm-glib-aux/tests/test-shared-general.c46
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 ();
}