mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-04 23:30:28 +01:00
glib-aux: refactor nm_strvarray_get_strv*() and nm_strvarray_set_strv*() helpers
Unfortunately, there are several possibilities how to handle NULL and empty arrays. Therefore we have different variants. Clean this up, and add a way to preserve whether the array is empty (previous variants could not distinguish that). Functions are also renamed, so that if you backport a user of the new API, you'll get a compiler error if this patch is missing. Also, nm_strvarray_get_strv_notnull() no longer takes a pointer to a "GArray*". Previously, it used that to fake an empty strv array. Now this returns NM_STRV_EMPTY_CC().
This commit is contained in:
parent
e48fc3ee3e
commit
563fad718c
6 changed files with 198 additions and 73 deletions
|
|
@ -908,7 +908,7 @@ _nm_setting_connection_verify_secondaries(GArray *secondaries, GError **error)
|
|||
* Now, when we find any invalid/non-normalized values, we reject/normalize
|
||||
* them. We also filter out duplicates. */
|
||||
|
||||
strv = nm_strvarray_get_strv_non_empty(secondaries, NULL);
|
||||
strv = nm_strvarray_get_strv_notempty(secondaries, NULL);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
const char *uuid = strv[i];
|
||||
|
|
@ -977,7 +977,7 @@ _normalize_connection_secondaries(NMConnection *self)
|
|||
if (_nm_setting_connection_verify_secondaries(secondaries, NULL))
|
||||
return FALSE;
|
||||
|
||||
strv = nm_strvarray_get_strv_non_empty_dup(secondaries, NULL);
|
||||
strv = nm_strvarray_get_strv_notempty_dup(secondaries, NULL);
|
||||
for (i = 0, j = 0; strv[i]; i++) {
|
||||
gs_free char *s = g_steal_pointer(&strv[i]);
|
||||
char uuid_normalized[37];
|
||||
|
|
|
|||
|
|
@ -5352,8 +5352,8 @@ nm_setting_ip_config_get_dhcp_reject_servers(NMSettingIPConfig *setting, guint *
|
|||
{
|
||||
g_return_val_if_fail(NM_IS_SETTING_IP_CONFIG(setting), NULL);
|
||||
|
||||
return nm_strvarray_get_strv(
|
||||
&NM_SETTING_IP_CONFIG_GET_PRIVATE(setting)->dhcp_reject_servers.arr,
|
||||
return nm_strvarray_get_strv_notnull(
|
||||
NM_SETTING_IP_CONFIG_GET_PRIVATE(setting)->dhcp_reject_servers.arr,
|
||||
out_len);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ nm_setting_match_get_interface_names(NMSettingMatch *setting, guint *length)
|
|||
{
|
||||
g_return_val_if_fail(NM_IS_SETTING_MATCH(setting), NULL);
|
||||
|
||||
return nm_strvarray_get_strv(&setting->interface_name.arr, length);
|
||||
return nm_strvarray_get_strv_notnull(setting->interface_name.arr, length);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -320,7 +320,7 @@ nm_setting_match_get_kernel_command_lines(NMSettingMatch *setting, guint *length
|
|||
{
|
||||
g_return_val_if_fail(NM_IS_SETTING_MATCH(setting), NULL);
|
||||
|
||||
return nm_strvarray_get_strv(&setting->kernel_command_line.arr, length);
|
||||
return nm_strvarray_get_strv_notnull(setting->kernel_command_line.arr, length);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -456,7 +456,7 @@ nm_setting_match_get_drivers(NMSettingMatch *setting, guint *length)
|
|||
{
|
||||
g_return_val_if_fail(NM_IS_SETTING_MATCH(setting), NULL);
|
||||
|
||||
return nm_strvarray_get_strv(&setting->driver.arr, length);
|
||||
return nm_strvarray_get_strv_notnull(setting->driver.arr, length);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -592,7 +592,7 @@ nm_setting_match_get_paths(NMSettingMatch *setting, guint *length)
|
|||
{
|
||||
g_return_val_if_fail(NM_IS_SETTING_MATCH(setting), NULL);
|
||||
|
||||
return nm_strvarray_get_strv(&setting->path.arr, length);
|
||||
return nm_strvarray_get_strv_notnull(setting->path.arr, length);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -817,7 +817,7 @@ _nm_setting_property_get_property_direct(GObject *object,
|
|||
{
|
||||
const NMValueStrv *p_val = _nm_setting_get_private_field(setting, sett_info, property_info);
|
||||
|
||||
g_value_take_boxed(value, nm_strvarray_get_strv_non_empty_dup(p_val->arr, NULL));
|
||||
g_value_take_boxed(value, nm_strvarray_get_strv_notempty_dup(p_val->arr, NULL));
|
||||
return;
|
||||
}
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -5108,44 +5108,42 @@ test_setting_connection_secondaries_verify(void)
|
|||
|
||||
g_object_set(s_con, NM_SETTING_CONNECTION_SECONDARIES, arr->pdata, NULL);
|
||||
|
||||
#define _assert_secondaries(s_con, expected) \
|
||||
G_STMT_START \
|
||||
{ \
|
||||
NMSettingConnection *const _s_con = (s_con); \
|
||||
const char *const *_expected = (expected); \
|
||||
GArray *_secondaries; \
|
||||
const guint _expected_len = NM_PTRARRAY_LEN(_expected); \
|
||||
gs_strfreev char **_sec_strv = NULL; \
|
||||
guint _i; \
|
||||
\
|
||||
g_assert(_expected); \
|
||||
\
|
||||
if (nmtst_get_rand_bool()) { \
|
||||
_secondaries = _nm_setting_connection_get_secondaries(_s_con); \
|
||||
g_assert_cmpint(_expected_len, ==, nm_g_array_len(_secondaries)); \
|
||||
g_assert((_expected_len == 0) == (!_secondaries)); \
|
||||
g_assert(nm_strv_equal(_expected, \
|
||||
_secondaries ? nm_strvarray_get_strv(&_secondaries, NULL) \
|
||||
: NM_PTRARRAY_EMPTY(const char *))); \
|
||||
} \
|
||||
\
|
||||
if (nmtst_get_rand_bool()) { \
|
||||
g_object_get(_s_con, NM_SETTING_CONNECTION_SECONDARIES, &_sec_strv, NULL); \
|
||||
g_assert_cmpint(_expected_len, ==, NM_PTRARRAY_LEN(_sec_strv)); \
|
||||
g_assert((_expected_len == 0) == (!_sec_strv)); \
|
||||
g_assert(nm_strv_equal(_expected, _sec_strv ?: NM_STRV_EMPTY())); \
|
||||
} \
|
||||
\
|
||||
g_assert_cmpint(nm_setting_connection_get_num_secondaries(_s_con), ==, _expected_len); \
|
||||
if (nmtst_get_rand_bool()) { \
|
||||
for (_i = 0; _i < _expected_len; _i++) { \
|
||||
g_assert_cmpstr(nm_setting_connection_get_secondary(_s_con, _i), \
|
||||
==, \
|
||||
_expected[_i]); \
|
||||
} \
|
||||
g_assert_null(nm_setting_connection_get_secondary(_s_con, _expected_len)); \
|
||||
} \
|
||||
} \
|
||||
#define _assert_secondaries(s_con, expected) \
|
||||
G_STMT_START \
|
||||
{ \
|
||||
NMSettingConnection *const _s_con = (s_con); \
|
||||
const char *const *_expected = (expected); \
|
||||
GArray *_secondaries; \
|
||||
const guint _expected_len = NM_PTRARRAY_LEN(_expected); \
|
||||
gs_strfreev char **_sec_strv = NULL; \
|
||||
guint _i; \
|
||||
\
|
||||
g_assert(_expected); \
|
||||
\
|
||||
if (nmtst_get_rand_bool()) { \
|
||||
_secondaries = _nm_setting_connection_get_secondaries(_s_con); \
|
||||
g_assert_cmpint(_expected_len, ==, nm_g_array_len(_secondaries)); \
|
||||
g_assert((_expected_len == 0) == (!_secondaries)); \
|
||||
g_assert(nm_strv_equal(_expected, nm_strvarray_get_strv_notnull(_secondaries, NULL))); \
|
||||
} \
|
||||
\
|
||||
if (nmtst_get_rand_bool()) { \
|
||||
g_object_get(_s_con, NM_SETTING_CONNECTION_SECONDARIES, &_sec_strv, NULL); \
|
||||
g_assert_cmpint(_expected_len, ==, NM_PTRARRAY_LEN(_sec_strv)); \
|
||||
g_assert((_expected_len == 0) == (!_sec_strv)); \
|
||||
g_assert(nm_strv_equal(_expected, _sec_strv ?: NM_STRV_EMPTY())); \
|
||||
} \
|
||||
\
|
||||
g_assert_cmpint(nm_setting_connection_get_num_secondaries(_s_con), ==, _expected_len); \
|
||||
if (nmtst_get_rand_bool()) { \
|
||||
for (_i = 0; _i < _expected_len; _i++) { \
|
||||
g_assert_cmpstr(nm_setting_connection_get_secondary(_s_con, _i), \
|
||||
==, \
|
||||
_expected[_i]); \
|
||||
} \
|
||||
g_assert_null(nm_setting_connection_get_secondary(_s_con, _expected_len)); \
|
||||
} \
|
||||
} \
|
||||
G_STMT_END
|
||||
|
||||
_assert_secondaries(s_con, (const char *const *) arr->pdata);
|
||||
|
|
|
|||
|
|
@ -3040,53 +3040,159 @@ nm_strvarray_get_idx(const GArray *array, guint idx)
|
|||
_idx == _len ? NULL : nm_strvarray_get_idx(_arr, _idx); \
|
||||
})
|
||||
|
||||
/**
|
||||
* nm_strvarray_get_strv_full:
|
||||
* @arr: the strvarray.
|
||||
* @length: (out) (nullable): optionally return the length of the result.
|
||||
* @not_null: if true and @arr is NULL, return NM_STRV_EMPTY_CC() (otherwise NULL).
|
||||
* @preserve_empty: if true and the array is empty, return an empty
|
||||
* strv array. Otherwise, return NULL.
|
||||
*
|
||||
* If "arr" is NULL, this returns NULL, unless "not_null" is true (in which
|
||||
* case the static NM_STRV_EMPTY_CC() is returned).
|
||||
* If "arr" is empty, it depends on:
|
||||
* - if "preserve_empty" or "not_null", then the resulting strv array is the empty "arr".
|
||||
* - otherwise NULL is returned.
|
||||
* Otherwise, returns the non-empty, non-deep-cloned strv array.
|
||||
*
|
||||
* Like nm_strvarray_get_strv_full_dup(), but the strings are not cloned.
|
||||
*
|
||||
* Returns: (transfer none): a strv list or NULL.
|
||||
*/
|
||||
static inline const char *const *
|
||||
nm_strvarray_get_strv_non_empty(GArray *arr, guint *length)
|
||||
nm_strvarray_get_strv_full(const GArray *arr,
|
||||
guint *length,
|
||||
gboolean not_null,
|
||||
gboolean preserve_empty)
|
||||
{
|
||||
nm_assert(!arr || sizeof(char *) == g_array_get_element_size(arr));
|
||||
|
||||
if (!arr || arr->len == 0) {
|
||||
if (!arr) {
|
||||
NM_SET_OUT(length, 0);
|
||||
return NULL;
|
||||
return not_null ? NM_STRV_EMPTY_CC() : NULL;
|
||||
}
|
||||
|
||||
nm_assert(sizeof(char *) == g_array_get_element_size((GArray *) arr));
|
||||
|
||||
NM_SET_OUT(length, arr->len);
|
||||
|
||||
if (arr->len == 0 && !(preserve_empty || not_null))
|
||||
return NULL;
|
||||
|
||||
return &g_array_index(arr, const char *, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_strvarray_get_strv_full_dup:
|
||||
* @arr: the strvarray.
|
||||
* @length: (out) (nullable): optionally return the length of the result.
|
||||
* @not_null: if true, never return NULL but allocate an empty strv array.
|
||||
* @preserve_empty: if true and the array is empty, return an empty
|
||||
* strv array. Otherwise, return NULL.
|
||||
*
|
||||
* If "arr" is NULL, this returns NULL, unless "not_null" is true (in which case
|
||||
* am empty strv array is allocated.
|
||||
* If "arr" is empty, it depends on:
|
||||
* - if "preserve_empty" || "not_null", then the resulting strv array is allocated (and empty).
|
||||
* - otherwise, NULL is returned.
|
||||
* Otherwise, return the non-empty, deep-cloned strv array.
|
||||
*
|
||||
* Like nm_strvarray_get_strv_full(), but the strings are cloned.
|
||||
*
|
||||
* Returns: (transfer full): a deep-cloned strv list or NULL.
|
||||
*/
|
||||
static inline char **
|
||||
nm_strvarray_get_strv_non_empty_dup(GArray *arr, guint *length)
|
||||
nm_strvarray_get_strv_full_dup(const GArray *arr,
|
||||
guint *length,
|
||||
gboolean not_null,
|
||||
gboolean preserve_empty)
|
||||
{
|
||||
const char *const *strv;
|
||||
|
||||
nm_assert(!arr || sizeof(char *) == g_array_get_element_size(arr));
|
||||
|
||||
if (!arr || arr->len == 0) {
|
||||
if (!arr) {
|
||||
NM_SET_OUT(length, 0);
|
||||
return not_null ? g_new0(char *, 1) : NULL;
|
||||
}
|
||||
|
||||
nm_assert(sizeof(char *) == g_array_get_element_size((GArray *) arr));
|
||||
|
||||
NM_SET_OUT(length, arr->len);
|
||||
|
||||
if (arr->len == 0) {
|
||||
if (preserve_empty || not_null)
|
||||
return g_new0(char *, 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NM_SET_OUT(length, arr->len);
|
||||
strv = &g_array_index(arr, const char *, 0);
|
||||
return nm_strv_dup(strv, arr->len, TRUE);
|
||||
return nm_strv_dup(&g_array_index(arr, const char *, 0), arr->len, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_strvarray_get_strv_notnull:
|
||||
* @arr: the strvarray.
|
||||
* @length: (out) (nullable): optionally return the length of the result.
|
||||
*
|
||||
* This never returns NULL. If @arr is NULL, this returns NM_STRV_EMPTY_CC().
|
||||
*
|
||||
* Like nm_strvarray_get_strv_notempty(), but never returns NULL.
|
||||
*
|
||||
* Returns: (transfer none): a pointer to the strv list in @arr or NM_STRV_EMPTY_CC().
|
||||
*/
|
||||
static inline const char *const *
|
||||
nm_strvarray_get_strv(GArray **arr, guint *length)
|
||||
nm_strvarray_get_strv_notnull(const GArray *arr, guint *length)
|
||||
{
|
||||
if (!*arr) {
|
||||
NM_SET_OUT(length, 0);
|
||||
return (const char *const *) arr;
|
||||
}
|
||||
|
||||
nm_assert(sizeof(char *) == g_array_get_element_size(*arr));
|
||||
|
||||
NM_SET_OUT(length, (*arr)->len);
|
||||
return &g_array_index(*arr, const char *, 0);
|
||||
return nm_strvarray_get_strv_full(arr, length, TRUE, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_strvarray_get_strv_notempty:
|
||||
* @arr: the strvarray.
|
||||
* @length: (out) (nullable): optionally return the length of the result.
|
||||
*
|
||||
* This never returns an empty strv array. If @arr is NULL or empty, this
|
||||
* returns NULL.
|
||||
*
|
||||
* Like nm_strvarray_get_strv_notempty_dup(), but does not clone strings.
|
||||
*
|
||||
* Returns: (transfer none): a pointer to the strv list in @arr or NULL.
|
||||
*/
|
||||
static inline const char *const *
|
||||
nm_strvarray_get_strv_notempty(const GArray *arr, guint *length)
|
||||
{
|
||||
return nm_strvarray_get_strv_full(arr, length, FALSE, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_strvarray_get_strv_notempty_dup:
|
||||
* @arr: the strvarray.
|
||||
* @length: (out) (nullable): optionally return the length of the result.
|
||||
*
|
||||
* This never returns an empty strv array. If @arr is NULL or empty, this
|
||||
* returns NULL.
|
||||
*
|
||||
* Like nm_strvarray_get_strv_notempty(), but clones strings.
|
||||
*
|
||||
* Returns: (transfer full): a deep-cloned strv list or NULL.
|
||||
*/
|
||||
static inline char **
|
||||
nm_strvarray_get_strv_notempty_dup(const GArray *arr, guint *length)
|
||||
{
|
||||
return nm_strvarray_get_strv_full_dup(arr, length, FALSE, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_strvarray_set_strv_full:
|
||||
* @array: a pointer to the array to set.
|
||||
* @strv: the strv array. May be NULL.
|
||||
* @preserve_empty: how to treat if strv is empty (strv[0]==NULL).
|
||||
*
|
||||
* The old array will be freed (in a way so that the function is self-assignment
|
||||
* safe).
|
||||
*
|
||||
* If "strv" is NULL, then the resulting GArray is NULL.
|
||||
* If "strv" is empty, then it depends on "preserve_empty":
|
||||
* - if "preserve_empty", then the resulting GArray is allocated (and empty).
|
||||
* - if "!preserve_empty", then the resulting GArray is NULL.
|
||||
* If "strv" is not empty, a GArray gets allocated and the strv array deep-cloned.
|
||||
*/
|
||||
static inline void
|
||||
nm_strvarray_set_strv(GArray **array, const char *const *strv)
|
||||
nm_strvarray_set_strv_full(GArray **array, const char *const *strv, gboolean preserve_empty)
|
||||
{
|
||||
gs_unref_array GArray *array_old = NULL;
|
||||
|
||||
|
|
@ -3094,14 +3200,35 @@ nm_strvarray_set_strv(GArray **array, const char *const *strv)
|
|||
|
||||
nm_assert(!array_old || sizeof(char *) == g_array_get_element_size(array_old));
|
||||
|
||||
if (!strv || !strv[0])
|
||||
if (!strv)
|
||||
return;
|
||||
|
||||
if (!strv[0] && !preserve_empty) {
|
||||
/* An empty strv array is treated like NULL. Don't allocate a GArray. */
|
||||
return;
|
||||
}
|
||||
|
||||
nm_strvarray_ensure(array);
|
||||
for (; strv[0]; strv++)
|
||||
nm_strvarray_add(*array, strv[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_strvarray_set_strv:
|
||||
* @array: a pointer to the array to set.
|
||||
* @strv: the strv array. May be NULL.
|
||||
*
|
||||
* The old array will be freed (in a way so that the function is self-assignment
|
||||
* safe).
|
||||
*
|
||||
* Note that this will never initialize an empty GArray. If strv is NULL or
|
||||
* empty, the @array pointer will be set to NULL. */
|
||||
static inline void
|
||||
nm_strvarray_set_strv(GArray **array, const char *const *strv)
|
||||
{
|
||||
nm_strvarray_set_strv_full(array, strv, FALSE);
|
||||
}
|
||||
|
||||
static inline gssize
|
||||
nm_strvarray_find_first(const GArray *strv, const char *needle)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue