summary refs log tree commit diff
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.c7727
1 files changed, 4100 insertions, 3627 deletions
diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c
index 3d1b0098..b0e02381 100644
--- a/shared/nm-glib-aux/nm-shared-utils.c
+++ b/shared/nm-glib-aux/nm-shared-utils.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: LGPL-2.1+
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /*
  * Copyright (C) 2016 Red Hat, Inc.
  */
@@ -7,6 +7,7 @@
 
 #include "nm-shared-utils.h"
 
+#include <pwd.h>
 #include <arpa/inet.h>
 #include <poll.h>
 #include <fcntl.h>
@@ -18,16 +19,19 @@
 #include "nm-errno.h"
 #include "nm-str-buf.h"
 
-G_STATIC_ASSERT (sizeof (NMUtilsNamedEntry) == sizeof (const char *));
-G_STATIC_ASSERT (G_STRUCT_OFFSET (NMUtilsNamedValue, value_ptr) == sizeof (const char *));
+G_STATIC_ASSERT(sizeof(NMUtilsNamedEntry) == sizeof(const char *));
+G_STATIC_ASSERT(G_STRUCT_OFFSET(NMUtilsNamedValue, value_ptr) == sizeof(const char *));
 
 /*****************************************************************************/
 
-const void *const _NM_PTRARRAY_EMPTY[1] = { NULL };
+const char _nm_hexchar_table_lower[16] = "0123456789abcdef";
+const char _nm_hexchar_table_upper[16] = "0123456789ABCDEF";
+
+const void *const _NM_PTRARRAY_EMPTY[1] = {NULL};
 
 /*****************************************************************************/
 
-const NMIPAddr nm_ip_addr_zero = { };
+const NMIPAddr nm_ip_addr_zero = {};
 
 /* this initializes a struct in_addr/in6_addr and allows for untrusted
  * arguments (like unsuitable @addr_family or @src_len). It's almost safe
@@ -42,131 +46,66 @@ const NMIPAddr nm_ip_addr_zero = { };
  *   Meaning, if @dst is an NMIPAddr union, only the first bytes will be set.
  *   If that matter to you, clear @dst before. */
 gboolean
-nm_ip_addr_set_from_untrusted (int addr_family,
-                               gpointer dst,
-                               gconstpointer src,
-                               gsize src_len,
-                               int *out_addr_family)
-{
-	nm_assert (dst);
-
-	switch (addr_family) {
-	case AF_UNSPEC:
-		if (!out_addr_family) {
-			/* when the callers allow undefined @addr_family, they must provide
-			 * an @out_addr_family argument. */
-			nm_assert_not_reached ();
-			return FALSE;
-		}
-		switch (src_len) {
-		case sizeof (struct in_addr):  addr_family = AF_INET;  break;
-		case sizeof (struct in6_addr): addr_family = AF_INET6; break;
-		default:
-			return FALSE;
-		}
-		break;
-	case AF_INET:
-		if (src_len != sizeof (struct in_addr))
-			return FALSE;
-		break;
-	case AF_INET6:
-		if (src_len != sizeof (struct in6_addr))
-			return FALSE;
-		break;
-	default:
-		/* when the callers allow undefined @addr_family, they must provide
-		 * an @out_addr_family argument. */
-		nm_assert (out_addr_family);
-		return FALSE;
-	}
-
-	nm_assert (src);
-
-	memcpy (dst, src, src_len);
-	NM_SET_OUT (out_addr_family, addr_family);
-	return TRUE;
+nm_ip_addr_set_from_untrusted(int           addr_family,
+                              gpointer      dst,
+                              gconstpointer src,
+                              gsize         src_len,
+                              int *         out_addr_family)
+{
+    nm_assert(dst);
+
+    switch (addr_family) {
+    case AF_UNSPEC:
+        if (!out_addr_family) {
+            /* when the callers allow undefined @addr_family, they must provide
+             * an @out_addr_family argument. */
+            nm_assert_not_reached();
+            return FALSE;
+        }
+        switch (src_len) {
+        case sizeof(struct in_addr):
+            addr_family = AF_INET;
+            break;
+        case sizeof(struct in6_addr):
+            addr_family = AF_INET6;
+            break;
+        default:
+            return FALSE;
+        }
+        break;
+    case AF_INET:
+        if (src_len != sizeof(struct in_addr))
+            return FALSE;
+        break;
+    case AF_INET6:
+        if (src_len != sizeof(struct in6_addr))
+            return FALSE;
+        break;
+    default:
+        /* when the callers allow undefined @addr_family, they must provide
+         * an @out_addr_family argument. */
+        nm_assert(out_addr_family);
+        return FALSE;
+    }
+
+    nm_assert(src);
+
+    memcpy(dst, src, src_len);
+    NM_SET_OUT(out_addr_family, addr_family);
+    return TRUE;
 }
 
 /*****************************************************************************/
 
-G_STATIC_ASSERT (ETH_ALEN == sizeof (struct ether_addr));
-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;
-}
+G_STATIC_ASSERT(ETH_ALEN == sizeof(struct ether_addr));
+G_STATIC_ASSERT(ETH_ALEN == 6);
 
 /*****************************************************************************/
 
 pid_t
-nm_utils_gettid (void)
+nm_utils_gettid(void)
 {
-	return (pid_t) syscall (SYS_gettid);
+    return (pid_t) syscall(SYS_gettid);
 }
 
 /* Used for asserting that this function is called on the main-thread.
@@ -175,155 +114,154 @@ nm_utils_gettid (void)
  *
  * When forking, the thread-id is again reset upon first call. */
 gboolean
-_nm_assert_on_main_thread (void)
+_nm_assert_on_main_thread(void)
 {
-	G_LOCK_DEFINE_STATIC (lock);
-	static pid_t seen_tid;
-	static pid_t seen_pid;
-	pid_t tid;
-	pid_t pid;
-	gboolean success = FALSE;
+    G_LOCK_DEFINE_STATIC(lock);
+    static pid_t seen_tid;
+    static pid_t seen_pid;
+    pid_t        tid;
+    pid_t        pid;
+    gboolean     success = FALSE;
 
-	tid = nm_utils_gettid ();
-	nm_assert (tid != 0);
+    tid = nm_utils_gettid();
+    nm_assert(tid != 0);
 
-	G_LOCK (lock);
+    G_LOCK(lock);
 
-	if (G_LIKELY (tid == seen_tid)) {
-		/* we don't care about false positives (when the process forked, and the thread-id
-		 * is accidentally re-used) . It's for assertions only. */
-		success = TRUE;
-	} else {
-		pid = getpid ();
-		nm_assert (pid != 0);
+    if (G_LIKELY(tid == seen_tid)) {
+        /* we don't care about false positives (when the process forked, and the thread-id
+         * is accidentally re-used) . It's for assertions only. */
+        success = TRUE;
+    } else {
+        pid = getpid();
+        nm_assert(pid != 0);
 
-		if (   seen_tid == 0
-			|| seen_pid != pid) {
-			/* either this is the first time we call the function, or the process
-			 * forked. In both cases, remember the thread-id. */
-			seen_tid = tid;
-			seen_pid = pid;
-			success = TRUE;
-		}
-	}
+        if (seen_tid == 0 || seen_pid != pid) {
+            /* either this is the first time we call the function, or the process
+             * forked. In both cases, remember the thread-id. */
+            seen_tid = tid;
+            seen_pid = pid;
+            success  = TRUE;
+        }
+    }
 
-	G_UNLOCK (lock);
+    G_UNLOCK(lock);
 
-	return success;
+    return success;
 }
 
 /*****************************************************************************/
 
 void
-nm_utils_strbuf_append_c (char **buf, gsize *len, char c)
-{
-	switch (*len) {
-	case 0:
-		return;
-	case 1:
-		(*buf)[0] = '\0';
-		*len = 0;
-		(*buf)++;
-		return;
-	default:
-		(*buf)[0] = c;
-		(*buf)[1] = '\0';
-		(*len)--;
-		(*buf)++;
-		return;
-	}
+nm_utils_strbuf_append_c(char **buf, gsize *len, char c)
+{
+    switch (*len) {
+    case 0:
+        return;
+    case 1:
+        (*buf)[0] = '\0';
+        *len      = 0;
+        (*buf)++;
+        return;
+    default:
+        (*buf)[0] = c;
+        (*buf)[1] = '\0';
+        (*len)--;
+        (*buf)++;
+        return;
+    }
 }
 
 void
-nm_utils_strbuf_append_bin (char **buf, gsize *len, gconstpointer str, gsize str_len)
-{
-	switch (*len) {
-	case 0:
-		return;
-	case 1:
-		if (str_len == 0) {
-			(*buf)[0] = '\0';
-			return;
-		}
-		(*buf)[0] = '\0';
-		*len = 0;
-		(*buf)++;
-		return;
-	default:
-		if (str_len == 0) {
-			(*buf)[0] = '\0';
-			return;
-		}
-		if (str_len >= *len) {
-			memcpy (*buf, str, *len - 1);
-			(*buf)[*len - 1] = '\0';
-			*buf = &(*buf)[*len];
-			*len = 0;
-		} else {
-			memcpy (*buf, str, str_len);
-			*buf = &(*buf)[str_len];
-			(*buf)[0] = '\0';
-			*len -= str_len;
-		}
-		return;
-	}
+nm_utils_strbuf_append_bin(char **buf, gsize *len, gconstpointer str, gsize str_len)
+{
+    switch (*len) {
+    case 0:
+        return;
+    case 1:
+        if (str_len == 0) {
+            (*buf)[0] = '\0';
+            return;
+        }
+        (*buf)[0] = '\0';
+        *len      = 0;
+        (*buf)++;
+        return;
+    default:
+        if (str_len == 0) {
+            (*buf)[0] = '\0';
+            return;
+        }
+        if (str_len >= *len) {
+            memcpy(*buf, str, *len - 1);
+            (*buf)[*len - 1] = '\0';
+            *buf             = &(*buf)[*len];
+            *len             = 0;
+        } else {
+            memcpy(*buf, str, str_len);
+            *buf      = &(*buf)[str_len];
+            (*buf)[0] = '\0';
+            *len -= str_len;
+        }
+        return;
+    }
 }
 
 void
-nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str)
-{
-	gsize src_len;
-
-	switch (*len) {
-	case 0:
-		return;
-	case 1:
-		if (!str || !*str) {
-			(*buf)[0] = '\0';
-			return;
-		}
-		(*buf)[0] = '\0';
-		*len = 0;
-		(*buf)++;
-		return;
-	default:
-		if (!str || !*str) {
-			(*buf)[0] = '\0';
-			return;
-		}
-		src_len = g_strlcpy (*buf, str, *len);
-		if (src_len >= *len) {
-			*buf = &(*buf)[*len];
-			*len = 0;
-		} else {
-			*buf = &(*buf)[src_len];
-			*len -= src_len;
-		}
-		return;
-	}
+nm_utils_strbuf_append_str(char **buf, gsize *len, const char *str)
+{
+    gsize src_len;
+
+    switch (*len) {
+    case 0:
+        return;
+    case 1:
+        if (!str || !*str) {
+            (*buf)[0] = '\0';
+            return;
+        }
+        (*buf)[0] = '\0';
+        *len      = 0;
+        (*buf)++;
+        return;
+    default:
+        if (!str || !*str) {
+            (*buf)[0] = '\0';
+            return;
+        }
+        src_len = g_strlcpy(*buf, str, *len);
+        if (src_len >= *len) {
+            *buf = &(*buf)[*len];
+            *len = 0;
+        } else {
+            *buf = &(*buf)[src_len];
+            *len -= src_len;
+        }
+        return;
+    }
 }
 
 void
-nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...)
+nm_utils_strbuf_append(char **buf, gsize *len, const char *format, ...)
 {
-	char *p = *buf;
-	va_list args;
-	int retval;
+    char *  p = *buf;
+    va_list args;
+    int     retval;
 
-	if (*len == 0)
-		return;
+    if (*len == 0)
+        return;
 
-	va_start (args, format);
-	retval = g_vsnprintf (p, *len, format, args);
-	va_end (args);
+    va_start(args, format);
+    retval = g_vsnprintf(p, *len, format, args);
+    va_end(args);
 
-	if ((gsize) retval >= *len) {
-		*buf = &p[*len];
-		*len = 0;
-	} else {
-		*buf = &p[retval];
-		*len -= retval;
-	}
+    if ((gsize) retval >= *len) {
+        *buf = &p[*len];
+        *len = 0;
+    } else {
+        *buf = &p[retval];
+        *len -= retval;
+    }
 }
 
 /**
@@ -369,59 +307,58 @@ nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...)
  *    nm_utils_strbuf_seek_end() would then NUL terminate it.
  */
 void
-nm_utils_strbuf_seek_end (char **buf, gsize *len)
+nm_utils_strbuf_seek_end(char **buf, gsize *len)
 {
-	gsize l;
-	char *end;
+    gsize l;
+    char *end;
 
-	nm_assert (len);
-	nm_assert (buf && *buf);
+    nm_assert(len);
+    nm_assert(buf && *buf);
 
-	if (*len <= 1) {
-		if (   *len == 1
-		    && (*buf)[0])
-			goto truncate;
-		return;
-	}
+    if (*len <= 1) {
+        if (*len == 1 && (*buf)[0])
+            goto truncate;
+        return;
+    }
 
-	end = memchr (*buf, 0, *len);
-	if (end) {
-		l = end - *buf;
-		nm_assert (l < *len);
+    end = memchr(*buf, 0, *len);
+    if (end) {
+        l = end - *buf;
+        nm_assert(l < *len);
 
-		*buf = end;
-		*len -= l;
-		return;
-	}
+        *buf = end;
+        *len -= l;
+        return;
+    }
 
 truncate:
-	/* hm, no NUL character within len bytes.
-	 * Just NUL terminate the array and consume them
-	 * all. */
-	*buf += *len;
-	(*buf)[-1] = '\0';
-	*len = 0;
-	return;
+    /* hm, no NUL character within len bytes.
+     * Just NUL terminate the array and consume them
+     * all. */
+    *buf += *len;
+    (*buf)[-1] = '\0';
+    *len       = 0;
+    return;
 }
 
 /*****************************************************************************/
 
 GBytes *
-nm_gbytes_get_empty (void)
+nm_gbytes_get_empty(void)
 {
-	static GBytes *bytes = NULL;
-	GBytes *b;
+    static GBytes *bytes = NULL;
+    GBytes *       b;
 
 again:
-	b = g_atomic_pointer_get (&bytes);
-	if (G_UNLIKELY (!b)) {
-		b = g_bytes_new_static ("", 0);
-		if (!g_atomic_pointer_compare_and_exchange (&bytes, NULL, b)) {
-			g_bytes_unref (b);
-			goto again;
-		}
-	}
-	return b;
+    b = g_atomic_pointer_get(&bytes);
+    if (G_UNLIKELY(!b)) {
+        b = g_bytes_new_static("", 0);
+        if (!g_atomic_pointer_compare_and_exchange(&bytes, NULL, b)) {
+            g_bytes_unref(b);
+            goto again;
+        }
+    }
+    return b;
 }
 
 /**
@@ -435,38 +372,64 @@ again:
  *   special case, a %NULL @bytes is treated like an empty array.
  */
 gboolean
-nm_utils_gbytes_equal_mem (GBytes *bytes,
-                           gconstpointer mem_data,
-                           gsize mem_len)
+nm_utils_gbytes_equal_mem(GBytes *bytes, gconstpointer mem_data, gsize mem_len)
 {
-	gconstpointer p;
-	gsize l;
+    gconstpointer p;
+    gsize         l;
 
-	if (!bytes) {
-		/* as a special case, let %NULL GBytes compare idential
-		 * to an empty array. */
-		return (mem_len == 0);
-	}
+    if (!bytes) {
+        /* as a special case, let %NULL GBytes compare identical
+         * to an empty array. */
+        return (mem_len == 0);
+    }
 
-	p = g_bytes_get_data (bytes, &l);
-	return    l == mem_len
-	       && (   mem_len == 0 /* allow @mem_data to be %NULL */
-	           || memcmp (p, mem_data, mem_len) == 0);
+    p = g_bytes_get_data(bytes, &l);
+    return l == mem_len
+           && (mem_len == 0 /* allow @mem_data to be %NULL */
+               || memcmp(p, mem_data, mem_len) == 0);
 }
 
 GVariant *
-nm_utils_gbytes_to_variant_ay (GBytes *bytes)
+nm_utils_gbytes_to_variant_ay(GBytes *bytes)
 {
-	const guint8 *p;
-	gsize l;
+    const guint8 *p;
+    gsize         l;
+
+    if (!bytes) {
+        /* for convenience, accept NULL to return an empty variant */
+        return g_variant_new_array(G_VARIANT_TYPE_BYTE, NULL, 0);
+    }
 
-	if (!bytes) {
-		/* for convenience, accept NULL to return an empty variant */
-		return g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0);
-	}
+    p = g_bytes_get_data(bytes, &l);
+    return g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, p, l, 1);
+}
+
+/*****************************************************************************/
 
-	p = g_bytes_get_data (bytes, &l);
-	return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, p, l, 1);
+#define _variant_singleton_get(create_variant)                                   \
+    ({                                                                           \
+        static GVariant *_singleton = NULL;                                      \
+        GVariant *       _v;                                                     \
+                                                                                 \
+again:                                                                           \
+        _v = g_atomic_pointer_get(&_singleton);                                  \
+        if (G_UNLIKELY(!_v)) {                                                   \
+            _v = (create_variant);                                               \
+            nm_assert(_v);                                                       \
+            nm_assert(g_variant_is_floating(_v));                                \
+            g_variant_ref_sink(_v);                                              \
+            if (!g_atomic_pointer_compare_and_exchange(&_singleton, NULL, _v)) { \
+                g_variant_unref(_v);                                             \
+                goto again;                                                      \
+            }                                                                    \
+        }                                                                        \
+        _v;                                                                      \
+    })
+
+GVariant *
+nm_g_variant_singleton_u_0(void)
+{
+    return _variant_singleton_get(g_variant_new_uint32(0));
 }
 
 /*****************************************************************************/
@@ -476,53 +439,46 @@ nm_utils_gbytes_to_variant_ay (GBytes *bytes)
  * Returns a floating reference.
  */
 GVariant *
-nm_utils_strdict_to_variant_ass (GHashTable *strdict)
-{
-	GHashTableIter iter;
-	const char *key, *value;
-	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;
-
-	g_hash_table_iter_init (&iter, strdict);
-	if (!g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value))
-		nm_assert_not_reached ();
-
-	if (len == 1)
-		g_variant_builder_add (&builder, "{ss}", key, value);
-	else {
-		gs_free NMUtilsNamedValue *idx_free = NULL;
-		NMUtilsNamedValue *idx;
-
-		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);
-
-		nm_utils_named_value_list_sort (idx, len, NULL, NULL);
-
-		for (i = 0; i < len; i++)
-			g_variant_builder_add (&builder, "{ss}", idx[i].name, idx[i].value_str);
-	}
+nm_utils_strdict_to_variant_ass(GHashTable *strdict)
+{
+    gs_free NMUtilsNamedValue *values_free = NULL;
+    NMUtilsNamedValue          values_prepared[20];
+    const NMUtilsNamedValue *  values;
+    GVariantBuilder            builder;
+    guint                      i;
+    guint                      n;
 
-out:
-	return g_variant_builder_end (&builder);
+    values = nm_utils_named_values_from_strdict(strdict, &n, values_prepared, &values_free);
+
+    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);
+}
+
+/*****************************************************************************/
+
+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;
+
+    values = nm_utils_named_values_from_strdict(strdict, &n, values_prepared, &values_free);
+
+    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));
+    }
+    return g_variant_builder_end(&builder);
 }
 
 /*****************************************************************************/
@@ -548,54 +504,54 @@ out:
  * Returns: the input buffer with the quoted string.
  */
 const char *
-nm_strquote (char *buf, gsize buf_len, const char *str)
-{
-	const char *const buf0 = buf;
-
-	if (!str) {
-		nm_utils_strbuf_append_str (&buf, &buf_len, "(null)");
-		goto out;
-	}
-
-	if (G_UNLIKELY (buf_len <= 2)) {
-		switch (buf_len) {
-		case 2:
-			*(buf++) = '^';
-			/* fall-through */
-		case 1:
-			*(buf++) = '\0';
-			break;
-		}
-		goto out;
-	}
-
-	*(buf++) = '"';
-	buf_len--;
-
-	nm_utils_strbuf_append_str (&buf, &buf_len, str);
-
-	/* if the string was too long we indicate truncation with a
-	 * '^' instead of a closing quote. */
-	if (G_UNLIKELY (buf_len <= 1)) {
-		switch (buf_len) {
-		case 1:
-			buf[-1] = '^';
-			break;
-		case 0:
-			buf[-2] = '^';
-			break;
-		default:
-			nm_assert_not_reached ();
-			break;
-		}
-	} else {
-		nm_assert (buf_len >= 2);
-		*(buf++) = '"';
-		*(buf++) = '\0';
-	}
+nm_strquote(char *buf, gsize buf_len, const char *str)
+{
+    const char *const buf0 = buf;
+
+    if (!str) {
+        nm_utils_strbuf_append_str(&buf, &buf_len, "(null)");
+        goto out;
+    }
+
+    if (G_UNLIKELY(buf_len <= 2)) {
+        switch (buf_len) {
+        case 2:
+            *(buf++) = '^';
+            /* fall-through */
+        case 1:
+            *(buf++) = '\0';
+            break;
+        }
+        goto out;
+    }
+
+    *(buf++) = '"';
+    buf_len--;
+
+    nm_utils_strbuf_append_str(&buf, &buf_len, str);
+
+    /* if the string was too long we indicate truncation with a
+     * '^' instead of a closing quote. */
+    if (G_UNLIKELY(buf_len <= 1)) {
+        switch (buf_len) {
+        case 1:
+            buf[-1] = '^';
+            break;
+        case 0:
+            buf[-2] = '^';
+            break;
+        default:
+            nm_assert_not_reached();
+            break;
+        }
+    } else {
+        nm_assert(buf_len >= 2);
+        *(buf++) = '"';
+        *(buf++) = '\0';
+    }
 
 out:
-	return buf0;
+    return buf0;
 }
 
 /*****************************************************************************/
@@ -603,82 +559,81 @@ out:
 char _nm_utils_to_string_buffer[];
 
 void
-nm_utils_to_string_buffer_init (char **buf, gsize *len)
+nm_utils_to_string_buffer_init(char **buf, gsize *len)
 {
-	if (!*buf) {
-		*buf = _nm_utils_to_string_buffer;
-		*len = sizeof (_nm_utils_to_string_buffer);
-	}
+    if (!*buf) {
+        *buf = _nm_utils_to_string_buffer;
+        *len = sizeof(_nm_utils_to_string_buffer);
+    }
 }
 
 gboolean
-nm_utils_to_string_buffer_init_null (gconstpointer obj, char **buf, gsize *len)
+nm_utils_to_string_buffer_init_null(gconstpointer obj, char **buf, gsize *len)
 {
-	nm_utils_to_string_buffer_init (buf, len);
-	if (!obj) {
-		g_strlcpy (*buf, "(null)", *len);
-		return FALSE;
-	}
-	return TRUE;
+    nm_utils_to_string_buffer_init(buf, len);
+    if (!obj) {
+        g_strlcpy(*buf, "(null)", *len);
+        return FALSE;
+    }
+    return TRUE;
 }
 
 /*****************************************************************************/
 
 const char *
-nm_utils_flags2str (const NMUtilsFlags2StrDesc *descs,
-                    gsize n_descs,
-                    unsigned flags,
-                    char *buf,
-                    gsize len)
+nm_utils_flags2str(const NMUtilsFlags2StrDesc *descs,
+                   gsize                       n_descs,
+                   unsigned                    flags,
+                   char *                      buf,
+                   gsize                       len)
 {
-	gsize i;
-	char *p;
+    gsize i;
+    char *p;
 
 #if NM_MORE_ASSERTS > 10
-	nm_assert (descs);
-	nm_assert (n_descs > 0);
-	for (i = 0; i < n_descs; i++) {
-		gsize j;
-
-		nm_assert (descs[i].name && descs[i].name[0]);
-		for (j = 0; j < i; j++)
-			nm_assert (descs[j].flag != descs[i].flag);
-	}
+    nm_assert(descs);
+    nm_assert(n_descs > 0);
+    for (i = 0; i < n_descs; i++) {
+        gsize j;
+
+        nm_assert(descs[i].name && descs[i].name[0]);
+        for (j = 0; j < i; j++)
+            nm_assert(descs[j].flag != descs[i].flag);
+    }
 #endif
 
-	nm_utils_to_string_buffer_init (&buf, &len);
-
-	if (!len)
-		return buf;
-
-	buf[0] = '\0';
-	p = buf;
-	if (!flags) {
-		for (i = 0; i < n_descs; i++) {
-			if (!descs[i].flag) {
-				nm_utils_strbuf_append_str (&p, &len, descs[i].name);
-				break;
-			}
-		}
-		return buf;
-	}
-
-	for (i = 0; flags && i < n_descs; i++) {
-		if (   descs[i].flag
-		    && NM_FLAGS_ALL (flags, descs[i].flag)) {
-			flags &= ~descs[i].flag;
-
-			if (buf[0] != '\0')
-				nm_utils_strbuf_append_c (&p, &len, ',');
-			nm_utils_strbuf_append_str (&p, &len, descs[i].name);
-		}
-	}
-	if (flags) {
-		if (buf[0] != '\0')
-			nm_utils_strbuf_append_c (&p, &len, ',');
-		nm_utils_strbuf_append (&p, &len, "0x%x", flags);
-	}
-	return buf;
+    nm_utils_to_string_buffer_init(&buf, &len);
+
+    if (!len)
+        return buf;
+
+    buf[0] = '\0';
+    p      = buf;
+    if (!flags) {
+        for (i = 0; i < n_descs; i++) {
+            if (!descs[i].flag) {
+                nm_utils_strbuf_append_str(&p, &len, descs[i].name);
+                break;
+            }
+        }
+        return buf;
+    }
+
+    for (i = 0; flags && i < n_descs; i++) {
+        if (descs[i].flag && NM_FLAGS_ALL(flags, descs[i].flag)) {
+            flags &= ~descs[i].flag;
+
+            if (buf[0] != '\0')
+                nm_utils_strbuf_append_c(&p, &len, ',');
+            nm_utils_strbuf_append_str(&p, &len, descs[i].name);
+        }
+    }
+    if (flags) {
+        if (buf[0] != '\0')
+            nm_utils_strbuf_append_c(&p, &len, ',');
+        nm_utils_strbuf_append(&p, &len, "0x%x", flags);
+    }
+    return buf;
 };
 
 /*****************************************************************************/
@@ -690,34 +645,34 @@ nm_utils_flags2str (const NMUtilsFlags2StrDesc *descs,
  * Returns: the netmask represented by the prefix, in network byte order
  **/
 guint32
-_nm_utils_ip4_prefix_to_netmask (guint32 prefix)
+_nm_utils_ip4_prefix_to_netmask(guint32 prefix)
 {
-	return prefix < 32 ? ~htonl(0xFFFFFFFF >> prefix) : 0xFFFFFFFF;
+    return prefix < 32 ? ~htonl(0xFFFFFFFFu >> prefix) : 0xFFFFFFFFu;
 }
 
 gconstpointer
-nm_utils_ipx_address_clear_host_address (int family, gpointer dst, gconstpointer src, guint8 plen)
+nm_utils_ipx_address_clear_host_address(int family, gpointer dst, gconstpointer src, guint8 plen)
 {
-	g_return_val_if_fail (dst, NULL);
+    g_return_val_if_fail(dst, NULL);
 
-	switch (family) {
-	case AF_INET:
-		g_return_val_if_fail (plen <= 32, NULL);
+    switch (family) {
+    case AF_INET:
+        g_return_val_if_fail(plen <= 32, NULL);
 
-		if (!src) {
-			/* allow "self-assignment", by specifying %NULL as source. */
-			src = dst;
-		}
+        if (!src) {
+            /* allow "self-assignment", by specifying %NULL as source. */
+            src = dst;
+        }
 
-		*((guint32 *) dst) = nm_utils_ip4_address_clear_host_address (*((guint32 *) src), plen);
-		break;
-	case AF_INET6:
-		nm_utils_ip6_address_clear_host_address (dst, src, plen);
-		break;
-	default:
-		g_return_val_if_reached (NULL);
-	}
-	return dst;
+        *((guint32 *) dst) = nm_utils_ip4_address_clear_host_address(*((guint32 *) src), plen);
+        break;
+    case AF_INET6:
+        nm_utils_ip6_address_clear_host_address(dst, src, plen);
+        break;
+    default:
+        g_return_val_if_reached(NULL);
+    }
+    return dst;
 }
 
 /* nm_utils_ip4_address_clear_host_address:
@@ -727,9 +682,9 @@ nm_utils_ipx_address_clear_host_address (int family, gpointer dst, gconstpointer
  * returns: the input address, with the host address set to 0.
  */
 in_addr_t
-nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen)
+nm_utils_ip4_address_clear_host_address(in_addr_t addr, guint8 plen)
 {
-	return addr & _nm_utils_ip4_prefix_to_netmask (plen);
+    return addr & _nm_utils_ip4_prefix_to_netmask(plen);
 }
 
 /* nm_utils_ip6_address_clear_host_address:
@@ -741,54 +696,58 @@ nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen)
  * @dst and @src to the same destination or set @src NULL.
  */
 const struct in6_addr *
-nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_addr *src, guint8 plen)
+nm_utils_ip6_address_clear_host_address(struct in6_addr *      dst,
+                                        const struct in6_addr *src,
+                                        guint8                 plen)
 {
-	g_return_val_if_fail (plen <= 128, NULL);
-	g_return_val_if_fail (dst, NULL);
+    g_return_val_if_fail(plen <= 128, NULL);
+    g_return_val_if_fail(dst, NULL);
 
-	if (!src)
-		src = dst;
+    if (!src)
+        src = dst;
 
-	if (plen < 128) {
-		guint nbytes = plen / 8;
-		guint nbits = plen % 8;
+    if (plen < 128) {
+        guint nbytes = plen / 8;
+        guint nbits  = plen % 8;
 
-		if (nbytes && dst != src)
-			memcpy (dst, src, nbytes);
-		if (nbits) {
-			dst->s6_addr[nbytes] = (src->s6_addr[nbytes] & (0xFF << (8 - nbits)));
-			nbytes++;
-		}
-		if (nbytes <= 15)
-			memset (&dst->s6_addr[nbytes], 0, 16 - nbytes);
-	} else if (src != dst)
-		*dst = *src;
+        if (nbytes && dst != src)
+            memcpy(dst, src, nbytes);
+        if (nbits) {
+            dst->s6_addr[nbytes] = (src->s6_addr[nbytes] & (0xFF << (8 - nbits)));
+            nbytes++;
+        }
+        if (nbytes <= 15)
+            memset(&dst->s6_addr[nbytes], 0, 16 - nbytes);
+    } else if (src != dst)
+        *dst = *src;
 
-	return dst;
+    return dst;
 }
 
 int
-nm_utils_ip6_address_same_prefix_cmp (const struct in6_addr *addr_a, const struct in6_addr *addr_b, guint8 plen)
-{
-	int nbytes;
-	guint8 va, vb, m;
-
-	if (plen >= 128)
-		NM_CMP_DIRECT_MEMCMP (addr_a, addr_b, sizeof (struct in6_addr));
-	else {
-		nbytes = plen / 8;
-		if (nbytes)
-			NM_CMP_DIRECT_MEMCMP (addr_a, addr_b, nbytes);
-
-		plen = plen % 8;
-		if (plen != 0) {
-			m = ~((1 << (8 - plen)) - 1);
-			va = ((((const guint8 *) addr_a))[nbytes]) & m;
-			vb = ((((const guint8 *) addr_b))[nbytes]) & m;
-			NM_CMP_DIRECT (va, vb);
-		}
-	}
-	return 0;
+nm_utils_ip6_address_same_prefix_cmp(const struct in6_addr *addr_a,
+                                     const struct in6_addr *addr_b,
+                                     guint8                 plen)
+{
+    int    nbytes;
+    guint8 va, vb, m;
+
+    if (plen >= 128)
+        NM_CMP_DIRECT_MEMCMP(addr_a, addr_b, sizeof(struct in6_addr));
+    else {
+        nbytes = plen / 8;
+        if (nbytes)
+            NM_CMP_DIRECT_MEMCMP(addr_a, addr_b, nbytes);
+
+        plen = plen % 8;
+        if (plen != 0) {
+            m  = ~((1 << (8 - plen)) - 1);
+            va = ((((const guint8 *) addr_a))[nbytes]) & m;
+            vb = ((((const guint8 *) addr_b))[nbytes]) & m;
+            NM_CMP_DIRECT(va, vb);
+        }
+    }
+    return 0;
 }
 
 /**
@@ -804,347 +763,349 @@ nm_utils_ip6_address_same_prefix_cmp (const struct in6_addr *addr_a, const struc
  **/
 /* The function is originally from ipcalc.c of Red Hat's initscripts. */
 guint32
-_nm_utils_ip4_get_default_prefix (guint32 ip)
+_nm_utils_ip4_get_default_prefix(guint32 ip)
 {
-	if (((ntohl (ip) & 0xFF000000) >> 24) <= 127)
-		return 8;  /* Class A - 255.0.0.0 */
-	else if (((ntohl (ip) & 0xFF000000) >> 24) <= 191)
-		return 16;  /* Class B - 255.255.0.0 */
+    if (((ntohl(ip) & 0xFF000000) >> 24) <= 127)
+        return 8; /* Class A - 255.0.0.0 */
+    else if (((ntohl(ip) & 0xFF000000) >> 24) <= 191)
+        return 16; /* Class B - 255.255.0.0 */
 
-	return 24;  /* Class C - 255.255.255.0 */
+    return 24; /* Class C - 255.255.255.0 */
 }
 
 gboolean
-nm_utils_ip_is_site_local (int addr_family,
-                           const void *address)
-{
-	in_addr_t addr4;
-
-	switch (addr_family) {
-	case AF_INET:
-		/* RFC1918 private addresses
-		 * 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 */
-		addr4 = ntohl (*((const in_addr_t *) address));
-		return    (addr4 & 0xff000000) == 0x0a000000
-		       || (addr4 & 0xfff00000) == 0xac100000
-		       || (addr4 & 0xffff0000) == 0xc0a80000;
-	case AF_INET6:
-		return IN6_IS_ADDR_SITELOCAL (address);
-	default:
-		g_return_val_if_reached (FALSE);
-	}
+nm_utils_ip_is_site_local(int addr_family, const void *address)
+{
+    in_addr_t addr4;
+
+    switch (addr_family) {
+    case AF_INET:
+        /* RFC1918 private addresses
+         * 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 */
+        addr4 = ntohl(*((const in_addr_t *) address));
+        return (addr4 & 0xff000000) == 0x0a000000 || (addr4 & 0xfff00000) == 0xac100000
+               || (addr4 & 0xffff0000) == 0xc0a80000;
+    case AF_INET6:
+        return IN6_IS_ADDR_SITELOCAL(address);
+    default:
+        g_return_val_if_reached(FALSE);
+    }
 }
 
 /*****************************************************************************/
 
 static gboolean
-_parse_legacy_addr4 (const char *text, in_addr_t *out_addr, GError **error)
-{
-	gs_free char *s_free = NULL;
-	struct in_addr a1;
-	guint8 bin[sizeof (a1)];
-	char *s;
-	int i;
-
-	if (inet_aton (text, &a1) != 1) {
-		g_set_error_literal (error,
-		                     NM_UTILS_ERROR,
-		                     NM_UTILS_ERROR_INVALID_ARGUMENT,
-		                     "address invalid according to inet_aton()");
-		return FALSE;
-	}
-
-	/* OK, inet_aton() accepted the format. That's good, because we want
-	 * to accept IPv4 addresses in octal format, like 255.255.000.000.
-	 * That's what "legacy" means here. inet_pton() doesn't accept those.
-	 *
-	 * But inet_aton() also ignores trailing garbage and formats with fewer than
-	 * 4 digits. That is just too crazy and we don't do that. Perform additional checks
-	 * and reject some forms that inet_aton() accepted.
-	 *
-	 * Note that we still should (of course) accept everything that inet_pton()
-	 * accepts. However this code never gets called if inet_pton() succeeds
-	 * (see below, aside the assertion code). */
-
-	if (NM_STRCHAR_ANY (text, ch, (   !(ch >= '0' && ch <= '9')
-	                               && !NM_IN_SET (ch, '.', 'x')))) {
-		/* We only accepts '.', digits, and 'x' for "0x". */
-		g_set_error_literal (error,
-		                     NM_UTILS_ERROR,
-		                     NM_UTILS_ERROR_INVALID_ARGUMENT,
-		                     "contains an invalid character");
-		return FALSE;
-	}
-
-	s = nm_memdup_maybe_a (300, text, strlen (text) + 1, &s_free);
-
-	for (i = 0; i < G_N_ELEMENTS (bin); i++) {
-		char *current_token = s;
-		gint32 v;
-
-		s = strchr (s, '.');
-		if (s) {
-			s[0] = '\0';
-			s++;
-		}
-
-		if ((i == G_N_ELEMENTS (bin) - 1) != (s == NULL)) {
-			/* Exactly for the last digit, we expect to have no more following token.
-			 * But this isn't the case. Abort. */
-			g_set_error (error,
-			             NM_UTILS_ERROR,
-			             NM_UTILS_ERROR_INVALID_ARGUMENT,
-			             "wrong number of tokens (index %d, token '%s')",
-			             i, s);
-			return FALSE;
-		}
-
-		v = _nm_utils_ascii_str_to_int64 (current_token, 0, 0, 0xFF, -1);
-		if (v == -1) {
-			int errsv = errno;
-
-			/* we do accept octal and hex (even with leading "0x"). But something
-			 * about this token is wrong. */
-			g_set_error (error,
-			             NM_UTILS_ERROR,
-			             NM_UTILS_ERROR_INVALID_ARGUMENT,
-			             "invalid token '%s': %s (%d)",
-			             current_token,
-			             nm_strerror_native (errsv),
-			             errsv);
-			return FALSE;
-		}
-
-		bin[i] = v;
-	}
-
-	if (memcmp (bin, &a1, sizeof (bin)) != 0) {
-		/* our parsing did not agree with what inet_aton() gave. Something
-		 * is wrong. Abort. */
-		g_set_error (error,
-		             NM_UTILS_ERROR,
-		             NM_UTILS_ERROR_INVALID_ARGUMENT,
-		             "inet_aton() result 0x%08x differs from computed value 0x%02hhx%02hhx%02hhx%02hhx",
-		             a1.s_addr,
-		             bin[0], bin[1], bin[2], bin[3]);
-		return FALSE;
-	}
-
-	*out_addr = a1.s_addr;
-	return TRUE;
+_parse_legacy_addr4(const char *text, in_addr_t *out_addr, GError **error)
+{
+    gs_free char * s_free = NULL;
+    struct in_addr a1;
+    guint8         bin[sizeof(a1)];
+    char *         s;
+    int            i;
+
+    if (inet_aton(text, &a1) != 1) {
+        g_set_error_literal(error,
+                            NM_UTILS_ERROR,
+                            NM_UTILS_ERROR_INVALID_ARGUMENT,
+                            "address invalid according to inet_aton()");
+        return FALSE;
+    }
+
+    /* OK, inet_aton() accepted the format. That's good, because we want
+     * to accept IPv4 addresses in octal format, like 255.255.000.000.
+     * That's what "legacy" means here. inet_pton() doesn't accept those.
+     *
+     * But inet_aton() also ignores trailing garbage and formats with fewer than
+     * 4 digits. That is just too crazy and we don't do that. Perform additional checks
+     * and reject some forms that inet_aton() accepted.
+     *
+     * Note that we still should (of course) accept everything that inet_pton()
+     * accepts. However this code never gets called if inet_pton() succeeds
+     * (see below, aside the assertion code). */
+
+    if (NM_STRCHAR_ANY(text, ch, (!(ch >= '0' && ch <= '9') && !NM_IN_SET(ch, '.', 'x')))) {
+        /* We only accepts '.', digits, and 'x' for "0x". */
+        g_set_error_literal(error,
+                            NM_UTILS_ERROR,
+                            NM_UTILS_ERROR_INVALID_ARGUMENT,
+                            "contains an invalid character");
+        return FALSE;
+    }
+
+    s = nm_memdup_maybe_a(300, text, strlen(text) + 1, &s_free);
+
+    for (i = 0; i < G_N_ELEMENTS(bin); i++) {
+        char * current_token = s;
+        gint32 v;
+
+        s = strchr(s, '.');
+        if (s) {
+            s[0] = '\0';
+            s++;
+        }
+
+        if ((i == G_N_ELEMENTS(bin) - 1) != (s == NULL)) {
+            /* Exactly for the last digit, we expect to have no more following token.
+             * But this isn't the case. Abort. */
+            g_set_error(error,
+                        NM_UTILS_ERROR,
+                        NM_UTILS_ERROR_INVALID_ARGUMENT,
+                        "wrong number of tokens (index %d, token '%s')",
+                        i,
+                        s);
+            return FALSE;
+        }
+
+        v = _nm_utils_ascii_str_to_int64(current_token, 0, 0, 0xFF, -1);
+        if (v == -1) {
+            int errsv = errno;
+
+            /* we do accept octal and hex (even with leading "0x"). But something
+             * about this token is wrong. */
+            g_set_error(error,
+                        NM_UTILS_ERROR,
+                        NM_UTILS_ERROR_INVALID_ARGUMENT,
+                        "invalid token '%s': %s (%d)",
+                        current_token,
+                        nm_strerror_native(errsv),
+                        errsv);
+            return FALSE;
+        }
+
+        bin[i] = v;
+    }
+
+    if (memcmp(bin, &a1, sizeof(bin)) != 0) {
+        /* our parsing did not agree with what inet_aton() gave. Something
+         * is wrong. Abort. */
+        g_set_error(
+            error,
+            NM_UTILS_ERROR,
+            NM_UTILS_ERROR_INVALID_ARGUMENT,
+            "inet_aton() result 0x%08x differs from computed value 0x%02hhx%02hhx%02hhx%02hhx",
+            a1.s_addr,
+            bin[0],
+            bin[1],
+            bin[2],
+            bin[3]);
+        return FALSE;
+    }
+
+    *out_addr = a1.s_addr;
+    return TRUE;
 }
 
 gboolean
-nm_utils_parse_inaddr_bin_full (int addr_family,
-                                gboolean accept_legacy,
-                                const char *text,
-                                int *out_addr_family,
-                                gpointer out_addr)
-{
-	NMIPAddr addrbin;
-
-	g_return_val_if_fail (text, FALSE);
-
-	if (addr_family == AF_UNSPEC) {
-		g_return_val_if_fail (!out_addr || out_addr_family, FALSE);
-		addr_family = strchr (text, ':') ? AF_INET6 : AF_INET;
-	} else
-		g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), FALSE);
-
-	if (inet_pton (addr_family, text, &addrbin) != 1) {
-		if (   accept_legacy
-		    && addr_family == AF_INET
-		    && _parse_legacy_addr4 (text, &addrbin.addr4, NULL)) {
-			/* The address is in some legacy format which inet_aton() accepts, but not inet_pton().
-			 * Most likely octal digits (leading zeros). We accept the address. */
-		} else
-			return FALSE;
-	}
+nm_utils_parse_inaddr_bin_full(int         addr_family,
+                               gboolean    accept_legacy,
+                               const char *text,
+                               int *       out_addr_family,
+                               gpointer    out_addr)
+{
+    NMIPAddr addrbin;
+
+    g_return_val_if_fail(text, FALSE);
+
+    if (addr_family == AF_UNSPEC) {
+        g_return_val_if_fail(!out_addr || out_addr_family, FALSE);
+        addr_family = strchr(text, ':') ? AF_INET6 : AF_INET;
+    } else
+        g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), FALSE);
+
+    if (inet_pton(addr_family, text, &addrbin) != 1) {
+        if (accept_legacy && addr_family == AF_INET
+            && _parse_legacy_addr4(text, &addrbin.addr4, NULL)) {
+            /* The address is in some legacy format which inet_aton() accepts, but not inet_pton().
+             * Most likely octal digits (leading zeros). We accept the address. */
+        } else
+            return FALSE;
+    }
 
 #if NM_MORE_ASSERTS > 10
-	if (addr_family == AF_INET) {
-		gs_free_error GError *error = NULL;
-		in_addr_t a;
-
-		/* The legacy parser should accept everything that inet_pton() accepts too. Meaning,
-		 * it should strictly parse *more* formats. And of course, parse it the same way. */
-		if (!_parse_legacy_addr4 (text, &a, &error)) {
-			char buf[INET_ADDRSTRLEN];
-
-			g_error ("unexpected assertion failure: could parse \"%s\" as %s, but not accepted by legacy parser: %s",
-			         text, _nm_utils_inet4_ntop (addrbin.addr4, buf), error->message);
-		}
-		nm_assert (addrbin.addr4 == a);
-	}
+    if (addr_family == AF_INET) {
+        gs_free_error GError *error = NULL;
+        in_addr_t             a;
+
+        /* The legacy parser should accept everything that inet_pton() accepts too. Meaning,
+         * it should strictly parse *more* formats. And of course, parse it the same way. */
+        if (!_parse_legacy_addr4(text, &a, &error)) {
+            char buf[INET_ADDRSTRLEN];
+
+            g_error("unexpected assertion failure: could parse \"%s\" as %s, but not accepted by "
+                    "legacy parser: %s",
+                    text,
+                    _nm_utils_inet4_ntop(addrbin.addr4, buf),
+                    error->message);
+        }
+        nm_assert(addrbin.addr4 == a);
+    }
 #endif
 
-	NM_SET_OUT (out_addr_family, addr_family);
-	if (out_addr)
-		nm_ip_addr_set (addr_family, out_addr, &addrbin);
-	return TRUE;
+    NM_SET_OUT(out_addr_family, addr_family);
+    if (out_addr)
+        nm_ip_addr_set(addr_family, out_addr, &addrbin);
+    return TRUE;
 }
 
 gboolean
-nm_utils_parse_inaddr (int addr_family,
-                       const char *text,
-                       char **out_addr)
+nm_utils_parse_inaddr(int addr_family, const char *text, char **out_addr)
 {
-	NMIPAddr addrbin;
-	char addrstr_buf[MAX (INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
+    NMIPAddr addrbin;
+    char     addrstr_buf[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
 
-	g_return_val_if_fail (text, FALSE);
+    g_return_val_if_fail(text, FALSE);
 
-	if (addr_family == AF_UNSPEC)
-		addr_family = strchr (text, ':') ? AF_INET6 : AF_INET;
-	else
-		g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), FALSE);
+    if (addr_family == AF_UNSPEC)
+        addr_family = strchr(text, ':') ? AF_INET6 : AF_INET;
+    else
+        g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), FALSE);
 
-	if (inet_pton (addr_family, text, &addrbin) != 1)
-		return FALSE;
+    if (inet_pton(addr_family, text, &addrbin) != 1)
+        return FALSE;
 
-	NM_SET_OUT (out_addr, g_strdup (inet_ntop (addr_family, &addrbin, addrstr_buf, sizeof (addrstr_buf))));
-	return TRUE;
+    NM_SET_OUT(out_addr,
+               g_strdup(inet_ntop(addr_family, &addrbin, addrstr_buf, sizeof(addrstr_buf))));
+    return TRUE;
 }
 
 gboolean
-nm_utils_parse_inaddr_prefix_bin (int addr_family,
-                                  const char *text,
-                                  int *out_addr_family,
-                                  gpointer out_addr,
-                                  int *out_prefix)
-{
-	gs_free char *addrstr_free = NULL;
-	int prefix = -1;
-	const char *slash;
-	const char *addrstr;
-	NMIPAddr addrbin;
-
-	g_return_val_if_fail (text, FALSE);
-
-	if (addr_family == AF_UNSPEC) {
-		g_return_val_if_fail (!out_addr || out_addr_family, FALSE);
-		addr_family = strchr (text, ':') ? AF_INET6 : AF_INET;
-	} else
-		g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), FALSE);
-
-	slash = strchr (text, '/');
-	if (slash)
-		addrstr = addrstr_free = g_strndup (text, slash - text);
-	else
-		addrstr = text;
-
-	if (inet_pton (addr_family, addrstr, &addrbin) != 1)
-		return FALSE;
-
-	if (slash) {
-		/* For IPv4, `ip addr add` supports the prefix-length as a netmask. We don't
-		 * do that. */
-		prefix = _nm_utils_ascii_str_to_int64 (slash + 1, 10,
-		                                       0,
-		                                       addr_family == AF_INET ? 32 : 128,
-		                                       -1);
-		if (prefix == -1)
-			return FALSE;
-	}
-
-	NM_SET_OUT (out_addr_family, addr_family);
-	if (out_addr)
-		nm_ip_addr_set (addr_family, out_addr, &addrbin);
-	NM_SET_OUT (out_prefix, prefix);
-	return TRUE;
+nm_utils_parse_inaddr_prefix_bin(int         addr_family,
+                                 const char *text,
+                                 int *       out_addr_family,
+                                 gpointer    out_addr,
+                                 int *       out_prefix)
+{
+    gs_free char *addrstr_free = NULL;
+    int           prefix       = -1;
+    const char *  slash;
+    const char *  addrstr;
+    NMIPAddr      addrbin;
+
+    g_return_val_if_fail(text, FALSE);
+
+    if (addr_family == AF_UNSPEC) {
+        g_return_val_if_fail(!out_addr || out_addr_family, FALSE);
+        addr_family = strchr(text, ':') ? AF_INET6 : AF_INET;
+    } else
+        g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), FALSE);
+
+    slash = strchr(text, '/');
+    if (slash)
+        addrstr = nm_strndup_a(300, text, slash - text, &addrstr_free);
+    else
+        addrstr = text;
+
+    if (inet_pton(addr_family, addrstr, &addrbin) != 1)
+        return FALSE;
+
+    if (slash) {
+        /* For IPv4, `ip addr add` supports the prefix-length as a netmask. We don't
+         * do that. */
+        prefix =
+            _nm_utils_ascii_str_to_int64(&slash[1], 10, 0, addr_family == AF_INET ? 32 : 128, -1);
+        if (prefix == -1)
+            return FALSE;
+    }
+
+    NM_SET_OUT(out_addr_family, addr_family);
+    if (out_addr)
+        nm_ip_addr_set(addr_family, out_addr, &addrbin);
+    NM_SET_OUT(out_prefix, prefix);
+    return TRUE;
 }
 
 gboolean
-nm_utils_parse_inaddr_prefix (int addr_family,
-                              const char *text,
-                              char **out_addr,
-                              int *out_prefix)
+nm_utils_parse_inaddr_prefix(int addr_family, const char *text, char **out_addr, int *out_prefix)
 {
-	NMIPAddr addrbin;
-	char addrstr_buf[MAX (INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
+    NMIPAddr addrbin;
+    char     addrstr_buf[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
 
-	if (!nm_utils_parse_inaddr_prefix_bin (addr_family, text, &addr_family, &addrbin, out_prefix))
-		return FALSE;
-	NM_SET_OUT (out_addr, g_strdup (inet_ntop (addr_family, &addrbin, addrstr_buf, sizeof (addrstr_buf))));
-	return TRUE;
+    if (!nm_utils_parse_inaddr_prefix_bin(addr_family, text, &addr_family, &addrbin, out_prefix))
+        return FALSE;
+    NM_SET_OUT(out_addr,
+               g_strdup(inet_ntop(addr_family, &addrbin, addrstr_buf, sizeof(addrstr_buf))));
+    return TRUE;
 }
 
 gboolean
-nm_utils_parse_next_line (const char **inout_ptr,
-                          gsize *inout_len,
-                          const char **out_line,
-                          gsize *out_line_len)
-{
-	const char *line_start;
-	const char *line_end;
-
-	g_return_val_if_fail (inout_ptr, FALSE);
-	g_return_val_if_fail (inout_len, FALSE);
-	g_return_val_if_fail (out_line, FALSE);
-
-	if (*inout_len <= 0)
-		goto error;
-
-	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));
-
-	if (*inout_len > 0)
-		NM_SET_OUT (inout_ptr, line_end + 1);
-	else
-		NM_SET_OUT (inout_ptr, NULL);
-	return TRUE;
-
-error:
-	NM_SET_OUT (out_line, NULL);
-	NM_SET_OUT (out_line_len, 0);
-	return FALSE;
+nm_utils_parse_next_line(const char **inout_ptr,
+                         gsize *      inout_len,
+                         const char **out_line,
+                         gsize *      out_line_len)
+{
+    gboolean    eol_is_carriage_return;
+    const char *line_start;
+    gsize       line_len;
+
+    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 (G_UNLIKELY(*inout_len == 0))
+        return FALSE;
+
+    line_start = *inout_ptr;
+
+    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;
+        }
+    }
+
+done:
+    *out_line     = line_start;
+    *out_line_len = line_len;
+    return TRUE;
 }
 
 /*****************************************************************************/
 
 gboolean
-nm_utils_ipaddr_is_valid (int addr_family,
-                          const char *str_addr)
+nm_utils_ipaddr_is_valid(int addr_family, const char *str_addr)
 {
-	nm_assert (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET, AF_INET6));
+    nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6));
 
-	return    str_addr
-	       && nm_utils_parse_inaddr_bin (addr_family,
-	                                     str_addr,
-	                                     NULL,
-	                                     NULL);
+    return str_addr && nm_utils_parse_inaddr_bin(addr_family, str_addr, NULL, NULL);
 }
 
 gboolean
-nm_utils_ipaddr_is_normalized (int addr_family,
-                               const char *str_addr)
+nm_utils_ipaddr_is_normalized(int addr_family, const char *str_addr)
 {
-	NMIPAddr addr;
-	char sbuf[NM_UTILS_INET_ADDRSTRLEN];
+    NMIPAddr addr;
+    char     sbuf[NM_UTILS_INET_ADDRSTRLEN];
 
-	nm_assert (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET, AF_INET6));
+    nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6));
 
-	if (!str_addr)
-		return FALSE;
+    if (!str_addr)
+        return FALSE;
 
-	if (!nm_utils_parse_inaddr_bin (addr_family,
-	                                str_addr,
-	                                &addr_family,
-	                                &addr))
-		return FALSE;
+    if (!nm_utils_parse_inaddr_bin(addr_family, str_addr, &addr_family, &addr))
+        return FALSE;
 
-	nm_utils_inet_ntop (addr_family, &addr, sbuf);
-	return nm_streq (sbuf, str_addr);
+    nm_utils_inet_ntop(addr_family, &addr, sbuf);
+    return nm_streq(sbuf, str_addr);
 }
 
 /*****************************************************************************/
@@ -1168,137 +1129,124 @@ nm_utils_ipaddr_is_normalized (int addr_family,
  * This wrapper tries to workaround that condition.
  */
 gint64
-nm_g_ascii_strtoll (const char *nptr,
-                    char **endptr,
-                    guint base)
+nm_g_ascii_strtoll(const char *nptr, char **endptr, guint base)
 {
-	int try_count = 2;
-	gint64 v;
-	const int errsv_orig = errno;
-	int errsv;
+    int       try_count = 2;
+    gint64    v;
+    const int errsv_orig = errno;
+    int       errsv;
 
-	nm_assert (nptr);
-	nm_assert (base == 0u || (base >= 2u && base <= 36u));
+    nm_assert(nptr);
+    nm_assert(base == 0u || (base >= 2u && base <= 36u));
 
 again:
-	errno = 0;
-	v = g_ascii_strtoll (nptr, endptr, base);
-	errsv = errno;
+    errno = 0;
+    v     = g_ascii_strtoll(nptr, endptr, base);
+    errsv = errno;
 
-	if (errsv == 0) {
-		if (errsv_orig != 0)
-			errno = errsv_orig;
-		return v;
-	}
+    if (errsv == 0) {
+        if (errsv_orig != 0)
+            errno = errsv_orig;
+        return v;
+    }
 
-	if (   errsv == ERANGE
-	    && NM_IN_SET (v, G_MININT64, G_MAXINT64))
-		return v;
+    if (errsv == ERANGE && NM_IN_SET(v, G_MININT64, G_MAXINT64))
+        return v;
 
-	if (   errsv == EINVAL
-	    && v == 0
-	    && nptr
-	    && nptr[0] == '\0')
-		return v;
+    if (errsv == EINVAL && v == 0 && nptr && nptr[0] == '\0')
+        return v;
 
-	if (try_count-- > 0)
-		goto again;
+    if (try_count-- > 0)
+        goto again;
 
 #if NM_MORE_ASSERTS
-	g_critical ("g_ascii_strtoll() for \"%s\" failed with errno=%d (%s) and v=%"G_GINT64_FORMAT,
-	            nptr,
-	            errsv,
-	            nm_strerror_native (errsv),
-	            v);
+    g_critical("g_ascii_strtoll() for \"%s\" failed with errno=%d (%s) and v=%" G_GINT64_FORMAT,
+               nptr,
+               errsv,
+               nm_strerror_native(errsv),
+               v);
 #endif
 
-	return v;
+    return v;
 }
 
 /* See nm_g_ascii_strtoll() */
 guint64
-nm_g_ascii_strtoull (const char *nptr,
-                     char **endptr,
-                     guint base)
+nm_g_ascii_strtoull(const char *nptr, char **endptr, guint base)
 {
-	int try_count = 2;
-	guint64 v;
-	const int errsv_orig = errno;
-	int errsv;
+    int       try_count = 2;
+    guint64   v;
+    const int errsv_orig = errno;
+    int       errsv;
 
-	nm_assert (nptr);
-	nm_assert (base == 0u || (base >= 2u && base <= 36u));
+    nm_assert(nptr);
+    nm_assert(base == 0u || (base >= 2u && base <= 36u));
 
 again:
-	errno = 0;
-	v = g_ascii_strtoull (nptr, endptr, base);
-	errsv = errno;
+    errno = 0;
+    v     = g_ascii_strtoull(nptr, endptr, base);
+    errsv = errno;
 
-	if (errsv == 0) {
-		if (errsv_orig != 0)
-			errno = errsv_orig;
-		return v;
-	}
+    if (errsv == 0) {
+        if (errsv_orig != 0)
+            errno = errsv_orig;
+        return v;
+    }
 
-	if (   errsv == ERANGE
-	    && NM_IN_SET (v, G_MAXUINT64))
-		return v;
+    if (errsv == ERANGE && NM_IN_SET(v, G_MAXUINT64))
+        return v;
 
-	if (   errsv == EINVAL
-	    && v == 0
-	    && nptr
-	    && nptr[0] == '\0')
-		return v;
+    if (errsv == EINVAL && v == 0 && nptr && nptr[0] == '\0')
+        return v;
 
-	if (try_count-- > 0)
-		goto again;
+    if (try_count-- > 0)
+        goto again;
 
 #if NM_MORE_ASSERTS
-	g_critical ("g_ascii_strtoull() for \"%s\" failed with errno=%d (%s) and v=%"G_GUINT64_FORMAT,
-	            nptr,
-	            errsv,
-	            nm_strerror_native (errsv),
-	            v);
+    g_critical("g_ascii_strtoull() for \"%s\" failed with errno=%d (%s) and v=%" G_GUINT64_FORMAT,
+               nptr,
+               errsv,
+               nm_strerror_native(errsv),
+               v);
 #endif
 
-	return v;
+    return v;
 }
 
 /* see nm_g_ascii_strtoll(). */
 double
-nm_g_ascii_strtod (const char *nptr,
-                   char **endptr)
+nm_g_ascii_strtod(const char *nptr, char **endptr)
 {
-	int try_count = 2;
-	double v;
-	int errsv;
+    int    try_count = 2;
+    double v;
+    int    errsv;
 
-	nm_assert (nptr);
+    nm_assert(nptr);
 
 again:
-	v = g_ascii_strtod (nptr, endptr);
-	errsv = errno;
+    v     = g_ascii_strtod(nptr, endptr);
+    errsv = errno;
 
-	if (errsv == 0)
-		return v;
+    if (errsv == 0)
+        return v;
 
-	if (errsv == ERANGE)
-		return v;
+    if (errsv == ERANGE)
+        return v;
 
-	if (try_count-- > 0)
-		goto again;
+    if (try_count-- > 0)
+        goto again;
 
 #if NM_MORE_ASSERTS
-	g_critical ("g_ascii_strtod() for \"%s\" failed with errno=%d (%s) and v=%f",
-	            nptr,
-	            errsv,
-	            nm_strerror_native (errsv),
-	            v);
+    g_critical("g_ascii_strtod() for \"%s\" failed with errno=%d (%s) and v=%f",
+               nptr,
+               errsv,
+               nm_strerror_native(errsv),
+               v);
 #endif
 
-	/* Not really much else to do. Return the parsed value and leave errno set
-	 * to the unexpected value. */
-	return v;
+    /* Not really much else to do. Return the parsed value and leave errno set
+     * to the unexpected value. */
+    return v;
 }
 
 /* _nm_utils_ascii_str_to_int64:
@@ -1316,91 +1264,94 @@ again:
  * white space.
  **/
 gint64
-_nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback)
+_nm_utils_ascii_str_to_int64(const char *str, guint base, gint64 min, gint64 max, gint64 fallback)
 {
-	gint64 v;
-	const char *s = NULL;
+    gint64      v;
+    const char *s = NULL;
 
-	str = nm_str_skip_leading_spaces (str);
-	if (!str || !str[0]) {
-		errno = EINVAL;
-		return fallback;
-	}
+    str = nm_str_skip_leading_spaces(str);
+    if (!str || !str[0]) {
+        errno = EINVAL;
+        return fallback;
+    }
 
-	errno = 0;
-	v = nm_g_ascii_strtoll (str, (char **) &s, base);
+    errno = 0;
+    v     = nm_g_ascii_strtoll(str, (char **) &s, base);
 
-	if (errno != 0)
-		return fallback;
+    if (errno != 0)
+        return fallback;
 
-	if (s[0] != '\0') {
-		s = nm_str_skip_leading_spaces (s);
-		if (s[0] != '\0') {
-			errno = EINVAL;
-			return fallback;
-		}
-	}
-	if (v > max || v < min) {
-		errno = ERANGE;
-		return fallback;
-	}
+    if (s[0] != '\0') {
+        s = nm_str_skip_leading_spaces(s);
+        if (s[0] != '\0') {
+            errno = EINVAL;
+            return fallback;
+        }
+    }
+    if (v > max || v < min) {
+        errno = ERANGE;
+        return fallback;
+    }
 
-	return v;
+    return v;
 }
 
 guint64
-_nm_utils_ascii_str_to_uint64 (const char *str, guint base, guint64 min, guint64 max, guint64 fallback)
-{
-	guint64 v;
-	const char *s = NULL;
-
-	if (str) {
-		while (g_ascii_isspace (str[0]))
-			str++;
-	}
-	if (!str || !str[0]) {
-		errno = EINVAL;
-		return fallback;
-	}
-
-	errno = 0;
-	v = nm_g_ascii_strtoull (str, (char **) &s, base);
-
-	if (errno != 0)
-		return fallback;
-	if (s[0] != '\0') {
-		while (g_ascii_isspace (s[0]))
-			s++;
-		if (s[0] != '\0') {
-			errno = EINVAL;
-			return fallback;
-		}
-	}
-	if (v > max || v < min) {
-		errno = ERANGE;
-		return fallback;
-	}
-
-	if (   v != 0
-	    && str[0] == '-') {
-		/* As documented, g_ascii_strtoull() accepts negative values, and returns their
-		 * absolute value. We don't. */
-		errno = ERANGE;
-		return fallback;
-	}
-
-	return v;
+_nm_utils_ascii_str_to_uint64(const char *str,
+                              guint       base,
+                              guint64     min,
+                              guint64     max,
+                              guint64     fallback)
+{
+    guint64     v;
+    const char *s = NULL;
+
+    if (str) {
+        while (g_ascii_isspace(str[0]))
+            str++;
+    }
+    if (!str || !str[0]) {
+        errno = EINVAL;
+        return fallback;
+    }
+
+    errno = 0;
+    v     = nm_g_ascii_strtoull(str, (char **) &s, base);
+
+    if (errno != 0)
+        return fallback;
+    if (s[0] != '\0') {
+        while (g_ascii_isspace(s[0]))
+            s++;
+        if (s[0] != '\0') {
+            errno = EINVAL;
+            return fallback;
+        }
+    }
+    if (v > max || v < min) {
+        errno = ERANGE;
+        return fallback;
+    }
+
+    if (v != 0 && str[0] == '-') {
+        /* As documented, g_ascii_strtoull() accepts negative values, and returns their
+         * absolute value. We don't. */
+        errno = ERANGE;
+        return fallback;
+    }
+
+    return v;
 }
 
 /*****************************************************************************/
 
 int
-nm_strcmp_with_data (gconstpointer a, gconstpointer b, gpointer user_data)
+nm_strcmp_with_data(gconstpointer a, gconstpointer b, gpointer user_data)
 {
-	const char *s1 = a;
-	const char *s2 = b;
+    const char *s1 = a;
+    const char *s2 = b;
 
-	return strcmp (s1, s2);
+    return strcmp(s1, s2);
 }
 
 /* like nm_strcmp_p(), suitable for g_ptr_array_sort_with_data().
@@ -1411,202 +1362,220 @@ nm_strcmp_with_data (gconstpointer a, gconstpointer b, gpointer user_data)
  * For NetworkManager, we'd rather avoid such stunts.
  **/
 int
-nm_strcmp_p_with_data (gconstpointer a, gconstpointer b, gpointer user_data)
+nm_strcmp_p_with_data(gconstpointer a, gconstpointer b, gpointer user_data)
+{
+    const char *s1 = *((const char **) a);
+    const char *s2 = *((const char **) b);
+
+    return strcmp(s1, s2);
+}
+
+int
+nm_strcmp0_p_with_data(gconstpointer a, gconstpointer b, gpointer user_data)
 {
-	const char *s1 = *((const char **) a);
-	const char *s2 = *((const char **) b);
+    const char *s1 = *((const char **) a);
+    const char *s2 = *((const char **) b);
 
-	return strcmp (s1, s2);
+    return nm_strcmp0(s1, s2);
 }
 
 int
-nm_strcmp0_p_with_data (gconstpointer a, gconstpointer b, gpointer user_data)
+nm_strcmp_ascii_case_with_data(gconstpointer a, gconstpointer b, gpointer user_data)
 {
-	const char *s1 = *((const char **) a);
-	const char *s2 = *((const char **) b);
+    const char *s1 = a;
+    const char *s2 = b;
 
-	return nm_strcmp0 (s1, s2);
+    return g_ascii_strcasecmp(s1, s2);
 }
 
 int
-nm_cmp_uint32_p_with_data (gconstpointer p_a, gconstpointer p_b, gpointer user_data)
+nm_cmp_uint32_p_with_data(gconstpointer p_a, gconstpointer p_b, gpointer user_data)
 {
-	const guint32 a = *((const guint32 *) p_a);
-	const guint32 b = *((const guint32 *) p_b);
+    const guint32 a = *((const guint32 *) p_a);
+    const guint32 b = *((const guint32 *) p_b);
 
-	if (a < b)
-		return -1;
-	if (a > b)
-		return 1;
-	return 0;
+    if (a < b)
+        return -1;
+    if (a > b)
+        return 1;
+    return 0;
 }
 
 int
-nm_cmp_int2ptr_p_with_data (gconstpointer p_a, gconstpointer p_b, gpointer user_data)
+nm_cmp_int2ptr_p_with_data(gconstpointer p_a, gconstpointer p_b, gpointer user_data)
 {
-	/* p_a and p_b are two pointers to a pointer, where the pointer is
-	 * interpreted as a integer using GPOINTER_TO_INT().
-	 *
-	 * That is the case of a hash-table that uses GINT_TO_POINTER() to
-	 * convert integers as pointers, and the resulting keys-as-array
-	 * array. */
-	const int a = GPOINTER_TO_INT (*((gconstpointer *) p_a));
-	const int b = GPOINTER_TO_INT (*((gconstpointer *) p_b));
+    /* p_a and p_b are two pointers to a pointer, where the pointer is
+     * interpreted as a integer using GPOINTER_TO_INT().
+     *
+     * That is the case of a hash-table that uses GINT_TO_POINTER() to
+     * convert integers as pointers, and the resulting keys-as-array
+     * array. */
+    const int a = GPOINTER_TO_INT(*((gconstpointer *) p_a));
+    const int b = GPOINTER_TO_INT(*((gconstpointer *) p_b));
 
-	if (a < b)
-		return -1;
-	if (a > b)
-		return 1;
-	return 0;
+    if (a < b)
+        return -1;
+    if (a > b)
+        return 1;
+    return 0;
 }
 
 /*****************************************************************************/
 
 const char *
-nm_utils_dbus_path_get_last_component (const char *dbus_path)
+nm_utils_dbus_path_get_last_component(const char *dbus_path)
 {
-	if (dbus_path) {
-		dbus_path = strrchr (dbus_path, '/');
-		if (dbus_path)
-			return dbus_path + 1;
-	}
-	return NULL;
+    if (dbus_path) {
+        dbus_path = strrchr(dbus_path, '/');
+        if (dbus_path)
+            return dbus_path + 1;
+    }
+    return NULL;
 }
 
 static gint64
-_dbus_path_component_as_num (const char *p)
-{
-	gint64 n;
-
-	/* no odd stuff. No leading zeros, only a non-negative, decimal integer.
-	 *
-	 * Otherwise, there would be multiple ways to encode the same number "10"
-	 * and "010". That is just confusing. A number has no leading zeros,
-	 * if it has, it's not a number (as far as we are concerned here). */
-	if (p[0] == '0') {
-		if (p[1] != '\0')
-			return -1;
-		else
-			return 0;
-	}
-	if (!(p[0] >= '1' && p[0] <= '9'))
-		return -1;
-	if (!NM_STRCHAR_ALL (&p[1], ch, (ch >= '0' && ch <= '9')))
-		return -1;
-	n = _nm_utils_ascii_str_to_int64 (p, 10, 0, G_MAXINT64, -1);
-	nm_assert (n == -1 || nm_streq0 (p, nm_sprintf_bufa (100, "%"G_GINT64_FORMAT, n)));
-	return n;
+_dbus_path_component_as_num(const char *p)
+{
+    gint64 n;
+
+    /* no odd stuff. No leading zeros, only a non-negative, decimal integer.
+     *
+     * Otherwise, there would be multiple ways to encode the same number "10"
+     * and "010". That is just confusing. A number has no leading zeros,
+     * if it has, it's not a number (as far as we are concerned here). */
+    if (p[0] == '0') {
+        if (p[1] != '\0')
+            return -1;
+        else
+            return 0;
+    }
+    if (!(p[0] >= '1' && p[0] <= '9'))
+        return -1;
+    if (!NM_STRCHAR_ALL(&p[1], ch, (ch >= '0' && ch <= '9')))
+        return -1;
+    n = _nm_utils_ascii_str_to_int64(p, 10, 0, G_MAXINT64, -1);
+    nm_assert(n == -1 || nm_streq0(p, nm_sprintf_bufa(100, "%" G_GINT64_FORMAT, n)));
+    return n;
 }
 
 int
-nm_utils_dbus_path_cmp (const char *dbus_path_a, const char *dbus_path_b)
-{
-	const char *l_a, *l_b;
-	gsize plen;
-	gint64 n_a, n_b;
-
-	/* compare function for two D-Bus paths. It behaves like
-	 * strcmp(), except, if both paths have the same prefix,
-	 * and both end in a (positive) number, then the paths
-	 * will be sorted by number. */
-
-	NM_CMP_SELF (dbus_path_a, dbus_path_b);
-
-	/* if one or both paths have no slash (and no last component)
-	 * compare the full paths directly. */
-	if (   !(l_a = nm_utils_dbus_path_get_last_component (dbus_path_a))
-	    || !(l_b = nm_utils_dbus_path_get_last_component (dbus_path_b)))
-		goto comp_full;
-
-	/* check if both paths have the same prefix (up to the last-component). */
-	plen = l_a - dbus_path_a;
-	if (plen != (l_b - dbus_path_b))
-		goto comp_full;
-	NM_CMP_RETURN (strncmp (dbus_path_a, dbus_path_b, plen));
-
-	n_a = _dbus_path_component_as_num (l_a);
-	n_b = _dbus_path_component_as_num (l_b);
-	if (n_a == -1 && n_b == -1)
-		goto comp_l;
-
-	/* both components must be convertiable 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.
-	 *
-	 * An example of a not total ordering would be:
-	 *   "8"   < "010"  (numeric)
-	 *   "0x"  < "8"    (lexical)
-	 *   "0x"  > "010"  (lexical)
-	 * We avoid this, by forcing that a non-numeric entry "0x" always sorts
-	 * before numeric entries.
-	 *
-	 * Additionally, _dbus_path_component_as_num() would also reject "010" as
-	 * not a valid number.
-	 */
-	if (n_a == -1)
-		return -1;
-	if (n_b == -1)
-		return 1;
-
-	NM_CMP_DIRECT (n_a, n_b);
-	nm_assert (nm_streq (dbus_path_a, dbus_path_b));
-	return 0;
+nm_utils_dbus_path_cmp(const char *dbus_path_a, const char *dbus_path_b)
+{
+    const char *l_a, *l_b;
+    gsize       plen;
+    gint64      n_a, n_b;
+
+    /* compare function for two D-Bus paths. It behaves like
+     * strcmp(), except, if both paths have the same prefix,
+     * and both end in a (positive) number, then the paths
+     * will be sorted by number. */
+
+    NM_CMP_SELF(dbus_path_a, dbus_path_b);
+
+    /* if one or both paths have no slash (and no last component)
+     * compare the full paths directly. */
+    if (!(l_a = nm_utils_dbus_path_get_last_component(dbus_path_a))
+        || !(l_b = nm_utils_dbus_path_get_last_component(dbus_path_b)))
+        goto comp_full;
+
+    /* check if both paths have the same prefix (up to the last-component). */
+    plen = l_a - dbus_path_a;
+    if (plen != (l_b - dbus_path_b))
+        goto comp_full;
+    NM_CMP_RETURN(strncmp(dbus_path_a, dbus_path_b, plen));
+
+    n_a = _dbus_path_component_as_num(l_a);
+    n_b = _dbus_path_component_as_num(l_b);
+    if (n_a == -1 && n_b == -1)
+        goto comp_l;
+
+    /* 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.
+     *
+     * An example of a not total ordering would be:
+     *   "8"   < "010"  (numeric)
+     *   "0x"  < "8"    (lexical)
+     *   "0x"  > "010"  (lexical)
+     * We avoid this, by forcing that a non-numeric entry "0x" always sorts
+     * before numeric entries.
+     *
+     * Additionally, _dbus_path_component_as_num() would also reject "010" as
+     * not a valid number.
+     */
+    if (n_a == -1)
+        return -1;
+    if (n_b == -1)
+        return 1;
+
+    NM_CMP_DIRECT(n_a, n_b);
+    nm_assert(nm_streq(dbus_path_a, dbus_path_b));
+    return 0;
 
 comp_full:
-	NM_CMP_DIRECT_STRCMP0 (dbus_path_a, dbus_path_b);
-	return 0;
+    NM_CMP_DIRECT_STRCMP0(dbus_path_a, dbus_path_b);
+    return 0;
 comp_l:
-	NM_CMP_DIRECT_STRCMP0 (l_a, l_b);
-	nm_assert (nm_streq (dbus_path_a, dbus_path_b));
-	return 0;
+    NM_CMP_DIRECT_STRCMP0(l_a, l_b);
+    nm_assert(nm_streq(dbus_path_a, dbus_path_b));
+    return 0;
 }
 
 /*****************************************************************************/
 
+typedef struct {
+    union {
+        guint8  table[256];
+        guint64 _dummy_for_alignment;
+    };
+} CharLookupTable;
+
 static void
-_char_lookup_table_set_one (guint8 lookup[static 256],
-                             char ch)
+_char_lookup_table_set_one(CharLookupTable *lookup, char ch)
 {
-	lookup[(guint8) ch] = 1;
+    lookup->table[(guint8) ch] = 1;
 }
 
 static void
-_char_lookup_table_set_all (guint8 lookup[static 256],
-                            const char *candidates)
+_char_lookup_table_set_all(CharLookupTable *lookup, const char *candidates)
 {
-	while (candidates[0] != '\0')
-		_char_lookup_table_set_one (lookup, (candidates++)[0]);
+    while (candidates[0] != '\0')
+        _char_lookup_table_set_one(lookup, (candidates++)[0]);
 }
 
 static void
-_char_lookup_table_init (guint8 lookup[static 256],
-                         const char *candidates)
+_char_lookup_table_init(CharLookupTable *lookup, const char *candidates)
 {
-	memset (lookup, 0, 256);
-	if (candidates)
-		_char_lookup_table_set_all (lookup, candidates);
+    *lookup = (CharLookupTable){
+        .table = {0},
+    };
+    if (candidates)
+        _char_lookup_table_set_all(lookup, candidates);
 }
 
 static gboolean
-_char_lookup_has (const guint8 lookup[static 256],
-                  char ch)
+_char_lookup_has(const CharLookupTable *lookup, char ch)
 {
-	nm_assert (lookup[(guint8) '\0'] == 0);
-	return lookup[(guint8) ch] != 0;
+    /* with some optimization levels, the compiler thinks this code
+     * might access uninitialized @lookup. It is not -- when you look at the
+     * callers of this function. */
+    NM_PRAGMA_WARNING_DISABLE("-Wmaybe-uninitialized")
+    nm_assert(lookup->table[(guint8) '\0'] == 0);
+    return lookup->table[(guint8) ch] != 0;
+    NM_PRAGMA_WARNING_REENABLE
 }
 
 static gboolean
-_char_lookup_has_all (const guint8 lookup[static 256],
-                      const char *candidates)
+_char_lookup_has_all(const CharLookupTable *lookup, const char *candidates)
 {
-	if (candidates) {
-		while (candidates[0] != '\0') {
-			if (!_char_lookup_has (lookup, (candidates++)[0]))
-				return FALSE;
-		}
-	}
-	return TRUE;
+    if (candidates) {
+        while (candidates[0] != '\0') {
+            if (!_char_lookup_has(lookup, (candidates++)[0]))
+                return FALSE;
+        }
+    }
+    return TRUE;
 }
 
 /**
@@ -1635,344 +1604,329 @@ _char_lookup_has_all (const guint8 lookup[static 256],
  *   like "g_strstrip((char *) iter[0])".
  */
 const char **
-nm_utils_strsplit_set_full (const char *str,
-                            const char *delimiters,
-                            NMUtilsStrsplitSetFlags flags)
-{
-	const char **ptr;
-	gsize num_tokens;
-	gsize i_token;
-	gsize str_len_p1;
-	const char *c_str;
-	char *s;
-	guint8 ch_lookup[256];
-	const gboolean f_escaped = NM_FLAGS_HAS (flags, NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED);
-	const gboolean f_allow_escaping = f_escaped || NM_FLAGS_HAS (flags, NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING);
-	const gboolean f_preserve_empty = NM_FLAGS_HAS (flags, NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY);
-	const gboolean f_strstrip = NM_FLAGS_HAS (flags, NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP);
-
-	if (!str)
-		return NULL;
-
-	if (!delimiters) {
-		nm_assert_not_reached ();
-		delimiters = " \t\n";
-	}
-	_char_lookup_table_init (ch_lookup, delimiters);
-
-	nm_assert (   !f_allow_escaping
-	           || !_char_lookup_has (ch_lookup, '\\'));
-
-	if (!f_preserve_empty) {
-		while (_char_lookup_has (ch_lookup, str[0]))
-			str++;
-	}
-
-	if (!str[0]) {
-		/* We return %NULL here, also with NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY.
-		 * That makes nm_utils_strsplit_set_full() with NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY
-		 * different from g_strsplit_set(), which would in this case return an empty array.
-		 * If you need to handle %NULL, and "" specially, then check the input string first. */
-		return NULL;
-	}
-
-#define _char_is_escaped(str_start, str_cur) \
-	({ \
-		const char *const _str_start = (str_start); \
-		const char *const _str_cur = (str_cur); \
-		const char *_str_i = (_str_cur); \
-		\
-		while (   _str_i > _str_start \
-		       && _str_i[-1] == '\\') \
-			_str_i--; \
-		(((_str_cur - _str_i) % 2) != 0); \
-	})
-
-	num_tokens = 1;
-	c_str = str;
-	while (TRUE) {
-
-		while (G_LIKELY (!_char_lookup_has (ch_lookup, c_str[0]))) {
-			if (c_str[0] == '\0')
-				goto done1;
-			c_str++;
-		}
-
-		/* we assume escapings are not frequent. After we found
-		 * this delimiter, check whether it was escaped by counting
-		 * the backslashed before. */
-		if (   f_allow_escaping
-		    && _char_is_escaped (str, c_str)) {
-			/* the delimiter is escaped. This was not an accepted delimiter. */
-			c_str++;
-			continue;
-		}
-
-		c_str++;
-
-		/* if we drop empty tokens, then we now skip over all consecutive delimiters. */
-		if (!f_preserve_empty) {
-			while (_char_lookup_has (ch_lookup, c_str[0]))
-				c_str++;
-			if (c_str[0] == '\0')
-				break;
-		}
-
-		num_tokens++;
-	}
+nm_utils_strsplit_set_full(const char *str, const char *delimiters, NMUtilsStrsplitSetFlags flags)
+{
+    const char **   ptr;
+    gsize           num_tokens;
+    gsize           i_token;
+    gsize           str_len_p1;
+    const char *    c_str;
+    char *          s;
+    CharLookupTable ch_lookup;
+    const gboolean  f_escaped = NM_FLAGS_HAS(flags, NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED);
+    const gboolean  f_allow_escaping =
+        f_escaped || NM_FLAGS_HAS(flags, NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING);
+    const gboolean f_preserve_empty =
+        NM_FLAGS_HAS(flags, NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY);
+    const gboolean f_strstrip = NM_FLAGS_HAS(flags, NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP);
+
+    if (!str)
+        return NULL;
+
+    if (!delimiters) {
+        nm_assert_not_reached();
+        delimiters = " \t\n";
+    }
+    _char_lookup_table_init(&ch_lookup, delimiters);
+
+    nm_assert(!f_allow_escaping || !_char_lookup_has(&ch_lookup, '\\'));
+
+    if (!f_preserve_empty) {
+        while (_char_lookup_has(&ch_lookup, str[0]))
+            str++;
+    }
+
+    if (!str[0]) {
+        /* We return %NULL here, also with NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY.
+         * That makes nm_utils_strsplit_set_full() with NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY
+         * different from g_strsplit_set(), which would in this case return an empty array.
+         * If you need to handle %NULL, and "" specially, then check the input string first. */
+        return NULL;
+    }
+
+#define _char_is_escaped(str_start, str_cur)              \
+    ({                                                    \
+        const char *const _str_start = (str_start);       \
+        const char *const _str_cur   = (str_cur);         \
+        const char *      _str_i     = (_str_cur);        \
+                                                          \
+        while (_str_i > _str_start && _str_i[-1] == '\\') \
+            _str_i--;                                     \
+        (((_str_cur - _str_i) % 2) != 0);                 \
+    })
+
+    num_tokens = 1;
+    c_str      = str;
+    while (TRUE) {
+        while (G_LIKELY(!_char_lookup_has(&ch_lookup, c_str[0]))) {
+            if (c_str[0] == '\0')
+                goto done1;
+            c_str++;
+        }
+
+        /* we assume escapings are not frequent. After we found
+         * this delimiter, check whether it was escaped by counting
+         * the backslashed before. */
+        if (f_allow_escaping && _char_is_escaped(str, c_str)) {
+            /* the delimiter is escaped. This was not an accepted delimiter. */
+            c_str++;
+            continue;
+        }
+
+        c_str++;
+
+        /* if we drop empty tokens, then we now skip over all consecutive delimiters. */
+        if (!f_preserve_empty) {
+            while (_char_lookup_has(&ch_lookup, c_str[0]))
+                c_str++;
+            if (c_str[0] == '\0')
+                break;
+        }
+
+        num_tokens++;
+    }
 
 done1:
 
-	nm_assert (c_str[0] == '\0');
+    nm_assert(c_str[0] == '\0');
 
-	str_len_p1 = (c_str - str) + 1;
+    str_len_p1 = (c_str - str) + 1;
 
-	nm_assert (str[str_len_p1 - 1] == '\0');
+    nm_assert(str[str_len_p1 - 1] == '\0');
 
-	ptr = g_malloc ((sizeof (const char *) * (num_tokens + 1)) + str_len_p1);
-	s = (char *) &ptr[num_tokens + 1];
-	memcpy (s, str, str_len_p1);
+    ptr = g_malloc((sizeof(const char *) * (num_tokens + 1)) + str_len_p1);
+    s   = (char *) &ptr[num_tokens + 1];
+    memcpy(s, str, str_len_p1);
 
-	i_token = 0;
+    i_token = 0;
 
-	while (TRUE) {
+    while (TRUE) {
+        nm_assert(i_token < num_tokens);
+        ptr[i_token++] = s;
 
-		nm_assert (i_token < num_tokens);
-		ptr[i_token++] = s;
+        if (s[0] == '\0') {
+            nm_assert(f_preserve_empty);
+            goto done2;
+        }
+        nm_assert(f_preserve_empty || !_char_lookup_has(&ch_lookup, s[0]));
 
-		if (s[0] == '\0') {
-			nm_assert (f_preserve_empty);
-			goto done2;
-		}
-		nm_assert (   f_preserve_empty
-		           || !_char_lookup_has (ch_lookup, s[0]));
+        while (!_char_lookup_has(&ch_lookup, s[0])) {
+            if (G_UNLIKELY(s[0] == '\\' && f_allow_escaping)) {
+                s++;
+                if (s[0] == '\0')
+                    goto done2;
+                s++;
+            } else if (s[0] == '\0')
+                goto done2;
+            else
+                s++;
+        }
 
-		while (!_char_lookup_has (ch_lookup, s[0])) {
-			if (G_UNLIKELY (   s[0] == '\\'
-			                && f_allow_escaping)) {
-				s++;
-				if (s[0] == '\0')
-					goto done2;
-				s++;
-			} else if (s[0] == '\0')
-				goto done2;
-			else
-				s++;
-		}
+        nm_assert(_char_lookup_has(&ch_lookup, s[0]));
+        s[0] = '\0';
+        s++;
 
-		nm_assert (_char_lookup_has (ch_lookup, s[0]));
-		s[0] = '\0';
-		s++;
-
-		if (!f_preserve_empty) {
-			while (_char_lookup_has (ch_lookup, s[0]))
-				s++;
-			if (s[0] == '\0')
-				goto done2;
-		}
-	}
+        if (!f_preserve_empty) {
+            while (_char_lookup_has(&ch_lookup, s[0]))
+                s++;
+            if (s[0] == '\0')
+                goto done2;
+        }
+    }
 
 done2:
-	nm_assert (i_token == num_tokens);
-	ptr[i_token] = NULL;
-
-	if (f_strstrip) {
-		gsize i;
-
-		i_token = 0;
-		for (i = 0; ptr[i]; i++) {
-
-			s = (char *) nm_str_skip_leading_spaces (ptr[i]);
-			if (s[0] != '\0') {
-				char *s_last;
-
-				s_last = &s[strlen (s) - 1];
-				while (   s_last > s
-				       && g_ascii_isspace (s_last[0])
-				       && (   ! f_allow_escaping
-				           || !_char_is_escaped (s, s_last)))
-					(s_last--)[0] = '\0';
-			}
-
-			if (   !f_preserve_empty
-			    && s[0] == '\0')
-				continue;
-
-			ptr[i_token++] = s;
-		}
-
-		if (i_token == 0) {
-			g_free (ptr);
-			return NULL;
-		}
-		ptr[i_token] = NULL;
-	}
-
-	if (f_escaped) {
-		gsize i, j;
-
-		/* We no longer need ch_lookup for its original purpose. Modify it, so it
-		 * can detect the delimiters, '\\', and (optionally) whitespaces. */
-		_char_lookup_table_set_one (ch_lookup, '\\');
-		if (f_strstrip)
-			_char_lookup_table_set_all (ch_lookup, NM_ASCII_SPACES);
-
-		for (i_token = 0; ptr[i_token]; i_token++) {
-			s = (char *) ptr[i_token];
-			j = 0;
-			for (i = 0; s[i] != '\0'; ) {
-				if (   s[i] == '\\'
-				    && _char_lookup_has (ch_lookup, s[i + 1]))
-					i++;
-				s[j++] = s[i++];
-			}
-			s[j] = '\0';
-		}
-	}
-
-	nm_assert (ptr && ptr[0]);
-	return ptr;
+    nm_assert(i_token == num_tokens);
+    ptr[i_token] = NULL;
+
+    if (f_strstrip) {
+        gsize i;
+
+        i_token = 0;
+        for (i = 0; ptr[i]; i++) {
+            s = (char *) nm_str_skip_leading_spaces(ptr[i]);
+            if (s[0] != '\0') {
+                char *s_last;
+
+                s_last = &s[strlen(s) - 1];
+                while (s_last > s && g_ascii_isspace(s_last[0])
+                       && (!f_allow_escaping || !_char_is_escaped(s, s_last)))
+                    (s_last--)[0] = '\0';
+            }
+
+            if (!f_preserve_empty && s[0] == '\0')
+                continue;
+
+            ptr[i_token++] = s;
+        }
+
+        if (i_token == 0) {
+            g_free(ptr);
+            return NULL;
+        }
+        ptr[i_token] = NULL;
+    }
+
+    if (f_escaped) {
+        gsize i, j;
+
+        /* We no longer need ch_lookup for its original purpose. Modify it, so it
+         * can detect the delimiters, '\\', and (optionally) whitespaces. */
+        _char_lookup_table_set_one(&ch_lookup, '\\');
+        if (f_strstrip)
+            _char_lookup_table_set_all(&ch_lookup, NM_ASCII_SPACES);
+
+        for (i_token = 0; ptr[i_token]; i_token++) {
+            s = (char *) ptr[i_token];
+            j = 0;
+            for (i = 0; s[i] != '\0';) {
+                if (s[i] == '\\' && _char_lookup_has(&ch_lookup, s[i + 1]))
+                    i++;
+                s[j++] = s[i++];
+            }
+            s[j] = '\0';
+        }
+    }
+
+    nm_assert(ptr && ptr[0]);
+    return ptr;
 }
 
 /*****************************************************************************/
 
 const char *
-nm_utils_escaped_tokens_escape_full (const char *str,
-                                     const char *delimiters,
-                                     const char *delimiters_as_needed,
-                                     NMUtilsEscapedTokensEscapeFlags flags,
-                                     char **out_to_free)
-{
-	guint8 ch_lookup[256];
-	guint8 ch_lookup_as_needed[256];
-	gboolean has_ch_lookup_as_needed = FALSE;
-	char *ret;
-	gsize str_len;
-	gsize alloc_len;
-	gsize n_escapes;
-	gsize i, j;
-	gboolean escape_leading_space;
-	gboolean escape_trailing_space;
-	gboolean escape_backslash_as_needed;
-
-	nm_assert (   !delimiters_as_needed
-	           || (   delimiters_as_needed[0]
-	               && NM_FLAGS_HAS (flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED)));
-
-	if (!str || str[0] == '\0') {
-		*out_to_free = NULL;
-		return str;
-	}
-
-	str_len = strlen (str);
-
-	_char_lookup_table_init (ch_lookup, delimiters);
-	if (   !delimiters
-	    || NM_FLAGS_HAS (flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_SPACES)) {
-		flags &= ~(  NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE
-		           | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE);
-		_char_lookup_table_set_all (ch_lookup, NM_ASCII_SPACES);
-	}
-
-	if (NM_FLAGS_HAS (flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_ALWAYS)) {
-		_char_lookup_table_set_one (ch_lookup, '\\');
-		escape_backslash_as_needed = FALSE;
-	} else if (_char_lookup_has (ch_lookup, '\\'))
-		escape_backslash_as_needed = FALSE;
-	else {
-		escape_backslash_as_needed = NM_FLAGS_HAS (flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED);
-		if (escape_backslash_as_needed) {
-			if (    NM_FLAGS_ANY (flags,   NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE
-			                             | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE)
-			    && !_char_lookup_has_all (ch_lookup, NM_ASCII_SPACES)) {
-				/* ESCAPE_LEADING_SPACE and ESCAPE_TRAILING_SPACE implies that we escape backslash
-				 * before whitespaces. */
-				if (!has_ch_lookup_as_needed) {
-					has_ch_lookup_as_needed = TRUE;
-					_char_lookup_table_init (ch_lookup_as_needed, NULL);
-				}
-				_char_lookup_table_set_all (ch_lookup_as_needed, NM_ASCII_SPACES);
-			}
-			if (   delimiters_as_needed
-			    && !_char_lookup_has_all (ch_lookup, delimiters_as_needed)) {
-				if (!has_ch_lookup_as_needed) {
-					has_ch_lookup_as_needed = TRUE;
-					_char_lookup_table_init (ch_lookup_as_needed, NULL);
-				}
-				_char_lookup_table_set_all (ch_lookup_as_needed, delimiters_as_needed);
-			}
-		}
-	}
-
-	escape_leading_space =    NM_FLAGS_HAS (flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE)
-	                       && g_ascii_isspace (str[0])
-	                       && !_char_lookup_has (ch_lookup, str[0]);
-	if (str_len == 1)
-		escape_trailing_space = FALSE;
-	else {
-		escape_trailing_space =    NM_FLAGS_HAS (flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE)
-		                        && g_ascii_isspace (str[str_len - 1])
-		                        && !_char_lookup_has (ch_lookup, str[str_len - 1]);
-	}
-
-	n_escapes = 0;
-	for (i = 0; str[i] != '\0'; i++) {
-		if (_char_lookup_has (ch_lookup, str[i]))
-			n_escapes++;
-		else if (   str[i] == '\\'
-		         && escape_backslash_as_needed
-		         && (   _char_lookup_has (ch_lookup, str[i + 1])
-		             || NM_IN_SET (str[i + 1], '\0', '\\')
-		             || (   has_ch_lookup_as_needed
-		                 && _char_lookup_has (ch_lookup_as_needed, str[i + 1]))))
-			n_escapes++;
-	}
-	if (escape_leading_space)
-		n_escapes++;
-	if (escape_trailing_space)
-		n_escapes++;
-
-	if (n_escapes == 0u) {
-		*out_to_free = NULL;
-		return str;
-	}
-
-	alloc_len = str_len + n_escapes + 1u;
-	ret = g_new (char, alloc_len);
-
-	j = 0;
-	i = 0;
-
-	if (escape_leading_space) {
-		ret[j++] = '\\';
-		ret[j++] = str[i++];
-	}
-	for (; str[i] != '\0'; i++) {
-		if (_char_lookup_has (ch_lookup, str[i]))
-			ret[j++] = '\\';
-		else if (   str[i] == '\\'
-		         && escape_backslash_as_needed
-		         && (   _char_lookup_has (ch_lookup, str[i + 1])
-		             || NM_IN_SET (str[i + 1], '\0', '\\')
-		             || (   has_ch_lookup_as_needed
-		                 && _char_lookup_has (ch_lookup_as_needed, str[i + 1]))))
-			ret[j++] = '\\';
-		ret[j++] = str[i];
-	}
-	if (escape_trailing_space) {
-		nm_assert (   !_char_lookup_has (ch_lookup, ret[j - 1])
-		           && g_ascii_isspace (ret[j - 1]));
-		ret[j] = ret[j - 1];
-		ret[j - 1] = '\\';
-		j++;
-	}
-
-	nm_assert (j == alloc_len - 1);
-	ret[j] = '\0';
-	nm_assert (strlen (ret) == j);
-
-	*out_to_free = ret;
-	return ret;
+nm_utils_escaped_tokens_escape_full(const char *                    str,
+                                    const char *                    delimiters,
+                                    const char *                    delimiters_as_needed,
+                                    NMUtilsEscapedTokensEscapeFlags flags,
+                                    char **                         out_to_free)
+{
+    CharLookupTable ch_lookup;
+    CharLookupTable ch_lookup_as_needed;
+    gboolean        has_ch_lookup_as_needed = FALSE;
+    char *          ret;
+    gsize           str_len;
+    gsize           alloc_len;
+    gsize           n_escapes;
+    gsize           i, j;
+    gboolean        escape_leading_space;
+    gboolean        escape_trailing_space;
+    gboolean        escape_backslash_as_needed;
+
+    nm_assert(
+        !delimiters_as_needed
+        || (delimiters_as_needed[0]
+            && NM_FLAGS_HAS(flags,
+                            NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED)));
+
+    if (!str || str[0] == '\0') {
+        *out_to_free = NULL;
+        return str;
+    }
+
+    str_len = strlen(str);
+
+    _char_lookup_table_init(&ch_lookup, delimiters);
+    if (!delimiters || NM_FLAGS_HAS(flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_SPACES)) {
+        flags &= ~(NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE
+                   | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE);
+        _char_lookup_table_set_all(&ch_lookup, NM_ASCII_SPACES);
+    }
+
+    if (NM_FLAGS_HAS(flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_ALWAYS)) {
+        _char_lookup_table_set_one(&ch_lookup, '\\');
+        escape_backslash_as_needed = FALSE;
+    } else if (_char_lookup_has(&ch_lookup, '\\'))
+        escape_backslash_as_needed = FALSE;
+    else {
+        escape_backslash_as_needed =
+            NM_FLAGS_HAS(flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED);
+        if (escape_backslash_as_needed) {
+            if (NM_FLAGS_ANY(flags,
+                             NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE
+                                 | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE)
+                && !_char_lookup_has_all(&ch_lookup, NM_ASCII_SPACES)) {
+                /* ESCAPE_LEADING_SPACE and ESCAPE_TRAILING_SPACE implies that we escape backslash
+                 * before whitespaces. */
+                if (!has_ch_lookup_as_needed) {
+                    has_ch_lookup_as_needed = TRUE;
+                    _char_lookup_table_init(&ch_lookup_as_needed, NULL);
+                }
+                _char_lookup_table_set_all(&ch_lookup_as_needed, NM_ASCII_SPACES);
+            }
+            if (delimiters_as_needed && !_char_lookup_has_all(&ch_lookup, delimiters_as_needed)) {
+                if (!has_ch_lookup_as_needed) {
+                    has_ch_lookup_as_needed = TRUE;
+                    _char_lookup_table_init(&ch_lookup_as_needed, NULL);
+                }
+                _char_lookup_table_set_all(&ch_lookup_as_needed, delimiters_as_needed);
+            }
+        }
+    }
+
+    escape_leading_space =
+        NM_FLAGS_HAS(flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE)
+        && g_ascii_isspace(str[0]) && !_char_lookup_has(&ch_lookup, str[0]);
+    if (str_len == 1)
+        escape_trailing_space = FALSE;
+    else {
+        escape_trailing_space =
+            NM_FLAGS_HAS(flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE)
+            && g_ascii_isspace(str[str_len - 1]) && !_char_lookup_has(&ch_lookup, str[str_len - 1]);
+    }
+
+    n_escapes = 0;
+    for (i = 0; str[i] != '\0'; i++) {
+        if (_char_lookup_has(&ch_lookup, str[i]))
+            n_escapes++;
+        else if (str[i] == '\\' && escape_backslash_as_needed
+                 && (_char_lookup_has(&ch_lookup, str[i + 1]) || NM_IN_SET(str[i + 1], '\0', '\\')
+                     || (has_ch_lookup_as_needed
+                         && _char_lookup_has(&ch_lookup_as_needed, str[i + 1]))))
+            n_escapes++;
+    }
+    if (escape_leading_space)
+        n_escapes++;
+    if (escape_trailing_space)
+        n_escapes++;
+
+    if (n_escapes == 0u) {
+        *out_to_free = NULL;
+        return str;
+    }
+
+    alloc_len = str_len + n_escapes + 1u;
+    ret       = g_new(char, alloc_len);
+
+    j = 0;
+    i = 0;
+
+    if (escape_leading_space) {
+        ret[j++] = '\\';
+        ret[j++] = str[i++];
+    }
+    for (; str[i] != '\0'; i++) {
+        if (_char_lookup_has(&ch_lookup, str[i]))
+            ret[j++] = '\\';
+        else if (str[i] == '\\' && escape_backslash_as_needed
+                 && (_char_lookup_has(&ch_lookup, str[i + 1]) || NM_IN_SET(str[i + 1], '\0', '\\')
+                     || (has_ch_lookup_as_needed
+                         && _char_lookup_has(&ch_lookup_as_needed, str[i + 1]))))
+            ret[j++] = '\\';
+        ret[j++] = str[i];
+    }
+    if (escape_trailing_space) {
+        nm_assert(!_char_lookup_has(&ch_lookup, ret[j - 1]) && g_ascii_isspace(ret[j - 1]));
+        ret[j]     = ret[j - 1];
+        ret[j - 1] = '\\';
+        j++;
+    }
+
+    nm_assert(j == alloc_len - 1);
+    ret[j] = '\0';
+    nm_assert(strlen(ret) == j);
+
+    *out_to_free = ret;
+    return ret;
 }
 
 /**
@@ -1998,66 +1952,63 @@ nm_utils_escaped_tokens_escape_full (const char *str,
  * not be escaped, unless they are at the beginning or the end of key/value.
  */
 void
-nm_utils_escaped_tokens_options_split (char *str,
-                                       const char **out_key,
-                                       const char **out_val)
-{
-	const char *val = NULL;
-	gsize i;
-	gsize j;
-	gsize last_space_idx;
-	gboolean last_space_has;
-
-	nm_assert (str);
-
-	i = 0;
-	while (g_ascii_isspace (str[i]))
-		i++;
-
-	j = 0;
-	last_space_idx = 0;
-	last_space_has = FALSE;
-	while (str[i] != '\0') {
-		if (g_ascii_isspace (str[i])) {
-			if (!last_space_has) {
-				last_space_has = TRUE;
-				last_space_idx = j;
-			}
-		} else {
-			if (str[i] == '\\') {
-				if (   NM_IN_SET (str[i + 1u], '\\', ',', '=')
-				    || g_ascii_isspace (str[i + 1u]))
-					i++;
-			} else if (str[i] == '=') {
-				/* Encounter an unescaped '=' character. When we still parse the key, this
-				 * is the separator we were waiting for. If we are parsing the value,
-				 * we take the character verbatim. */
-				if (!val) {
-					if (last_space_has) {
-						str[last_space_idx] = '\0';
-						j = last_space_idx + 1;
-						last_space_has = FALSE;
-					} else
-						str[j++] = '\0';
-					val = &str[j];
-					i++;
-					while (g_ascii_isspace (str[i]))
-						i++;
-					continue;
-				}
-			}
-			last_space_has = FALSE;
-		}
-		str[j++] = str[i++];
-	}
-
-	if (last_space_has)
-		str[last_space_idx] = '\0';
-	else
-		str[j] = '\0';
-
-	*out_key = str;
-	*out_val = val;
+nm_utils_escaped_tokens_options_split(char *str, const char **out_key, const char **out_val)
+{
+    const char *val = NULL;
+    gsize       i;
+    gsize       j;
+    gsize       last_space_idx;
+    gboolean    last_space_has;
+
+    nm_assert(str);
+
+    i = 0;
+    while (g_ascii_isspace(str[i]))
+        i++;
+
+    j              = 0;
+    last_space_idx = 0;
+    last_space_has = FALSE;
+    while (str[i] != '\0') {
+        if (g_ascii_isspace(str[i])) {
+            if (!last_space_has) {
+                last_space_has = TRUE;
+                last_space_idx = j;
+            }
+        } else {
+            if (str[i] == '\\') {
+                if (NM_IN_SET(str[i + 1u], '\\', ',', '=') || g_ascii_isspace(str[i + 1u]))
+                    i++;
+            } else if (str[i] == '=') {
+                /* Encounter an unescaped '=' character. When we still parse the key, this
+                 * is the separator we were waiting for. If we are parsing the value,
+                 * we take the character verbatim. */
+                if (!val) {
+                    if (last_space_has) {
+                        str[last_space_idx] = '\0';
+                        j                   = last_space_idx + 1;
+                        last_space_has      = FALSE;
+                    } else
+                        str[j++] = '\0';
+                    val = &str[j];
+                    i++;
+                    while (g_ascii_isspace(str[i]))
+                        i++;
+                    continue;
+                }
+            }
+            last_space_has = FALSE;
+        }
+        str[j++] = str[i++];
+    }
+
+    if (last_space_has)
+        str[last_space_idx] = '\0';
+    else
+        str[j] = '\0';
+
+    *out_key = str;
+    *out_val = val;
 }
 
 /*****************************************************************************/
@@ -2078,80 +2029,80 @@ nm_utils_escaped_tokens_options_split (char *str,
  * Returns: (transfer full): the split string.
  */
 char **
-nm_utils_strsplit_quoted (const char *str)
-{
-	gs_unref_ptrarray GPtrArray *arr = NULL;
-	gs_free char *str_out = NULL;
-	guint8 ch_lookup[256];
-
-	nm_assert (str);
-
-	_char_lookup_table_init (ch_lookup, NM_ASCII_WHITESPACES);
-
-	for (;;) {
-		char quote;
-		gsize j;
-
-		while (_char_lookup_has (ch_lookup, str[0]))
-			str++;
-
-		if (str[0] == '\0')
-			break;
-
-		if (!str_out)
-			str_out = g_new (char, strlen (str) + 1);
-
-		quote = '\0';
-		j = 0;
-		for (;;) {
-			if (str[0] == '\\') {
-				str++;
-				if (str[0] == '\0')
-					break;
-				str_out[j++] = str[0];
-				str++;
-				continue;
-			}
-			if (quote) {
-				if (str[0] == '\0')
-					break;
-				if (str[0] == quote) {
-					quote = '\0';
-					str++;
-					continue;
-				}
-				str_out[j++] = str[0];
-				str++;
-				continue;
-			}
-			if (str[0] == '\0')
-				break;
-			if (NM_IN_SET (str[0], '\'', '"')) {
-				quote = str[0];
-				str++;
-				continue;
-			}
-			if (_char_lookup_has (ch_lookup, str[0])) {
-				str++;
-				break;
-			}
-			str_out[j++] = str[0];
-			str++;
-		}
-
-		if (!arr)
-			arr = g_ptr_array_new ();
-		g_ptr_array_add (arr, g_strndup (str_out, j));
-	}
-
-	if (!arr)
-		return g_new0 (char *, 1);
-
-	g_ptr_array_add (arr, NULL);
-
-	/* We want to return an optimally sized strv array, with no excess
-	 * memory allocated. Hence, clone once more. */
-	return nm_memdup (arr->pdata, sizeof (char *) * arr->len);
+nm_utils_strsplit_quoted(const char *str)
+{
+    gs_unref_ptrarray GPtrArray *arr     = NULL;
+    gs_free char *               str_out = NULL;
+    CharLookupTable              ch_lookup;
+
+    nm_assert(str);
+
+    _char_lookup_table_init(&ch_lookup, NM_ASCII_WHITESPACES);
+
+    for (;;) {
+        char  quote;
+        gsize j;
+
+        while (_char_lookup_has(&ch_lookup, str[0]))
+            str++;
+
+        if (str[0] == '\0')
+            break;
+
+        if (!str_out)
+            str_out = g_new(char, strlen(str) + 1);
+
+        quote = '\0';
+        j     = 0;
+        for (;;) {
+            if (str[0] == '\\') {
+                str++;
+                if (str[0] == '\0')
+                    break;
+                str_out[j++] = str[0];
+                str++;
+                continue;
+            }
+            if (quote) {
+                if (str[0] == '\0')
+                    break;
+                if (str[0] == quote) {
+                    quote = '\0';
+                    str++;
+                    continue;
+                }
+                str_out[j++] = str[0];
+                str++;
+                continue;
+            }
+            if (str[0] == '\0')
+                break;
+            if (NM_IN_SET(str[0], '\'', '"')) {
+                quote = str[0];
+                str++;
+                continue;
+            }
+            if (_char_lookup_has(&ch_lookup, str[0])) {
+                str++;
+                break;
+            }
+            str_out[j++] = str[0];
+            str++;
+        }
+
+        if (!arr)
+            arr = g_ptr_array_new();
+        g_ptr_array_add(arr, g_strndup(str_out, j));
+    }
+
+    if (!arr)
+        return g_new0(char *, 1);
+
+    g_ptr_array_add(arr, NULL);
+
+    /* We want to return an optimally sized strv array, with no excess
+     * memory allocated. Hence, clone once more. */
+    return nm_memdup(arr->pdata, sizeof(char *) * arr->len);
 }
 
 /*****************************************************************************/
@@ -2170,140 +2121,154 @@ nm_utils_strsplit_quoted (const char *str)
  * Returns: index of first occurrence or -1 if @needle is not found in @list.
  */
 gssize
-nm_utils_strv_find_first (char **list, gssize len, const char *needle)
-{
-	gssize i;
-
-	if (len > 0) {
-		g_return_val_if_fail (list, -1);
-
-		if (!needle) {
-			/* if we search a list with known length, %NULL is a valid @needle. */
-			for (i = 0; i < len; i++) {
-				if (!list[i])
-					return i;
-			}
-		} else {
-			for (i = 0; i < len; i++) {
-				if (list[i] && !strcmp (needle, list[i]))
-					return i;
-			}
-		}
-	} else if (len < 0) {
-		g_return_val_if_fail (needle, -1);
-
-		if (list) {
-			for (i = 0; list[i]; i++) {
-				if (strcmp (needle, list[i]) == 0)
-					return i;
-			}
-		}
-	}
-	return -1;
+nm_utils_strv_find_first(char **list, gssize len, const char *needle)
+{
+    gssize i;
+
+    if (len > 0) {
+        g_return_val_if_fail(list, -1);
+
+        if (!needle) {
+            /* if we search a list with known length, %NULL is a valid @needle. */
+            for (i = 0; i < len; i++) {
+                if (!list[i])
+                    return i;
+            }
+        } else {
+            for (i = 0; i < len; i++) {
+                if (list[i] && !strcmp(needle, list[i]))
+                    return i;
+            }
+        }
+    } else if (len < 0) {
+        g_return_val_if_fail(needle, -1);
+
+        if (list) {
+            for (i = 0; list[i]; i++) {
+                if (strcmp(needle, list[i]) == 0)
+                    return i;
+            }
+        }
+    }
+    return -1;
 }
 
 char **
-_nm_utils_strv_cleanup (char **strv,
-                        gboolean strip_whitespace,
-                        gboolean skip_empty,
-                        gboolean skip_repeated)
-{
-	guint i, j;
-
-	if (!strv || !*strv)
-		return strv;
-
-	if (strip_whitespace) {
-		/* we only modify the strings pointed to by @strv if @strip_whitespace is
-		 * requested. Otherwise, the strings themselves are untouched. */
-		for (i = 0; strv[i]; i++)
-			g_strstrip (strv[i]);
-	}
-	if (!skip_empty && !skip_repeated)
-		return strv;
-	j = 0;
-	for (i = 0; strv[i]; i++) {
-		if (   (skip_empty && !*strv[i])
-		    || (skip_repeated && nm_utils_strv_find_first (strv, j, strv[i]) >= 0))
-			g_free (strv[i]);
-		else
-			strv[j++] = strv[i];
-	}
-	strv[j] = NULL;
-	return strv;
+_nm_utils_strv_cleanup(char **  strv,
+                       gboolean strip_whitespace,
+                       gboolean skip_empty,
+                       gboolean skip_repeated)
+{
+    guint i, j;
+
+    if (!strv || !*strv)
+        return strv;
+
+    if (strip_whitespace) {
+        /* we only modify the strings pointed to by @strv if @strip_whitespace is
+         * requested. Otherwise, the strings themselves are untouched. */
+        for (i = 0; strv[i]; i++)
+            g_strstrip(strv[i]);
+    }
+    if (!skip_empty && !skip_repeated)
+        return strv;
+    j = 0;
+    for (i = 0; strv[i]; i++) {
+        if ((skip_empty && !*strv[i])
+            || (skip_repeated && nm_utils_strv_find_first(strv, j, strv[i]) >= 0))
+            g_free(strv[i]);
+        else
+            strv[j++] = strv[i];
+    }
+    strv[j] = NULL;
+    return strv;
+}
+
+/*****************************************************************************/
+
+GPtrArray *
+_nm_g_ptr_array_copy(GPtrArray *    array,
+                     GCopyFunc      func,
+                     gpointer       user_data,
+                     GDestroyNotify element_free_func)
+{
+    GPtrArray *new_array;
+    guint      i;
+
+    g_return_val_if_fail(array, NULL);
+
+    new_array = g_ptr_array_new_full(array->len, element_free_func);
+    for (i = 0; i < array->len; i++) {
+        g_ptr_array_add(new_array, func ? func(array->pdata[i], user_data) : array->pdata[i]);
+    }
+    return new_array;
 }
 
 /*****************************************************************************/
 
 int
-_nm_utils_ascii_str_to_bool (const char *str,
-                             int default_value)
+_nm_utils_ascii_str_to_bool(const char *str, int default_value)
 {
-	gs_free char *str_free = NULL;
+    gs_free char *str_free = NULL;
 
-	if (!str)
-		return default_value;
+    if (!str)
+        return default_value;
 
-	str = nm_strstrip_avoid_copy_a (300, str, &str_free);
-	if (str[0] == '\0')
-		return default_value;
+    str = nm_strstrip_avoid_copy_a(300, str, &str_free);
+    if (str[0] == '\0')
+        return default_value;
 
-	if (   !g_ascii_strcasecmp (str, "true")
-	    || !g_ascii_strcasecmp (str, "yes")
-	    || !g_ascii_strcasecmp (str, "on")
-	    || !g_ascii_strcasecmp (str, "1"))
-		return TRUE;
+    if (!g_ascii_strcasecmp(str, "true") || !g_ascii_strcasecmp(str, "yes")
+        || !g_ascii_strcasecmp(str, "on") || !g_ascii_strcasecmp(str, "1"))
+        return TRUE;
 
-	if (   !g_ascii_strcasecmp (str, "false")
-	    || !g_ascii_strcasecmp (str, "no")
-	    || !g_ascii_strcasecmp (str, "off")
-	    || !g_ascii_strcasecmp (str, "0"))
-		return FALSE;
+    if (!g_ascii_strcasecmp(str, "false") || !g_ascii_strcasecmp(str, "no")
+        || !g_ascii_strcasecmp(str, "off") || !g_ascii_strcasecmp(str, "0"))
+        return FALSE;
 
-	return default_value;
+    return default_value;
 }
 
 /*****************************************************************************/
 
-NM_CACHED_QUARK_FCN ("nm-utils-error-quark", nm_utils_error_quark)
+NM_CACHED_QUARK_FCN("nm-utils-error-quark", nm_utils_error_quark);
 
 void
-nm_utils_error_set_cancelled (GError **error,
-                              gboolean is_disposing,
-                              const char *instance_name)
+nm_utils_error_set_cancelled(GError **error, gboolean is_disposing, const char *instance_name)
 {
-	if (is_disposing) {
-		g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING,
-		             "Disposing %s instance",
-		             instance_name && *instance_name ? instance_name : "source");
-	} else {
-		g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
-		                     "Request cancelled");
-	}
+    if (is_disposing) {
+        g_set_error(error,
+                    NM_UTILS_ERROR,
+                    NM_UTILS_ERROR_CANCELLED_DISPOSING,
+                    "Disposing %s instance",
+                    instance_name && *instance_name ? instance_name : "source");
+    } else {
+        g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Request cancelled");
+    }
 }
 
 gboolean
-nm_utils_error_is_cancelled_or_disposing (GError *error)
+nm_utils_error_is_cancelled_or_disposing(GError *error)
 {
-	if (error) {
-		if (error->domain == G_IO_ERROR)
-			return NM_IN_SET (error->code, G_IO_ERROR_CANCELLED);
-		if (error->domain == NM_UTILS_ERROR)
-			return NM_IN_SET (error->code, NM_UTILS_ERROR_CANCELLED_DISPOSING);
-	}
-	return FALSE;
+    if (error) {
+        if (error->domain == G_IO_ERROR)
+            return NM_IN_SET(error->code, G_IO_ERROR_CANCELLED);
+        if (error->domain == NM_UTILS_ERROR)
+            return NM_IN_SET(error->code, NM_UTILS_ERROR_CANCELLED_DISPOSING);
+    }
+    return FALSE;
 }
 
 gboolean
-nm_utils_error_is_notfound (GError *error)
+nm_utils_error_is_notfound(GError *error)
 {
-	if (error) {
-		if (error->domain == G_IO_ERROR)
-			return NM_IN_SET (error->code, G_IO_ERROR_NOT_FOUND);
-		if (error->domain == G_FILE_ERROR)
-			return NM_IN_SET (error->code, G_FILE_ERROR_NOENT);
-	}
-	return FALSE;
+    if (error) {
+        if (error->domain == G_IO_ERROR)
+            return NM_IN_SET(error->code, G_IO_ERROR_NOT_FOUND);
+        if (error->domain == G_FILE_ERROR)
+            return NM_IN_SET(error->code, G_FILE_ERROR_NOENT);
+    }
+    return FALSE;
 }
 
 /*****************************************************************************/
@@ -2324,220 +2289,233 @@ nm_utils_error_is_notfound (GError *error)
  * Returns: whether the value was successfully set.
  */
 gboolean
-nm_g_object_set_property (GObject *object,
-                          const char *property_name,
-                          const GValue *value,
-                          GError **error)
-{
-	GParamSpec *pspec;
-	nm_auto_unset_gvalue GValue tmp_value = G_VALUE_INIT;
-	GObjectClass *klass;
-
-	g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
-	g_return_val_if_fail (property_name != NULL, FALSE);
-	g_return_val_if_fail (G_IS_VALUE (value), FALSE);
-	g_return_val_if_fail (!error || !*error, FALSE);
-
-	/* g_object_class_find_property() does g_param_spec_get_redirect_target(),
-	 * where we differ from a plain g_object_set_property(). */
-	pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), property_name);
-
-	if (!pspec) {
-		g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-		             _("object class '%s' has no property named '%s'"),
-		             G_OBJECT_TYPE_NAME (object),
-		             property_name);
-		return FALSE;
-	}
-	if (!(pspec->flags & G_PARAM_WRITABLE)) {
-		g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-		             _("property '%s' of object class '%s' is not writable"),
-		             pspec->name,
-		             G_OBJECT_TYPE_NAME (object));
-		return FALSE;
-	}
-	if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY)) {
-		g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-		             _("construct property \"%s\" for object '%s' can't be set after construction"),
-		             pspec->name, G_OBJECT_TYPE_NAME (object));
-		return FALSE;
-	}
-
-	klass = g_type_class_peek (pspec->owner_type);
-	if (klass == NULL) {
-		g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-		             _("'%s::%s' is not a valid property name; '%s' is not a GObject subtype"),
-		            g_type_name (pspec->owner_type), pspec->name, g_type_name (pspec->owner_type));
-		return FALSE;
-	}
-
-	/* provide a copy to work from, convert (if necessary) and validate */
-	g_value_init (&tmp_value, pspec->value_type);
-	if (!g_value_transform (value, &tmp_value)) {
-		g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-		             _("unable to set property '%s' of type '%s' from value of type '%s'"),
-		             pspec->name,
-		             g_type_name (pspec->value_type),
-		             G_VALUE_TYPE_NAME (value));
-		return FALSE;
-	}
-	if (   g_param_value_validate (pspec, &tmp_value)
-	    && !(pspec->flags & G_PARAM_LAX_VALIDATION)) {
-		gs_free char *contents = g_strdup_value_contents (value);
-
-		g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-		             _("value \"%s\" of type '%s' is invalid or out of range for property '%s' of type '%s'"),
-		             contents,
-		             G_VALUE_TYPE_NAME (value),
-		             pspec->name,
-		             g_type_name (pspec->value_type));
-		return FALSE;
-	}
-
-	g_object_set_property (object, property_name, &tmp_value);
-	return TRUE;
-}
-
-#define _set_property(object, property_name, gtype, gtype_set, value, error) \
-	G_STMT_START { \
-		nm_auto_unset_gvalue GValue gvalue = { 0 }; \
-		\
-		g_value_init (&gvalue, gtype); \
-		gtype_set (&gvalue, (value)); \
-		return nm_g_object_set_property ((object), (property_name), &gvalue, (error)); \
-	} G_STMT_END
+nm_g_object_set_property(GObject *     object,
+                         const char *  property_name,
+                         const GValue *value,
+                         GError **     error)
+{
+    GParamSpec *                pspec;
+    nm_auto_unset_gvalue GValue tmp_value = G_VALUE_INIT;
+    GObjectClass *              klass;
+
+    g_return_val_if_fail(G_IS_OBJECT(object), FALSE);
+    g_return_val_if_fail(property_name != NULL, FALSE);
+    g_return_val_if_fail(G_IS_VALUE(value), FALSE);
+    g_return_val_if_fail(!error || !*error, FALSE);
+
+    /* g_object_class_find_property() does g_param_spec_get_redirect_target(),
+     * where we differ from a plain g_object_set_property(). */
+    pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(object), property_name);
+
+    if (!pspec) {
+        g_set_error(error,
+                    NM_UTILS_ERROR,
+                    NM_UTILS_ERROR_UNKNOWN,
+                    _("object class '%s' has no property named '%s'"),
+                    G_OBJECT_TYPE_NAME(object),
+                    property_name);
+        return FALSE;
+    }
+    if (!(pspec->flags & G_PARAM_WRITABLE)) {
+        g_set_error(error,
+                    NM_UTILS_ERROR,
+                    NM_UTILS_ERROR_UNKNOWN,
+                    _("property '%s' of object class '%s' is not writable"),
+                    pspec->name,
+                    G_OBJECT_TYPE_NAME(object));
+        return FALSE;
+    }
+    if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY)) {
+        g_set_error(error,
+                    NM_UTILS_ERROR,
+                    NM_UTILS_ERROR_UNKNOWN,
+                    _("construct property \"%s\" for object '%s' can't be set after construction"),
+                    pspec->name,
+                    G_OBJECT_TYPE_NAME(object));
+        return FALSE;
+    }
+
+    klass = g_type_class_peek(pspec->owner_type);
+    if (klass == NULL) {
+        g_set_error(error,
+                    NM_UTILS_ERROR,
+                    NM_UTILS_ERROR_UNKNOWN,
+                    _("'%s::%s' is not a valid property name; '%s' is not a GObject subtype"),
+                    g_type_name(pspec->owner_type),
+                    pspec->name,
+                    g_type_name(pspec->owner_type));
+        return FALSE;
+    }
+
+    /* provide a copy to work from, convert (if necessary) and validate */
+    g_value_init(&tmp_value, pspec->value_type);
+    if (!g_value_transform(value, &tmp_value)) {
+        g_set_error(error,
+                    NM_UTILS_ERROR,
+                    NM_UTILS_ERROR_UNKNOWN,
+                    _("unable to set property '%s' of type '%s' from value of type '%s'"),
+                    pspec->name,
+                    g_type_name(pspec->value_type),
+                    G_VALUE_TYPE_NAME(value));
+        return FALSE;
+    }
+    if (g_param_value_validate(pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION)) {
+        gs_free char *contents = g_strdup_value_contents(value);
+
+        g_set_error(error,
+                    NM_UTILS_ERROR,
+                    NM_UTILS_ERROR_UNKNOWN,
+                    _("value \"%s\" of type '%s' is invalid or out of range for property '%s' of "
+                      "type '%s'"),
+                    contents,
+                    G_VALUE_TYPE_NAME(value),
+                    pspec->name,
+                    g_type_name(pspec->value_type));
+        return FALSE;
+    }
+
+    g_object_set_property(object, property_name, &tmp_value);
+    return TRUE;
+}
+
+#define _set_property(object, property_name, gtype, gtype_set, value, error)          \
+    G_STMT_START                                                                      \
+    {                                                                                 \
+        nm_auto_unset_gvalue GValue gvalue = {0};                                     \
+                                                                                      \
+        g_value_init(&gvalue, gtype);                                                 \
+        gtype_set(&gvalue, (value));                                                  \
+        return nm_g_object_set_property((object), (property_name), &gvalue, (error)); \
+    }                                                                                 \
+    G_STMT_END
 
 gboolean
-nm_g_object_set_property_string (GObject *object,
-                                 const char *property_name,
-                                 const char *value,
-                                 GError **error)
+nm_g_object_set_property_string(GObject *   object,
+                                const char *property_name,
+                                const char *value,
+                                GError **   error)
 {
-	_set_property (object, property_name, G_TYPE_STRING, g_value_set_string, value, error);
+    _set_property(object, property_name, G_TYPE_STRING, g_value_set_string, value, error);
 }
 
 gboolean
-nm_g_object_set_property_string_static (GObject *object,
-                                        const char *property_name,
-                                        const char *value,
-                                        GError **error)
+nm_g_object_set_property_string_static(GObject *   object,
+                                       const char *property_name,
+                                       const char *value,
+                                       GError **   error)
 {
-	_set_property (object, property_name, G_TYPE_STRING, g_value_set_static_string, value, error);
+    _set_property(object, property_name, G_TYPE_STRING, g_value_set_static_string, value, error);
 }
 
 gboolean
-nm_g_object_set_property_string_take (GObject *object,
-                                      const char *property_name,
-                                      char *value,
-                                      GError **error)
+nm_g_object_set_property_string_take(GObject *   object,
+                                     const char *property_name,
+                                     char *      value,
+                                     GError **   error)
 {
-	_set_property (object, property_name, G_TYPE_STRING, g_value_take_string, value, error);
+    _set_property(object, property_name, G_TYPE_STRING, g_value_take_string, value, error);
 }
 
 gboolean
-nm_g_object_set_property_boolean (GObject *object,
-                                  const char *property_name,
-                                  gboolean value,
-                                  GError **error)
+nm_g_object_set_property_boolean(GObject *   object,
+                                 const char *property_name,
+                                 gboolean    value,
+                                 GError **   error)
 {
-	_set_property (object, property_name, G_TYPE_BOOLEAN, g_value_set_boolean, !!value, error);
+    _set_property(object, property_name, G_TYPE_BOOLEAN, g_value_set_boolean, !!value, error);
 }
 
 gboolean
-nm_g_object_set_property_char (GObject *object,
-                               const char *property_name,
-                               gint8 value,
-                               GError **error)
+nm_g_object_set_property_char(GObject *   object,
+                              const char *property_name,
+                              gint8       value,
+                              GError **   error)
 {
-	/* glib says about G_TYPE_CHAR:
-	 *
-	 * The type designated by G_TYPE_CHAR is unconditionally an 8-bit signed integer.
-	 *
-	 * This is always a (signed!) char. */
-	_set_property (object, property_name, G_TYPE_CHAR, g_value_set_schar, value, error);
+    /* glib says about G_TYPE_CHAR:
+     *
+     * The type designated by G_TYPE_CHAR is unconditionally an 8-bit signed integer.
+     *
+     * This is always a (signed!) char. */
+    _set_property(object, property_name, G_TYPE_CHAR, g_value_set_schar, value, error);
 }
 
 gboolean
-nm_g_object_set_property_uchar (GObject *object,
-                                const char *property_name,
-                                guint8 value,
-                                GError **error)
+nm_g_object_set_property_uchar(GObject *   object,
+                               const char *property_name,
+                               guint8      value,
+                               GError **   error)
 {
-	_set_property (object, property_name, G_TYPE_UCHAR, g_value_set_uchar, value, error);
+    _set_property(object, property_name, G_TYPE_UCHAR, g_value_set_uchar, value, error);
 }
 
 gboolean
-nm_g_object_set_property_int (GObject *object,
-                              const char *property_name,
-                              int value,
-                              GError **error)
+nm_g_object_set_property_int(GObject *object, const char *property_name, int value, GError **error)
 {
-	_set_property (object, property_name, G_TYPE_INT, g_value_set_int, value, error);
+    _set_property(object, property_name, G_TYPE_INT, g_value_set_int, value, error);
 }
 
 gboolean
-nm_g_object_set_property_int64 (GObject *object,
-                                const char *property_name,
-                                gint64 value,
-                                GError **error)
+nm_g_object_set_property_int64(GObject *   object,
+                               const char *property_name,
+                               gint64      value,
+                               GError **   error)
 {
-	_set_property (object, property_name, G_TYPE_INT64, g_value_set_int64, value, error);
+    _set_property(object, property_name, G_TYPE_INT64, g_value_set_int64, value, error);
 }
 
 gboolean
-nm_g_object_set_property_uint (GObject *object,
-                               const char *property_name,
-                               guint value,
-                               GError **error)
+nm_g_object_set_property_uint(GObject *   object,
+                              const char *property_name,
+                              guint       value,
+                              GError **   error)
 {
-	_set_property (object, property_name, G_TYPE_UINT, g_value_set_uint, value, error);
+    _set_property(object, property_name, G_TYPE_UINT, g_value_set_uint, value, error);
 }
 
 gboolean
-nm_g_object_set_property_uint64 (GObject *object,
-                                 const char *property_name,
-                                 guint64 value,
-                                 GError **error)
+nm_g_object_set_property_uint64(GObject *   object,
+                                const char *property_name,
+                                guint64     value,
+                                GError **   error)
 {
-	_set_property (object, property_name, G_TYPE_UINT64, g_value_set_uint64, value, error);
+    _set_property(object, property_name, G_TYPE_UINT64, g_value_set_uint64, value, error);
 }
 
 gboolean
-nm_g_object_set_property_flags (GObject *object,
-                                const char *property_name,
-                                GType gtype,
-                                guint value,
-                                GError **error)
+nm_g_object_set_property_flags(GObject *   object,
+                               const char *property_name,
+                               GType       gtype,
+                               guint       value,
+                               GError **   error)
 {
-	nm_assert (({
-	                nm_auto_unref_gtypeclass GTypeClass *gtypeclass = g_type_class_ref (gtype);
-	                G_IS_FLAGS_CLASS (gtypeclass);
-	           }));
-	_set_property (object, property_name, gtype, g_value_set_flags, value, error);
+    nm_assert(({
+        nm_auto_unref_gtypeclass GTypeClass *gtypeclass = g_type_class_ref(gtype);
+        G_IS_FLAGS_CLASS(gtypeclass);
+    }));
+    _set_property(object, property_name, gtype, g_value_set_flags, value, error);
 }
 
 gboolean
-nm_g_object_set_property_enum (GObject *object,
-                               const char *property_name,
-                               GType gtype,
-                               int value,
-                               GError **error)
+nm_g_object_set_property_enum(GObject *   object,
+                              const char *property_name,
+                              GType       gtype,
+                              int         value,
+                              GError **   error)
 {
-	nm_assert (({
-	                nm_auto_unref_gtypeclass GTypeClass *gtypeclass = g_type_class_ref (gtype);
-	                G_IS_ENUM_CLASS (gtypeclass);
-	           }));
-	_set_property (object, property_name, gtype, g_value_set_enum, value, error);
+    nm_assert(({
+        nm_auto_unref_gtypeclass GTypeClass *gtypeclass = g_type_class_ref(gtype);
+        G_IS_ENUM_CLASS(gtypeclass);
+    }));
+    _set_property(object, property_name, gtype, g_value_set_enum, value, error);
 }
 
 GParamSpec *
-nm_g_object_class_find_property_from_gtype (GType gtype,
-                                            const char *property_name)
+nm_g_object_class_find_property_from_gtype(GType gtype, const char *property_name)
 {
-	nm_auto_unref_gtypeclass GObjectClass *gclass = NULL;
+    nm_auto_unref_gtypeclass GObjectClass *gclass = NULL;
 
-	gclass = g_type_class_ref (gtype);
-	return g_object_class_find_property (gclass, property_name);
+    gclass = g_type_class_ref(gtype);
+    return g_object_class_find_property(gclass, property_name);
 }
 
 /*****************************************************************************/
@@ -2557,163 +2535,208 @@ nm_g_object_class_find_property_from_gtype (GType gtype,
  *   that added @pname.
  */
 GType
-nm_g_type_find_implementing_class_for_property (GType gtype,
-                                                const char *pname)
+nm_g_type_find_implementing_class_for_property(GType gtype, const char *pname)
 {
-	nm_auto_unref_gtypeclass GObjectClass *klass = NULL;
-	GParamSpec *pspec;
+    nm_auto_unref_gtypeclass GObjectClass *klass = NULL;
+    GParamSpec *                           pspec;
 
-	g_return_val_if_fail (pname, G_TYPE_INVALID);
+    g_return_val_if_fail(pname, G_TYPE_INVALID);
 
-	klass = g_type_class_ref (gtype);
-	g_return_val_if_fail (G_IS_OBJECT_CLASS (klass), G_TYPE_INVALID);
+    klass = g_type_class_ref(gtype);
+    g_return_val_if_fail(G_IS_OBJECT_CLASS(klass), G_TYPE_INVALID);
 
-	pspec = g_object_class_find_property (klass, pname);
-	g_return_val_if_fail (pspec, G_TYPE_INVALID);
+    pspec = g_object_class_find_property(klass, pname);
+    g_return_val_if_fail(pspec, G_TYPE_INVALID);
 
-	gtype = G_TYPE_FROM_CLASS (klass);
+    gtype = G_TYPE_FROM_CLASS(klass);
 
-	while (TRUE) {
-		nm_auto_unref_gtypeclass GObjectClass *k = NULL;
+    while (TRUE) {
+        nm_auto_unref_gtypeclass GObjectClass *k = NULL;
 
-		k = g_type_class_ref (g_type_parent (gtype));
+        k = g_type_class_ref(g_type_parent(gtype));
 
-		g_return_val_if_fail (G_IS_OBJECT_CLASS (k), G_TYPE_INVALID);
+        g_return_val_if_fail(G_IS_OBJECT_CLASS(k), G_TYPE_INVALID);
 
-		if (g_object_class_find_property (k, pname) != pspec)
-			return gtype;
+        if (g_object_class_find_property(k, pname) != pspec)
+            return gtype;
 
-		gtype = G_TYPE_FROM_CLASS (k);
-	}
+        gtype = G_TYPE_FROM_CLASS(k);
+    }
 }
 
 /*****************************************************************************/
 
 static void
-_str_buf_append_c_escape_octal (NMStrBuf *strbuf,
-                                char ch)
+_str_buf_append_c_escape_octal(NMStrBuf *strbuf, char ch)
 {
-	nm_str_buf_append_c4 (strbuf,
-	                      '\\',
-	                      '0' + ((char) ((((guchar) ch) >> 6) & 07)),
-	                      '0' + ((char) ((((guchar) ch) >> 3) & 07)),
-	                      '0' + ((char) ((((guchar) ch)     ) & 07)));
+    nm_str_buf_append_c4(strbuf,
+                         '\\',
+                         '0' + ((char) ((((guchar) ch) >> 6) & 07)),
+                         '0' + ((char) ((((guchar) ch) >> 3) & 07)),
+                         '0' + ((char) ((((guchar) ch)) & 07)));
 }
 
+/**
+ * nm_utils_buf_utf8safe_unescape:
+ * @str: (allow-none): the string to unescape. The string itself is a NUL terminated
+ *   ASCII string, that can have C-style backslash escape sequences (which
+ *   are to be unescaped). Non-ASCII characters (e.g. UTF-8) are taken verbatim, so
+ *   it doesn't care that this string is UTF-8. However, usually this is a UTF-8 encoded
+ *   string.
+ * @flags: flags for unescaping. The following flags are supported.
+ *   %NM_UTILS_STR_UTF8_SAFE_UNESCAPE_STRIP_SPACES performs a g_strstrip() on the input string,
+ *   but preserving escaped spaces. For example, "a\\t " gives "a\t" (that is, the escaped space does
+ *   not get stripped). Likewise, the invalid escape sequence "a\\  " results in "a " (stripping
+ *   the unescaped space, but preserving the escaped one).
+ * @out_len: (out): the length of the parsed string.
+ * @to_free: (out): if @str requires unescaping, the function will clone the string. In
+ *   that case, the allocated buffer will be returned here.
+ *
+ * See C-style escapes at https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences.
+ * Note that hex escapes ("\\xhh") and unicode escapes ("\\uhhhh", "\\Uhhhhhhhh") are not supported.
+ *
+ * Also, this function is very similar to g_strcompress() but without issuing g_warning()
+ * assertions and proper handling of "\\000" escape sequences.
+ *
+ * Invalid escape sequences (or non-UTF-8 input) are gracefully accepted. For example "\\ "
+ * is an invalid escape sequence, in this case the backslash is removed and " " gets returned.
+ *
+ * The function never leaks secrets in memory.
+ *
+ * Returns: the unescaped buffer of length @out_len. If @str is %NULL, this returns %NULL
+ *   and sets @out_len to 0. Otherwise, a non-%NULL binary buffer is returned with
+ *   @out_len bytes. Note that the binary buffer is guaranteed to be NUL terminated. That
+ *   is @result[@out_len] is NUL.
+ *   Note that the result is binary, and may have embedded NUL characters and non-UTF-8.
+ *   If the function can avoid cloning the input string, it will return a pointer inside
+ *   the input @str. For example, if there is no backslash, no cloning is necessary. In that
+ *   case, @to_free will be %NULL. Otherwise, @to_free is set to a newly allocated buffer
+ *   containing the unescaped string and returned.
+ */
 gconstpointer
-nm_utils_buf_utf8safe_unescape (const char *str, NMUtilsStrUtf8SafeFlags flags, gsize *out_len, gpointer *to_free)
-{
-	gboolean strip_spaces = NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_UNESCAPE_STRIP_SPACES);
-	NMStrBuf strbuf;
-	const char *s;
-	gsize len;
-
-	g_return_val_if_fail (to_free, NULL);
-	g_return_val_if_fail (out_len, NULL);
-
-	if (!str) {
-		*out_len = 0;
-		*to_free = NULL;
-		return NULL;
-	}
-
-	if (strip_spaces)
-		str = nm_str_skip_leading_spaces (str);
-
-	len = strlen (str);
-
-	s = memchr (str, '\\', len);
-	if (!s) {
-		if (   strip_spaces
-		    && len > 0
-		    && g_ascii_isspace (str[len - 1])) {
-			len--;
-			while (   len > 0
-			       && g_ascii_isspace (str[len - 1]))
-				len--;
-			*out_len = len;
-			return (*to_free = g_strndup (str, len));
-		}
-		*out_len = len;
-		*to_free = NULL;
-		return str;
-	}
-
-	nm_str_buf_init (&strbuf, len + 1u, FALSE);
-
-	nm_str_buf_append_len (&strbuf, str, s - str);
-	str = s;
-
-	for (;;) {
-		char ch;
-		guint v;
-
-		nm_assert (str[0] == '\\');
-
-		ch = (++str)[0];
-
-		if (ch == '\0') {
-			/* error. Trailing '\\' */
-			break;
-		}
-
-		if (ch >= '0' && ch <= '9') {
-			v = ch - '0';
-			ch = (++str)[0];
-			if (ch >= '0' && ch <= '7') {
-				v = v * 8 + (ch - '0');
-				ch = (++str)[0];
-				if (ch >= '0' && ch <= '7') {
-					/* technically, escape sequences larger than \3FF are out of range
-					 * and invalid. We don't check for that, and do the same as
-					 * g_strcompress(): silently clip the value with & 0xFF. */
-					v = v * 8 + (ch - '0');
-					++str;
-				}
-			}
-			ch = v;
-		} else {
-			switch (ch) {
-			case 'b': ch = '\b'; break;
-			case 'f': ch = '\f'; break;
-			case 'n': ch = '\n'; break;
-			case 'r': ch = '\r'; break;
-			case 't': ch = '\t'; break;
-			case 'v': ch = '\v'; break;
-			default:
-				/* Here we handle "\\\\", but all other unexpected escape sequences are really a bug.
-				 * Take them literally, after removing the escape character */
-				break;
-			}
-			str++;
-		}
-
-		nm_str_buf_append_c (&strbuf, ch);
-
-		s = strchr (str, '\\');
-		if (!s) {
-			gsize l = strlen (str);
-
-			if (strip_spaces) {
-				while (   l > 0
-				       && g_ascii_isspace (str[l - 1]))
-					l--;
-			}
-			nm_str_buf_append_len (&strbuf, str, l);
-			break;
-		}
-
-		nm_str_buf_append_len (&strbuf, str, s - str);
-		str = s;
-	}
-
-	/* assert that no reallocation was necessary. For one, unescaping should
-	 * never result in a longer string than the input. Also, when unescaping
-	 * secrets, we want to ensure that we don't leak secrets in memory. */
-	nm_assert (strbuf.allocated == len + 1u);
-
-	return (*to_free = nm_str_buf_finalize (&strbuf,
-	                                        out_len));
+nm_utils_buf_utf8safe_unescape(const char *            str,
+                               NMUtilsStrUtf8SafeFlags flags,
+                               gsize *                 out_len,
+                               gpointer *              to_free)
+{
+    gboolean    strip_spaces = NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_UNESCAPE_STRIP_SPACES);
+    NMStrBuf    strbuf;
+    const char *s;
+    gsize       len;
+
+    g_return_val_if_fail(to_free, NULL);
+    g_return_val_if_fail(out_len, NULL);
+
+    if (!str) {
+        *out_len = 0;
+        *to_free = NULL;
+        return NULL;
+    }
+
+    if (strip_spaces)
+        str = nm_str_skip_leading_spaces(str);
+
+    len = strlen(str);
+
+    s = memchr(str, '\\', len);
+    if (!s) {
+        if (strip_spaces && len > 0 && g_ascii_isspace(str[len - 1])) {
+            len--;
+            while (len > 0 && g_ascii_isspace(str[len - 1]))
+                len--;
+            *out_len = len;
+            return (*to_free = g_strndup(str, len));
+        }
+        *out_len = len;
+        *to_free = NULL;
+        return str;
+    }
+
+    nm_str_buf_init(&strbuf, len + 1u, FALSE);
+
+    nm_str_buf_append_len(&strbuf, str, s - str);
+    str = s;
+
+    for (;;) {
+        char  ch;
+        guint v;
+
+        nm_assert(str[0] == '\\');
+
+        ch = (++str)[0];
+
+        if (ch == '\0') {
+            /* error. Trailing '\\' */
+            break;
+        }
+
+        if (ch >= '0' && ch <= '9') {
+            v  = ch - '0';
+            ch = (++str)[0];
+            if (ch >= '0' && ch <= '7') {
+                v  = v * 8 + (ch - '0');
+                ch = (++str)[0];
+                if (ch >= '0' && ch <= '7') {
+                    /* technically, escape sequences larger than \3FF are out of range
+                     * and invalid. We don't check for that, and do the same as
+                     * g_strcompress(): silently clip the value with & 0xFF. */
+                    v = v * 8 + (ch - '0');
+                    ++str;
+                }
+            }
+            ch = v;
+        } else {
+            switch (ch) {
+            case 'b':
+                ch = '\b';
+                break;
+            case 'f':
+                ch = '\f';
+                break;
+            case 'n':
+                ch = '\n';
+                break;
+            case 'r':
+                ch = '\r';
+                break;
+            case 't':
+                ch = '\t';
+                break;
+            case 'v':
+                ch = '\v';
+                break;
+            default:
+                /* Here we handle "\\\\", but all other unexpected escape sequences are really a bug.
+                 * Take them literally, after removing the escape character */
+                break;
+            }
+            str++;
+        }
+
+        nm_str_buf_append_c(&strbuf, ch);
+
+        s = strchr(str, '\\');
+        if (!s) {
+            gsize l = strlen(str);
+
+            if (strip_spaces) {
+                while (l > 0 && g_ascii_isspace(str[l - 1]))
+                    l--;
+            }
+            nm_str_buf_append_len(&strbuf, str, l);
+            break;
+        }
+
+        nm_str_buf_append_len(&strbuf, str, s - str);
+        str = s;
+    }
+
+    /* assert that no reallocation was necessary. For one, unescaping should
+     * never result in a longer string than the input. Also, when unescaping
+     * secrets, we want to ensure that we don't leak secrets in memory. */
+    nm_assert(strbuf.allocated == len + 1u);
+
+    return (*to_free = nm_str_buf_finalize(&strbuf, out_len));
 }
 
 /**
@@ -2748,126 +2771,125 @@ nm_utils_buf_utf8safe_unescape (const char *str, NMUtilsStrUtf8SafeFlags flags,
  *   with g_free. The escaping can be reverted by g_strcompress().
  **/
 const char *
-nm_utils_buf_utf8safe_escape (gconstpointer buf, gssize buflen, NMUtilsStrUtf8SafeFlags flags, char **to_free)
-{
-	const char *const str = buf;
-	const char *p = NULL;
-	const char *s;
-	gboolean nul_terminated = FALSE;
-	NMStrBuf strbuf;
-
-	g_return_val_if_fail (to_free, NULL);
-
-	*to_free = NULL;
-
-	if (buflen == 0)
-		return NULL;
-
-	if (buflen < 0) {
-		if (!str)
-			return NULL;
-		buflen = strlen (str);
-		if (buflen == 0)
-			return str;
-		nul_terminated = TRUE;
-	}
-
-	if (   g_utf8_validate (str, buflen, &p)
-	    && nul_terminated) {
-		/* note that g_utf8_validate() does not allow NUL character inside @str. Good.
-		 * We can treat @str like a NUL terminated string. */
-		if (!NM_STRCHAR_ANY (str, ch,
-		                        (   ch == '\\' \
-		                         || (   NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL) \
-		                             && ch < ' ') \
-		                         || (   NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII) \
-		                             && ((guchar) ch) >= 127))))
-			return str;
-	}
-
-	nm_str_buf_init (&strbuf,
-	                 buflen + 5,
-	                 NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_SECRET));
-
-	s = str;
-	do {
-		buflen -= p - s;
-		nm_assert (buflen >= 0);
-
-		for (; s < p; s++) {
-			char ch = s[0];
-
-			nm_assert (ch);
-			if (ch == '\\')
-				nm_str_buf_append_c2 (&strbuf, '\\', '\\');
-			else if (   (   NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL) \
-			             && ch < ' ') \
-			         || (   NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII) \
-			             && ((guchar) ch) >= 127))
-				_str_buf_append_c_escape_octal (&strbuf, ch);
-			else
-				nm_str_buf_append_c (&strbuf, ch);
-		}
-
-		if (buflen <= 0)
-			break;
-
-		_str_buf_append_c_escape_octal (&strbuf, p[0]);
-
-		buflen--;
-		if (buflen == 0)
-			break;
-
-		s = &p[1];
-		(void) g_utf8_validate (s, buflen, &p);
-	} while (TRUE);
-
-	return (*to_free = nm_str_buf_finalize (&strbuf, NULL));
+nm_utils_buf_utf8safe_escape(gconstpointer           buf,
+                             gssize                  buflen,
+                             NMUtilsStrUtf8SafeFlags flags,
+                             char **                 to_free)
+{
+    const char *const str = buf;
+    const char *      p   = NULL;
+    const char *      s;
+    gboolean          nul_terminated = FALSE;
+    NMStrBuf          strbuf;
+
+    g_return_val_if_fail(to_free, NULL);
+
+    *to_free = NULL;
+
+    if (buflen == 0)
+        return NULL;
+
+    if (buflen < 0) {
+        if (!str)
+            return NULL;
+        buflen = strlen(str);
+        if (buflen == 0)
+            return str;
+        nul_terminated = TRUE;
+    }
+
+    if (g_utf8_validate(str, buflen, &p) && nul_terminated) {
+        /* note that g_utf8_validate() does not allow NUL character inside @str. Good.
+         * We can treat @str like a NUL terminated string. */
+        if (!NM_STRCHAR_ANY(
+                str,
+                ch,
+                (ch == '\\'
+                 || (NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL) && ch < ' ')
+                 || (NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII)
+                     && ((guchar) ch) >= 127))))
+            return str;
+    }
+
+    nm_str_buf_init(&strbuf, buflen + 5, NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_SECRET));
+
+    s = str;
+    do {
+        buflen -= p - s;
+        nm_assert(buflen >= 0);
+
+        for (; s < p; s++) {
+            char ch = s[0];
+
+            nm_assert(ch);
+            if (ch == '\\')
+                nm_str_buf_append_c2(&strbuf, '\\', '\\');
+            else if ((NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL) && ch < ' ')
+                     || (NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII)
+                         && ((guchar) ch) >= 127))
+                _str_buf_append_c_escape_octal(&strbuf, ch);
+            else
+                nm_str_buf_append_c(&strbuf, ch);
+        }
+
+        if (buflen <= 0)
+            break;
+
+        _str_buf_append_c_escape_octal(&strbuf, p[0]);
+
+        buflen--;
+        if (buflen == 0)
+            break;
+
+        s = &p[1];
+        (void) g_utf8_validate(s, buflen, &p);
+    } while (TRUE);
+
+    return (*to_free = nm_str_buf_finalize(&strbuf, NULL));
 }
 
 const char *
-nm_utils_buf_utf8safe_escape_bytes (GBytes *bytes, NMUtilsStrUtf8SafeFlags flags, char **to_free)
+nm_utils_buf_utf8safe_escape_bytes(GBytes *bytes, NMUtilsStrUtf8SafeFlags flags, char **to_free)
 {
-	gconstpointer p;
-	gsize l;
+    gconstpointer p;
+    gsize         l;
 
-	if (bytes)
-		p = g_bytes_get_data (bytes, &l);
-	else {
-		p = NULL;
-		l = 0;
-	}
+    if (bytes)
+        p = g_bytes_get_data(bytes, &l);
+    else {
+        p = NULL;
+        l = 0;
+    }
 
-	return nm_utils_buf_utf8safe_escape (p, l, flags, to_free);
+    return nm_utils_buf_utf8safe_escape(p, l, flags, to_free);
 }
 
 char *
-nm_utils_buf_utf8safe_escape_cp (gconstpointer buf, gssize buflen, NMUtilsStrUtf8SafeFlags flags)
+nm_utils_buf_utf8safe_escape_cp(gconstpointer buf, gssize buflen, NMUtilsStrUtf8SafeFlags flags)
 {
-	const char *s_const;
-	char *s;
+    const char *s_const;
+    char *      s;
 
-	s_const = nm_utils_buf_utf8safe_escape (buf, buflen, flags, &s);
-	nm_assert (!s || s == s_const);
-	return s ?: g_strdup (s_const);
+    s_const = nm_utils_buf_utf8safe_escape(buf, buflen, flags, &s);
+    nm_assert(!s || s == s_const);
+    return s ?: g_strdup(s_const);
 }
 
 /*****************************************************************************/
 
 const char *
-nm_utils_str_utf8safe_unescape (const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free)
+nm_utils_str_utf8safe_unescape(const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free)
 {
-	const char *res;
-	gsize len;
+    const char *res;
+    gsize       len;
 
-	g_return_val_if_fail (to_free, NULL);
+    g_return_val_if_fail(to_free, NULL);
 
-	res = nm_utils_buf_utf8safe_unescape (str, flags, &len, (gpointer *) to_free);
+    res = nm_utils_buf_utf8safe_unescape(str, flags, &len, (gpointer *) to_free);
 
-	nm_assert (   (!res && len == 0)
-	           || (strlen (res) <= len));
+    nm_assert((!res && len == 0) || (strlen(res) <= len));
 
-	return res;
+    return res;
 }
 
 /**
@@ -2898,9 +2920,9 @@ nm_utils_str_utf8safe_unescape (const char *str, NMUtilsStrUtf8SafeFlags flags,
  *   with g_free. The escaping can be reverted by g_strcompress().
  **/
 const char *
-nm_utils_str_utf8safe_escape (const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free)
+nm_utils_str_utf8safe_escape(const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free)
 {
-	return nm_utils_buf_utf8safe_escape (str, -1, flags, to_free);
+    return nm_utils_buf_utf8safe_escape(str, -1, flags, to_free);
 }
 
 /**
@@ -2916,34 +2938,34 @@ nm_utils_str_utf8safe_escape (const char *str, NMUtilsStrUtf8SafeFlags flags, ch
  *   The escaping can be reverted by g_strcompress().
  **/
 char *
-nm_utils_str_utf8safe_escape_cp (const char *str, NMUtilsStrUtf8SafeFlags flags)
+nm_utils_str_utf8safe_escape_cp(const char *str, NMUtilsStrUtf8SafeFlags flags)
 {
-	char *s;
+    char *s;
 
-	nm_utils_str_utf8safe_escape (str, flags, &s);
-	return s ?: g_strdup (str);
+    nm_utils_str_utf8safe_escape(str, flags, &s);
+    return s ?: g_strdup(str);
 }
 
 char *
-nm_utils_str_utf8safe_unescape_cp (const char *str, NMUtilsStrUtf8SafeFlags flags)
+nm_utils_str_utf8safe_unescape_cp(const char *str, NMUtilsStrUtf8SafeFlags flags)
 {
-	char *s;
+    char *s;
 
-	str = nm_utils_str_utf8safe_unescape (str, flags, &s);
-	return s ?: g_strdup (str);
+    str = nm_utils_str_utf8safe_unescape(str, flags, &s);
+    return s ?: g_strdup(str);
 }
 
 char *
-nm_utils_str_utf8safe_escape_take (char *str, NMUtilsStrUtf8SafeFlags flags)
+nm_utils_str_utf8safe_escape_take(char *str, NMUtilsStrUtf8SafeFlags flags)
 {
-	char *str_to_free;
+    char *str_to_free;
 
-	nm_utils_str_utf8safe_escape (str, flags, &str_to_free);
-	if (str_to_free) {
-		g_free (str);
-		return str_to_free;
-	}
-	return str;
+    nm_utils_str_utf8safe_escape(str, flags, &str_to_free);
+    if (str_to_free) {
+        g_free(str);
+        return str_to_free;
+    }
+    return str;
 }
 
 /*****************************************************************************/
@@ -2951,358 +2973,569 @@ nm_utils_str_utf8safe_escape_take (char *str, NMUtilsStrUtf8SafeFlags flags)
 /* taken from systemd's fd_wait_for_event(). Note that the timeout
  * is here in nano-seconds, not micro-seconds. */
 int
-nm_utils_fd_wait_for_event (int fd, int event, gint64 timeout_nsec)
-{
-	struct pollfd pollfd = {
-		.fd = fd,
-		.events = event,
-	};
-	struct timespec ts, *pts;
-	int r;
-
-	if (timeout_nsec < 0)
-		pts = NULL;
-	else {
-		ts.tv_sec = (time_t) (timeout_nsec / NM_UTILS_NSEC_PER_SEC);
-		ts.tv_nsec = (long int) (timeout_nsec % NM_UTILS_NSEC_PER_SEC);
-		pts = &ts;
-	}
-
-	r = ppoll (&pollfd, 1, pts, NULL);
-	if (r < 0)
-		return -NM_ERRNO_NATIVE (errno);
-	if (r == 0)
-		return 0;
-	return pollfd.revents;
+nm_utils_fd_wait_for_event(int fd, int event, gint64 timeout_nsec)
+{
+    struct pollfd pollfd = {
+        .fd     = fd,
+        .events = event,
+    };
+    struct timespec ts, *pts;
+    int             r;
+
+    if (timeout_nsec < 0)
+        pts = NULL;
+    else {
+        ts.tv_sec  = (time_t)(timeout_nsec / NM_UTILS_NSEC_PER_SEC);
+        ts.tv_nsec = (long int) (timeout_nsec % NM_UTILS_NSEC_PER_SEC);
+        pts        = &ts;
+    }
+
+    r = ppoll(&pollfd, 1, pts, NULL);
+    if (r < 0)
+        return -NM_ERRNO_NATIVE(errno);
+    if (r == 0)
+        return 0;
+    return pollfd.revents;
 }
 
 /* taken from systemd's loop_read() */
 ssize_t
-nm_utils_fd_read_loop (int fd, void *buf, size_t nbytes, bool do_poll)
+nm_utils_fd_read_loop(int fd, void *buf, size_t nbytes, bool do_poll)
 {
-	uint8_t *p = buf;
-	ssize_t n = 0;
+    uint8_t *p = buf;
+    ssize_t  n = 0;
 
-	g_return_val_if_fail (fd >= 0, -EINVAL);
-	g_return_val_if_fail (buf, -EINVAL);
+    g_return_val_if_fail(fd >= 0, -EINVAL);
+    g_return_val_if_fail(buf, -EINVAL);
 
-	/* If called with nbytes == 0, let's call read() at least
-	 * once, to validate the operation */
+    /* If called with nbytes == 0, let's call read() at least
+     * once, to validate the operation */
 
-	if (nbytes > (size_t) SSIZE_MAX)
-		return -EINVAL;
+    if (nbytes > (size_t) SSIZE_MAX)
+        return -EINVAL;
 
-	do {
-		ssize_t k;
+    do {
+        ssize_t k;
 
-		k = read (fd, p, nbytes);
-		if (k < 0) {
-			int errsv = errno;
+        k = read(fd, p, nbytes);
+        if (k < 0) {
+            int errsv = errno;
 
-			if (errsv == EINTR)
-				continue;
+            if (errsv == EINTR)
+                continue;
 
-			if (errsv == EAGAIN && do_poll) {
+            if (errsv == EAGAIN && do_poll) {
+                /* We knowingly ignore any return value here,
+                 * and expect that any error/EOF is reported
+                 * via read() */
 
-				/* We knowingly ignore any return value here,
-				 * and expect that any error/EOF is reported
-				 * via read() */
+                (void) nm_utils_fd_wait_for_event(fd, POLLIN, -1);
+                continue;
+            }
 
-				(void) nm_utils_fd_wait_for_event (fd, POLLIN, -1);
-				continue;
-			}
+            return n > 0 ? n : -NM_ERRNO_NATIVE(errsv);
+        }
 
-			return n > 0 ? n : -NM_ERRNO_NATIVE (errsv);
-		}
+        if (k == 0)
+            return n;
 
-		if (k == 0)
-			return n;
+        g_assert((size_t) k <= nbytes);
 
-		g_assert ((size_t) k <= nbytes);
+        p += k;
+        nbytes -= k;
+        n += k;
+    } while (nbytes > 0);
 
-		p += k;
-		nbytes -= k;
-		n += k;
-	} while (nbytes > 0);
-
-	return n;
+    return n;
 }
 
 /* taken from systemd's loop_read_exact() */
 int
-nm_utils_fd_read_loop_exact (int fd, void *buf, size_t nbytes, bool do_poll)
+nm_utils_fd_read_loop_exact(int fd, void *buf, size_t nbytes, bool do_poll)
 {
-	ssize_t n;
+    ssize_t n;
 
-	n = nm_utils_fd_read_loop (fd, buf, nbytes, do_poll);
-	if (n < 0)
-		return (int) n;
-	if ((size_t) n != nbytes)
-		return -EIO;
+    n = nm_utils_fd_read_loop(fd, buf, nbytes, do_poll);
+    if (n < 0)
+        return (int) n;
+    if ((size_t) n != nbytes)
+        return -EIO;
 
-	return 0;
+    return 0;
 }
 
 /*****************************************************************************/
 
+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)
-{
-	GHashTableIter iter;
-	NMUtilsNamedValue *values;
-	guint i, len;
-
-	if (   !hash
-	    || !(len = g_hash_table_size (hash))) {
-		NM_SET_OUT (out_len, 0);
-		return NULL;
-	}
-
-	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))
-		i++;
-	nm_assert (i == len);
-	values[i].name = NULL;
-	values[i].value_ptr = NULL;
-
-	if (compare_func)
-		nm_utils_named_value_list_sort (values, len, compare_func, user_data);
-
-	NM_SET_OUT (out_len, len);
-	return values;
+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;
+    g_hash_table_iter_init(&iter, hash);
+    while (g_hash_table_iter_next(&iter, (gpointer *) &values[i].name, &values[i].value_ptr))
+        i++;
+    nm_assert(i == len);
+    values[i].name      = NULL;
+    values[i].value_ptr = NULL;
+
+    if (compare_func)
+        nm_utils_named_value_list_sort(values, len, compare_func, user_data);
+
+    NM_SET_OUT(out_len, len);
+    return values;
 }
 
 gssize
-nm_utils_named_value_list_find (const NMUtilsNamedValue *arr,
-                                gsize len,
-                                const char *name,
-                                gboolean sorted)
+nm_utils_named_value_list_find(const NMUtilsNamedValue *arr,
+                               gsize                    len,
+                               const char *             name,
+                               gboolean                 sorted)
 {
-	gsize i;
+    gsize i;
 
-	nm_assert (name);
+    nm_assert(name);
 
 #if NM_MORE_ASSERTS > 5
-	{
-		for (i = 0; i < len; i++) {
-			const NMUtilsNamedValue *v = &arr[i];
-
-			nm_assert (v->name);
-			if (   sorted
-			    && i > 0)
-				nm_assert (strcmp (arr[i - 1].name, v->name) < 0);
-		}
-	}
-
-	nm_assert (   !sorted
-	           || nm_utils_named_value_list_is_sorted (arr, len, FALSE, NULL, NULL));
+    {
+        for (i = 0; i < len; i++) {
+            const NMUtilsNamedValue *v = &arr[i];
+
+            nm_assert(v->name);
+            if (sorted && i > 0)
+                nm_assert(strcmp(arr[i - 1].name, v->name) < 0);
+        }
+    }
+
+    nm_assert(!sorted || nm_utils_named_value_list_is_sorted(arr, len, FALSE, NULL, NULL));
 #endif
 
-	if (sorted) {
-		return nm_utils_array_find_binary_search (arr,
-		                                          sizeof (NMUtilsNamedValue),
-		                                          len,
-		                                          &name,
-		                                          nm_strcmp_p_with_data,
-		                                          NULL);
-	}
-	for (i = 0; i < len; i++) {
-		if (nm_streq (arr[i].name, name))
-			return i;
-	}
-	return ~((gssize) len);
+    if (sorted) {
+        return nm_utils_array_find_binary_search(arr,
+                                                 sizeof(NMUtilsNamedValue),
+                                                 len,
+                                                 &name,
+                                                 nm_strcmp_p_with_data,
+                                                 NULL);
+    }
+    for (i = 0; i < len; i++) {
+        if (nm_streq(arr[i].name, name))
+            return i;
+    }
+    return ~((gssize) len);
 }
 
 gboolean
-nm_utils_named_value_list_is_sorted (const NMUtilsNamedValue *arr,
-                                     gsize len,
-                                     gboolean accept_duplicates,
-                                     GCompareDataFunc compare_func,
-                                     gpointer user_data)
+nm_utils_named_value_list_is_sorted(const NMUtilsNamedValue *arr,
+                                    gsize                    len,
+                                    gboolean                 accept_duplicates,
+                                    GCompareDataFunc         compare_func,
+                                    gpointer                 user_data)
 {
-	gsize i;
-	int c_limit;
+    gsize i;
+    int   c_limit;
 
-	if (len == 0)
-		return TRUE;
+    if (len == 0)
+        return TRUE;
 
-	g_return_val_if_fail (arr, FALSE);
+    g_return_val_if_fail(arr, FALSE);
 
-	if (!compare_func)
-		compare_func = nm_strcmp_p_with_data;
+    if (!compare_func)
+        compare_func = nm_strcmp_p_with_data;
 
-	c_limit = accept_duplicates ? 0 : -1;
+    c_limit = accept_duplicates ? 0 : -1;
 
-	for (i = 1; i < len; i++) {
-		int c;
+    for (i = 1; i < len; i++) {
+        int c;
 
-		c = compare_func (&arr[i - 1], &arr[i], user_data);
-		if (c > c_limit)
-			return FALSE;
-	}
-	return TRUE;
+        c = compare_func(&arr[i - 1], &arr[i], user_data);
+        if (c > c_limit)
+            return FALSE;
+    }
+    return TRUE;
 }
 
 void
-nm_utils_named_value_list_sort (NMUtilsNamedValue *arr,
-                                gsize len,
-                                GCompareDataFunc compare_func,
-                                gpointer user_data)
+nm_utils_named_value_list_sort(NMUtilsNamedValue *arr,
+                               gsize              len,
+                               GCompareDataFunc   compare_func,
+                               gpointer           user_data)
 {
-	if (len == 0)
-		return;
+    if (len == 0)
+        return;
 
-	g_return_if_fail (arr);
+    g_return_if_fail(arr);
 
-	if (len == 1)
-		return;
+    if (len == 1)
+        return;
 
-	g_qsort_with_data (arr,
-	                   len,
-	                   sizeof (NMUtilsNamedValue),
-	                   compare_func ?: nm_strcmp_p_with_data,
-	                   user_data);
+    g_qsort_with_data(arr,
+                      len,
+                      sizeof(NMUtilsNamedValue),
+                      compare_func ?: nm_strcmp_p_with_data,
+                      user_data);
 }
 
 /*****************************************************************************/
 
 gpointer *
-nm_utils_hash_keys_to_array (GHashTable *hash,
-                             GCompareDataFunc compare_func,
-                             gpointer user_data,
-                             guint *out_len)
-{
-	guint len;
-	gpointer *keys;
-
-	/* by convention, we never return an empty array. In that
-	 * case, always %NULL. */
-	if (   !hash
-	    || g_hash_table_size (hash) == 0) {
-		NM_SET_OUT (out_len, 0);
-		return NULL;
-	}
-
-	keys = g_hash_table_get_keys_as_array (hash, &len);
-	if (   len > 1
-	    && compare_func) {
-		g_qsort_with_data (keys,
-		                   len,
-		                   sizeof (gpointer),
-		                   compare_func,
-		                   user_data);
-	}
-	NM_SET_OUT (out_len, len);
-	return keys;
+nm_utils_hash_keys_to_array(GHashTable *     hash,
+                            GCompareDataFunc compare_func,
+                            gpointer         user_data,
+                            guint *          out_len)
+{
+    guint     len;
+    gpointer *keys;
+
+    /* by convention, we never return an empty array. In that
+     * case, always %NULL. */
+    if (!hash || g_hash_table_size(hash) == 0) {
+        NM_SET_OUT(out_len, 0);
+        return NULL;
+    }
+
+    keys = g_hash_table_get_keys_as_array(hash, &len);
+    if (len > 1 && compare_func) {
+        g_qsort_with_data(keys, len, sizeof(gpointer), compare_func, user_data);
+    }
+    NM_SET_OUT(out_len, len);
+    return keys;
 }
 
 gpointer *
-nm_utils_hash_values_to_array (GHashTable *hash,
-                               GCompareDataFunc compare_func,
-                               gpointer user_data,
-                               guint *out_len)
-{
-	GHashTableIter iter;
-	gpointer value;
-	gpointer *arr;
-	guint i, len;
-
-	if (   !hash
-	    || (len = g_hash_table_size (hash)) == 0u) {
-		NM_SET_OUT (out_len, 0);
-		return NULL;
-	}
-
-	arr = g_new (gpointer, ((gsize) len) + 1);
-	i = 0;
-	g_hash_table_iter_init (&iter, hash);
-	while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &value))
-		arr[i++] = value;
-
-	nm_assert (i == len);
-	arr[len] = NULL;
-
-	if (   len > 1
-	    && compare_func) {
-		g_qsort_with_data (arr,
-		                   len,
-		                   sizeof (gpointer),
-		                   compare_func,
-		                   user_data);
-	}
-
-	NM_SET_OUT (out_len, len);
-	return arr;
+nm_utils_hash_values_to_array(GHashTable *     hash,
+                              GCompareDataFunc compare_func,
+                              gpointer         user_data,
+                              guint *          out_len)
+{
+    GHashTableIter iter;
+    gpointer       value;
+    gpointer *     arr;
+    guint          i, len;
+
+    if (!hash || (len = g_hash_table_size(hash)) == 0u) {
+        NM_SET_OUT(out_len, 0);
+        return NULL;
+    }
+
+    arr = g_new(gpointer, ((gsize) len) + 1);
+    i   = 0;
+    g_hash_table_iter_init(&iter, hash);
+    while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &value))
+        arr[i++] = value;
+
+    nm_assert(i == len);
+    arr[len] = NULL;
+
+    if (len > 1 && compare_func) {
+        g_qsort_with_data(arr, len, sizeof(gpointer), compare_func, user_data);
+    }
+
+    NM_SET_OUT(out_len, len);
+    return arr;
+}
+
+static gboolean
+_utils_hashtable_equal(GHashTable *     hash_a,
+                       GHashTable *     hash_b,
+                       GCompareDataFunc cmp_values,
+                       gpointer         user_data)
+{
+    GHashTableIter h;
+    gpointer       a_key;
+    gpointer       a_val;
+    gpointer       b_val;
+
+    nm_assert(hash_a);
+    nm_assert(hash_b);
+    nm_assert(hash_a != hash_b);
+    nm_assert(g_hash_table_size(hash_a) == g_hash_table_size(hash_b));
+
+    /* We rely on both hashes to have the same hash/equal function. Otherwise, we would have to iterate
+     * both hashes and check whether all keys/values are present in the respective other hash (which
+     * would be O(n^2), since we couldn't use the plain lookup function. That is not a useful thing
+     * for this function. */
+
+    g_hash_table_iter_init(&h, hash_a);
+    while (g_hash_table_iter_next(&h, &a_key, &a_val)) {
+        if (!g_hash_table_lookup_extended(hash_b, a_key, NULL, &b_val))
+            return FALSE;
+
+        if (!cmp_values) {
+            /* we accept %NULL compare function to indicate that we don't care about the key. */
+            continue;
+        }
+
+        if (cmp_values(a_val, b_val, user_data) != 0)
+            return FALSE;
+    }
+
+    return TRUE;
 }
 
+/**
+ * nm_utils_hashtable_equal:
+ * @a: (allow-none): the hash table or %NULL
+ * @b: (allow-none): the other hash table or %NULL
+ * @cmp_values: (allow-none): if %NULL, only the keys
+ *   will be compared. Otherwise, this function is used to
+ *   check whether all keys are equal.
+ * @user_data: the argument for @cmp_values.
+ *
+ * It is required that both @a and @b have the same hash and equals
+ * function.
+ *
+ * Returns: %TRUE, if both keys have the same keys and (if
+ *   @cmp_values is given) all values are the same.
+ */
 gboolean
-nm_utils_hashtable_same_keys (const GHashTable *a,
-                              const GHashTable *b)
+nm_utils_hashtable_equal(const GHashTable *a,
+                         const GHashTable *b,
+                         GCompareDataFunc  cmp_values,
+                         gpointer          user_data)
 {
-	GHashTableIter h;
-	const char *k;
+    GHashTable *hash_a = (GHashTable *) a;
+    GHashTable *hash_b = (GHashTable *) b;
+    gboolean    same;
+    guint       size;
+
+    if (hash_a == hash_b)
+        return TRUE;
 
-	if (a == b)
-		return TRUE;
-	if (!a || !b)
-		return FALSE;
-	if (g_hash_table_size ((GHashTable *) a) != g_hash_table_size ((GHashTable *) b))
-		return FALSE;
+    if (!hash_a || !hash_b)
+        return FALSE;
 
-	g_hash_table_iter_init (&h, (GHashTable *) a);
-	while (g_hash_table_iter_next (&h, (gpointer) &k, NULL)) {
-		if (!g_hash_table_contains ((GHashTable *) b, k))
-			return FALSE;
-	}
+    size = g_hash_table_size(hash_a);
+    if (size != g_hash_table_size(hash_b))
+        return FALSE;
+
+    if (size == 0)
+        return TRUE;
+
+    same = _utils_hashtable_equal(hash_a, hash_b, cmp_values, user_data);
 
 #if NM_MORE_ASSERTS > 5
-	g_hash_table_iter_init (&h, (GHashTable *) b);
-	while (g_hash_table_iter_next (&h, (gpointer) &k, NULL))
-		nm_assert (g_hash_table_contains ((GHashTable *) a, k));
+    nm_assert(same == _utils_hashtable_equal(hash_b, hash_a, cmp_values, user_data));
 #endif
 
-	return TRUE;
+    return same;
+}
+
+typedef struct {
+    gpointer key;
+    gpointer val;
+} HashTableCmpData;
+
+typedef struct {
+    GCompareDataFunc cmp_keys;
+    gpointer         user_data;
+} HashTableUserData;
+
+static int
+_hashtable_cmp_func(gconstpointer a, gconstpointer b, gpointer user_data)
+{
+    const HashTableUserData *d   = user_data;
+    const HashTableCmpData * d_a = *((const HashTableCmpData *const *) a);
+    const HashTableCmpData * d_b = *((const HashTableCmpData *const *) b);
+
+    NM_CMP_RETURN(d->cmp_keys(d_a, d_b, d->user_data));
+    return 0;
+}
+
+/**
+ * nm_utils_hashtable_cmp:
+ * @a: (allow-none): the hash to compare. May be %NULL.
+ * @b: (allow-none): the other hash to compare. May be %NULL.
+ * @do_fast_precheck: if %TRUE, assume that the hashes are equal
+ *   and that it is worth calling nm_utils_hashtable_equal() first.
+ *   That requires, that both hashes have the same equals function
+ *   which is compatible with the @cmp_keys function.
+ * @cmp_keys: the compare function for keys. Usually, the hash/equal function
+ *   of both hashes corresponds to this function. If you set @do_fast_precheck
+ *   to false, then this is not a requirement.
+ * @cmp_values: (allow-none): if %NULL, only the keys are compared.
+ *   Otherwise, the values must are also compared with this function.
+ *
+ * Both hashes must have keys/values of the same domain, so that
+ * they can be effectively compared with @cmp_keys and @cmp_values.
+ *
+ * %NULL hashes compare equal to %NULL, but not to empty hashes.
+ *
+ * Returns: 0 if both hashes are equal, or -1 or 1 if one of the hashes
+ *   sorts before/after.
+ */
+int
+nm_utils_hashtable_cmp(const GHashTable *a,
+                       const GHashTable *b,
+                       gboolean          do_fast_precheck,
+                       GCompareDataFunc  cmp_keys,
+                       GCompareDataFunc  cmp_values,
+                       gpointer          user_data)
+{
+    GHashTable *hash_a                       = (GHashTable *) a;
+    GHashTable *hash_b                       = (GHashTable *) b;
+    gs_free HashTableCmpData *cmp_array_free = NULL;
+    HashTableCmpData *        cmp_array_a;
+    HashTableCmpData *        cmp_array_b;
+    GHashTableIter            h;
+    gpointer                  i_key;
+    gpointer                  i_val;
+    gsize                     size2;
+    guint                     size;
+    guint                     i;
+
+    nm_assert(cmp_keys);
+
+    NM_CMP_SELF(hash_a, hash_b);
+
+    size = g_hash_table_size(hash_a);
+
+    NM_CMP_DIRECT(size, g_hash_table_size(hash_b));
+
+    if (size == 0)
+        return 0;
+
+    if (do_fast_precheck) {
+        gboolean same;
+
+        /* we expect that the hashes are equal and the caller ensures us that they
+         * use the same hash/equal functions. Do a fast path check first...
+         *
+         * It's unclear whether this is worth it. The full comparison is O(n*ln(n)),
+         * while the fast check (using the hash lookup) is O(n). But then, the pre-check
+         * makes additional requirements on the hash's hash/equal functions -- the
+         * full comparison does not make such requirements. */
+        same = _utils_hashtable_equal(hash_a, hash_b, cmp_values, user_data);
+#if NM_MORE_ASSERTS > 5
+        nm_assert(same == _utils_hashtable_equal(hash_b, hash_a, cmp_values, user_data));
+#endif
+        if (same)
+            return 0;
+    }
+
+    size2 = ((gsize) size) * 2u;
+    if (size2 > 600u / sizeof(HashTableCmpData)) {
+        cmp_array_free = g_new(HashTableCmpData, size2);
+        cmp_array_a    = cmp_array_free;
+    } else
+        cmp_array_a = g_newa(HashTableCmpData, size2);
+    cmp_array_b = &cmp_array_a[size];
+
+    i = 0;
+    g_hash_table_iter_init(&h, hash_a);
+    while (g_hash_table_iter_next(&h, &i_key, &i_val)) {
+        nm_assert(i < size);
+        cmp_array_a[i++] = (HashTableCmpData){
+            .key = i_key,
+            .val = i_val,
+        };
+    }
+    nm_assert(i == size);
+
+    i = 0;
+    g_hash_table_iter_init(&h, hash_b);
+    while (g_hash_table_iter_next(&h, &i_key, &i_val)) {
+        nm_assert(i < size);
+        cmp_array_b[i++] = (HashTableCmpData){
+            .key = i_key,
+            .val = i_val,
+        };
+    }
+    nm_assert(i == size);
+
+    g_qsort_with_data(cmp_array_a,
+                      size,
+                      sizeof(HashTableCmpData),
+                      _hashtable_cmp_func,
+                      &((HashTableUserData){
+                          .cmp_keys  = cmp_keys,
+                          .user_data = user_data,
+                      }));
+
+    g_qsort_with_data(cmp_array_b,
+                      size,
+                      sizeof(HashTableCmpData),
+                      _hashtable_cmp_func,
+                      &((HashTableUserData){
+                          .cmp_keys  = cmp_keys,
+                          .user_data = user_data,
+                      }));
+
+    for (i = 0; i < size; i++) {
+        NM_CMP_RETURN(cmp_keys(cmp_array_a[i].key, cmp_array_b[i].key, user_data));
+    }
+
+    if (cmp_values) {
+        for (i = 0; i < size; i++) {
+            NM_CMP_RETURN(cmp_values(cmp_array_a[i].val, cmp_array_b[i].val, user_data));
+        }
+    }
+
+    /* the fast-precheck should have already told that the arrays are equal. */
+    nm_assert(!do_fast_precheck);
+
+    return 0;
 }
 
 char **
-nm_utils_strv_make_deep_copied (const char **strv)
+nm_utils_strv_make_deep_copied(const char **strv)
 {
-	gsize i;
+    gsize i;
 
-	/* it takes a strv list, and copies each
-	 * strings. Note that this updates @strv *in-place*
-	 * and returns it. */
+    /* it takes a strv list, and copies each
+     * strings. Note that this updates @strv *in-place*
+     * and returns it. */
 
-	if (!strv)
-		return NULL;
-	for (i = 0; strv[i]; i++)
-		strv[i] = g_strdup (strv[i]);
+    if (!strv)
+        return NULL;
+    for (i = 0; strv[i]; i++)
+        strv[i] = g_strdup(strv[i]);
 
-	return (char **) strv;
+    return (char **) strv;
 }
 
 char **
-nm_utils_strv_make_deep_copied_n (const char **strv, gsize len)
+nm_utils_strv_make_deep_copied_n(const char **strv, gsize len)
 {
-	gsize i;
+    gsize i;
 
-	/* it takes a strv array with len elements, and copies each
-	 * strings. Note that this updates @strv *in-place*
-	 * and returns it. */
+    /* it takes a strv array with len elements, and copies each
+     * strings. Note that this updates @strv *in-place*
+     * and returns it. */
 
-	if (!strv)
-		return NULL;
-	for (i = 0; i < len; i++)
-		strv[i] = g_strdup (strv[i]);
+    if (!strv)
+        return NULL;
+    for (i = 0; i < len; i++)
+        strv[i] = g_strdup(strv[i]);
 
-	return (char **) strv;
+    return (char **) strv;
 }
 
 /**
@@ -3324,7 +3557,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
@@ -3332,124 +3565,198 @@ nm_utils_strv_make_deep_copied_n (const char **strv, gsize len)
  *   cloned or not.
  */
 char **
-nm_utils_strv_dup (gpointer strv,
-                   gssize len,
-                   gboolean deep_copied)
-{
-	gsize i, l;
-	char **v;
-	const char *const *const src = strv;
-
-	if (len < 0)
-		l = NM_PTRARRAY_LEN (src);
-	else
-		l = len;
-	if (l == 0) {
-		/* this function never returns an empty strv array. If you
-		 * need that, handle it yourself. */
-		return NULL;
-	}
-
-	v = g_new (char *, l + 1);
-	for (i = 0; i < l; i++) {
-
-		if (G_UNLIKELY (!src[i])) {
-			/* NULL strings are not allowed. Clear the remainder of the array
-			 * and return it (with assertion failure). */
-			l++;
-			for (; i < l; i++)
-				v[i] = NULL;
-			g_return_val_if_reached (v);
-		}
-
-		if (deep_copied)
-			v[i] = g_strdup (src[i]);
-		else
-			v[i] = (char *) src[i];
-	}
-	v[l] = NULL;
-	return v;
+_nm_utils_strv_dup(const char *const *strv, gssize len, gboolean deep_copied)
+{
+    gsize  i, l;
+    char **v;
+
+    if (len < 0)
+        l = NM_PTRARRAY_LEN(strv);
+    else
+        l = len;
+    if (l == 0) {
+        /* this function never returns an empty strv array. If you
+         * need that, handle it yourself. */
+        return NULL;
+    }
+
+    v = g_new(char *, l + 1);
+    for (i = 0; i < l; i++) {
+        if (G_UNLIKELY(!strv[i])) {
+            /* NULL strings are not allowed. Clear the remainder of the array
+             * and return it (with assertion failure). */
+            l++;
+            for (; i < l; i++)
+                v[i] = NULL;
+            g_return_val_if_reached(v);
+        }
+
+        if (deep_copied)
+            v[i] = g_strdup(strv[i]);
+        else
+            v[i] = (char *) strv[i];
+    }
+    v[l] = NULL;
+    return v;
+}
+
+const char **
+_nm_utils_strv_dup_packed(const char *const *strv, gssize len)
+
+{
+    gs_free gsize *str_len_free = NULL;
+    gsize *        str_len;
+    const char **  result;
+    gsize          mem_len;
+    gsize          pre_len;
+    gsize          len2;
+    char *         sbuf;
+    gsize          i;
+
+    nm_assert(len >= -1);
+
+    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;
+        }
+        len2 = NM_PTRARRAY_LEN(strv);
+    } else {
+        if (len == 0)
+            return NULL;
+        len2 = len;
+    }
+
+    if (len2 > 300u / sizeof(gsize)) {
+        str_len_free = g_new(gsize, len2);
+        str_len      = str_len_free;
+    } else
+        str_len = g_newa(gsize, len2);
+
+    mem_len = 0;
+    for (i = 0; i < len2; i++) {
+        gsize l;
+
+        if (G_LIKELY(strv[i]))
+            l = strlen(strv[i]) + 1u;
+        else
+            l = 0;
+        str_len[i] = l;
+        mem_len += l;
+    }
+
+    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 = str_len[i];
+        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
-nm_utils_ptrarray_find_binary_search (gconstpointer *list,
-                                      gsize len,
-                                      gconstpointer needle,
-                                      GCompareDataFunc cmpfcn,
-                                      gpointer user_data,
-                                      gssize *out_idx_first,
-                                      gssize *out_idx_last)
-{
-	gssize imin, imax, imid, i2min, i2max, i2mid;
-	int cmp;
-
-	g_return_val_if_fail (list || !len, ~((gssize) 0));
-	g_return_val_if_fail (cmpfcn, ~((gssize) 0));
-
-	imin = 0;
-	if (len > 0) {
-		imax = len - 1;
-
-		while (imin <= imax) {
-			imid = imin + (imax - imin) / 2;
-
-			cmp = cmpfcn (list[imid], needle, user_data);
-			if (cmp == 0) {
-				/* we found a matching entry at index imid.
-				 *
-				 * Does the caller request the first/last index as well (in case that
-				 * there are multiple entries which compare equal). */
-
-				if (out_idx_first) {
-					i2min = imin;
-					i2max = imid + 1;
-					while (i2min <= i2max) {
-						i2mid = i2min + (i2max - i2min) / 2;
-
-						cmp = cmpfcn (list[i2mid], needle, user_data);
-						if (cmp == 0)
-							i2max = i2mid -1;
-						else {
-							nm_assert (cmp < 0);
-							i2min = i2mid + 1;
-						}
-					}
-					*out_idx_first = i2min;
-				}
-				if (out_idx_last) {
-					i2min = imid + 1;
-					i2max = imax;
-					while (i2min <= i2max) {
-						i2mid = i2min + (i2max - i2min) / 2;
-
-						cmp = cmpfcn (list[i2mid], needle, user_data);
-						if (cmp == 0)
-							i2min = i2mid + 1;
-						else {
-							nm_assert (cmp > 0);
-							i2max = i2mid - 1;
-						}
-					}
-					*out_idx_last = i2min - 1;
-				}
-				return imid;
-			}
-
-			if (cmp < 0)
-				imin = imid + 1;
-			else
-				imax = imid - 1;
-		}
-	}
-
-	/* return the inverse of @imin. This is a negative number, but
-	 * also is ~imin the position where the value should be inserted. */
-	imin = ~imin;
-	NM_SET_OUT (out_idx_first, imin);
-	NM_SET_OUT (out_idx_last, imin);
-	return imin;
+nm_utils_ptrarray_find_binary_search(gconstpointer *  list,
+                                     gsize            len,
+                                     gconstpointer    needle,
+                                     GCompareDataFunc cmpfcn,
+                                     gpointer         user_data,
+                                     gssize *         out_idx_first,
+                                     gssize *         out_idx_last)
+{
+    gssize imin, imax, imid, i2min, i2max, i2mid;
+    int    cmp;
+
+    g_return_val_if_fail(list || !len, ~((gssize) 0));
+    g_return_val_if_fail(cmpfcn, ~((gssize) 0));
+
+    imin = 0;
+    if (len > 0) {
+        imax = len - 1;
+
+        while (imin <= imax) {
+            imid = imin + (imax - imin) / 2;
+
+            cmp = cmpfcn(list[imid], needle, user_data);
+            if (cmp == 0) {
+                /* we found a matching entry at index imid.
+                 *
+                 * Does the caller request the first/last index as well (in case that
+                 * there are multiple entries which compare equal). */
+
+                if (out_idx_first) {
+                    i2min = imin;
+                    i2max = imid + 1;
+                    while (i2min <= i2max) {
+                        i2mid = i2min + (i2max - i2min) / 2;
+
+                        cmp = cmpfcn(list[i2mid], needle, user_data);
+                        if (cmp == 0)
+                            i2max = i2mid - 1;
+                        else {
+                            nm_assert(cmp < 0);
+                            i2min = i2mid + 1;
+                        }
+                    }
+                    *out_idx_first = i2min;
+                }
+                if (out_idx_last) {
+                    i2min = imid + 1;
+                    i2max = imax;
+                    while (i2min <= i2max) {
+                        i2mid = i2min + (i2max - i2min) / 2;
+
+                        cmp = cmpfcn(list[i2mid], needle, user_data);
+                        if (cmp == 0)
+                            i2min = i2mid + 1;
+                        else {
+                            nm_assert(cmp > 0);
+                            i2max = i2mid - 1;
+                        }
+                    }
+                    *out_idx_last = i2min - 1;
+                }
+                return imid;
+            }
+
+            if (cmp < 0)
+                imin = imid + 1;
+            else
+                imax = imid - 1;
+        }
+    }
+
+    /* return the inverse of @imin. This is a negative number, but
+     * also is ~imin the position where the value should be inserted. */
+    imin = ~imin;
+    NM_SET_OUT(out_idx_first, imin);
+    NM_SET_OUT(out_idx_last, imin);
+    return imin;
 }
 
 /*****************************************************************************/
@@ -3479,42 +3786,42 @@ nm_utils_ptrarray_find_binary_search (gconstpointer *list,
  *   position where it should be.
  */
 gssize
-nm_utils_array_find_binary_search (gconstpointer list,
-                                   gsize elem_size,
-                                   gsize len,
-                                   gconstpointer needle,
-                                   GCompareDataFunc cmpfcn,
-                                   gpointer user_data)
+nm_utils_array_find_binary_search(gconstpointer    list,
+                                  gsize            elem_size,
+                                  gsize            len,
+                                  gconstpointer    needle,
+                                  GCompareDataFunc cmpfcn,
+                                  gpointer         user_data)
 {
-	gssize imin, imax, imid;
-	int cmp;
+    gssize imin, imax, imid;
+    int    cmp;
 
-	g_return_val_if_fail (list || !len, ~((gssize) 0));
-	g_return_val_if_fail (cmpfcn, ~((gssize) 0));
-	g_return_val_if_fail (elem_size > 0, ~((gssize) 0));
+    g_return_val_if_fail(list || !len, ~((gssize) 0));
+    g_return_val_if_fail(cmpfcn, ~((gssize) 0));
+    g_return_val_if_fail(elem_size > 0, ~((gssize) 0));
 
-	imin = 0;
-	if (len == 0)
-		return ~imin;
+    imin = 0;
+    if (len == 0)
+        return ~imin;
 
-	imax = len - 1;
+    imax = len - 1;
 
-	while (imin <= imax) {
-		imid = imin + (imax - imin) / 2;
+    while (imin <= imax) {
+        imid = imin + (imax - imin) / 2;
 
-		cmp = cmpfcn (&((const char *) list)[elem_size * imid], needle, user_data);
-		if (cmp == 0)
-			return imid;
+        cmp = cmpfcn(&((const char *) list)[elem_size * imid], needle, user_data);
+        if (cmp == 0)
+            return imid;
 
-		if (cmp < 0)
-			imin = imid + 1;
-		else
-			imax = imid - 1;
-	}
+        if (cmp < 0)
+            imin = imid + 1;
+        else
+            imax = imid - 1;
+    }
 
-	/* return the inverse of @imin. This is a negative number, but
-	 * also is ~imin the position where the value should be inserted. */
-	return ~imin;
+    /* return the inverse of @imin. This is a negative number, but
+     * also is ~imin the position where the value should be inserted. */
+    return ~imin;
 }
 
 /*****************************************************************************/
@@ -3540,38 +3847,37 @@ nm_utils_array_find_binary_search (gconstpointer list,
  * Returns: %TRUE, if both dictionaries have the same content.
  */
 gboolean
-nm_utils_hash_table_equal (const GHashTable *a,
-                           const GHashTable *b,
-                           gboolean treat_null_as_empty,
-                           NMUtilsHashTableEqualFunc equal_func)
-{
-	guint n;
-	GHashTableIter iter;
-	gconstpointer key, v_a, v_b;
-
-	if (a == b)
-		return TRUE;
-	if (!treat_null_as_empty) {
-		if (!a || !b)
-			return FALSE;
-	}
-
-	n = a ? g_hash_table_size ((GHashTable *) a) : 0;
-	if (n != (b ? g_hash_table_size ((GHashTable *) b) : 0))
-		return FALSE;
-
-	if (n > 0) {
-		g_hash_table_iter_init (&iter, (GHashTable *) a);
-		while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &v_a)) {
-			if (!g_hash_table_lookup_extended ((GHashTable *) b, key, NULL, (gpointer *) &v_b))
-				return FALSE;
-			if (   equal_func
-			    && !equal_func (v_a, v_b))
-				return FALSE;
-		}
-	}
-
-	return TRUE;
+nm_utils_hash_table_equal(const GHashTable *        a,
+                          const GHashTable *        b,
+                          gboolean                  treat_null_as_empty,
+                          NMUtilsHashTableEqualFunc equal_func)
+{
+    guint          n;
+    GHashTableIter iter;
+    gconstpointer  key, v_a, v_b;
+
+    if (a == b)
+        return TRUE;
+    if (!treat_null_as_empty) {
+        if (!a || !b)
+            return FALSE;
+    }
+
+    n = a ? g_hash_table_size((GHashTable *) a) : 0;
+    if (n != (b ? g_hash_table_size((GHashTable *) b) : 0))
+        return FALSE;
+
+    if (n > 0) {
+        g_hash_table_iter_init(&iter, (GHashTable *) a);
+        while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &v_a)) {
+            if (!g_hash_table_lookup_extended((GHashTable *) b, key, NULL, (gpointer *) &v_b))
+                return FALSE;
+            if (equal_func && !equal_func(v_a, v_b))
+                return FALSE;
+        }
+    }
+
+    return TRUE;
 }
 
 /*****************************************************************************/
@@ -3591,65 +3897,65 @@ nm_utils_hash_table_equal (const GHashTable *a,
  * The returned start time counts since boot, in the unit HZ (with HZ usually being (1/100) seconds)
  **/
 guint64
-nm_utils_get_start_time_for_pid (pid_t pid, char *out_state, pid_t *out_ppid)
+nm_utils_get_start_time_for_pid(pid_t pid, char *out_state, pid_t *out_ppid)
 {
-	guint64 start_time;
-	char filename[256];
-	gs_free char *contents = NULL;
-	size_t length;
-	gs_free const char **tokens = NULL;
-	char *p;
-	char state = ' ';
-	gint64 ppid = 0;
+    guint64              start_time;
+    char                 filename[256];
+    gs_free char *       contents = NULL;
+    size_t               length;
+    gs_free const char **tokens = NULL;
+    char *               p;
+    char                 state = ' ';
+    gint64               ppid  = 0;
 
-	start_time = 0;
-	contents = NULL;
+    start_time = 0;
+    contents   = NULL;
 
-	g_return_val_if_fail (pid > 0, 0);
+    g_return_val_if_fail(pid > 0, 0);
 
-	G_STATIC_ASSERT_EXPR (sizeof (GPid) >= sizeof (pid_t));
+    G_STATIC_ASSERT_EXPR(sizeof(GPid) >= sizeof(pid_t));
 
-	nm_sprintf_buf (filename, "/proc/%"G_PID_FORMAT"/stat", (GPid) pid);
+    nm_sprintf_buf(filename, "/proc/%" G_PID_FORMAT "/stat", (GPid) pid);
 
-	if (!g_file_get_contents (filename, &contents, &length, NULL))
-		goto fail;
+    if (!g_file_get_contents(filename, &contents, &length, NULL))
+        goto fail;
 
-	/* start time is the token at index 19 after the '(process name)' entry - since only this
-	 * field can contain the ')' character, search backwards for this to avoid malicious
-	 * processes trying to fool us
-	 */
-	p = strrchr (contents, ')');
-	if (!p)
-		goto fail;
-	p += 2; /* skip ') ' */
-	if (p - contents >= (int) length)
-		goto fail;
+    /* start time is the token at index 19 after the '(process name)' entry - since only this
+     * field can contain the ')' character, search backwards for this to avoid malicious
+     * processes trying to fool us
+     */
+    p = strrchr(contents, ')');
+    if (!p)
+        goto fail;
+    p += 2; /* skip ') ' */
+    if (p - contents >= (int) length)
+        goto fail;
 
-	state = p[0];
+    state = p[0];
 
-	tokens = nm_utils_strsplit_set (p, " ");
+    tokens = nm_utils_strsplit_set(p, " ");
 
-	if (NM_PTRARRAY_LEN (tokens) < 20)
-		goto fail;
+    if (NM_PTRARRAY_LEN(tokens) < 20)
+        goto fail;
 
-	if (out_ppid) {
-		ppid = _nm_utils_ascii_str_to_int64 (tokens[1], 10, 1, G_MAXINT, 0);
-		if (ppid == 0)
-			goto fail;
-	}
+    if (out_ppid) {
+        ppid = _nm_utils_ascii_str_to_int64(tokens[1], 10, 1, G_MAXINT, 0);
+        if (ppid == 0)
+            goto fail;
+    }
 
-	start_time = _nm_utils_ascii_str_to_int64 (tokens[19], 10, 1, G_MAXINT64, 0);
-	if (start_time == 0)
-		goto fail;
+    start_time = _nm_utils_ascii_str_to_int64(tokens[19], 10, 1, G_MAXINT64, 0);
+    if (start_time == 0)
+        goto fail;
 
-	NM_SET_OUT (out_state, state);
-	NM_SET_OUT (out_ppid, ppid);
-	return start_time;
+    NM_SET_OUT(out_state, state);
+    NM_SET_OUT(out_ppid, ppid);
+    return start_time;
 
 fail:
-	NM_SET_OUT (out_state, ' ');
-	NM_SET_OUT (out_ppid, 0);
-	return 0;
+    NM_SET_OUT(out_state, ' ');
+    NM_SET_OUT(out_ppid, 0);
+    return 0;
 }
 
 /*****************************************************************************/
@@ -3669,29 +3975,25 @@ fail:
  * comparison.
  */
 void
-_nm_utils_strv_sort (const char **strv, gssize len)
+_nm_utils_strv_sort(const char **strv, gssize len)
 {
-	GCompareDataFunc cmp;
-	gsize l;
+    GCompareDataFunc cmp;
+    gsize            l;
 
-	if (len < 0) {
-		l = NM_PTRARRAY_LEN (strv);
-		cmp = nm_strcmp_p_with_data;
-	} else {
-		l = len;
-		cmp = nm_strcmp0_p_with_data;
-	}
+    if (len < 0) {
+        l   = NM_PTRARRAY_LEN(strv);
+        cmp = nm_strcmp_p_with_data;
+    } else {
+        l   = len;
+        cmp = nm_strcmp0_p_with_data;
+    }
 
-	if (l <= 1)
-		return;
+    if (l <= 1)
+        return;
 
-	nm_assert (l <= (gsize) G_MAXINT);
+    nm_assert(l <= (gsize) G_MAXINT);
 
-	g_qsort_with_data (strv,
-	                   l,
-	                   sizeof (const char *),
-	                   cmp,
-	                   NULL);
+    g_qsort_with_data(strv, l, sizeof(const char *), cmp, NULL);
 }
 
 /**
@@ -3718,31 +4020,28 @@ _nm_utils_strv_sort (const char **strv, gssize len)
  * Returns: 0 if the arrays are equal (using strcmp).
  **/
 int
-_nm_utils_strv_cmp_n (const char *const*strv1,
-                      gssize len1,
-                      const char *const*strv2,
-                      gssize len2)
+_nm_utils_strv_cmp_n(const char *const *strv1, gssize len1, const char *const *strv2, gssize len2)
 {
-	gsize n, n2;
+    gsize n, n2;
 
-	if (len1 < 0) {
-		if (!strv1)
-			return (len2 < 0 && !strv2) ? 0 : -1;
-		n = NM_PTRARRAY_LEN (strv1);
-	} else
-		n = len1;
+    if (len1 < 0) {
+        if (!strv1)
+            return (len2 < 0 && !strv2) ? 0 : -1;
+        n = NM_PTRARRAY_LEN(strv1);
+    } else
+        n = len1;
 
-	if (len2 < 0) {
-		if (!strv2)
-			return 1;
-		n2 = NM_PTRARRAY_LEN (strv2);
-	} else
-		n2 = len2;
+    if (len2 < 0) {
+        if (!strv2)
+            return 1;
+        n2 = NM_PTRARRAY_LEN(strv2);
+    } else
+        n2 = len2;
 
-	NM_CMP_DIRECT (n, n2);
-	for (; n > 0; n--, strv1++, strv2++)
-		NM_CMP_DIRECT_STRCMP0 (*strv1, *strv2);
-	return 0;
+    NM_CMP_DIRECT(n, n2);
+    for (; n > 0; n--, strv1++, strv2++)
+        NM_CMP_DIRECT_STRCMP0(*strv1, *strv2);
+    return 0;
 }
 
 /*****************************************************************************/
@@ -3760,17 +4059,16 @@ _nm_utils_strv_cmp_n (const char *const*strv1,
  *   %NULL if not found.
  */
 GSList *
-nm_utils_g_slist_find_str (const GSList *list,
-                           const char *needle)
+nm_utils_g_slist_find_str(const GSList *list, const char *needle)
 {
-	nm_assert (needle);
+    nm_assert(needle);
 
-	for (; list; list = list->next) {
-		nm_assert (list->data);
-		if (nm_streq (list->data, needle))
-			return (GSList *) list;
-	}
-	return NULL;
+    for (; list; list = list->next) {
+        nm_assert(list->data);
+        if (nm_streq(list->data, needle))
+            return (GSList *) list;
+    }
+    return NULL;
 }
 
 /**
@@ -3779,250 +4077,246 @@ 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.
  */
 int
-nm_utils_g_slist_strlist_cmp (const GSList *a, const GSList *b)
+nm_utils_g_slist_strlist_cmp(const GSList *a, const GSList *b)
 {
-	while (TRUE) {
-		if (!a)
-			return !b ? 0 : -1;
-		if (!b)
-			return 1;
-		NM_CMP_DIRECT_STRCMP0 (a->data, b->data);
-		a = a->next;
-		b = b->next;
-	}
+    while (TRUE) {
+        if (!a)
+            return !b ? 0 : -1;
+        if (!b)
+            return 1;
+        NM_CMP_DIRECT_STRCMP0(a->data, b->data);
+        a = a->next;
+        b = b->next;
+    }
 }
 
 char *
-nm_utils_g_slist_strlist_join (const GSList *a, const char *separator)
+nm_utils_g_slist_strlist_join(const GSList *a, const char *separator)
 {
-	GString *str = NULL;
+    GString *str = NULL;
 
-	if (!a)
-		return NULL;
+    if (!a)
+        return NULL;
 
-	for (; a; a = a->next) {
-		if (!str)
-			str = g_string_new (NULL);
-		else
-			g_string_append (str, separator);
-		g_string_append (str, a->data);
-	}
-	return g_string_free (str, FALSE);
+    for (; a; a = a->next) {
+        if (!str)
+            str = g_string_new(NULL);
+        else
+            g_string_append(str, separator);
+        g_string_append(str, a->data);
+    }
+    return g_string_free(str, FALSE);
 }
 
 /*****************************************************************************/
 
 gpointer
-_nm_utils_user_data_pack (int nargs, gconstpointer *args)
+_nm_utils_user_data_pack(int nargs, gconstpointer *args)
 {
-	int i;
-	gpointer *data;
+    int       i;
+    gpointer *data;
 
-	nm_assert (nargs > 0);
-	nm_assert (args);
+    nm_assert(nargs > 0);
+    nm_assert(args);
 
-	data = g_slice_alloc (((gsize) nargs) * sizeof (gconstpointer));
-	for (i = 0; i < nargs; i++)
-		data[i] = (gpointer) args[i];
-	return data;
+    data = g_slice_alloc(((gsize) nargs) * sizeof(gconstpointer));
+    for (i = 0; i < nargs; i++)
+        data[i] = (gpointer) args[i];
+    return data;
 }
 
 void
-_nm_utils_user_data_unpack (gpointer user_data, int nargs, ...)
+_nm_utils_user_data_unpack(gpointer user_data, int nargs, ...)
 {
-	gpointer *data = user_data;
-	va_list ap;
-	int i;
+    gpointer *data = user_data;
+    va_list   ap;
+    int       i;
 
-	nm_assert (data);
-	nm_assert (nargs > 0);
+    nm_assert(data);
+    nm_assert(nargs > 0);
 
-	va_start (ap, nargs);
-	for (i = 0; i < nargs; i++) {
-		gpointer *dst;
+    va_start(ap, nargs);
+    for (i = 0; i < nargs; i++) {
+        gpointer *dst;
 
-		dst = va_arg (ap, gpointer *);
-		nm_assert (dst);
+        dst = va_arg(ap, gpointer *);
+        nm_assert(dst);
 
-		*dst = data[i];
-	}
-	va_end (ap);
+        *dst = data[i];
+    }
+    va_end(ap);
 
-	g_slice_free1 (((gsize) nargs) * sizeof (gconstpointer), data);
+    g_slice_free1(((gsize) nargs) * sizeof(gconstpointer), data);
 }
 
 /*****************************************************************************/
 
 typedef struct {
-	gpointer callback_user_data;
-	GCancellable *cancellable;
-	GSource *source;
-	NMUtilsInvokeOnIdleCallback callback;
-	gulong cancelled_id;
+    gpointer                    callback_user_data;
+    GCancellable *              cancellable;
+    GSource *                   source;
+    NMUtilsInvokeOnIdleCallback callback;
+    gulong                      cancelled_id;
 } InvokeOnIdleData;
 
 static gboolean
-_nm_utils_invoke_on_idle_cb_idle (gpointer user_data)
+_nm_utils_invoke_on_idle_cb_idle(gpointer user_data)
 {
-	InvokeOnIdleData *data = user_data;
+    InvokeOnIdleData *data = user_data;
 
-	nm_clear_g_signal_handler (data->cancellable, &data->cancelled_id);
+    nm_clear_g_signal_handler(data->cancellable, &data->cancelled_id);
 
-	data->callback (data->callback_user_data, data->cancellable);
+    data->callback(data->callback_user_data, data->cancellable);
 
-	nm_g_object_unref (data->cancellable);
-	g_source_destroy (data->source);
-	nm_g_slice_free (data);
-	return G_SOURCE_REMOVE;
+    nm_g_object_unref(data->cancellable);
+    g_source_destroy(data->source);
+    nm_g_slice_free(data);
+    return G_SOURCE_REMOVE;
 }
 
 static void
-_nm_utils_invoke_on_idle_cb_cancelled (GCancellable *cancellable,
-                                       InvokeOnIdleData *data)
+_nm_utils_invoke_on_idle_cb_cancelled(GCancellable *cancellable, InvokeOnIdleData *data)
 {
-	/* on cancellation, we invoke the callback synchronously. */
-	nm_clear_g_signal_handler (data->cancellable, &data->cancelled_id);
-	nm_clear_g_source_inst (&data->source);
-	data->callback (data->callback_user_data, data->cancellable);
-	nm_g_object_unref (data->cancellable);
-	nm_g_slice_free (data);
+    /* on cancellation, we invoke the callback synchronously. */
+    nm_clear_g_signal_handler(data->cancellable, &data->cancelled_id);
+    nm_clear_g_source_inst(&data->source);
+    data->callback(data->callback_user_data, data->cancellable);
+    nm_g_object_unref(data->cancellable);
+    nm_g_slice_free(data);
 }
 
 static void
-_nm_utils_invoke_on_idle_start (gboolean use_timeout,
-                                guint timeout_msec,
-                                GCancellable *cancellable,
-                                NMUtilsInvokeOnIdleCallback callback,
-                                gpointer callback_user_data)
-{
-	InvokeOnIdleData *data;
-	GSource *source;
-
-	g_return_if_fail (callback);
-
-	data = g_slice_new (InvokeOnIdleData);
-	*data = (InvokeOnIdleData) {
-		.callback           = callback,
-		.callback_user_data = callback_user_data,
-		.cancellable        = nm_g_object_ref (cancellable),
-		.cancelled_id       = 0,
-	};
-
-	if (cancellable) {
-		if (g_cancellable_is_cancelled (cancellable)) {
-			/* the cancellable is already cancelled. We ignore the timeout
-			 * and always schedule an idle action. */
-			use_timeout = FALSE;
-		} else {
-			/* if we are passed a non-cancelled cancellable, we register to the "cancelled"
-			 * signal an invoke the callback synchronously (from the signal handler).
-			 *
-			 * We don't do that,
-			 *  - if the cancellable is already cancelled (because we don't want to invoke
-			 *    the callback synchronously from the caller).
-			 *  - if we have no cancellable at hand. */
-			data->cancelled_id = g_signal_connect (cancellable,
-			                                       "cancelled",
-			                                       G_CALLBACK (_nm_utils_invoke_on_idle_cb_cancelled),
-			                                       data);
-		}
-	}
-
-	if (use_timeout) {
-		source = nm_g_timeout_source_new (timeout_msec,
-		                                  G_PRIORITY_DEFAULT,
-		                                  _nm_utils_invoke_on_idle_cb_idle,
-		                                  data,
-		                                  NULL);
-	} else {
-		source = nm_g_idle_source_new (G_PRIORITY_DEFAULT,
-		                               _nm_utils_invoke_on_idle_cb_idle,
-		                               data,
-		                               NULL);
-	}
-
-	/* use the current thread default context. */
-	g_source_attach (source,
-	                 g_main_context_get_thread_default ());
-
-	data->source = source;
+_nm_utils_invoke_on_idle_start(gboolean                    use_timeout,
+                               guint                       timeout_msec,
+                               GCancellable *              cancellable,
+                               NMUtilsInvokeOnIdleCallback callback,
+                               gpointer                    callback_user_data)
+{
+    InvokeOnIdleData *data;
+    GSource *         source;
+
+    g_return_if_fail(callback);
+
+    data  = g_slice_new(InvokeOnIdleData);
+    *data = (InvokeOnIdleData){
+        .callback           = callback,
+        .callback_user_data = callback_user_data,
+        .cancellable        = nm_g_object_ref(cancellable),
+        .cancelled_id       = 0,
+    };
+
+    if (cancellable) {
+        if (g_cancellable_is_cancelled(cancellable)) {
+            /* the cancellable is already cancelled. We ignore the timeout
+             * and always schedule an idle action. */
+            use_timeout = FALSE;
+        } else {
+            /* if we are passed a non-cancelled cancellable, we register to the "cancelled"
+             * signal an invoke the callback synchronously (from the signal handler).
+             *
+             * We don't do that,
+             *  - if the cancellable is already cancelled (because we don't want to invoke
+             *    the callback synchronously from the caller).
+             *  - if we have no cancellable at hand. */
+            data->cancelled_id = g_signal_connect(cancellable,
+                                                  "cancelled",
+                                                  G_CALLBACK(_nm_utils_invoke_on_idle_cb_cancelled),
+                                                  data);
+        }
+    }
+
+    if (use_timeout) {
+        source = nm_g_timeout_source_new(timeout_msec,
+                                         G_PRIORITY_DEFAULT,
+                                         _nm_utils_invoke_on_idle_cb_idle,
+                                         data,
+                                         NULL);
+    } else {
+        source =
+            nm_g_idle_source_new(G_PRIORITY_DEFAULT, _nm_utils_invoke_on_idle_cb_idle, data, NULL);
+    }
+
+    /* use the current thread default context. */
+    g_source_attach(source, g_main_context_get_thread_default());
+
+    data->source = source;
 }
 
 void
-nm_utils_invoke_on_idle (GCancellable *cancellable,
-                         NMUtilsInvokeOnIdleCallback callback,
-                         gpointer callback_user_data)
+nm_utils_invoke_on_idle(GCancellable *              cancellable,
+                        NMUtilsInvokeOnIdleCallback callback,
+                        gpointer                    callback_user_data)
 {
-	_nm_utils_invoke_on_idle_start (FALSE, 0, cancellable, callback, callback_user_data);
+    _nm_utils_invoke_on_idle_start(FALSE, 0, cancellable, callback, callback_user_data);
 }
 
 void
-nm_utils_invoke_on_timeout (guint timeout_msec,
-                            GCancellable *cancellable,
-                            NMUtilsInvokeOnIdleCallback callback,
-                            gpointer callback_user_data)
+nm_utils_invoke_on_timeout(guint                       timeout_msec,
+                           GCancellable *              cancellable,
+                           NMUtilsInvokeOnIdleCallback callback,
+                           gpointer                    callback_user_data)
 {
-	_nm_utils_invoke_on_idle_start (TRUE, timeout_msec, cancellable, callback, callback_user_data);
+    _nm_utils_invoke_on_idle_start(TRUE, timeout_msec, cancellable, callback, callback_user_data);
 }
 
 /*****************************************************************************/
 
 int
-nm_utils_getpagesize (void)
+nm_utils_getpagesize(void)
 {
-	static volatile int val = 0;
-	long l;
-	int v;
+    static volatile int val = 0;
+    long                l;
+    int                 v;
 
-	v = g_atomic_int_get (&val);
+    v = g_atomic_int_get(&val);
 
-	if (G_UNLIKELY (v == 0)) {
-		l = sysconf (_SC_PAGESIZE);
+    if (G_UNLIKELY(v == 0)) {
+        l = sysconf(_SC_PAGESIZE);
 
-		g_return_val_if_fail (l > 0 && l < G_MAXINT, 4*1024);
+        g_return_val_if_fail(l > 0 && l < G_MAXINT, 4 * 1024);
 
-		v = (int) l;
-		if (!g_atomic_int_compare_and_exchange (&val, 0, v)) {
-			v = g_atomic_int_get (&val);
-			g_return_val_if_fail (v > 0, 4*1024);
-		}
-	}
+        v = (int) l;
+        if (!g_atomic_int_compare_and_exchange(&val, 0, v)) {
+            v = g_atomic_int_get(&val);
+            g_return_val_if_fail(v > 0, 4 * 1024);
+        }
+    }
 
-	nm_assert (v > 0);
+    nm_assert(v > 0);
 #if NM_MORE_ASSERTS > 5
-	nm_assert (v == getpagesize ());
-	nm_assert (v == sysconf (_SC_PAGESIZE));
+    nm_assert(v == getpagesize());
+    nm_assert(v == sysconf(_SC_PAGESIZE));
 #endif
 
-	return v;
+    return v;
 }
 
 gboolean
-nm_utils_memeqzero (gconstpointer data, gsize length)
+nm_utils_memeqzero(gconstpointer data, gsize length)
 {
-	const unsigned char *p = data;
-	int len;
+    const unsigned char *p = data;
+    int                  len;
 
-	/* Taken from https://github.com/rustyrussell/ccan/blob/9d2d2c49f053018724bcc6e37029da10b7c3d60d/ccan/mem/mem.c#L92,
-	 * CC-0 licensed. */
+    /* Taken from https://github.com/rustyrussell/ccan/blob/9d2d2c49f053018724bcc6e37029da10b7c3d60d/ccan/mem/mem.c#L92,
+     * CC-0 licensed. */
 
-	/* Check first 16 bytes manually */
-	for (len = 0; len < 16; len++) {
-		if (!length)
-			return TRUE;
-		if (*p)
-			return FALSE;
-		p++;
-		length--;
-	}
+    /* Check first 16 bytes manually */
+    for (len = 0; len < 16; len++) {
+        if (!length)
+            return TRUE;
+        if (*p)
+            return FALSE;
+        p++;
+        length--;
+    }
 
-	/* Now we know that's zero, memcmp with self. */
-	return memcmp (data, p, length) == 0;
+    /* Now we know that's zero, memcmp with self. */
+    return memcmp(data, p, length) == 0;
 }
 
 /**
@@ -4046,273 +4340,255 @@ 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,
-                          gsize length,
-                          char delimiter,
-                          gboolean upper_case,
-                          char *out)
-{
-	const guint8 *in = addr;
-	const char *LOOKUP = upper_case ? "0123456789ABCDEF" : "0123456789abcdef";
-	char *out0;
-
-	if (out)
-		out0 = out;
-	else {
-		out0 = out = g_new (char, length == 0
-		                          ? 1u
-		                          : (  delimiter == '\0'
-		                             ? length * 2u + 1u
-		                             : length * 3u));
-	}
-
-	/* @out must contain at least @length*3 bytes if @delimiter is set,
-	 * otherwise, @length*2+1. */
-
-	if (length > 0) {
-		nm_assert (in);
-		for (;;) {
-			const guint8 v = *in++;
-
-			*out++ = LOOKUP[v >> 4];
-			*out++ = LOOKUP[v & 0x0F];
-			length--;
-			if (!length)
-				break;
-			if (delimiter)
-				*out++ = delimiter;
-		}
-	}
-
-	*out = '\0';
-	return out0;
+nm_utils_bin2hexstr_full(gconstpointer addr,
+                         gsize         length,
+                         char          delimiter,
+                         gboolean      upper_case,
+                         char *        out)
+{
+    const guint8 *in     = addr;
+    const char *  LOOKUP = upper_case ? "0123456789ABCDEF" : "0123456789abcdef";
+    char *        out0;
+
+    if (out)
+        out0 = out;
+    else {
+        out0 = out =
+            g_new(char, length == 0 ? 1u : (delimiter == '\0' ? length * 2u + 1u : length * 3u));
+    }
+
+    /* @out must contain at least @length*3 bytes if @delimiter is set,
+     * otherwise, @length*2+1. */
+
+    if (length > 0) {
+        nm_assert(in);
+        for (;;) {
+            const guint8 v = *in++;
+
+            *out++ = LOOKUP[v >> 4];
+            *out++ = LOOKUP[v & 0x0F];
+            length--;
+            if (!length)
+                break;
+            if (delimiter)
+                *out++ = delimiter;
+        }
+    }
+
+    *out = '\0';
+    return out0;
 }
 
 guint8 *
-nm_utils_hexstr2bin_full (const char *hexstr,
-                          gboolean allow_0x_prefix,
-                          gboolean delimiter_required,
-                          const char *delimiter_candidates,
-                          gsize required_len,
-                          guint8 *buffer,
-                          gsize buffer_len,
-                          gsize *out_len)
-{
-	const char *in = hexstr;
-	guint8 *out = buffer;
-	gboolean delimiter_has = TRUE;
-	guint8 delimiter = '\0';
-	gsize len;
-
-	nm_assert (hexstr);
-	nm_assert (buffer);
-	nm_assert (required_len > 0 || out_len);
-
-	if (   allow_0x_prefix
-	    && in[0] == '0'
-	    && in[1] == 'x')
-		in += 2;
-
-	while (TRUE) {
-		const guint8 d1 = in[0];
-		guint8 d2;
-		int i1, i2;
-
-		i1 = nm_utils_hexchar_to_int (d1);
-		if (i1 < 0)
-			goto fail;
-
-		/* If there's no leading zero (ie "aa:b:cc") then fake it */
-		d2 = in[1];
-		if (   d2
-		    && (i2 = nm_utils_hexchar_to_int (d2)) >= 0) {
-			*out++ = (i1 << 4) + i2;
-			d2 = in[2];
-			if (!d2)
-				break;
-			in += 2;
-		} else {
-			/* Fake leading zero */
-			*out++ = i1;
-			if (!d2) {
-				if (!delimiter_has) {
-					/* when using no delimiter, there must be pairs of hex chars */
-					goto fail;
-				}
-				break;
-			}
-			in += 1;
-		}
-
-		if (--buffer_len == 0)
-			goto fail;
-
-		if (delimiter_has) {
-			if (d2 != delimiter) {
-				if (delimiter)
-					goto fail;
-				if (delimiter_candidates) {
-					while (delimiter_candidates[0]) {
-						if (delimiter_candidates++[0] == d2)
-							delimiter = d2;
-					}
-				}
-				if (!delimiter) {
-					if (delimiter_required)
-						goto fail;
-					delimiter_has = FALSE;
-					continue;
-				}
-			}
-			in++;
-		}
-	}
-
-	len = out - buffer;
-	if (   required_len == 0
-	    || len == required_len) {
-		NM_SET_OUT (out_len, len);
-		return buffer;
-	}
+nm_utils_hexstr2bin_full(const char *hexstr,
+                         gboolean    allow_0x_prefix,
+                         gboolean    delimiter_required,
+                         gboolean    hexdigit_pairs_required,
+                         const char *delimiter_candidates,
+                         gsize       required_len,
+                         guint8 *    buffer,
+                         gsize       buffer_len,
+                         gsize *     out_len)
+{
+    const char *in            = hexstr;
+    guint8 *    out           = buffer;
+    gboolean    delimiter_has = TRUE;
+    guint8      delimiter     = '\0';
+    gsize       len;
+
+    nm_assert(hexstr);
+    nm_assert(buffer);
+    nm_assert(required_len > 0 || out_len);
+
+    if (allow_0x_prefix && in[0] == '0' && in[1] == 'x')
+        in += 2;
+
+    while (TRUE) {
+        const guint8 d1 = in[0];
+        guint8       d2;
+        int          i1, i2;
+
+        i1 = nm_utils_hexchar_to_int(d1);
+        if (i1 < 0)
+            goto fail;
+
+        /* If there's no leading zero (ie "aa:b:cc") then fake it */
+        d2 = in[1];
+        if (d2 && (i2 = nm_utils_hexchar_to_int(d2)) >= 0) {
+            *out++ = (i1 << 4) + i2;
+            d2     = in[2];
+            if (!d2)
+                break;
+            in += 2;
+        } else {
+            /* Fake leading zero */
+            *out++ = i1;
+            if (!d2) {
+                if (!delimiter_has || hexdigit_pairs_required) {
+                    /* when using no delimiter, there must be pairs of hex chars */
+                    goto fail;
+                }
+                break;
+            } else if (hexdigit_pairs_required)
+                goto fail;
+            in += 1;
+        }
+
+        if (--buffer_len == 0)
+            goto fail;
+
+        if (delimiter_has) {
+            if (d2 != delimiter) {
+                if (delimiter)
+                    goto fail;
+                if (delimiter_candidates) {
+                    while (delimiter_candidates[0]) {
+                        if (delimiter_candidates++[0] == d2)
+                            delimiter = d2;
+                    }
+                }
+                if (!delimiter) {
+                    if (delimiter_required)
+                        goto fail;
+                    delimiter_has = FALSE;
+                    continue;
+                }
+            }
+            in++;
+        }
+    }
+
+    len = out - buffer;
+    if (required_len == 0 || len == required_len) {
+        NM_SET_OUT(out_len, len);
+        return buffer;
+    }
 
 fail:
-	NM_SET_OUT (out_len, 0);
-	return NULL;
+    NM_SET_OUT(out_len, 0);
+    return NULL;
 }
 
 guint8 *
-nm_utils_hexstr2bin_alloc (const char *hexstr,
-                           gboolean allow_0x_prefix,
-                           gboolean delimiter_required,
-                           const char *delimiter_candidates,
-                           gsize required_len,
-                           gsize *out_len)
-{
-	guint8 *buffer;
-	gsize buffer_len, len;
-
-	if (G_UNLIKELY (!hexstr)) {
-		NM_SET_OUT (out_len, 0);
-		g_return_val_if_fail (hexstr, NULL);
-	}
-
-	nm_assert (required_len > 0 || out_len);
-
-	if (   allow_0x_prefix
-	    && hexstr[0] == '0'
-	    && hexstr[1] == 'x')
-		hexstr += 2;
-
-	if (!hexstr[0])
-		goto fail;
-
-	if (required_len > 0)
-		buffer_len = required_len;
-	else
-		buffer_len = strlen (hexstr) / 2 + 3;
-
-	buffer = g_malloc (buffer_len);
-
-	if (nm_utils_hexstr2bin_full (hexstr,
-	                              FALSE,
-	                              delimiter_required,
-	                              delimiter_candidates,
-	                              required_len,
-	                              buffer,
-	                              buffer_len,
-	                              &len)) {
-		NM_SET_OUT (out_len, len);
-		return buffer;
-	}
-
-	g_free (buffer);
+nm_utils_hexstr2bin_alloc(const char *hexstr,
+                          gboolean    allow_0x_prefix,
+                          gboolean    delimiter_required,
+                          const char *delimiter_candidates,
+                          gsize       required_len,
+                          gsize *     out_len)
+{
+    guint8 *buffer;
+    gsize   buffer_len, len;
+
+    if (G_UNLIKELY(!hexstr)) {
+        NM_SET_OUT(out_len, 0);
+        g_return_val_if_fail(hexstr, NULL);
+    }
+
+    nm_assert(required_len > 0 || out_len);
+
+    if (allow_0x_prefix && hexstr[0] == '0' && hexstr[1] == 'x')
+        hexstr += 2;
+
+    if (!hexstr[0])
+        goto fail;
+
+    if (required_len > 0)
+        buffer_len = required_len;
+    else
+        buffer_len = strlen(hexstr) / 2 + 3;
+
+    buffer = g_malloc(buffer_len);
+
+    if (nm_utils_hexstr2bin_full(hexstr,
+                                 FALSE,
+                                 delimiter_required,
+                                 FALSE,
+                                 delimiter_candidates,
+                                 required_len,
+                                 buffer,
+                                 buffer_len,
+                                 &len)) {
+        NM_SET_OUT(out_len, len);
+        return buffer;
+    }
+
+    g_free(buffer);
 
 fail:
-	NM_SET_OUT (out_len, 0);
-	return NULL;
+    NM_SET_OUT(out_len, 0);
+    return NULL;
 }
 
 /*****************************************************************************/
 
 GVariant *
-nm_utils_gvariant_vardict_filter (GVariant *src,
-                                  gboolean (*filter_fcn) (const char *key,
-                                                          GVariant *val,
-                                                          char **out_key,
-                                                          GVariant **out_val,
-                                                          gpointer user_data),
-                                  gpointer user_data)
-{
-	GVariantIter iter;
-	GVariantBuilder builder;
-	const char *key;
-	GVariant *val;
-
-	g_return_val_if_fail (src && g_variant_is_of_type (src, G_VARIANT_TYPE_VARDICT), NULL);
-	g_return_val_if_fail (filter_fcn, NULL);
-
-	g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
-
-	g_variant_iter_init (&iter, src);
-	while (g_variant_iter_next (&iter, "{&sv}", &key, &val)) {
-		_nm_unused gs_unref_variant GVariant *val_free = val;
-		gs_free char *key2 = NULL;
-		gs_unref_variant GVariant *val2 = NULL;
-
-		if (filter_fcn (key,
-		                val,
-		                &key2,
-		                &val2,
-		                user_data)) {
-			g_variant_builder_add (&builder,
-			                       "{sv}",
-			                       key2 ?: key,
-			                       val2 ?: val);
-		}
-	}
-
-	return g_variant_builder_end (&builder);
+nm_utils_gvariant_vardict_filter(GVariant *src,
+                                 gboolean (*filter_fcn)(const char *key,
+                                                        GVariant *  val,
+                                                        char **     out_key,
+                                                        GVariant ** out_val,
+                                                        gpointer    user_data),
+                                 gpointer user_data)
+{
+    GVariantIter    iter;
+    GVariantBuilder builder;
+    const char *    key;
+    GVariant *      val;
+
+    g_return_val_if_fail(src && g_variant_is_of_type(src, G_VARIANT_TYPE_VARDICT), NULL);
+    g_return_val_if_fail(filter_fcn, NULL);
+
+    g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+
+    g_variant_iter_init(&iter, src);
+    while (g_variant_iter_next(&iter, "{&sv}", &key, &val)) {
+        _nm_unused gs_unref_variant GVariant *val_free = val;
+        gs_free char *                        key2     = NULL;
+        gs_unref_variant GVariant *val2                = NULL;
+
+        if (filter_fcn(key, val, &key2, &val2, user_data)) {
+            g_variant_builder_add(&builder, "{sv}", key2 ?: key, val2 ?: val);
+        }
+    }
+
+    return g_variant_builder_end(&builder);
 }
 
 static gboolean
-_gvariant_vardict_filter_drop_one (const char *key,
-                                   GVariant *val,
-                                   char **out_key,
-                                   GVariant **out_val,
-                                   gpointer user_data)
+_gvariant_vardict_filter_drop_one(const char *key,
+                                  GVariant *  val,
+                                  char **     out_key,
+                                  GVariant ** out_val,
+                                  gpointer    user_data)
 {
-	return !nm_streq (key, user_data);
+    return !nm_streq(key, user_data);
 }
 
 GVariant *
-nm_utils_gvariant_vardict_filter_drop_one (GVariant *src,
-                                           const char *key)
+nm_utils_gvariant_vardict_filter_drop_one(GVariant *src, const char *key)
 {
-	return nm_utils_gvariant_vardict_filter (src,
-	                                         _gvariant_vardict_filter_drop_one,
-	                                         (gpointer) key);
+    return nm_utils_gvariant_vardict_filter(src, _gvariant_vardict_filter_drop_one, (gpointer) key);
 }
 
 /*****************************************************************************/
 
 static gboolean
-debug_key_matches (const char *key,
-                   const char *token,
-                   guint        length)
+debug_key_matches(const char *key, const char *token, guint length)
 {
-	/* may not call GLib functions: see note in g_parse_debug_string() */
-	for (; length; length--, key++, token++) {
-		char k = (*key   == '_') ? '-' : g_ascii_tolower (*key  );
-		char t = (*token == '_') ? '-' : g_ascii_tolower (*token);
+    /* may not call GLib functions: see note in g_parse_debug_string() */
+    for (; length; length--, key++, token++) {
+        char k = (*key == '_') ? '-' : g_ascii_tolower(*key);
+        char t = (*token == '_') ? '-' : g_ascii_tolower(*token);
 
-		if (k != t)
-			return FALSE;
-	}
+        if (k != t)
+            return FALSE;
+    }
 
-	return *key == '\0';
+    return *key == '\0';
 }
 
 /**
@@ -4327,415 +4603,436 @@ debug_key_matches (const char *key,
  * Returns: the flags
  */
 guint
-nm_utils_parse_debug_string (const char *string,
-                             const GDebugKey *keys,
-                             guint nkeys)
+nm_utils_parse_debug_string(const char *string, const GDebugKey *keys, guint nkeys)
 {
-	guint i;
-	guint result = 0;
-	const char *q;
+    guint       i;
+    guint       result = 0;
+    const char *q;
 
-	if (string == NULL)
-		return 0;
+    if (string == NULL)
+        return 0;
 
-	while (*string) {
-		q = strpbrk (string, ":;, \t");
-		if (!q)
-			q = string + strlen (string);
+    while (*string) {
+        q = strpbrk(string, ":;, \t");
+        if (!q)
+            q = string + strlen(string);
 
-		for (i = 0; i < nkeys; i++) {
-			if (debug_key_matches (keys[i].key, string, q - string))
-				result |= keys[i].value;
-		}
+        for (i = 0; i < nkeys; i++) {
+            if (debug_key_matches(keys[i].key, string, q - string))
+                result |= keys[i].value;
+        }
 
-		string = q;
-		if (*string)
-			string++;
-	}
+        string = q;
+        if (*string)
+            string++;
+    }
 
-	return result;
+    return result;
 }
 
 /*****************************************************************************/
 
 GSource *
-nm_g_idle_source_new (int priority,
-                      GSourceFunc func,
-                      gpointer user_data,
-                      GDestroyNotify destroy_notify)
+nm_g_idle_source_new(int            priority,
+                     GSourceFunc    func,
+                     gpointer       user_data,
+                     GDestroyNotify destroy_notify)
 {
-	GSource *source;
+    GSource *source;
 
-	source = g_idle_source_new ();
-	if (priority != G_PRIORITY_DEFAULT)
-		g_source_set_priority (source, priority);
-	g_source_set_callback (source, func, user_data, destroy_notify);
-	return source;
+    source = g_idle_source_new();
+    if (priority != G_PRIORITY_DEFAULT)
+        g_source_set_priority(source, priority);
+    g_source_set_callback(source, func, user_data, destroy_notify);
+    return source;
 }
 
 GSource *
-nm_g_timeout_source_new (guint timeout_msec,
-                         int priority,
-                         GSourceFunc func,
-                         gpointer user_data,
-                         GDestroyNotify destroy_notify)
+nm_g_timeout_source_new(guint          timeout_msec,
+                        int            priority,
+                        GSourceFunc    func,
+                        gpointer       user_data,
+                        GDestroyNotify destroy_notify)
 {
-	GSource *source;
+    GSource *source;
 
-	source = g_timeout_source_new (timeout_msec);
-	if (priority != G_PRIORITY_DEFAULT)
-		g_source_set_priority (source, priority);
-	g_source_set_callback (source, func, user_data, destroy_notify);
-	return source;
+    source = g_timeout_source_new(timeout_msec);
+    if (priority != G_PRIORITY_DEFAULT)
+        g_source_set_priority(source, priority);
+    g_source_set_callback(source, func, user_data, destroy_notify);
+    return source;
 }
 
 GSource *
-nm_g_unix_signal_source_new (int signum,
-                             int priority,
-                             GSourceFunc handler,
-                             gpointer user_data,
-                             GDestroyNotify notify)
+nm_g_timeout_source_new_seconds(guint          timeout_sec,
+                                int            priority,
+                                GSourceFunc    func,
+                                gpointer       user_data,
+                                GDestroyNotify destroy_notify)
 {
-	GSource *source;
+    GSource *source;
 
-	source = g_unix_signal_source_new (signum);
+    source = g_timeout_source_new_seconds(timeout_sec);
+    if (priority != G_PRIORITY_DEFAULT)
+        g_source_set_priority(source, priority);
+    g_source_set_callback(source, func, user_data, destroy_notify);
+    return source;
+}
+
+GSource *
+nm_g_unix_signal_source_new(int            signum,
+                            int            priority,
+                            GSourceFunc    handler,
+                            gpointer       user_data,
+                            GDestroyNotify notify)
+{
+    GSource *source;
+
+    source = g_unix_signal_source_new(signum);
 
-	if (priority != G_PRIORITY_DEFAULT)
-		g_source_set_priority (source, priority);
-	g_source_set_callback (source, handler, user_data, notify);
-	return source;
+    if (priority != G_PRIORITY_DEFAULT)
+        g_source_set_priority(source, priority);
+    g_source_set_callback(source, handler, user_data, notify);
+    return source;
 }
 
 GSource *
-nm_g_unix_fd_source_new (int fd,
-                         GIOCondition io_condition,
-                         int priority,
-                         gboolean (*source_func) (int fd,
-                                                  GIOCondition condition,
-                                                  gpointer user_data),
-                         gpointer user_data,
-                         GDestroyNotify destroy_notify)
+nm_g_unix_fd_source_new(int          fd,
+                        GIOCondition io_condition,
+                        int          priority,
+                        gboolean (*source_func)(int fd, GIOCondition condition, gpointer user_data),
+                        gpointer       user_data,
+                        GDestroyNotify destroy_notify)
 {
-	GSource *source;
+    GSource *source;
 
-	source = g_unix_fd_source_new (fd, io_condition);
+    source = g_unix_fd_source_new(fd, io_condition);
 
-	if (priority != G_PRIORITY_DEFAULT)
-		g_source_set_priority (source, priority);
-	g_source_set_callback (source, G_SOURCE_FUNC (source_func), user_data, destroy_notify);
-	return source;
+    if (priority != G_PRIORITY_DEFAULT)
+        g_source_set_priority(source, priority);
+    g_source_set_callback(source, G_SOURCE_FUNC(source_func), user_data, destroy_notify);
+    return source;
 }
 
 /*****************************************************************************/
 
-#define _CTX_LOG(fmt, ...) \
-	G_STMT_START { \
-		if (FALSE) { \
-			gint64 _ts = g_get_monotonic_time () / 100; \
-			\
-			g_printerr (">>>> [%"G_GINT64_FORMAT".%05"G_GINT64_FORMAT"] [src:%p]: " fmt "\n", \
-			            _ts / 10000, \
-			            _ts % 10000, \
-			            (ctx_src), \
-			            ##__VA_ARGS__); \
-		} \
-	} G_STMT_END
+#define _CTX_LOG(fmt, ...)                                                                       \
+    G_STMT_START                                                                                 \
+    {                                                                                            \
+        if (FALSE) {                                                                             \
+            gint64 _ts = g_get_monotonic_time() / 100;                                           \
+                                                                                                 \
+            g_printerr(">>>> [%" G_GINT64_FORMAT ".%05" G_GINT64_FORMAT "] [src:%p]: " fmt "\n", \
+                       _ts / 10000,                                                              \
+                       _ts % 10000,                                                              \
+                       (ctx_src),                                                                \
+                       ##__VA_ARGS__);                                                           \
+        }                                                                                        \
+    }                                                                                            \
+    G_STMT_END
 
 typedef struct {
-	int fd;
-	guint events;
-	guint registered_events;
-	union {
-		int one;
-		int *many;
-	} idx;
-	gpointer tag;
-	bool stale:1;
-	bool has_many_idx:1;
+    int   fd;
+    guint events;
+    guint registered_events;
+    union {
+        int  one;
+        int *many;
+    } idx;
+    gpointer tag;
+    bool     stale : 1;
+    bool     has_many_idx : 1;
 } PollData;
 
 typedef struct {
-	GSource source;
-	GMainContext *context;
-	GHashTable *fds;
-	GPollFD *fds_arr;
-	int fds_len;
-	int max_priority;
-	bool acquired:1;
+    GSource       source;
+    GMainContext *context;
+    GHashTable *  fds;
+    GPollFD *     fds_arr;
+    int           fds_len;
+    int           max_priority;
+    bool          acquired : 1;
 } CtxIntegSource;
 
 static void
-_poll_data_free (gpointer user_data)
+_poll_data_free(gpointer user_data)
 {
-	PollData *poll_data = user_data;
+    PollData *poll_data = user_data;
 
-	if (poll_data->has_many_idx)
-		g_free (poll_data->idx.many);
-	nm_g_slice_free (poll_data);
+    if (poll_data->has_many_idx)
+        g_free(poll_data->idx.many);
+    nm_g_slice_free(poll_data);
 }
 
 static void
-_ctx_integ_source_reacquire (CtxIntegSource *ctx_src)
+_ctx_integ_source_reacquire(CtxIntegSource *ctx_src)
 {
-	if (G_LIKELY (   ctx_src->acquired
-	              && g_main_context_is_owner (ctx_src->context)))
-		return;
+    if (G_LIKELY(ctx_src->acquired && g_main_context_is_owner(ctx_src->context)))
+        return;
 
-	/* the parent context now iterates on a different thread.
-	 * We need to release and reacquire the inner context. */
+    /* the parent context now iterates on a different thread.
+     * We need to release and reacquire the inner context. */
 
-	if (ctx_src->acquired)
-		g_main_context_release (ctx_src->context);
+    if (ctx_src->acquired)
+        g_main_context_release(ctx_src->context);
 
-	if (G_UNLIKELY (!g_main_context_acquire (ctx_src->context))) {
-		/* Nobody is supposed to reacquire the context while we use it. This is a bug
-		 * of the user. */
-		ctx_src->acquired = FALSE;
-		g_return_if_reached ();
-	}
-	ctx_src->acquired = TRUE;
+    if (G_UNLIKELY(!g_main_context_acquire(ctx_src->context))) {
+        /* Nobody is supposed to reacquire the context while we use it. This is a bug
+         * of the user. */
+        ctx_src->acquired = FALSE;
+        g_return_if_reached();
+    }
+    ctx_src->acquired = TRUE;
 }
 
 static gboolean
-_ctx_integ_source_prepare (GSource *source,
-                           int *out_timeout)
-{
-	CtxIntegSource *ctx_src = ((CtxIntegSource *) source);
-	int max_priority;
-	int timeout = -1;
-	gboolean any_ready;
-	int fds_allocated;
-	int fds_len_old;
-	gs_free GPollFD *fds_arr_old = NULL;
-	GHashTableIter h_iter;
-	PollData *poll_data;
-	gboolean fds_changed;
-	int i;
-
-	_CTX_LOG ("prepare...");
-
-	_ctx_integ_source_reacquire (ctx_src);
-
-	any_ready = g_main_context_prepare (ctx_src->context, &max_priority);
-
-	fds_arr_old = g_steal_pointer (&ctx_src->fds_arr);
-	fds_len_old = ctx_src->fds_len;
-
-	fds_allocated = NM_MAX (1, fds_len_old); /* there is at least the wakeup's FD */
-	ctx_src->fds_arr = g_new (GPollFD, fds_allocated);
-
-	while ((ctx_src->fds_len = g_main_context_query (ctx_src->context,
-	                                                 max_priority,
-	                                                 &timeout,
-	                                                 ctx_src->fds_arr,
-	                                                 fds_allocated)) > fds_allocated) {
-		fds_allocated = ctx_src->fds_len;
-		g_free (ctx_src->fds_arr);
-		ctx_src->fds_arr = g_new (GPollFD, fds_allocated);
-	}
-
-	fds_changed = FALSE;
-	if (fds_len_old != ctx_src->fds_len)
-		fds_changed = TRUE;
-	else {
-		for (i = 0; i < ctx_src->fds_len; i++) {
-			if (   fds_arr_old[i].fd != ctx_src->fds_arr[i].fd
-			    || fds_arr_old[i].events != ctx_src->fds_arr[i].events) {
-				fds_changed = TRUE;
-				break;
-			}
-		}
-	}
-
-	if (G_UNLIKELY (fds_changed)) {
-
-		g_hash_table_iter_init (&h_iter, ctx_src->fds);
-		while (g_hash_table_iter_next (&h_iter, (gpointer *) &poll_data, NULL))
-			poll_data->stale = TRUE;
-
-		for (i = 0; i < ctx_src->fds_len; i++) {
-			const GPollFD *fd = &ctx_src->fds_arr[i];
-
-			poll_data = g_hash_table_lookup (ctx_src->fds, &fd->fd);
-
-			if (G_UNLIKELY (!poll_data)) {
-				poll_data = g_slice_new (PollData);
-				*poll_data = (PollData) {
-					.fd                = fd->fd,
-					.idx.one           = i,
-					.has_many_idx      = FALSE,
-					.events            = fd->events,
-					.registered_events = 0,
-					.tag               = NULL,
-					.stale             = FALSE,
-				};
-				g_hash_table_add (ctx_src->fds, poll_data);
-				nm_assert (poll_data == g_hash_table_lookup (ctx_src->fds, &fd->fd));
-				continue;
-			}
-
-			if (G_LIKELY (poll_data->stale)) {
-				if (poll_data->has_many_idx) {
-					g_free (poll_data->idx.many);
-					poll_data->has_many_idx = FALSE;
-				}
-				poll_data->events = fd->events;
-				poll_data->idx.one = i;
-				poll_data->stale = FALSE;
-				continue;
-			}
-
-			/* How odd. We have duplicate FDs. In fact, currently g_main_context_query() always
-			 * coalesces the FDs and this cannot happen. However, that is not documented behavior,
-			 * so we should not rely on that. So we need to keep a list of indexes... */
-			poll_data->events |= fd->events;
-			if (!poll_data->has_many_idx) {
-				int idx0;
-
-				idx0 = poll_data->idx.one;
-				poll_data->has_many_idx = TRUE;
-				poll_data->idx.many = g_new (int, 4);
-				poll_data->idx.many[0] = 2; /* number allocated */
-				poll_data->idx.many[1] = 2; /* number used */
-				poll_data->idx.many[2] = idx0;
-				poll_data->idx.many[3] = i;
-			} else {
-				if (poll_data->idx.many[0] == poll_data->idx.many[1]) {
-					poll_data->idx.many[0] *= 2;
-					poll_data->idx.many = g_realloc (poll_data->idx.many, sizeof (int) * (2 + poll_data->idx.many[0]));
-				}
-				poll_data->idx.many[2 + poll_data->idx.many[1]] = i;
-				poll_data->idx.many[1]++;
-			}
-
-		}
-
-		g_hash_table_iter_init (&h_iter, ctx_src->fds);
-		while (g_hash_table_iter_next (&h_iter, (gpointer *) &poll_data, NULL)) {
-			if (poll_data->stale) {
-				nm_assert (poll_data->tag);
-				nm_assert (poll_data->events == poll_data->registered_events);
-				_CTX_LOG ("prepare: remove poll fd=%d, events=0x%x", poll_data->fd, poll_data->events);
-				g_source_remove_unix_fd (&ctx_src->source, poll_data->tag);
-				g_hash_table_iter_remove (&h_iter);
-				continue;
-			}
-			if (!poll_data->tag) {
-				_CTX_LOG ("prepare: add poll fd=%d, events=0x%x", poll_data->fd, poll_data->events);
-				poll_data->registered_events = poll_data->events;
-				poll_data->tag = g_source_add_unix_fd (&ctx_src->source, poll_data->fd, poll_data->registered_events);
-				continue;
-			}
-			if (poll_data->registered_events != poll_data->events) {
-				_CTX_LOG ("prepare: update poll fd=%d, events=0x%x", poll_data->fd, poll_data->events);
-				poll_data->registered_events = poll_data->events;
-				g_source_modify_unix_fd (&ctx_src->source, poll_data->tag, poll_data->registered_events);
-			}
-		}
-	}
-
-	NM_SET_OUT (out_timeout, timeout);
-	ctx_src->max_priority = max_priority;
-
-	_CTX_LOG ("prepare: done, any-ready=%d, timeout=%d, max-priority=%d", any_ready, timeout, max_priority);
-
-	/* we always need to poll, because we have some file descriptors. */
-	return FALSE;
+_ctx_integ_source_prepare(GSource *source, int *out_timeout)
+{
+    CtxIntegSource *ctx_src = ((CtxIntegSource *) source);
+    int             max_priority;
+    int             timeout = -1;
+    gboolean        any_ready;
+    int             fds_allocated;
+    int             fds_len_old;
+    gs_free GPollFD *fds_arr_old = NULL;
+    GHashTableIter   h_iter;
+    PollData *       poll_data;
+    gboolean         fds_changed;
+    int              i;
+
+    _CTX_LOG("prepare...");
+
+    _ctx_integ_source_reacquire(ctx_src);
+
+    any_ready = g_main_context_prepare(ctx_src->context, &max_priority);
+
+    fds_arr_old = g_steal_pointer(&ctx_src->fds_arr);
+    fds_len_old = ctx_src->fds_len;
+
+    fds_allocated    = NM_MAX(1, fds_len_old); /* there is at least the wakeup's FD */
+    ctx_src->fds_arr = g_new(GPollFD, fds_allocated);
+
+    while ((ctx_src->fds_len = g_main_context_query(ctx_src->context,
+                                                    max_priority,
+                                                    &timeout,
+                                                    ctx_src->fds_arr,
+                                                    fds_allocated))
+           > fds_allocated) {
+        fds_allocated = ctx_src->fds_len;
+        g_free(ctx_src->fds_arr);
+        ctx_src->fds_arr = g_new(GPollFD, fds_allocated);
+    }
+
+    fds_changed = FALSE;
+    if (fds_len_old != ctx_src->fds_len)
+        fds_changed = TRUE;
+    else {
+        for (i = 0; i < ctx_src->fds_len; i++) {
+            if (fds_arr_old[i].fd != ctx_src->fds_arr[i].fd
+                || fds_arr_old[i].events != ctx_src->fds_arr[i].events) {
+                fds_changed = TRUE;
+                break;
+            }
+        }
+    }
+
+    if (G_UNLIKELY(fds_changed)) {
+        g_hash_table_iter_init(&h_iter, ctx_src->fds);
+        while (g_hash_table_iter_next(&h_iter, (gpointer *) &poll_data, NULL))
+            poll_data->stale = TRUE;
+
+        for (i = 0; i < ctx_src->fds_len; i++) {
+            const GPollFD *fd = &ctx_src->fds_arr[i];
+
+            poll_data = g_hash_table_lookup(ctx_src->fds, &fd->fd);
+
+            if (G_UNLIKELY(!poll_data)) {
+                poll_data  = g_slice_new(PollData);
+                *poll_data = (PollData){
+                    .fd                = fd->fd,
+                    .idx.one           = i,
+                    .has_many_idx      = FALSE,
+                    .events            = fd->events,
+                    .registered_events = 0,
+                    .tag               = NULL,
+                    .stale             = FALSE,
+                };
+                g_hash_table_add(ctx_src->fds, poll_data);
+                nm_assert(poll_data == g_hash_table_lookup(ctx_src->fds, &fd->fd));
+                continue;
+            }
+
+            if (G_LIKELY(poll_data->stale)) {
+                if (poll_data->has_many_idx) {
+                    g_free(poll_data->idx.many);
+                    poll_data->has_many_idx = FALSE;
+                }
+                poll_data->events  = fd->events;
+                poll_data->idx.one = i;
+                poll_data->stale   = FALSE;
+                continue;
+            }
+
+            /* How odd. We have duplicate FDs. In fact, currently g_main_context_query() always
+             * coalesces the FDs and this cannot happen. However, that is not documented behavior,
+             * so we should not rely on that. So we need to keep a list of indexes... */
+            poll_data->events |= fd->events;
+            if (!poll_data->has_many_idx) {
+                int idx0;
+
+                idx0                    = poll_data->idx.one;
+                poll_data->has_many_idx = TRUE;
+                poll_data->idx.many     = g_new(int, 4);
+                poll_data->idx.many[0]  = 2; /* number allocated */
+                poll_data->idx.many[1]  = 2; /* number used */
+                poll_data->idx.many[2]  = idx0;
+                poll_data->idx.many[3]  = i;
+            } else {
+                if (poll_data->idx.many[0] == poll_data->idx.many[1]) {
+                    poll_data->idx.many[0] *= 2;
+                    poll_data->idx.many =
+                        g_realloc(poll_data->idx.many, sizeof(int) * (2 + poll_data->idx.many[0]));
+                }
+                poll_data->idx.many[2 + poll_data->idx.many[1]] = i;
+                poll_data->idx.many[1]++;
+            }
+        }
+
+        g_hash_table_iter_init(&h_iter, ctx_src->fds);
+        while (g_hash_table_iter_next(&h_iter, (gpointer *) &poll_data, NULL)) {
+            if (poll_data->stale) {
+                nm_assert(poll_data->tag);
+                nm_assert(poll_data->events == poll_data->registered_events);
+                _CTX_LOG("prepare: remove poll fd=%d, events=0x%x",
+                         poll_data->fd,
+                         poll_data->events);
+                g_source_remove_unix_fd(&ctx_src->source, poll_data->tag);
+                g_hash_table_iter_remove(&h_iter);
+                continue;
+            }
+            if (!poll_data->tag) {
+                _CTX_LOG("prepare: add poll fd=%d, events=0x%x", poll_data->fd, poll_data->events);
+                poll_data->registered_events = poll_data->events;
+                poll_data->tag               = g_source_add_unix_fd(&ctx_src->source,
+                                                      poll_data->fd,
+                                                      poll_data->registered_events);
+                continue;
+            }
+            if (poll_data->registered_events != poll_data->events) {
+                _CTX_LOG("prepare: update poll fd=%d, events=0x%x",
+                         poll_data->fd,
+                         poll_data->events);
+                poll_data->registered_events = poll_data->events;
+                g_source_modify_unix_fd(&ctx_src->source,
+                                        poll_data->tag,
+                                        poll_data->registered_events);
+            }
+        }
+    }
+
+    NM_SET_OUT(out_timeout, timeout);
+    ctx_src->max_priority = max_priority;
+
+    _CTX_LOG("prepare: done, any-ready=%d, timeout=%d, max-priority=%d",
+             any_ready,
+             timeout,
+             max_priority);
+
+    /* we always need to poll, because we have some file descriptors. */
+    return FALSE;
 }
 
 static gboolean
-_ctx_integ_source_check (GSource *source)
+_ctx_integ_source_check(GSource *source)
 {
-	CtxIntegSource *ctx_src = ((CtxIntegSource *) source);
-	GHashTableIter h_iter;
-	gboolean some_ready;
-	PollData *poll_data;
+    CtxIntegSource *ctx_src = ((CtxIntegSource *) source);
+    GHashTableIter  h_iter;
+    gboolean        some_ready;
+    PollData *      poll_data;
 
-	nm_assert (ctx_src->context);
+    nm_assert(ctx_src->context);
 
-	_CTX_LOG ("check");
+    _CTX_LOG("check");
 
-	_ctx_integ_source_reacquire (ctx_src);
+    _ctx_integ_source_reacquire(ctx_src);
 
-	g_hash_table_iter_init (&h_iter, ctx_src->fds);
-	while (g_hash_table_iter_next (&h_iter, (gpointer *) &poll_data, NULL)) {
-		guint revents;
+    g_hash_table_iter_init(&h_iter, ctx_src->fds);
+    while (g_hash_table_iter_next(&h_iter, (gpointer *) &poll_data, NULL)) {
+        guint revents;
 
-		revents = g_source_query_unix_fd (&ctx_src->source, poll_data->tag);
-		if (G_UNLIKELY (poll_data->has_many_idx)) {
-			int num = poll_data->idx.many[1];
-			int *p_idx = &poll_data->idx.many[2];
+        revents = g_source_query_unix_fd(&ctx_src->source, poll_data->tag);
+        if (G_UNLIKELY(poll_data->has_many_idx)) {
+            int  num   = poll_data->idx.many[1];
+            int *p_idx = &poll_data->idx.many[2];
 
-			for (; num > 0; num--, p_idx++)
-				ctx_src->fds_arr[*p_idx].revents = revents;
-		} else
-			ctx_src->fds_arr[poll_data->idx.one].revents = revents;
-	}
+            for (; num > 0; num--, p_idx++)
+                ctx_src->fds_arr[*p_idx].revents = revents;
+        } else
+            ctx_src->fds_arr[poll_data->idx.one].revents = revents;
+    }
 
-	some_ready = g_main_context_check (ctx_src->context,
-	                                   ctx_src->max_priority,
-	                                   ctx_src->fds_arr,
-	                                   ctx_src->fds_len);
+    some_ready = g_main_context_check(ctx_src->context,
+                                      ctx_src->max_priority,
+                                      ctx_src->fds_arr,
+                                      ctx_src->fds_len);
 
-	_CTX_LOG ("check (some-ready=%d)...", some_ready);
+    _CTX_LOG("check (some-ready=%d)...", some_ready);
 
-	return some_ready;
+    return some_ready;
 }
 
 static gboolean
-_ctx_integ_source_dispatch (GSource *source,
-                            GSourceFunc callback,
-                            gpointer user_data)
+_ctx_integ_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
 {
-	CtxIntegSource *ctx_src = ((CtxIntegSource *) source);
+    CtxIntegSource *ctx_src = ((CtxIntegSource *) source);
 
-	nm_assert (ctx_src->context);
+    nm_assert(ctx_src->context);
 
-	_ctx_integ_source_reacquire (ctx_src);
+    _ctx_integ_source_reacquire(ctx_src);
 
-	_CTX_LOG ("dispatch");
+    _CTX_LOG("dispatch");
 
-	g_main_context_dispatch (ctx_src->context);
+    g_main_context_dispatch(ctx_src->context);
 
-	return G_SOURCE_CONTINUE;
+    return G_SOURCE_CONTINUE;
 }
 
 static void
-_ctx_integ_source_finalize (GSource *source)
+_ctx_integ_source_finalize(GSource *source)
 {
-	CtxIntegSource *ctx_src = ((CtxIntegSource *) source);
-	GHashTableIter h_iter;
-	PollData *poll_data;
+    CtxIntegSource *ctx_src = ((CtxIntegSource *) source);
+    GHashTableIter  h_iter;
+    PollData *      poll_data;
 
-	g_return_if_fail (ctx_src->context);
+    g_return_if_fail(ctx_src->context);
 
-	_CTX_LOG ("finalize...");
+    _CTX_LOG("finalize...");
 
-	g_hash_table_iter_init (&h_iter, ctx_src->fds);
-	while (g_hash_table_iter_next (&h_iter, (gpointer *) &poll_data, NULL)) {
-		nm_assert (poll_data->tag);
-		_CTX_LOG ("prepare: remove poll fd=%d, events=0x%x", poll_data->fd, poll_data->events);
-		g_source_remove_unix_fd (&ctx_src->source, poll_data->tag);
-		g_hash_table_iter_remove (&h_iter);
-	}
+    g_hash_table_iter_init(&h_iter, ctx_src->fds);
+    while (g_hash_table_iter_next(&h_iter, (gpointer *) &poll_data, NULL)) {
+        nm_assert(poll_data->tag);
+        _CTX_LOG("prepare: remove poll fd=%d, events=0x%x", poll_data->fd, poll_data->events);
+        g_source_remove_unix_fd(&ctx_src->source, poll_data->tag);
+        g_hash_table_iter_remove(&h_iter);
+    }
 
-	nm_clear_pointer (&ctx_src->fds, g_hash_table_unref);
-	nm_clear_g_free (&ctx_src->fds_arr);
-	ctx_src->fds_len = 0;
+    nm_clear_pointer(&ctx_src->fds, g_hash_table_unref);
+    nm_clear_g_free(&ctx_src->fds_arr);
+    ctx_src->fds_len = 0;
 
-	if (ctx_src->acquired) {
-		ctx_src->acquired = FALSE;
-		g_main_context_release (ctx_src->context);
-	}
+    if (ctx_src->acquired) {
+        ctx_src->acquired = FALSE;
+        g_main_context_release(ctx_src->context);
+    }
 
-	nm_clear_pointer (&ctx_src->context, g_main_context_unref);
+    nm_clear_pointer(&ctx_src->context, g_main_context_unref);
 }
 
 static GSourceFuncs ctx_integ_source_funcs = {
-	.prepare  = _ctx_integ_source_prepare,
-	.check    = _ctx_integ_source_check,
-	.dispatch = _ctx_integ_source_dispatch,
-	.finalize = _ctx_integ_source_finalize,
+    .prepare  = _ctx_integ_source_prepare,
+    .check    = _ctx_integ_source_check,
+    .dispatch = _ctx_integ_source_dispatch,
+    .finalize = _ctx_integ_source_finalize,
 };
 
 /**
@@ -4760,260 +5057,260 @@ static GSourceFuncs ctx_integ_source_funcs = {
  *   outer context.
  */
 GSource *
-nm_utils_g_main_context_create_integrate_source (GMainContext *inner_context)
+nm_utils_g_main_context_create_integrate_source(GMainContext *inner_context)
 {
-	CtxIntegSource *ctx_src;
+    CtxIntegSource *ctx_src;
 
-	g_return_val_if_fail (inner_context, NULL);
+    g_return_val_if_fail(inner_context, NULL);
 
-	if (!g_main_context_acquire (inner_context)) {
-		/* We require to acquire the context while it's integrated. We need to keep it acquired
-		 * for the entire duration.
-		 *
-		 * This is also necessary because g_source_attach() only wakes up the context, if
-		 * the context is currently acquired. */
-		g_return_val_if_reached (NULL);
-	}
+    if (!g_main_context_acquire(inner_context)) {
+        /* We require to acquire the context while it's integrated. We need to keep it acquired
+         * for the entire duration.
+         *
+         * This is also necessary because g_source_attach() only wakes up the context, if
+         * the context is currently acquired. */
+        g_return_val_if_reached(NULL);
+    }
 
-	ctx_src = (CtxIntegSource *) g_source_new (&ctx_integ_source_funcs, sizeof (CtxIntegSource));
+    ctx_src = (CtxIntegSource *) g_source_new(&ctx_integ_source_funcs, sizeof(CtxIntegSource));
 
-	g_source_set_name (&ctx_src->source, "ContextIntegrateSource");
+    g_source_set_name(&ctx_src->source, "ContextIntegrateSource");
 
-	ctx_src->context = g_main_context_ref (inner_context);
-	ctx_src->fds = g_hash_table_new_full (nm_pint_hash, nm_pint_equals, _poll_data_free, NULL);
-	ctx_src->fds_len = 0;
-	ctx_src->fds_arr = NULL;
-	ctx_src->acquired = TRUE;
-	ctx_src->max_priority = G_MAXINT;
+    ctx_src->context  = g_main_context_ref(inner_context);
+    ctx_src->fds      = g_hash_table_new_full(nm_pint_hash, nm_pint_equals, _poll_data_free, NULL);
+    ctx_src->fds_len  = 0;
+    ctx_src->fds_arr  = NULL;
+    ctx_src->acquired = TRUE;
+    ctx_src->max_priority = G_MAXINT;
 
-	_CTX_LOG ("create new integ-source for %p", inner_context);
+    _CTX_LOG("create new integ-source for %p", inner_context);
 
-	return &ctx_src->source;
+    return &ctx_src->source;
 }
 
 gboolean
-nm_utils_ifname_valid_kernel (const char *name, GError **error)
-{
-	int i;
-
-	/* This function follows kernel's interface validation
-	 * function dev_valid_name() in net/core/dev.c.
-	 */
-
-	if (!name) {
-		g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-		                     _("interface name is missing"));
-		return FALSE;
-	}
-
-	if (name[0] == '\0') {
-		g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-		                     _("interface name is too short"));
-		return FALSE;
-	}
-
-	if (   name[0] == '.'
-	    && (   name[1] == '\0'
-	        || (   name[1] == '.'
-	            && name[2] == '\0'))) {
-		g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-		                     _("interface name is reserved"));
-		return FALSE;
-	}
-
-	for (i = 0; i < IFNAMSIZ; i++) {
-		char ch = name[i];
-
-		if (ch == '\0')
-			return TRUE;
-		if (   NM_IN_SET (ch, '/', ':')
-		    || g_ascii_isspace (ch)) {
-			g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-			                     _("interface name contains an invalid character"));
-			return FALSE;
-		}
-	}
-
-	g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-	                     _("interface name is longer than 15 characters"));
-	return FALSE;
+nm_utils_ifname_valid_kernel(const char *name, GError **error)
+{
+    int i;
+
+    /* This function follows kernel's interface validation
+     * function dev_valid_name() in net/core/dev.c.
+     */
+
+    if (!name) {
+        g_set_error_literal(error,
+                            NM_UTILS_ERROR,
+                            NM_UTILS_ERROR_UNKNOWN,
+                            _("interface name is missing"));
+        return FALSE;
+    }
+
+    if (name[0] == '\0') {
+        g_set_error_literal(error,
+                            NM_UTILS_ERROR,
+                            NM_UTILS_ERROR_UNKNOWN,
+                            _("interface name is too short"));
+        return FALSE;
+    }
+
+    if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) {
+        g_set_error_literal(error,
+                            NM_UTILS_ERROR,
+                            NM_UTILS_ERROR_UNKNOWN,
+                            _("interface name is reserved"));
+        return FALSE;
+    }
+
+    for (i = 0; i < IFNAMSIZ; i++) {
+        char ch = name[i];
+
+        if (ch == '\0')
+            return TRUE;
+        if (NM_IN_SET(ch, '/', ':') || g_ascii_isspace(ch)) {
+            g_set_error_literal(error,
+                                NM_UTILS_ERROR,
+                                NM_UTILS_ERROR_UNKNOWN,
+                                _("interface name contains an invalid character"));
+            return FALSE;
+        }
+    }
+
+    g_set_error_literal(error,
+                        NM_UTILS_ERROR,
+                        NM_UTILS_ERROR_UNKNOWN,
+                        _("interface name is longer than 15 characters"));
+    return FALSE;
 }
 
 /*****************************************************************************/
 
 static gboolean
-_nm_utils_ifname_valid_kernel (const char *name, GError **error)
-{
-	if (!nm_utils_ifname_valid_kernel (name, error))
-		return FALSE;
-
-	if (strchr (name, '%')) {
-		/* Kernel's dev_valid_name() accepts (almost) any binary up to 15 chars.
-		 * However, '%' is treated special as a format specifier. Try
-		 *
-		 *   ip link add 'dummy%dx' type dummy
-		 *
-		 * Don't allow that for "connection.interface-name", which either
-		 * matches an existing netdev name (thus, it cannot have a '%') or
-		 * is used to configure a name (in which case we don't want kernel
-		 * to replace the format specifier). */
-		g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-		                     _("'%%' is not allowed in interface names"));
-		return FALSE;
-	}
-
-	if (NM_IN_STRSET (name, "all",
-	                        "default",
-	                        "bonding_masters")) {
-		/* Certain names are not allowed. The "all" and "default" names are reserved
-		 * due to their directories in "/proc/sys/net/ipv4/conf/" and "/proc/sys/net/ipv6/conf/".
-		 *
-		 * Also, there is "/sys/class/net/bonding_masters" file.
-		 */
-		nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN,
-		                    _("'%s' is not allowed as interface name"), name);
-		return FALSE;
-	}
-
-	return TRUE;
+_nm_utils_ifname_valid_kernel(const char *name, GError **error)
+{
+    if (!nm_utils_ifname_valid_kernel(name, error))
+        return FALSE;
+
+    if (strchr(name, '%')) {
+        /* Kernel's dev_valid_name() accepts (almost) any binary up to 15 chars.
+         * However, '%' is treated special as a format specifier. Try
+         *
+         *   ip link add 'dummy%dx' type dummy
+         *
+         * Don't allow that for "connection.interface-name", which either
+         * matches an existing netdev name (thus, it cannot have a '%') or
+         * is used to configure a name (in which case we don't want kernel
+         * to replace the format specifier). */
+        g_set_error_literal(error,
+                            NM_UTILS_ERROR,
+                            NM_UTILS_ERROR_UNKNOWN,
+                            _("'%%' is not allowed in interface names"));
+        return FALSE;
+    }
+
+    if (NM_IN_STRSET(name, "all", "default", "bonding_masters")) {
+        /* Certain names are not allowed. The "all" and "default" names are reserved
+         * due to their directories in "/proc/sys/net/ipv4/conf/" and "/proc/sys/net/ipv6/conf/".
+         *
+         * Also, there is "/sys/class/net/bonding_masters" file.
+         */
+        nm_utils_error_set(error,
+                           NM_UTILS_ERROR_UNKNOWN,
+                           _("'%s' is not allowed as interface name"),
+                           name);
+        return FALSE;
+    }
+
+    return TRUE;
 }
 
 static gboolean
-_nm_utils_ifname_valid_ovs (const char *name, GError **error)
-{
-	const char *ch;
-
-	/* OVS actually accepts a wider range of chars (all printable UTF-8 chars),
-	 NetworkManager restricts this to ASCII char as it's a safer option for
-	 now since OVS is not well documented on this matter.
-	 */
-	for (ch = name; *ch; ++ch) {
-		if (   *ch == '\\'
-		    || *ch == '/'
-		    || !g_ascii_isgraph (*ch)) {
-			g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-			                     _("interface name must be alphanumerical with "
-			                       "no forward or backward slashes"));
-			return FALSE;
-		}
-	};
-	return TRUE;
+_nm_utils_ifname_valid_ovs(const char *name, GError **error)
+{
+    const char *ch;
+
+    /* OVS actually accepts a wider range of chars (all printable UTF-8 chars),
+     * NetworkManager restricts this to ASCII char as it's a safer option for
+     * now since OVS is not well documented on this matter.
+     **/
+    for (ch = name; *ch; ++ch) {
+        if (*ch == '\\' || *ch == '/' || !g_ascii_isgraph(*ch)) {
+            g_set_error_literal(error,
+                                NM_UTILS_ERROR,
+                                NM_UTILS_ERROR_UNKNOWN,
+                                _("interface name must be alphanumerical with "
+                                  "no forward or backward slashes"));
+            return FALSE;
+        }
+    };
+    return TRUE;
 }
 
 gboolean
-nm_utils_ifname_valid (const char* name,
-                       NMUtilsIfaceType type,
-                       GError **error)
-{
-	g_return_val_if_fail (!error || !(*error), FALSE);
-
-	if (!name || !(name[0])) {
-		g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-		                     _("interface name must not be empty"));
-		return FALSE;
-	}
-
-	if (!g_utf8_validate (name, -1, NULL)) {
-		g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-		                     _("interface name must be UTF-8 encoded"));
-		return FALSE;
-	}
-
-	switch (type) {
-	case NMU_IFACE_KERNEL:
-		return _nm_utils_ifname_valid_kernel (name, error);
-	case NMU_IFACE_OVS:
-		return _nm_utils_ifname_valid_ovs (name, error);
-	case NMU_IFACE_OVS_AND_KERNEL:
-		return    _nm_utils_ifname_valid_kernel (name, error)
-		       && _nm_utils_ifname_valid_ovs (name, error);
-	case NMU_IFACE_ANY: {
-		gs_free_error GError *local = NULL;
-
-		if (_nm_utils_ifname_valid_kernel (name, error ? &local : NULL))
-			return TRUE;
-		if (_nm_utils_ifname_valid_ovs (name, NULL))
-			return TRUE;
-		if (error)
-			g_propagate_error (error, g_steal_pointer (&local));
-		return FALSE;
-	}
-	}
-
-	g_return_val_if_reached (FALSE);
+nm_utils_ifname_valid(const char *name, NMUtilsIfaceType type, GError **error)
+{
+    g_return_val_if_fail(!error || !(*error), FALSE);
+
+    if (!name || !(name[0])) {
+        g_set_error_literal(error,
+                            NM_UTILS_ERROR,
+                            NM_UTILS_ERROR_UNKNOWN,
+                            _("interface name must not be empty"));
+        return FALSE;
+    }
+
+    if (!g_utf8_validate(name, -1, NULL)) {
+        g_set_error_literal(error,
+                            NM_UTILS_ERROR,
+                            NM_UTILS_ERROR_UNKNOWN,
+                            _("interface name must be UTF-8 encoded"));
+        return FALSE;
+    }
+
+    switch (type) {
+    case NMU_IFACE_KERNEL:
+        return _nm_utils_ifname_valid_kernel(name, error);
+    case NMU_IFACE_OVS:
+        return _nm_utils_ifname_valid_ovs(name, error);
+    case NMU_IFACE_OVS_AND_KERNEL:
+        return _nm_utils_ifname_valid_kernel(name, error)
+               && _nm_utils_ifname_valid_ovs(name, error);
+    case NMU_IFACE_ANY:
+    {
+        gs_free_error GError *local = NULL;
+
+        if (_nm_utils_ifname_valid_kernel(name, error ? &local : NULL))
+            return TRUE;
+        if (_nm_utils_ifname_valid_ovs(name, NULL))
+            return TRUE;
+        if (error)
+            g_propagate_error(error, g_steal_pointer(&local));
+        return FALSE;
+    }
+    }
+
+    g_return_val_if_reached(FALSE);
 }
 
 /*****************************************************************************/
 
 void
-_nm_str_buf_ensure_size (NMStrBuf *strbuf,
-                         gsize new_size,
-                         gboolean reserve_exact)
+_nm_str_buf_ensure_size(NMStrBuf *strbuf, gsize new_size, gboolean reserve_exact)
 {
-	_nm_str_buf_assert (strbuf);
+    _nm_str_buf_assert(strbuf);
 
-	/* Currently this only supports strictly growing the buffer. */
-	nm_assert (new_size > strbuf->_priv_allocated);
+    /* Currently, this only supports strictly growing the buffer. */
+    nm_assert(new_size > strbuf->_priv_allocated);
 
-	if (!reserve_exact) {
-		new_size = nm_utils_get_next_realloc_size (!strbuf->_priv_do_bzero_mem,
-		                                           new_size);
-	}
+    if (!reserve_exact) {
+        new_size = nm_utils_get_next_realloc_size(!strbuf->_priv_do_bzero_mem, new_size);
+    }
 
-	strbuf->_priv_str = nm_secret_mem_realloc (strbuf->_priv_str,
-	                                           strbuf->_priv_do_bzero_mem,
-	                                           strbuf->_priv_allocated,
-	                                           new_size);
-	strbuf->_priv_allocated = new_size;
+    strbuf->_priv_str       = nm_secret_mem_realloc(strbuf->_priv_str,
+                                              strbuf->_priv_do_bzero_mem,
+                                              strbuf->_priv_allocated,
+                                              new_size);
+    strbuf->_priv_allocated = new_size;
 }
 
 void
-nm_str_buf_append_printf (NMStrBuf *strbuf,
-                          const char *format,
-                          ...)
+nm_str_buf_append_printf(NMStrBuf *strbuf, const char *format, ...)
 {
-	va_list args;
-	gsize available;
-	int l;
+    va_list args;
+    gsize   available;
+    int     l;
 
-	_nm_str_buf_assert (strbuf);
+    _nm_str_buf_assert(strbuf);
 
-	available = strbuf->_priv_allocated - strbuf->_priv_len;
+    available = strbuf->_priv_allocated - strbuf->_priv_len;
 
-	nm_assert (available < G_MAXULONG);
+    nm_assert(available < G_MAXULONG);
 
-	va_start (args, format);
-	l = g_vsnprintf (&strbuf->_priv_str[strbuf->_priv_len],
-	                 available,
-	                 format,
-	                 args);
-	va_end (args);
+    va_start(args, format);
+    l = g_vsnprintf(&strbuf->_priv_str[strbuf->_priv_len], available, format, args);
+    va_end(args);
 
-	nm_assert (l >= 0);
-	nm_assert (l < G_MAXINT);
+    nm_assert(l >= 0);
+    nm_assert(l < G_MAXINT);
 
-	if ((gsize) l >= available) {
-		gsize l2;
+    if ((gsize) l >= available) {
+        gsize l2;
 
-		if (l == 0)
-			return;
+        if (l == 0)
+            return;
 
-		l2 = ((gsize) l) + 1u;
+        l2 = ((gsize) l) + 1u;
 
-		nm_str_buf_maybe_expand (strbuf, l2, FALSE);
+        nm_str_buf_maybe_expand(strbuf, l2, FALSE);
 
-		va_start (args, format);
-		l = g_vsnprintf (&strbuf->_priv_str[strbuf->_priv_len],
-		                 l2,
-		                 format,
-		                 args);
-		va_end (args);
+        va_start(args, format);
+        l = g_vsnprintf(&strbuf->_priv_str[strbuf->_priv_len], l2, format, args);
+        va_end(args);
 
-		nm_assert (l >= 0);
-		nm_assert ((gsize) l == l2 - 1u);
-	}
+        nm_assert(l >= 0);
+        nm_assert((gsize) l == l2 - 1u);
+    }
 
-	strbuf->_priv_len += (gsize) l;
+    strbuf->_priv_len += (gsize) l;
 }
 
 /*****************************************************************************/
@@ -5029,109 +5326,285 @@ nm_str_buf_append_printf (NMStrBuf *strbuf,
  * the first pointer.
  */
 void
-nm_indirect_g_free (gpointer arg)
+nm_indirect_g_free(gpointer arg)
 {
-	gpointer *p = arg;
+    gpointer *p = arg;
 
-	nm_clear_g_free (p);
+    nm_clear_g_free(p);
 }
 
 /*****************************************************************************/
 
 static char *
-attribute_escape (const char *src, char c1, char c2)
+attribute_escape(const char *src, char c1, char c2)
 {
-	char *ret, *dest;
+    char *ret, *dest;
 
-	dest = ret = g_malloc (strlen (src) * 2 + 1);
+    dest = ret = g_malloc(strlen(src) * 2 + 1);
 
-	while (*src) {
-		if (*src == c1 || *src == c2 || *src == '\\')
-			*dest++ = '\\';
-		*dest++ = *src++;
-	}
-	*dest++ = '\0';
+    while (*src) {
+        if (*src == c1 || *src == c2 || *src == '\\')
+            *dest++ = '\\';
+        *dest++ = *src++;
+    }
+    *dest++ = '\0';
 
-	return ret;
+    return ret;
 }
 
 void
-_nm_utils_format_variant_attributes_full (GString *str,
-                                          const NMUtilsNamedValue *values,
-                                          guint num_values,
-                                          char attr_separator,
-                                          char key_value_separator)
-{
-	const char *name, *value;
-	GVariant *variant;
-	char *escaped;
-	char buf[64];
-	char sep = 0;
-	guint i;
-
-	for (i = 0; i < num_values; i++) {
-		name = values[i].name;
-		variant = (GVariant *) values[i].value_ptr;
-		value = NULL;
-
-		if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32))
-			value = nm_sprintf_buf (buf, "%u", g_variant_get_uint32 (variant));
-		else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_INT32))
-			value = nm_sprintf_buf (buf, "%d", (int) g_variant_get_int32 (variant));
-		else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT64))
-			value = nm_sprintf_buf (buf, "%"G_GUINT64_FORMAT, g_variant_get_uint64 (variant));
-		else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTE))
-			value = nm_sprintf_buf (buf, "%hhu", g_variant_get_byte (variant));
-		else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN))
-			value = g_variant_get_boolean (variant) ? "true" : "false";
-		else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING))
-			value = g_variant_get_string (variant, NULL);
-		else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTESTRING)) {
-			/* FIXME: there is no guarantee that the byte array
-			 * is valid UTF-8.*/
-			value = g_variant_get_bytestring (variant);
-		} else
-			continue;
-
-		if (sep)
-			g_string_append_c (str, sep);
-
-		escaped = attribute_escape (name, attr_separator, key_value_separator);
-		g_string_append (str, escaped);
-		g_free (escaped);
-
-		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);
-
-		sep = attr_separator;
-	}
+_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;
+    char                                 buf[64];
+    char                                 sep = 0;
+    guint                                i;
+
+    for (i = 0; i < num_values; i++) {
+        name    = values[i].name;
+        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));
+        else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_INT32))
+            value = nm_sprintf_buf(buf, "%d", (int) g_variant_get_int32(variant));
+        else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT64))
+            value = nm_sprintf_buf(buf, "%" G_GUINT64_FORMAT, g_variant_get_uint64(variant));
+        else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_BYTE))
+            value = nm_sprintf_buf(buf, "%hhu", g_variant_get_byte(variant));
+        else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN))
+            value = g_variant_get_boolean(variant) ? "true" : "false";
+        else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING))
+            value = g_variant_get_string(variant, NULL);
+        else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_BYTESTRING)) {
+            /* FIXME: there is no guarantee that the byte array
+             * is valid UTF-8.*/
+            value = g_variant_get_bytestring(variant);
+        } else
+            continue;
+
+        if (sep)
+            g_string_append_c(str, sep);
+
+        escaped = attribute_escape(name, attr_separator, key_value_separator);
+        g_string_append(str, escaped);
+        g_free(escaped);
+
+        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);
+        }
+
+        sep = attr_separator;
+    }
 }
 
 char *
-_nm_utils_format_variant_attributes (GHashTable *attributes,
-                                     char attr_separator,
-                                     char key_value_separator)
+_nm_utils_format_variant_attributes(GHashTable *                         attributes,
+                                    const NMVariantAttributeSpec *const *spec,
+                                    char                                 attr_separator,
+                                    char                                 key_value_separator)
 {
-	GString *str = NULL;
-	gs_free NMUtilsNamedValue *values = NULL;
-	guint len;
+    gs_free NMUtilsNamedValue *values_free = NULL;
+    NMUtilsNamedValue          values_prepared[20];
+    const NMUtilsNamedValue *  values;
+    GString *                  str = NULL;
+    guint                      len;
+
+    g_return_val_if_fail(attr_separator, NULL);
+    g_return_val_if_fail(key_value_separator, NULL);
 
-	g_return_val_if_fail (attr_separator, NULL);
-	g_return_val_if_fail (key_value_separator, NULL);
+    if (!attributes)
+        return NULL;
 
-	if (!attributes || !g_hash_table_size (attributes))
-		return NULL;
+    values = nm_utils_named_values_from_strdict(attributes, &len, values_prepared, &values_free);
+    if (len == 0)
+        return NULL;
 
-	values = nm_utils_named_values_from_str_dict (attributes, &len);
+    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);
+}
+
+/*****************************************************************************/
+
+gboolean
+nm_utils_is_localhost(const char *name)
+{
+    static const char *const NAMES[] = {
+        "localhost",
+        "localhost4",
+        "localhost6",
+        "localhost.localdomain",
+        "localhost4.localdomain4",
+        "localhost6.localdomain6",
+    };
+    gsize name_len;
+    int   i;
 
-	str = g_string_new ("");
-	_nm_utils_format_variant_attributes_full (str,
-	                                          values,
-	                                          len,
-	                                          attr_separator,
-	                                          key_value_separator);
-	return g_string_free (str, FALSE);
+    if (!name)
+        return FALSE;
+
+    /* This tries to identify local host and domain names
+     * described in RFC6761 plus the redhatism of localdomain.
+     *
+     * Similar to systemd's is_localhost(). */
+
+    name_len = strlen(name);
+
+    if (name_len == 0)
+        return FALSE;
+
+    if (name[name_len - 1] == '.') {
+        /* one trailing dot is fine. Hide it. */
+        name_len--;
+    }
+
+    for (i = 0; i < (int) G_N_ELEMENTS(NAMES); i++) {
+        const char *n = NAMES[i];
+        gsize       l = strlen(n);
+        gsize       s;
+
+        if (name_len < l)
+            continue;
+
+        s = name_len - l;
+
+        if (g_ascii_strncasecmp(&name[s], n, l) != 0)
+            continue;
+
+        /* we accept the name if it is equal to one of the well-known names,
+         * or if it is some prefix, a '.' and the well-known name. */
+        if (s == 0)
+            return TRUE;
+        if (name[s - 1] == '.')
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+gboolean
+nm_utils_is_specific_hostname(const char *name)
+{
+    if (nm_str_is_empty(name))
+        return FALSE;
+
+    if (nm_streq(name, "(none)")) {
+        /* This is not a special hostname. Probably an artefact by somebody wrongly
+         * printing NULL. */
+        return FALSE;
+    }
+
+    if (nm_utils_is_localhost(name))
+        return FALSE;
+
+    /* FIXME: properly validate the hostname, like systemd's hostname_is_valid() */
+
+    return TRUE;
+}
+
+/*****************************************************************************/
+
+/* taken from systemd's uid_to_name(). */
+char *
+nm_utils_uid_to_name(uid_t uid)
+{
+    gs_free char *buf_heap = NULL;
+    char          buf_stack[4096];
+    gsize         bufsize;
+    char *        buf;
+
+    bufsize = sizeof(buf_stack);
+    buf     = buf_stack;
+
+    for (;;) {
+        struct passwd  pwbuf;
+        struct passwd *pw = NULL;
+        int            r;
+
+        r = getpwuid_r(uid, &pwbuf, buf, bufsize, &pw);
+        if (r == 0 && pw)
+            return nm_strdup_not_empty(pw->pw_name);
+
+        if (r != ERANGE)
+            return NULL;
+
+        if (bufsize > G_MAXSIZE / 2u)
+            return NULL;
+
+        bufsize *= 2u;
+        g_free(buf_heap);
+        buf_heap = g_malloc(bufsize);
+        buf      = buf_heap;
+    }
+}
+
+/* taken from systemd's nss_user_record_by_name() */
+gboolean
+nm_utils_name_to_uid(const char *name, uid_t *out_uid)
+{
+    gs_free char *buf_heap = NULL;
+    char          buf_stack[4096];
+    gsize         bufsize;
+    char *        buf;
+
+    if (!name)
+        return nm_assert_unreachable_val(FALSE);
+
+    bufsize = sizeof(buf_stack);
+    buf     = buf_stack;
+
+    for (;;) {
+        struct passwd *result;
+        struct passwd  pwd;
+        int            r;
+
+        r = getpwnam_r(name, &pwd, buf, bufsize, &result);
+        if (r == 0) {
+            if (!result)
+                return FALSE;
+            NM_SET_OUT(out_uid, pwd.pw_uid);
+            return TRUE;
+        }
+
+        if (r != ERANGE)
+            return FALSE;
+
+        if (bufsize > G_MAXSIZE / 2u)
+            return FALSE;
+
+        bufsize *= 2u;
+        g_free(buf_heap);
+        buf_heap = g_malloc(bufsize);
+        buf      = buf_heap;
+    }
 }