summaryrefslogtreecommitdiff
path: root/shared/nm-glib-aux/nm-shared-utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'shared/nm-glib-aux/nm-shared-utils.c')
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.c290
1 files changed, 140 insertions, 150 deletions
diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c
index 681b4dd14a..ee917fdf6e 100644
--- a/shared/nm-glib-aux/nm-shared-utils.c
+++ b/shared/nm-glib-aux/nm-shared-utils.c
@@ -23,6 +23,9 @@ G_STATIC_ASSERT (G_STRUCT_OFFSET (NMUtilsNamedValue, value_ptr) == sizeof (const
/*****************************************************************************/
+const char _nm_hexchar_table_lower[16] = "0123456789abcdef";
+const char _nm_hexchar_table_upper[16] = "0123456789ABCDEF";
+
const void *const _NM_PTRARRAY_EMPTY[1] = { NULL };
/*****************************************************************************/
@@ -94,75 +97,6 @@ G_STATIC_ASSERT (ETH_ALEN == 6);
/*****************************************************************************/
-gsize
-nm_utils_get_next_realloc_size (gboolean true_realloc, gsize requested)
-{
- gsize n, x;
-
- /* https://doc.qt.io/qt-5/containers.html#growth-strategies */
-
- if (requested <= 40) {
- /* small allocations. Increase in small steps of 8 bytes.
- *
- * We get thus sizes of 8, 16, 32, 40. */
- if (requested <= 8)
- return 8;
- if (requested <= 16)
- return 16;
- if (requested <= 32)
- return 32;
-
- /* The return values for < 104 are essentially hard-coded, and the choice here is
- * made without very strong reasons.
- *
- * We want to stay 24 bytes below the power-of-two border 64. Hence, return 40 here.
- * However, the next step then is already 104 (128 - 24). It's a larger gap than in
- * the steps before.
- *
- * It's not clear whether some of the steps should be adjusted (or how exactly). */
- return 40;
- }
-
- if ( requested <= 0x2000u - 24u
- || G_UNLIKELY (!true_realloc)) {
- /* mid sized allocations. Return next power of two, minus 24 bytes extra space
- * at the beginning.
- * That means, we double the size as we grow.
- *
- * With !true_realloc, it means that the caller does not intend to call
- * realloc() but instead clone the buffer. This is for example the case, when we
- * want to nm_explicit_bzero() the old buffer. In that case we really want to grow
- * the buffer exponentially every time and not increment in page sizes of 4K (below).
- *
- * We get thus sizes of 104, 232, 488, 1000, 2024, 4072, 8168... */
-
- if (G_UNLIKELY (requested > G_MAXSIZE / 2u - 24u))
- return G_MAXSIZE;
-
- x = requested + 24u;
- n = 128u;
- while (n < x) {
- n <<= 1;
- nm_assert (n > 128u);
- }
-
- nm_assert (n > 24u && n - 24u >= requested);
- return n - 24u;
- }
-
- if (G_UNLIKELY (requested > G_MAXSIZE - 0x1000u - 24u))
- return G_MAXSIZE;
-
- /* For large allocations (with !true_realloc) we allocate memory in chunks of
- * 4K (- 24 bytes extra), assuming that the memory gets mmapped and thus
- * realloc() is efficient by just reordering pages. */
- n = ((requested + (0x0FFFu + 24u)) & ~((gsize) 0x0FFFu)) - 24u;
- nm_assert (n >= requested);
- return n;
-}
-
-/*****************************************************************************/
-
pid_t
nm_utils_gettid (void)
{
@@ -443,7 +377,7 @@ nm_utils_gbytes_equal_mem (GBytes *bytes,
gsize l;
if (!bytes) {
- /* as a special case, let %NULL GBytes compare idential
+ /* as a special case, let %NULL GBytes compare identical
* to an empty array. */
return (mem_len == 0);
}
@@ -478,50 +412,52 @@ nm_utils_gbytes_to_variant_ay (GBytes *bytes)
GVariant *
nm_utils_strdict_to_variant_ass (GHashTable *strdict)
{
- GHashTableIter iter;
- const char *key, *value;
+ gs_free NMUtilsNamedValue *values_free = NULL;
+ NMUtilsNamedValue values_prepared[20];
+ const NMUtilsNamedValue *values;
GVariantBuilder builder;
- guint i, len;
-
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
-
- if (!strdict)
- goto out;
- len = g_hash_table_size (strdict);
- if (!len)
- goto out;
+ guint i;
+ guint n;
- g_hash_table_iter_init (&iter, strdict);
- if (!g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value))
- nm_assert_not_reached ();
+ values = nm_utils_named_values_from_strdict (strdict,
+ &n,
+ values_prepared,
+ &values_free);
- if (len == 1)
- g_variant_builder_add (&builder, "{ss}", key, value);
- else {
- gs_free NMUtilsNamedValue *idx_free = NULL;
- NMUtilsNamedValue *idx;
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
+ for (i = 0; i < n; i++) {
+ g_variant_builder_add (&builder,
+ "{ss}",
+ values[i].name,
+ values[i].value_str);
+ }
+ return g_variant_builder_end (&builder);
+}
- if (len > 300 / sizeof (NMUtilsNamedValue)) {
- idx_free = g_new (NMUtilsNamedValue, len);
- idx = idx_free;
- } else
- idx = g_alloca (sizeof (NMUtilsNamedValue) * len);
+/*****************************************************************************/
- i = 0;
- do {
- idx[i].name = key;
- idx[i].value_str = value;
- i++;
- } while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value));
- nm_assert (i == len);
+GVariant *
+nm_utils_strdict_to_variant_asv (GHashTable *strdict)
+{
+ gs_free NMUtilsNamedValue *values_free = NULL;
+ NMUtilsNamedValue values_prepared[20];
+ const NMUtilsNamedValue *values;
+ GVariantBuilder builder;
+ guint i;
+ guint n;
- nm_utils_named_value_list_sort (idx, len, NULL, NULL);
+ values = nm_utils_named_values_from_strdict (strdict,
+ &n,
+ values_prepared,
+ &values_free);
- for (i = 0; i < len; i++)
- g_variant_builder_add (&builder, "{ss}", idx[i].name, idx[i].value_str);
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+ for (i = 0; i < n; i++) {
+ g_variant_builder_add (&builder,
+ "{sv}",
+ values[i].name,
+ g_variant_new_string (values[i].value_str));
}
-
-out:
return g_variant_builder_end (&builder);
}
@@ -1075,39 +1011,53 @@ nm_utils_parse_next_line (const char **inout_ptr,
const char **out_line,
gsize *out_line_len)
{
+ gboolean eol_is_carriage_return;
const char *line_start;
- const char *line_end;
+ gsize line_len;
- g_return_val_if_fail (inout_ptr, FALSE);
- g_return_val_if_fail (inout_len, FALSE);
- g_return_val_if_fail (out_line, FALSE);
+ nm_assert (inout_ptr);
+ nm_assert (inout_len);
+ nm_assert (*inout_len == 0 || *inout_ptr);
+ nm_assert (out_line);
+ nm_assert (out_line_len);
- if (*inout_len <= 0)
- goto error;
+ if (G_UNLIKELY (*inout_len == 0))
+ return FALSE;
line_start = *inout_ptr;
- line_end = memchr (line_start, '\n', *inout_len);
- if (!line_end)
- line_end = memchr (line_start, '\0', *inout_len);
- if (!line_end) {
- line_end = line_start + *inout_len;
- NM_SET_OUT (inout_len, 0);
- } else
- NM_SET_OUT (inout_len, *inout_len - (line_end - line_start) - 1);
- NM_SET_OUT (out_line, line_start);
- NM_SET_OUT (out_line_len, (gsize) (line_end - line_start));
+ eol_is_carriage_return = FALSE;
+ for (line_len = 0; ; line_len++) {
+ if (line_len >= *inout_len) {
+ /* if we consumed the entire line, we place the pointer at
+ * one character after the end. */
+ *inout_ptr = &line_start[line_len];
+ *inout_len = 0;
+ goto done;
+ }
+ switch (line_start[line_len]) {
+ case '\r':
+ eol_is_carriage_return = TRUE;
+ /* fall-through*/
+ case '\0':
+ case '\n':
+ *inout_ptr = &line_start[line_len + 1];
+ *inout_len = *inout_len - line_len - 1u;
+ if ( eol_is_carriage_return
+ && *inout_len > 0
+ && (*inout_ptr)[0] == '\n') {
+ /* also consume "\r\n" as one. */
+ (*inout_len)--;
+ (*inout_ptr)++;
+ }
+ goto done;
+ }
+ }
- if (*inout_len > 0)
- NM_SET_OUT (inout_ptr, line_end + 1);
- else
- NM_SET_OUT (inout_ptr, NULL);
+done:
+ *out_line = line_start;
+ *out_line_len = line_len;
return TRUE;
-
-error:
- NM_SET_OUT (out_line, NULL);
- NM_SET_OUT (out_line_len, 0);
- return FALSE;
}
/*****************************************************************************/
@@ -1529,7 +1479,7 @@ nm_utils_dbus_path_cmp (const char *dbus_path_a, const char *dbus_path_b)
if (n_a == -1 && n_b == -1)
goto comp_l;
- /* both components must be convertiable to a number. If they are not,
+ /* both components must be convertible to a number. If they are not,
* (and only one of them is), then we must always strictly sort numeric parts
* after non-numeric components. If we wouldn't, we wouldn't have
* a total order.
@@ -3045,28 +2995,44 @@ nm_utils_fd_read_loop_exact (int fd, void *buf, size_t nbytes, bool do_poll)
/*****************************************************************************/
+G_STATIC_ASSERT (G_STRUCT_OFFSET (NMUtilsNamedValue, name) == 0);
+
NMUtilsNamedValue *
-nm_utils_named_values_from_str_dict_with_sort (GHashTable *hash,
- guint *out_len,
- GCompareDataFunc compare_func,
- gpointer user_data)
+nm_utils_named_values_from_strdict_full (GHashTable *hash,
+ guint *out_len,
+ GCompareDataFunc compare_func,
+ gpointer user_data,
+ NMUtilsNamedValue *provided_buffer,
+ guint provided_buffer_len,
+ NMUtilsNamedValue **out_allocated_buffer)
{
GHashTableIter iter;
NMUtilsNamedValue *values;
guint i, len;
+ nm_assert (provided_buffer_len == 0 || provided_buffer);
+ nm_assert (!out_allocated_buffer || !*out_allocated_buffer);
+
if ( !hash
|| !(len = g_hash_table_size (hash))) {
NM_SET_OUT (out_len, 0);
return NULL;
}
+ if (provided_buffer_len >= len + 1) {
+ /* the buffer provided by the caller is large enough. Use it. */
+ values = provided_buffer;
+ } else {
+ /* allocate a new buffer. */
+ values = g_new (NMUtilsNamedValue, len + 1);
+ NM_SET_OUT (out_allocated_buffer, values);
+ }
+
i = 0;
- values = g_new (NMUtilsNamedValue, len + 1);
g_hash_table_iter_init (&iter, hash);
while (g_hash_table_iter_next (&iter,
(gpointer *) &values[i].name,
- (gpointer *) &values[i].value_ptr))
+ &values[i].value_ptr))
i++;
nm_assert (i == len);
values[i].name = NULL;
@@ -3324,7 +3290,7 @@ nm_utils_strv_make_deep_copied_n (const char **strv, gsize len)
*
* Note that if @len is non-negative, then it still must not
* contain any %NULL pointers within the first @len elements.
- * Otherwise you would leak elements if you try to free the
+ * Otherwise, you would leak elements if you try to free the
* array with g_strfreev(). Allowing that would be error prone.
*
* Returns: (transfer full): a clone of the strv array. Always
@@ -3779,7 +3745,7 @@ nm_utils_g_slist_find_str (const GSList *list,
* @b: the right #GSList of strings to compare.
*
* Compares two string lists. The data elements are compared with
- * strcmp(), alloing %NULL elements.
+ * strcmp(), allowing %NULL elements.
*
* Returns: 0, 1, or -1, depending on how the lists compare.
*/
@@ -4046,7 +4012,7 @@ nm_utils_memeqzero (gconstpointer data, gsize length)
* Returns: the binary value converted to a hex string. If @out is given,
* this always returns @out. If @out is %NULL, a newly allocated string
* is returned. This never returns %NULL, for buffers of length zero
- * an empty string is returend.
+ * an empty string is returned.
*/
char *
nm_utils_bin2hexstr_full (gconstpointer addr,
@@ -4949,7 +4915,7 @@ _nm_str_buf_ensure_size (NMStrBuf *strbuf,
{
_nm_str_buf_assert (strbuf);
- /* Currently this only supports strictly growing the buffer. */
+ /* Currently, this only supports strictly growing the buffer. */
nm_assert (new_size > strbuf->_priv_allocated);
if (!reserve_exact) {
@@ -5056,9 +5022,11 @@ void
_nm_utils_format_variant_attributes_full (GString *str,
const NMUtilsNamedValue *values,
guint num_values,
+ const NMVariantAttributeSpec *const *spec,
char attr_separator,
char key_value_separator)
{
+ const NMVariantAttributeSpec *const *s;
const char *name, *value;
GVariant *variant;
char *escaped;
@@ -5068,8 +5036,19 @@ _nm_utils_format_variant_attributes_full (GString *str,
for (i = 0; i < num_values; i++) {
name = values[i].name;
- variant = (GVariant *) values[i].value_ptr;
+ variant = values[i].value_ptr;
value = NULL;
+ s = NULL;
+
+ if (spec) {
+ for (s = spec; *s; s++) {
+ if (nm_streq0 ((*s)->name, name))
+ break;
+ }
+
+ if (!*s)
+ continue;
+ }
if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32))
value = nm_sprintf_buf (buf, "%u", g_variant_get_uint32 (variant));
@@ -5097,11 +5076,13 @@ _nm_utils_format_variant_attributes_full (GString *str,
g_string_append (str, escaped);
g_free (escaped);
- g_string_append_c (str, key_value_separator);
+ if (!s || !*s || !(*s)->no_value) {
+ g_string_append_c (str, key_value_separator);
- escaped = attribute_escape (value, attr_separator, key_value_separator);
- g_string_append (str, escaped);
- g_free (escaped);
+ escaped = attribute_escape (value, attr_separator, key_value_separator);
+ g_string_append (str, escaped);
+ g_free (escaped);
+ }
sep = attr_separator;
}
@@ -5109,25 +5090,34 @@ _nm_utils_format_variant_attributes_full (GString *str,
char *
_nm_utils_format_variant_attributes (GHashTable *attributes,
+ const NMVariantAttributeSpec *const *spec,
char attr_separator,
char key_value_separator)
{
+ gs_free NMUtilsNamedValue *values_free = NULL;
+ NMUtilsNamedValue values_prepared[20];
+ const NMUtilsNamedValue *values;
GString *str = NULL;
- gs_free NMUtilsNamedValue *values = NULL;
guint len;
g_return_val_if_fail (attr_separator, NULL);
g_return_val_if_fail (key_value_separator, NULL);
- if (!attributes || !g_hash_table_size (attributes))
+ if (!attributes)
return NULL;
- values = nm_utils_named_values_from_str_dict (attributes, &len);
+ values = nm_utils_named_values_from_strdict (attributes,
+ &len,
+ values_prepared,
+ &values_free);
+ if (len == 0)
+ return NULL;
str = g_string_new ("");
_nm_utils_format_variant_attributes_full (str,
values,
len,
+ spec,
attr_separator,
key_value_separator);
return g_string_free (str, FALSE);