about summary refs log tree commit diff
path: root/src/libnm-glib-aux/nm-macros-internal.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnm-glib-aux/nm-macros-internal.h')
-rw-r--r--src/libnm-glib-aux/nm-macros-internal.h236
1 files changed, 161 insertions, 75 deletions
diff --git a/src/libnm-glib-aux/nm-macros-internal.h b/src/libnm-glib-aux/nm-macros-internal.h
index f2a4461e..71a17e3e 100644
--- a/src/libnm-glib-aux/nm-macros-internal.h
+++ b/src/libnm-glib-aux/nm-macros-internal.h
@@ -43,6 +43,27 @@
 
 /*****************************************************************************/
 
+/* Historically, our cleanup macros come from a long gone library
+ * libgsystem, hence the "gs_" prefix. We still keep using them,
+ * although maybe we should drop them and use our respective nm_auto*
+ * macros (TODO).
+ *
+ * GLib also has g_auto() since 2.44. First of all, we still don't
+ * depend on 2.44, so we would have add compat implementations to
+ * "nm-glib.h" or bump the version.
+ * Also, they work differently (nm_auto_unref_hashtable vs g_auto(GHashTable)).
+ * If we were to switch to g_auto(), the change would be slightly more complicated
+ * than replacing one macro with another (but still easy).
+ * However, the reason for using our nm_auto* macros is that we also want cleanup
+ * macros in libnm-std-aux, which has no glib dependency. So we still would have
+ * some nm_auto* macros mixed with g_auto(). Instead, we consistently use
+ * nm_auto* macros (and the gs_* aliases).
+ *
+ * Note that c-stdaux also brings cleanup macros like _c_cleanup_(c_freep).
+ * We use c-stdaux like a proper internal library, so we could instead switch
+ * from nm_auto* macros to _c_cleanup_(). Unlike glib, c-stdaux is used by
+ * libnm-std-aux. Again, _c_cleanup_ follows a different pattern both from
+ * nm_auto* and g_auto(). */
 #define gs_free            nm_auto_g_free
 #define gs_unref_object    nm_auto_unref_object
 #define gs_unref_variant   nm_auto_unref_variant
@@ -110,6 +131,9 @@ NM_AUTO_DEFINE_FCN_VOID0(void *, _nm_auto_unref_gtypeclass, g_type_class_unref);
 NM_AUTO_DEFINE_FCN0(GByteArray *, _nm_auto_unref_bytearray, g_byte_array_unref);
 #define nm_auto_unref_bytearray nm_auto(_nm_auto_unref_bytearray)
 
+NM_AUTO_DEFINE_FCN0(GDateTime *, _nm_auto_unref_gdatetime, g_date_time_unref);
+#define nm_auto_unref_gdatetime nm_auto(_nm_auto_unref_gdatetime)
+
 static inline void
 _nm_auto_free_gstring(GString **str)
 {
@@ -236,68 +260,40 @@ NM_G_ERROR_MSG(GError *error)
 #if _NM_CC_SUPPORT_GENERIC
 #define _NM_CONSTCAST_FULL_1(type, obj_expr, obj) \
     (_Generic ((obj_expr), \
-               const void        *const: ((const type *) (obj)), \
-               const void        *     : ((const type *) (obj)), \
-                     void        *const: ((      type *) (obj)), \
-                     void        *     : ((      type *) (obj)), \
-               const type        *const: ((const type *) (obj)), \
-               const type        *     : ((const type *) (obj)), \
-                     type        *const: ((      type *) (obj)), \
-                     type        *     : ((      type *) (obj))))
+               const void        *: ((const type *) (obj)), \
+                     void        *: ((      type *) (obj)), \
+               const type        *: ((const type *) (obj)), \
+                     type        *: ((      type *) (obj))))
 #define _NM_CONSTCAST_FULL_2(type, obj_expr, obj, alias_type2) \
     (_Generic ((obj_expr), \
-               const void        *const: ((const type *) (obj)), \
-               const void        *     : ((const type *) (obj)), \
-                     void        *const: ((      type *) (obj)), \
-                     void        *     : ((      type *) (obj)), \
-               const alias_type2 *const: ((const type *) (obj)), \
-               const alias_type2 *     : ((const type *) (obj)), \
-                     alias_type2 *const: ((      type *) (obj)), \
-                     alias_type2 *     : ((      type *) (obj)), \
-               const type        *const: ((const type *) (obj)), \
-               const type        *     : ((const type *) (obj)), \
-                     type        *const: ((      type *) (obj)), \
-                     type        *     : ((      type *) (obj))))
+               const void        *: ((const type *) (obj)), \
+                     void        *: ((      type *) (obj)), \
+               const alias_type2 *: ((const type *) (obj)), \
+                     alias_type2 *: ((      type *) (obj)), \
+               const type        *: ((const type *) (obj)), \
+                     type        *: ((      type *) (obj))))
 #define _NM_CONSTCAST_FULL_3(type, obj_expr, obj, alias_type2, alias_type3) \
     (_Generic ((obj_expr), \
-               const void        *const: ((const type *) (obj)), \
-               const void        *     : ((const type *) (obj)), \
-                     void        *const: ((      type *) (obj)), \
-                     void        *     : ((      type *) (obj)), \
-               const alias_type2 *const: ((const type *) (obj)), \
-               const alias_type2 *     : ((const type *) (obj)), \
-                     alias_type2 *const: ((      type *) (obj)), \
-                     alias_type2 *     : ((      type *) (obj)), \
-               const alias_type3 *const: ((const type *) (obj)), \
-               const alias_type3 *     : ((const type *) (obj)), \
-                     alias_type3 *const: ((      type *) (obj)), \
-                     alias_type3 *     : ((      type *) (obj)), \
-               const type        *const: ((const type *) (obj)), \
-               const type        *     : ((const type *) (obj)), \
-                     type        *const: ((      type *) (obj)), \
-                     type        *     : ((      type *) (obj))))
+               const void        *: ((const type *) (obj)), \
+                     void        *: ((      type *) (obj)), \
+               const alias_type2 *: ((const type *) (obj)), \
+                     alias_type2 *: ((      type *) (obj)), \
+               const alias_type3 *: ((const type *) (obj)), \
+                     alias_type3 *: ((      type *) (obj)), \
+               const type        *: ((const type *) (obj)), \
+                     type        *: ((      type *) (obj))))
 #define _NM_CONSTCAST_FULL_4(type, obj_expr, obj, alias_type2, alias_type3, alias_type4) \
     (_Generic ((obj_expr), \
-               const void        *const: ((const type *) (obj)), \
-               const void        *     : ((const type *) (obj)), \
-                     void        *const: ((      type *) (obj)), \
-                     void        *     : ((      type *) (obj)), \
-               const alias_type2 *const: ((const type *) (obj)), \
-               const alias_type2 *     : ((const type *) (obj)), \
-                     alias_type2 *const: ((      type *) (obj)), \
-                     alias_type2 *     : ((      type *) (obj)), \
-               const alias_type3 *const: ((const type *) (obj)), \
-               const alias_type3 *     : ((const type *) (obj)), \
-                     alias_type3 *const: ((      type *) (obj)), \
-                     alias_type3 *     : ((      type *) (obj)), \
-               const alias_type4 *const: ((const type *) (obj)), \
-               const alias_type4 *     : ((const type *) (obj)), \
-                     alias_type4 *const: ((      type *) (obj)), \
-                     alias_type4 *     : ((      type *) (obj)), \
-               const type        *const: ((const type *) (obj)), \
-               const type        *     : ((const type *) (obj)), \
-                     type        *const: ((      type *) (obj)), \
-                     type        *     : ((      type *) (obj))))
+               const void        *: ((const type *) (obj)), \
+                     void        *: ((      type *) (obj)), \
+               const alias_type2 *: ((const type *) (obj)), \
+                     alias_type2 *: ((      type *) (obj)), \
+               const alias_type3 *: ((const type *) (obj)), \
+                     alias_type3 *: ((      type *) (obj)), \
+               const alias_type4 *: ((const type *) (obj)), \
+                     alias_type4 *: ((      type *) (obj)), \
+               const type        *: ((const type *) (obj)), \
+                     type        *: ((      type *) (obj))))
 #define _NM_CONSTCAST_FULL_x(type, obj_expr, obj, n, ...) \
     (_NM_CONSTCAST_FULL_##n(type, obj_expr, obj, ##__VA_ARGS__))
 #define _NM_CONSTCAST_FULL_y(type, obj_expr, obj, n, ...) \
@@ -393,13 +389,7 @@ NM_G_ERROR_MSG(GError *error)
                      char *const*: (const char *const*) (value), \
                      char *     *: (const char *const*) (value), \
                      const void *: (const char *const*) (value), \
-                           void *: (const char *const*) (value), \
-               const char *const*const: (const char *const*) (value), \
-               const char *     *const: (const char *const*) (value), \
-                     char *const*const: (const char *const*) (value), \
-                     char *     *const: (const char *const*) (value), \
-                     const void *const: (const char *const*) (value), \
-                           void *const: (const char *const*) (value)))
+                           void *: (const char *const*) (value)))
 #else
 #define NM_CAST_STRV_MC(value) ((const char **) (value))
 #define NM_CAST_STRV_CC(value) ((const char *const *) (value))
@@ -496,6 +486,17 @@ nm_strdup_not_empty(const char *str)
 }
 
 static inline char *
+nm_str_truncate(char *str)
+{
+    /* This is trivial, and is only useful in a macro, to
+     * ensure that we access the macro argument only once. */
+    nm_assert(str);
+
+    str[0] = '\0';
+    return str;
+}
+
+static inline char *
 nm_str_realloc(char *str)
 {
     gs_free char *s = str;
@@ -527,16 +528,27 @@ nm_str_realloc(char *str)
 /*****************************************************************************/
 
 /* redefine assertions to use g_assert*() */
-#undef _nm_assert_call
-#undef _nm_assert_call_not_reached
-#define _nm_assert_call(cond)         g_assert(cond)
-#define _nm_assert_call_not_reached() g_assert_not_reached()
+#undef _nm_assert_fail
+#define _nm_assert_fail(msg)                                                        \
+    G_STMT_START                                                                    \
+    {                                                                               \
+        g_assertion_message_expr(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg); \
+        _nm_unreachable_code();                                                     \
+    }                                                                               \
+    G_STMT_END
+
+#undef _NM_ASSERT_FAIL_ENABLED
+#ifndef G_DISABLE_ASSERT
+#define _NM_ASSERT_FAIL_ENABLED 1
+#else
+#define _NM_ASSERT_FAIL_ENABLED 0
+#endif
 
 /* Usage:
  *
  *   if (NM_MORE_ASSERT_ONCE (5)) { extra_check (); }
  *
- * This will only run the check once, and only if NM_MORE_ASSERT is >= than
+ * This will only run the check once, and only if NM_MORE_ASSERTS is >= than
  * more_assert_level.
  */
 #define NM_MORE_ASSERT_ONCE(more_assert_level)                                                    \
@@ -652,6 +664,24 @@ nm_str_realloc(char *str)
 
 /*****************************************************************************/
 
+/* Unfortunately, G_TYPE_CHECK_INSTANCE_CAST() just does a direct cast,
+ * which can trigger a "-Wcast-align" warning, especially when casting
+ * a GObject pointer to the desired type.
+ *
+ * _NM_G_TYPE_CHECK_INSTANCE_CAST() avoids that warning.
+ *
+ * Since the entire point of G_TYPE_CHECK_INSTANCE_CAST_() is to do a
+ * runtime check on the type (with conditional assertions via G_DISABLE_CAST_CHECKS),
+ * we already assert that the gtype is right, and the alignment is also
+ * expected to be right.
+ *
+ * See https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3139
+ */
+#define _NM_G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type) \
+    G_TYPE_CHECK_INSTANCE_CAST(((void *) (instance)), (g_type), c_type)
+
+/*****************************************************************************/
+
 static inline gpointer
 nm_g_object_ref(gpointer obj)
 {
@@ -1003,15 +1033,15 @@ nm_g_variant_equal(GVariant *a, GVariant *b)
         const typeof(flags) _flags = (flags); \
         const typeof(flags) _val   = (val);   \
                                               \
-        _flags &(~_val);                      \
+        _flags & (~_val);                     \
     })
 
-#define NM_FLAGS_ASSIGN(flags, val, assign)           \
-    ({                                                \
-        const typeof(flags) _flags = (flags);         \
-        const typeof(flags) _val   = (val);           \
-                                                      \
-        (assign) ? _flags | (_val) : _flags &(~_val); \
+#define NM_FLAGS_ASSIGN(flags, val, assign)            \
+    ({                                                 \
+        const typeof(flags) _flags = (flags);          \
+        const typeof(flags) _val   = (val);            \
+                                                       \
+        (assign) ? _flags | (_val) : _flags & (~_val); \
     })
 
 #define NM_FLAGS_ASSIGN_MASK(flags, mask, val) \
@@ -1071,6 +1101,32 @@ nm_ascii_is_newline(char ch)
     return NM_IN_SET(ch, '\n', '\t');
 }
 
+static inline gboolean
+nm_ascii_is_regular_char(char ch)
+{
+    /* Checks whether "ch" is "regular", which basically
+     * means it's either a digit, a alpha, or some special
+     * characters that are suitable for base64 encoding.
+     *
+     * The meaning of what "regular" means is not well defined,
+     * but it's used to validate the keys for "ovs.external-ids"
+     * dictionary. */
+    switch (ch) {
+    case 'a' ... 'z':
+    case 'A' ... 'Z':
+    case '0' ... '9':
+    case '-':
+    case '_':
+    case '+':
+    case '/':
+    case '=':
+    case '.':
+        return TRUE;
+    default:
+        return FALSE;
+    }
+}
+
 #define nm_str_skip_leading_spaces(str)                          \
     ({                                                           \
         typeof(*(str))              *_str_sls        = (str);    \
@@ -1276,6 +1332,36 @@ nm_memdup(gconstpointer data, gsize size)
     return p;
 }
 
+static inline gpointer
+nm_memdup_nul(gconstpointer data, gsize size)
+{
+    gpointer p;
+
+    /* Like systemd's memdup_suffix0() and kernel's kmemdup_nul().
+     *
+     * This:
+     * - never returns NULL
+     * - always has one NUL byte after the @size data. Thus,
+     *   the actually allocated buffer is size+1.
+     *
+     * This is like nm_memdup() except:
+     * - never returns NULL
+     * - always returns one NUL character appended to the data.
+     *
+     * This is like g_strndup(), except
+     * - never returns NULL.
+     * - g_strndup() treats the src pointer as a NUL terminated string,
+     *   so if src is shorter than size, the rest is filled with padding.
+     *   Essentially, it uses strncpy() to copy the input which does the
+     *   truncation. If @data contains no NUL byte in teh first @size bytes,
+     *   it behaves the same as g_strndup(). */
+
+    p = g_malloc(size + 1u);
+    nm_memcpy(p, data, size);
+    ((char *) p)[size] = '\0';
+    return p;
+}
+
 #define nm_malloc_maybe_a(alloca_maxlen, bytes, to_free)  \
     ({                                                    \
         const gsize       _bytes   = (bytes);             \