summaryrefslogtreecommitdiff
path: root/shared
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2017-09-07 17:45:21 +0200
committerThomas Haller <thaller@redhat.com>2017-09-07 18:11:54 +0200
commit61ab0224c54d1c52e5e46e6d08228f82eab3a390 (patch)
treef4daeea34d8058f24ab34544876cd0928b5a527b /shared
parent83e798d9eff577aa2f7f1f8f2f3fb2601e41b359 (diff)
downloadnetwork-manager-applet-61ab0224c54d1c52e5e46e6d08228f82eab3a390.tar.gz
shared: re-import shared/nm-utils files from NetworkManager
Import the shared files from NetworkManager, commit 19716df23ddfd3047b64620c389fa336e4427c69. No local modifications but import as-is.
Diffstat (limited to 'shared')
-rw-r--r--shared/nm-utils/nm-glib.h25
-rw-r--r--shared/nm-utils/nm-macros-internal.h468
-rw-r--r--shared/nm-utils/nm-shared-utils.c446
-rw-r--r--shared/nm-utils/nm-shared-utils.h204
-rw-r--r--shared/nm-utils/nm-test-utils.h317
5 files changed, 1313 insertions, 147 deletions
diff --git a/shared/nm-utils/nm-glib.h b/shared/nm-utils/nm-glib.h
index 824a08ca..dd18756a 100644
--- a/shared/nm-utils/nm-glib.h
+++ b/shared/nm-utils/nm-glib.h
@@ -134,17 +134,20 @@ __g_type_ensure (GType type)
/* Rumtime check for glib version. First do a compile time check which
* (if satisfied) shortcuts the runtime check. */
-#define nm_glib_check_version(major, minor, micro) \
- ( GLIB_CHECK_VERSION ((major), (minor), (micro)) \
- || ( ( glib_major_version > (major)) \
- || ( glib_major_version == (major) \
- && glib_minor_version > (minor)) \
- || ( glib_major_version == (major) \
- && glib_minor_version == (minor) \
- && glib_micro_version >= (micro))))
+static inline gboolean
+nm_glib_check_version (guint major, guint minor, guint micro)
+{
+ return GLIB_CHECK_VERSION (major, minor, micro)
+ || ( ( glib_major_version > major)
+ || ( glib_major_version == major
+ && glib_minor_version > minor)
+ || ( glib_major_version == major
+ && glib_minor_version == minor
+ && glib_micro_version < micro));
+}
/* g_test_skip() is only available since glib 2.38. Add a compatibility wrapper. */
-inline static void
+static inline void
__nmtst_g_test_skip (const gchar *msg)
{
#if GLIB_CHECK_VERSION (2, 38, 0)
@@ -159,7 +162,7 @@ __nmtst_g_test_skip (const gchar *msg)
/* g_test_add_data_func_full() is only available since glib 2.34. Add a compatibility wrapper. */
-inline static void
+static inline void
__g_test_add_data_func_full (const char *testpath,
gpointer test_data,
GTestDataFunc test_func,
@@ -275,7 +278,7 @@ _nm_g_ptr_array_insert (GPtrArray *array,
#if !GLIB_CHECK_VERSION (2, 40, 0)
-inline static gboolean
+static inline gboolean
_g_key_file_save_to_file (GKeyFile *key_file,
const gchar *filename,
GError **error)
diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h
index 14510535..d11766f9 100644
--- a/shared/nm-utils/nm-macros-internal.h
+++ b/shared/nm-utils/nm-macros-internal.h
@@ -22,7 +22,9 @@
#ifndef __NM_MACROS_INTERNAL_H__
#define __NM_MACROS_INTERNAL_H__
+#include <stdio.h>
#include <stdlib.h>
+#include <errno.h>
#include "nm-glib.h"
@@ -34,6 +36,8 @@
#define _nm_const __attribute__ ((const))
#define _nm_printf(a,b) __attribute__ ((__format__ (__printf__, a, b)))
+#define nm_offsetofend(t,m) (G_STRUCT_OFFSET (t,m) + sizeof (((t *) NULL)->m))
+
#define nm_auto(fcn) __attribute__ ((cleanup(fcn)))
/**
@@ -52,6 +56,14 @@ _nm_auto_unset_gvalue_impl (GValue *v)
#define nm_auto_unset_gvalue nm_auto(_nm_auto_unset_gvalue_impl)
static inline void
+_nm_auto_unref_gtypeclass (gpointer v)
+{
+ if (v && *((gpointer *) v))
+ g_type_class_unref (*((gpointer *) v));
+}
+#define nm_auto_unref_gtypeclass nm_auto(_nm_auto_unref_gtypeclass)
+
+static inline void
_nm_auto_free_gstring_impl (GString **str)
{
if (*str)
@@ -59,6 +71,37 @@ _nm_auto_free_gstring_impl (GString **str)
}
#define nm_auto_free_gstring nm_auto(_nm_auto_free_gstring_impl)
+static inline void
+_nm_auto_close_impl (int *pfd)
+{
+ if (*pfd >= 0) {
+ int errsv = errno;
+
+ (void) close (*pfd);
+ errno = errsv;
+ }
+}
+#define nm_auto_close nm_auto(_nm_auto_close_impl)
+
+static inline void
+_nm_auto_fclose_impl (FILE **pfd)
+{
+ if (*pfd) {
+ int errsv = errno;
+
+ (void) fclose (*pfd);
+ errno = errsv;
+ }
+}
+#define nm_auto_fclose nm_auto(_nm_auto_fclose_impl)
+
+static inline void
+_nm_auto_protect_errno (int *p_saved_errno)
+{
+ errno = *p_saved_errno;
+}
+#define NM_AUTO_PROTECT_ERRNO(errsv_saved) nm_auto(_nm_auto_protect_errno) _nm_unused const int errsv_saved = (errno)
+
/*****************************************************************************/
/* http://stackoverflow.com/a/11172679 */
@@ -71,12 +114,14 @@ _nm_auto_free_gstring_impl (GString **str)
#define __NM_UTILS_MACRO_REST_HELPER_ONE(first)
#define __NM_UTILS_MACRO_REST_HELPER_TWOORMORE(first, ...) , __VA_ARGS__
#define __NM_UTILS_MACRO_REST_NUM(...) \
- __NM_UTILS_MACRO_REST_SELECT_20TH(__VA_ARGS__, \
+ __NM_UTILS_MACRO_REST_SELECT_30TH(__VA_ARGS__, \
+ TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE,\
+ TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE,\
TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE,\
TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE,\
TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE,\
TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway)
-#define __NM_UTILS_MACRO_REST_SELECT_20TH(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, ...) a20
+#define __NM_UTILS_MACRO_REST_SELECT_30TH(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, ...) a30
/*****************************************************************************/
@@ -143,7 +188,7 @@ _nm_auto_free_gstring_impl (GString **str)
/**
* NM_G_ERROR_MSG:
- * @error: (allow none): the #GError instance
+ * @error: (allow-none): the #GError instance
*
* All functions must follow the convention that when they
* return a failure, they must also set the GError to a valid
@@ -164,6 +209,23 @@ NM_G_ERROR_MSG (GError *error)
/* macro to return strlen() of a compile time string. */
#define NM_STRLEN(str) ( sizeof ("" str) - 1 )
+/* returns the length of a NULL terminated array of pointers,
+ * like g_strv_length() does. The difference is:
+ * - it operats on arrays of pointers (of any kind, requiring no cast).
+ * - it accepts NULL to return zero. */
+#define NM_PTRARRAY_LEN(array) \
+ ({ \
+ typeof (*(array)) *const _array = (array); \
+ gsize _n = 0; \
+ \
+ if (_array) { \
+ _nm_unused typeof (*(_array[0])) *_array_check = _array[0]; \
+ while (_array[_n]) \
+ _n++; \
+ } \
+ _n; \
+ })
+
/* Note: @value is only evaluated when *out_val is present.
* Thus,
* NM_SET_OUT (out_str, g_strdup ("hallo"));
@@ -180,6 +242,35 @@ NM_G_ERROR_MSG (GError *error)
/*****************************************************************************/
+#if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 9 ))) || (defined (__clang__))
+#define _NM_CC_SUPPORT_GENERIC 1
+#else
+#define _NM_CC_SUPPORT_GENERIC 0
+#endif
+
+#if _NM_CC_SUPPORT_GENERIC
+#define _NM_CONSTCAST(type, obj) \
+ (_Generic ((obj), \
+ void * : ((type *) (obj)), \
+ void *const : ((type *) (obj)), \
+ const void * : ((const type *) (obj)), \
+ const void *const: ((const type *) (obj)), \
+ const type * : (obj), \
+ const type *const: (obj), \
+ type * : (obj), \
+ type *const : (obj)))
+#else
+/* _NM_CONSTCAST() is there to preserve constness of a pointer.
+ * It uses C11's _Generic(). If that is not supported, we fall back
+ * to casting away constness. So, with _Generic, we get some additional
+ * static type checking by preserving constness, without, we cast it
+ * to a non-const pointer. */
+#define _NM_CONSTCAST(type, obj) \
+ ((type *) (obj))
+#endif
+
+/*****************************************************************************/
+
#define _NM_IN_SET_EVAL_1( op, _x, y) (_x == (y))
#define _NM_IN_SET_EVAL_2( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_1 (op, _x, __VA_ARGS__)
#define _NM_IN_SET_EVAL_3( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_2 (op, _x, __VA_ARGS__)
@@ -198,21 +289,34 @@ NM_G_ERROR_MSG (GError *error)
#define _NM_IN_SET_EVAL_16(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_15 (op, _x, __VA_ARGS__)
#define _NM_IN_SET_EVAL_N2(op, _x, n, ...) (_NM_IN_SET_EVAL_##n(op, _x, __VA_ARGS__))
-#define _NM_IN_SET_EVAL_N(op, x, n, ...) \
+#define _NM_IN_SET_EVAL_N(op, type, x, n, ...) \
({ \
- typeof(x) _x = (x); \
+ type _x = (x); \
+ \
+ /* trigger a -Wenum-compare warning */ \
+ nm_assert (TRUE || _x == (x)); \
+ \
!!_NM_IN_SET_EVAL_N2(op, _x, n, __VA_ARGS__); \
})
+#define _NM_IN_SET(op, type, x, ...) _NM_IN_SET_EVAL_N(op, type, x, NM_NARG (__VA_ARGS__), __VA_ARGS__)
+
/* Beware that this does short-circuit evaluation (use "||" instead of "|")
* which has a possibly unexpected non-function-like behavior.
* Use NM_IN_SET_SE if you need all arguments to be evaluted. */
-#define NM_IN_SET(x, ...) _NM_IN_SET_EVAL_N(||, x, NM_NARG (__VA_ARGS__), __VA_ARGS__)
+#define NM_IN_SET(x, ...) _NM_IN_SET(||, typeof (x), x, __VA_ARGS__)
/* "SE" stands for "side-effect". Contrary to NM_IN_SET(), this does not do
* short-circuit evaluation, which can make a difference if the arguments have
* side-effects. */
-#define NM_IN_SET_SE(x, ...) _NM_IN_SET_EVAL_N(|, x, NM_NARG (__VA_ARGS__), __VA_ARGS__)
+#define NM_IN_SET_SE(x, ...) _NM_IN_SET(|, typeof (x), x, __VA_ARGS__)
+
+/* the *_TYPED forms allow to explicitly select the type of "x". This is useful
+ * if "x" doesn't support typeof (bitfields) or you want to gracefully convert
+ * a type using automatic type conversion rules (but not forcing the conversion
+ * with a cast). */
+#define NM_IN_SET_TYPED(type, x, ...) _NM_IN_SET(||, type, x, __VA_ARGS__)
+#define NM_IN_SET_SE_TYPED(type, x, ...) _NM_IN_SET(|, type, x, __VA_ARGS__)
/*****************************************************************************/
@@ -243,8 +347,8 @@ _NM_IN_STRSET_streq (const char *x, const char *s)
#define _NM_IN_STRSET_EVAL_N(op, x, n, ...) \
({ \
const char *_x = (x); \
- ( ((_x == NULL) && _NM_IN_SET_EVAL_N2 (op, (const char *) NULL, n, __VA_ARGS__)) \
- || ((_x != NULL) && _NM_IN_STRSET_EVAL_N2 (op, _x, n, __VA_ARGS__)) \
+ ( ((_x == NULL) && _NM_IN_SET_EVAL_N2 (op, ((const char *) NULL), n, __VA_ARGS__)) \
+ || ((_x != NULL) && _NM_IN_STRSET_EVAL_N2 (op, _x, n, __VA_ARGS__)) \
); \
})
@@ -258,27 +362,149 @@ _NM_IN_STRSET_streq (const char *x, const char *s)
* side-effects. */
#define NM_IN_STRSET_SE(x, ...) _NM_IN_STRSET_EVAL_N(|, x, NM_NARG (__VA_ARGS__), __VA_ARGS__)
+#define NM_STRCHAR_ALL(str, ch_iter, predicate) \
+ ({ \
+ gboolean _val = TRUE; \
+ const char *_str = (str); \
+ \
+ if (_str) { \
+ for (;;) { \
+ const char ch_iter = _str[0]; \
+ \
+ if (ch_iter != '\0') { \
+ if (predicate) {\
+ _str++; \
+ continue; \
+ } \
+ _val = FALSE; \
+ } \
+ break; \
+ } \
+ } \
+ _val; \
+ })
+
+#define NM_STRCHAR_ANY(str, ch_iter, predicate) \
+ ({ \
+ gboolean _val = FALSE; \
+ const char *_str = (str); \
+ \
+ if (_str) { \
+ for (;;) { \
+ const char ch_iter = _str[0]; \
+ \
+ if (ch_iter != '\0') { \
+ if (predicate) { \
+ ; \
+ } else { \
+ _str++; \
+ continue; \
+ } \
+ _val = TRUE; \
+ } \
+ break; \
+ } \
+ } \
+ _val; \
+ })
+
/*****************************************************************************/
-#define nm_streq(s1, s2) (strcmp (s1, s2) == 0)
-#define nm_streq0(s1, s2) (g_strcmp0 (s1, s2) == 0)
+static inline guint
+NM_HASH_COMBINE (guint h, guint val)
+{
+ /* see g_str_hash() for reasons */
+ return (h << 5) + h + val;
+}
+
+static inline guint
+NM_HASH_COMBINE_UINT64 (guint h, guint64 val)
+{
+ return NM_HASH_COMBINE (h, (((guint) val) & 0xFFFFFFFFu) + ((guint) (val >> 32)));
+}
/*****************************************************************************/
-#define nm_str_not_empty(str) \
+/* NM_CACHED_QUARK() returns the GQuark for @string, but caches
+ * it in a static variable to speed up future lookups.
+ *
+ * @string must be a string literal.
+ */
+#define NM_CACHED_QUARK(string) \
({ \
- /* implemented as macro to preserve constness */ \
- typeof (str) __str = (str); \
- _nm_unused const char *__str_type_check = __str; \
- ((__str && __str[0]) ? __str : ((char *) NULL)); \
+ static GQuark _nm_cached_quark = 0; \
+ \
+ (G_LIKELY (_nm_cached_quark != 0) \
+ ? _nm_cached_quark \
+ : (_nm_cached_quark = g_quark_from_static_string (""string""))); \
})
+/* NM_CACHED_QUARK_FCN() is essentially the same as G_DEFINE_QUARK
+ * with two differences:
+ * - @string must be a quited string-literal
+ * - @fcn must be the full function name, while G_DEFINE_QUARK() appends
+ * "_quark" to the function name.
+ * Both properties of G_DEFINE_QUARK() are non favorable, because you can no
+ * longer grep for string/fcn -- unless you are aware that you are searching
+ * for G_DEFINE_QUARK() and omit quotes / append _quark(). With NM_CACHED_QUARK_FCN(),
+ * ctags/cscope can locate the use of @fcn (though it doesn't recognize that
+ * NM_CACHED_QUARK_FCN() defines it).
+ */
+#define NM_CACHED_QUARK_FCN(string, fcn) \
+GQuark \
+fcn (void) \
+{ \
+ return NM_CACHED_QUARK (string); \
+}
+
+/*****************************************************************************/
+
+#define nm_streq(s1, s2) (strcmp (s1, s2) == 0)
+#define nm_streq0(s1, s2) (g_strcmp0 (s1, s2) == 0)
+
+/*****************************************************************************/
+
+static inline GString *
+nm_gstring_prepare (GString **l)
+{
+ if (*l)
+ g_string_set_size (*l, 0);
+ else
+ *l = g_string_sized_new (30);
+ return *l;
+}
+
+static inline const char *
+nm_str_not_empty (const char *str)
+{
+ return str && str[0] ? str : NULL;
+}
+
static inline char *
nm_strdup_not_empty (const char *str)
{
return str && str[0] ? g_strdup (str) : NULL;
}
+static inline char *
+nm_str_realloc (char *str)
+{
+ gs_free char *s = str;
+
+ /* Returns a new clone of @str and frees @str. The point is that @str
+ * possibly points to a larger chunck of memory. We want to freshly allocate
+ * a buffer.
+ *
+ * We could use realloc(), but that might not do anything or leave
+ * @str in its memory pool for chunks of a different size (bad for
+ * fragmentation).
+ *
+ * This is only useful when we want to keep the buffer around for a long
+ * time and want to re-allocate a more optimal buffer. */
+
+ return g_strdup (s);
+}
+
/*****************************************************************************/
#define NM_PRINT_FMT_QUOTED(cond, prefix, str, suffix, str_else) \
@@ -307,9 +533,11 @@ nm_strdup_not_empty (const char *str)
#if NM_MORE_ASSERTS
#define nm_assert(cond) G_STMT_START { g_assert (cond); } G_STMT_END
+#define nm_assert_se(cond) G_STMT_START { if (G_LIKELY (cond)) { ; } else { g_assert (FALSE && (cond)); } } G_STMT_END
#define nm_assert_not_reached() G_STMT_START { g_assert_not_reached (); } G_STMT_END
#else
#define nm_assert(cond) G_STMT_START { if (FALSE) { if (cond) { } } } G_STMT_END
+#define nm_assert_se(cond) G_STMT_START { if (G_LIKELY (cond)) { ; } } G_STMT_END
#define nm_assert_not_reached() G_STMT_START { ; } G_STMT_END
#endif
@@ -335,21 +563,39 @@ _notify (obj_type *obj, _PropertyEnums prop) \
/*****************************************************************************/
-#define __NM_GET_PRIVATE(self, type, is_check, result_cmd) \
+/* these are implemented as a macro, because they accept self
+ * as both (type*) and (const type*), and return a const
+ * private pointer accordingly. */
+#define __NM_GET_PRIVATE(self, type, is_check, addrop) \
({ \
/* preserve the const-ness of self. Unfortunately, that
* way, @self cannot be a void pointer */ \
typeof (self) _self = (self); \
\
/* Get compiler error if variable is of wrong type */ \
- _nm_unused const type *_self2 = (_self); \
+ _nm_unused const type *const _self2 = (_self); \
+ \
+ nm_assert (is_check (_self)); \
+ ( addrop ( _NM_CONSTCAST (type, _self)->_priv) ); \
+ })
+
+#define _NM_GET_PRIVATE(self, type, is_check) __NM_GET_PRIVATE(self, type, is_check, &)
+#define _NM_GET_PRIVATE_PTR(self, type, is_check) __NM_GET_PRIVATE(self, type, is_check, )
+
+#define __NM_GET_PRIVATE_VOID(self, type, is_check, result_cmd) \
+ ({ \
+ /* (self) can be any non-const pointer. It will be cast to "type *".
+ * We don't explicitly cast but assign first to (void *) which
+ * will fail if @self is pointing to const. */ \
+ void *const _self1 = (self); \
+ type *const _self = _self1; \
\
nm_assert (is_check (_self)); \
( result_cmd ); \
})
-#define _NM_GET_PRIVATE(self, type, is_check) __NM_GET_PRIVATE(self, type, is_check, &_self->_priv)
-#define _NM_GET_PRIVATE_PTR(self, type, is_check) __NM_GET_PRIVATE(self, type, is_check, _self->_priv)
+#define _NM_GET_PRIVATE_VOID(self, type, is_check) __NM_GET_PRIVATE_VOID(self, type, is_check, &_self->_priv)
+#define _NM_GET_PRIVATE_PTR_VOID(self, type, is_check) __NM_GET_PRIVATE_VOID(self, type, is_check, _self->_priv)
/*****************************************************************************/
@@ -442,18 +688,57 @@ nm_clear_g_cancellable (GCancellable **cancellable)
/*****************************************************************************/
/* Determine whether @x is a power of two (@x being an integer type).
- * For the special cases @x equals zero or one, it also returns true.
- * For negative @x, always returns FALSE. That only applies, if the data
- * type of @x is signed. */
+ * Basically, this returns TRUE, if @x has exactly one bit set.
+ * For negative values and zero, this always returns FALSE. */
#define nm_utils_is_power_of_two(x) ({ \
typeof(x) __x = (x); \
\
- /* Check if the value is negative. In that case, return FALSE.
- * The first expression is a compile time constant, depending on whether
- * the type is signed. The second expression is a clumsy way for (__x >= 0),
- * which causes a compiler warning for unsigned types. */ \
- ( ( ((typeof(__x)) -1) > ((typeof(__x)) 0) ) || (__x > 0) || (__x == 0) ) \
- && ((__x & (__x - 1)) == 0); \
+ ( (__x > ((typeof(__x)) 0)) \
+ && ((__x & (__x - (((typeof(__x)) 1)))) == ((typeof(__x)) 0))); \
+ })
+
+/*****************************************************************************/
+
+#define NM_UTILS_LOOKUP_DEFAULT(v) return (v)
+#define NM_UTILS_LOOKUP_DEFAULT_WARN(v) g_return_val_if_reached (v)
+#define NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT(v) { nm_assert_not_reached (); return (v); }
+#define NM_UTILS_LOOKUP_ITEM(v, n) (void) 0; case v: return (n); (void) 0
+#define NM_UTILS_LOOKUP_STR_ITEM(v, n) NM_UTILS_LOOKUP_ITEM(v, ""n"")
+#define NM_UTILS_LOOKUP_ITEM_IGNORE(v) (void) 0; case v: break; (void) 0
+#define NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER() (void) 0; default: break; (void) 0
+
+#define _NM_UTILS_LOOKUP_DEFINE(scope, fcn_name, lookup_type, result_type, unknown_val, ...) \
+scope result_type \
+fcn_name (lookup_type val) \
+{ \
+ switch (val) { \
+ (void) 0, \
+ __VA_ARGS__ \
+ (void) 0; \
+ }; \
+ { unknown_val; } \
+}
+
+#define NM_UTILS_LOOKUP_STR_DEFINE(fcn_name, lookup_type, unknown_val, ...) \
+ _NM_UTILS_LOOKUP_DEFINE (, fcn_name, lookup_type, const char *, unknown_val, __VA_ARGS__)
+#define NM_UTILS_LOOKUP_STR_DEFINE_STATIC(fcn_name, lookup_type, unknown_val, ...) \
+ _NM_UTILS_LOOKUP_DEFINE (static, fcn_name, lookup_type, const char *, unknown_val, __VA_ARGS__)
+
+/* Call the string-lookup-table function @fcn_name. If the function returns
+ * %NULL, the numeric index is converted to string using a alloca() buffer.
+ * Beware: this macro uses alloca(). */
+#define NM_UTILS_LOOKUP_STR(fcn_name, idx) \
+ ({ \
+ typeof (idx) _idx = (idx); \
+ const char *_s; \
+ \
+ _s = fcn_name (_idx); \
+ if (!_s) { \
+ _s = g_alloca (30); \
+ \
+ g_snprintf ((char *) _s, 30, "(%lld)", (long long) _idx); \
+ } \
+ _s; \
})
/*****************************************************************************/
@@ -461,7 +746,7 @@ nm_clear_g_cancellable (GCancellable **cancellable)
/* check if @flags has exactly one flag (@check) set. You should call this
* only with @check being a compile time constant and a power of two. */
#define NM_FLAGS_HAS(flags, check) \
- ( (G_STATIC_ASSERT_EXPR ( ((check) != 0) && ((check) & ((check)-1)) == 0 )), (NM_FLAGS_ANY ((flags), (check))) )
+ ( G_STATIC_ASSERT_EXPR ((check) > 0 && ((check) & ((check) - 1)) == 0), NM_FLAGS_ANY ((flags), (check)) )
#define NM_FLAGS_ANY(flags, check) ( ( ((flags) & (check)) != 0 ) ? TRUE : FALSE )
#define NM_FLAGS_ALL(flags, check) ( ( ((flags) & (check)) == (check) ) ? TRUE : FALSE )
@@ -505,6 +790,18 @@ _NM_BACKPORT_SYMBOL_IMPL(VERSION, RETURN_TYPE, FUNC, _##FUNC##_##VERSION, ARGS_T
/*****************************************************************************/
+#define nm_str_skip_leading_spaces(str) \
+ ({ \
+ typeof (*(str)) *_str = (str); \
+ _nm_unused const char *_str_type_check = _str; \
+ \
+ if (_str) { \
+ while (g_ascii_isspace (_str[0])) \
+ _str++; \
+ } \
+ _str; \
+ })
+
static inline char *
nm_strstrip (char *str)
{
@@ -602,67 +899,86 @@ nm_cmp_uint32_p_with_data (gconstpointer p_a, gconstpointer p_b, gpointer user_d
/*****************************************************************************/
static inline guint
-nm_encode_version (guint major, guint minor, guint micro) {
+nm_encode_version (guint major, guint minor, guint micro)
+{
/* analog to the preprocessor macro NM_ENCODE_VERSION(). */
return (major << 16) | (minor << 8) | micro;
}
static inline void
-nm_decode_version (guint version, guint *major, guint *minor, guint *micro) {
+nm_decode_version (guint version, guint *major, guint *minor, guint *micro)
+{
*major = (version & 0xFFFF0000u) >> 16;
*minor = (version & 0x0000FF00u) >> 8;
*micro = (version & 0x000000FFu);
}
+
+/*****************************************************************************/
+
+/* taken from systemd's DECIMAL_STR_MAX()
+ *
+ * Returns the number of chars needed to format variables of the
+ * specified type as a decimal string. Adds in extra space for a
+ * negative '-' prefix (hence works correctly on signed
+ * types). Includes space for the trailing NUL. */
+#define NM_DECIMAL_STR_MAX(type) \
+ (2+(sizeof(type) <= 1 ? 3 : \
+ sizeof(type) <= 2 ? 5 : \
+ sizeof(type) <= 4 ? 10 : \
+ sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)])))
+
/*****************************************************************************/
/* if @str is NULL, return "(null)". Otherwise, allocate a buffer using
- * alloca() of size @bufsize and fill it with @str. @str will be quoted with
- * single quote, and in case @str is too long, the final quote will be '^'. */
-#define nm_strquote_a(bufsize, str) \
+ * alloca() of and fill it with @str. @str will be quoted with double quote.
+ * If @str is longer then @trunc_at, the string is truncated and the closing
+ * quote is instead '^' to indicate truncation.
+ *
+ * Thus, the maximum stack allocated buffer will be @trunc_at+3. */
+#define nm_strquote_a(trunc_at, str) \
({ \
- G_STATIC_ASSERT ((bufsize) >= 6); \
- const gsize _BUFSIZE = (bufsize); \
- const char *const _s = (str); \
- char *_r; \
- gsize _l; \
- gboolean _truncated; \
+ const char *const _str = (str); \
\
- nm_assert (_BUFSIZE >= 6); \
- \
- if (_s) { \
- _l = strlen (_s) + 3; \
- if ((_truncated = (_BUFSIZE < _l))) \
- _l = _BUFSIZE; \
- \
- _r = g_alloca (_l); \
- _r[0] = '\''; \
- memcpy (&_r[1], _s, _l - 3); \
- _r[_l - 2] = _truncated ? '^' : '\''; \
- _r[_l - 1] = '\0'; \
- } else \
- _r = "(null)"; \
- _r; \
+ (_str \
+ ? ({ \
+ const gsize _trunc_at = (trunc_at); \
+ const gsize _strlen_trunc = NM_MIN (strlen (_str), _trunc_at); \
+ char *_buf; \
+ \
+ _buf = g_alloca (_strlen_trunc + 3); \
+ _buf[0] = '"'; \
+ memcpy (&_buf[1], _str, _strlen_trunc); \
+ _buf[_strlen_trunc + 1] = _str[_strlen_trunc] ? '^' : '"'; \
+ _buf[_strlen_trunc + 2] = '\0'; \
+ _buf; \
+ }) \
+ : "(null)"); \
})
-#define nm_sprintf_buf(buf, format, ...) ({ \
+#define nm_sprintf_buf(buf, format, ...) \
+ ({ \
char * _buf = (buf); \
+ int _buf_len; \
\
/* some static assert trying to ensure that the buffer is statically allocated.
* It disallows a buffer size of sizeof(gpointer) to catch that. */ \
G_STATIC_ASSERT (G_N_ELEMENTS (buf) == sizeof (buf) && sizeof (buf) != sizeof (char *)); \
- g_snprintf (_buf, sizeof (buf), \
- ""format"", ##__VA_ARGS__); \
+ _buf_len = g_snprintf (_buf, sizeof (buf), \
+ ""format"", ##__VA_ARGS__); \
+ nm_assert (_buf_len < sizeof (buf)); \
_buf; \
})
#define nm_sprintf_bufa(n_elements, format, ...) \
({ \
char *_buf; \
+ int _buf_len; \
+ typeof (n_elements) _n_elements = (n_elements); \
\
- G_STATIC_ASSERT (sizeof (char[MAX ((n_elements), 1)]) == (n_elements)); \
- _buf = g_alloca (n_elements); \
- g_snprintf (_buf, n_elements, \
- ""format"", ##__VA_ARGS__); \
+ _buf = g_alloca (_n_elements); \
+ _buf_len = g_snprintf (_buf, _n_elements, \
+ ""format"", ##__VA_ARGS__); \
+ nm_assert (_buf_len < _n_elements); \
_buf; \
})
@@ -713,6 +1029,32 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro) {
#define false 0
#endif
+
+#ifdef _G_BOOLEAN_EXPR
+/* g_assert() uses G_LIKELY(), which in turn uses _G_BOOLEAN_EXPR().
+ * As glib's implementation uses a local variable _g_boolean_var_,
+ * we cannot do
+ * g_assert (some_macro ());
+ * where some_macro() itself expands to ({g_assert(); ...}).
+ * In other words, you cannot have a g_assert() inside a g_assert()
+ * without getting a -Werror=shadow failure.
+ *
+ * Workaround that by re-defining _G_BOOLEAN_EXPR()
+ **/
+#undef _G_BOOLEAN_EXPR
+#define __NM_G_BOOLEAN_EXPR_IMPL(v, expr) \
+ ({ \
+ int NM_UNIQ_T(V, v); \
+ \
+ if (expr) \
+ NM_UNIQ_T(V, v) = 1; \
+ else \
+ NM_UNIQ_T(V, v) = 0; \
+ NM_UNIQ_T(V, v); \
+ })
+#define _G_BOOLEAN_EXPR(expr) __NM_G_BOOLEAN_EXPR_IMPL (NM_UNIQ, expr)
+#endif
+
/*****************************************************************************/
#endif /* __NM_MACROS_INTERNAL_H__ */
diff --git a/shared/nm-utils/nm-shared-utils.c b/shared/nm-utils/nm-shared-utils.c
index 38f6529d..0109818a 100644
--- a/shared/nm-utils/nm-shared-utils.c
+++ b/shared/nm-utils/nm-shared-utils.c
@@ -24,6 +24,221 @@
#include "nm-shared-utils.h"
#include <errno.h>
+#include <arpa/inet.h>
+
+/*****************************************************************************/
+
+const void *const _NM_PTRARRAY_EMPTY[1] = { NULL };
+
+/*****************************************************************************/
+
+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;
+ }
+}
+
+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;
+ }
+}
+
+void
+nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...)
+{
+ char *p = *buf;
+ va_list args;
+ gint retval;
+
+ if (*len == 0)
+ return;
+
+ va_start (args, format);
+ retval = g_vsnprintf (p, *len, format, args);
+ va_end (args);
+
+ if (retval >= *len) {
+ *buf = &p[*len];
+ *len = 0;
+ } else {
+ *buf = &p[retval];
+ *len -= retval;
+ }
+}
+
+/*****************************************************************************/
+
+/**
+ * _nm_utils_ip4_prefix_to_netmask:
+ * @prefix: a CIDR prefix
+ *
+ * Returns: the netmask represented by the prefix, in network byte order
+ **/
+guint32
+_nm_utils_ip4_prefix_to_netmask (guint32 prefix)
+{
+ return prefix < 32 ? ~htonl(0xFFFFFFFF >> prefix) : 0xFFFFFFFF;
+}
+
+/**
+ * _nm_utils_ip4_get_default_prefix:
+ * @ip: an IPv4 address (in network byte order)
+ *
+ * When the Internet was originally set up, various ranges of IP addresses were
+ * segmented into three network classes: A, B, and C. This function will return
+ * a prefix that is associated with the IP address specified defining where it
+ * falls in the predefined classes.
+ *
+ * Returns: the default class prefix for the given IP
+ **/
+/* The function is originally from ipcalc.c of Red Hat's initscripts. */
+guint32
+_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 */
+
+ 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);
+ }
+}
+
+/*****************************************************************************/
+
+gboolean
+nm_utils_parse_inaddr (const char *text,
+ int family,
+ char **out_addr)
+{
+ union {
+ in_addr_t v4;
+ struct in6_addr v6;
+ } addrbin;
+ char addrstr_buf[MAX (INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
+
+ g_return_val_if_fail (text, FALSE);
+
+ if (family == AF_UNSPEC)
+ family = strchr (text, ':') ? AF_INET6 : AF_INET;
+ else
+ g_return_val_if_fail (NM_IN_SET (family, AF_INET, AF_INET6), FALSE);
+
+ if (inet_pton (family, text, &addrbin) != 1)
+ return FALSE;
+
+ NM_SET_OUT (out_addr, g_strdup (inet_ntop (family, &addrbin, addrstr_buf, sizeof (addrstr_buf))));
+ return TRUE;
+}
+
+gboolean
+nm_utils_parse_inaddr_prefix (const char *text,
+ int family,
+ char **out_addr,
+ int *out_prefix)
+{
+ gs_free char *addrstr_free = NULL;
+ int prefix = -1;
+ const char *slash;
+ const char *addrstr;
+ union {
+ in_addr_t v4;
+ struct in6_addr v6;
+ } addrbin;
+ char addrstr_buf[MAX (INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
+
+ g_return_val_if_fail (text, FALSE);
+
+ if (family == AF_UNSPEC)
+ family = strchr (text, ':') ? AF_INET6 : AF_INET;
+ else
+ g_return_val_if_fail (NM_IN_SET (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 (family, addrstr, &addrbin) != 1)
+ return FALSE;
+
+ if (slash) {
+ prefix = _nm_utils_ascii_str_to_int64 (slash + 1, 10,
+ 0,
+ family == AF_INET ? 32 : 128,
+ -1);
+ if (prefix == -1)
+ return FALSE;
+ }
+
+ NM_SET_OUT (out_addr, g_strdup (inet_ntop (family, &addrbin, addrstr_buf, sizeof (addrstr_buf))));
+ NM_SET_OUT (out_prefix, prefix);
+ return TRUE;
+}
/*****************************************************************************/
@@ -45,7 +260,7 @@ gint64
_nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback)
{
gint64 v;
- char *s = NULL;
+ const char *s = NULL;
if (str) {
while (g_ascii_isspace (str[0]))
@@ -57,7 +272,7 @@ _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 ma
}
errno = 0;
- v = g_ascii_strtoll (str, &s, base);
+ v = g_ascii_strtoll (str, (char **) &s, base);
if (errno != 0)
return fallback;
@@ -79,6 +294,83 @@ _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 ma
/*****************************************************************************/
+/**
+ * nm_utils_strv_find_first:
+ * @list: the strv list to search
+ * @len: the length of the list, or a negative value if @list is %NULL terminated.
+ * @needle: the value to search for. The search is done using strcmp().
+ *
+ * Searches @list for @needle and returns the index of the first match (based
+ * on strcmp()).
+ *
+ * For convenience, @list has type 'char**' instead of 'const char **'.
+ *
+ * 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;
+}
+
+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) {
+ 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;
+}
+
+/*****************************************************************************/
+
gint
_nm_utils_ascii_str_to_bool (const char *str,
gint default_value)
@@ -113,7 +405,7 @@ _nm_utils_ascii_str_to_bool (const char *str,
/*****************************************************************************/
-G_DEFINE_QUARK (nm-utils-error-quark, nm_utils_error)
+NM_CACHED_QUARK_FCN ("nm-utils-error-quark", nm_utils_error_quark)
void
nm_utils_error_set_cancelled (GError **error,
@@ -236,4 +528,152 @@ nm_g_object_set_property (GObject *object,
return TRUE;
}
+GParamSpec *
+nm_g_object_class_find_property_from_gtype (GType gtype,
+ const char *property_name)
+{
+ nm_auto_unref_gtypeclass GObjectClass *gclass = NULL;
+
+ gclass = g_type_class_ref (gtype);
+ return g_object_class_find_property (gclass, property_name);
+}
+
/*****************************************************************************/
+
+static void
+_str_append_escape (GString *s, char ch)
+{
+ g_string_append_c (s, '\\');
+ g_string_append_c (s, '0' + ((((guchar) ch) >> 6) & 07));
+ g_string_append_c (s, '0' + ((((guchar) ch) >> 3) & 07));
+ g_string_append_c (s, '0' + ( ((guchar) ch) & 07));
+}
+
+/**
+ * nm_utils_str_utf8safe_escape:
+ * @str: NUL terminated input string, possibly in utf-8 encoding
+ * @flags: #NMUtilsStrUtf8SafeFlags flags
+ * @to_free: (out): return the pointer location of the string
+ * if a copying was necessary.
+ *
+ * Returns the possible non-UTF-8 NUL terminated string @str
+ * and uses backslash escaping (C escaping, like g_strescape())
+ * to sanitize non UTF-8 characters. The result is valid
+ * UTF-8.
+ *
+ * The operation can be reverted with g_strcompress() or
+ * nm_utils_str_utf8safe_unescape().
+ *
+ * Depending on @flags, valid UTF-8 characters are not escaped at all
+ * (except the escape character '\\'). This is the difference to g_strescape(),
+ * which escapes all non-ASCII characters. This allows to pass on
+ * valid UTF-8 characters as-is and can be directly shown to the user
+ * as UTF-8 -- with exception of the backslash escape character,
+ * invalid UTF-8 sequences, and other (depending on @flags).
+ *
+ * Returns: the escaped input string, as valid UTF-8. If no escaping
+ * is necessary, it returns the input @str. Otherwise, an allocated
+ * string @to_free is returned which must be freed by the caller
+ * 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)
+{
+ const char *p = NULL;
+ GString *s;
+
+ g_return_val_if_fail (to_free, NULL);
+
+ *to_free = NULL;
+ if (!str || !str[0])
+ return str;
+
+ if ( g_utf8_validate (str, -1, &p)
+ && !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;
+
+ s = g_string_sized_new ((p - str) + strlen (p) + 5);
+
+ do {
+ for (; str < p; str++) {
+ char ch = str[0];
+
+ if (ch == '\\')
+ g_string_append (s, "\\\\");
+ 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_append_escape (s, ch);
+ else
+ g_string_append_c (s, ch);
+ }
+
+ if (p[0] == '\0')
+ break;
+ _str_append_escape (s, p[0]);
+
+ str = &p[1];
+ g_utf8_validate (str, -1, &p);
+ } while (TRUE);
+
+ *to_free = g_string_free (s, FALSE);
+ return *to_free;
+}
+
+const char *
+nm_utils_str_utf8safe_unescape (const char *str, char **to_free)
+{
+ g_return_val_if_fail (to_free, NULL);
+
+ if (!str || !strchr (str, '\\')) {
+ *to_free = NULL;
+ return str;
+ }
+ return (*to_free = g_strcompress (str));
+}
+
+/**
+ * nm_utils_str_utf8safe_escape_cp:
+ * @str: NUL terminated input string, possibly in utf-8 encoding
+ * @flags: #NMUtilsStrUtf8SafeFlags flags
+ *
+ * Like nm_utils_str_utf8safe_escape(), except the returned value
+ * is always a copy of the input and must be freed by the caller.
+ *
+ * Returns: the escaped input string in UTF-8 encoding. The returned
+ * value should be freed with g_free().
+ * The escaping can be reverted by g_strcompress().
+ **/
+char *
+nm_utils_str_utf8safe_escape_cp (const char *str, NMUtilsStrUtf8SafeFlags flags)
+{
+ char *s;
+
+ nm_utils_str_utf8safe_escape (str, flags, &s);
+ return s ?: g_strdup (str);
+}
+
+char *
+nm_utils_str_utf8safe_unescape_cp (const char *str)
+{
+ return str ? g_strcompress (str) : NULL;
+}
+
+char *
+nm_utils_str_utf8safe_escape_take (char *str, NMUtilsStrUtf8SafeFlags flags)
+{
+ 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;
+}
diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h
index f77fb0e3..8d1085f6 100644
--- a/shared/nm-utils/nm-shared-utils.h
+++ b/shared/nm-utils/nm-shared-utils.h
@@ -24,6 +24,142 @@
/*****************************************************************************/
+#define NM_CMP_RETURN(c) \
+ G_STMT_START { \
+ const int _cc = (c); \
+ if (_cc) \
+ return _cc < 0 ? -1 : 1; \
+ } G_STMT_END
+
+#define NM_CMP_SELF(a, b) \
+ G_STMT_START { \
+ typeof (a) _a = (a); \
+ typeof (b) _b = (b); \
+ \
+ if (_a == _b) \
+ return 0; \
+ if (!_a) \
+ return -1; \
+ if (!_b) \
+ return 1; \
+ } G_STMT_END
+
+#define NM_CMP_DIRECT(a, b) \
+ G_STMT_START { \
+ typeof (a) _a = (a); \
+ typeof (b) _b = (b); \
+ \
+ if (_a != _b) \
+ return (_a < _b) ? -1 : 1; \
+ } G_STMT_END
+
+#define NM_CMP_DIRECT_MEMCMP(a, b, size) \
+ NM_CMP_RETURN (memcmp ((a), (b), (size)))
+
+#define NM_CMP_DIRECT_IN6ADDR(a, b) \
+ G_STMT_START { \
+ const struct in6_addr *const _a = (a); \
+ const struct in6_addr *const _b = (b); \
+ NM_CMP_RETURN (memcmp (_a, _b, sizeof (struct in6_addr))); \
+ } G_STMT_END
+
+#define NM_CMP_FIELD(a, b, field) \
+ NM_CMP_DIRECT (((a)->field), ((b)->field))
+
+#define NM_CMP_FIELD_UNSAFE(a, b, field) \
+ G_STMT_START { \
+ /* it's unsafe, because it evaluates the arguments more then once.
+ * This is necessary for bitfields, for which typeof() doesn't work. */ \
+ if (((a)->field) != ((b)->field)) \
+ return ((a)->field < ((b)->field)) ? -1 : 1; \
+ } G_STMT_END
+
+#define NM_CMP_FIELD_BOOL(a, b, field) \
+ NM_CMP_DIRECT (!!((a)->field), !!((b)->field))
+
+#define NM_CMP_FIELD_STR(a, b, field) \
+ NM_CMP_RETURN (strcmp (((a)->field), ((b)->field)))
+
+#define NM_CMP_FIELD_STR_INTERNED(a, b, field) \
+ G_STMT_START { \
+ const char *_a = ((a)->field); \
+ const char *_b = ((b)->field); \
+ \
+ if (_a != _b) { \
+ NM_CMP_RETURN (g_strcmp0 (_a, _b)); \
+ } \
+ } G_STMT_END
+
+#define NM_CMP_FIELD_STR0(a, b, field) \
+ NM_CMP_RETURN (g_strcmp0 (((a)->field), ((b)->field)))
+
+#define NM_CMP_FIELD_MEMCMP_LEN(a, b, field, len) \
+ NM_CMP_RETURN (memcmp (&((a)->field), &((b)->field), \
+ MIN (len, sizeof ((a)->field))))
+
+#define NM_CMP_FIELD_MEMCMP(a, b, field) \
+ NM_CMP_RETURN (memcmp (&((a)->field), \
+ &((b)->field), \
+ sizeof ((a)->field)))
+
+#define NM_CMP_FIELD_IN6ADDR(a, b, field) \
+ G_STMT_START { \
+ const struct in6_addr *const _a = &((a)->field); \
+ const struct in6_addr *const _b = &((b)->field); \
+ NM_CMP_RETURN (memcmp (_a, _b, sizeof (struct in6_addr))); \
+ } G_STMT_END
+
+/*****************************************************************************/
+
+extern const void *const _NM_PTRARRAY_EMPTY[1];
+
+#define NM_PTRARRAY_EMPTY(type) ((type const*) _NM_PTRARRAY_EMPTY)
+
+static inline void
+_nm_utils_strbuf_init (char *buf, gsize len, char **p_buf_ptr, gsize *p_buf_len)
+{
+ NM_SET_OUT (p_buf_len, len);
+ NM_SET_OUT (p_buf_ptr, buf);
+ buf[0] = '\0';
+}
+
+#define nm_utils_strbuf_init(buf, p_buf_ptr, p_buf_len) \
+ G_STMT_START { \
+ G_STATIC_ASSERT (G_N_ELEMENTS (buf) == sizeof (buf) && sizeof (buf) > sizeof (char *)); \
+ _nm_utils_strbuf_init ((buf), sizeof (buf), (p_buf_ptr), (p_buf_len)); \
+ } G_STMT_END
+void nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...) _nm_printf (3, 4);
+void nm_utils_strbuf_append_c (char **buf, gsize *len, char c);
+void nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str);
+
+/*****************************************************************************/
+
+gssize nm_utils_strv_find_first (char **list, gssize len, const char *needle);
+
+char **_nm_utils_strv_cleanup (char **strv,
+ gboolean strip_whitespace,
+ gboolean skip_empty,
+ gboolean skip_repeated);
+
+/*****************************************************************************/
+
+guint32 _nm_utils_ip4_prefix_to_netmask (guint32 prefix);
+guint32 _nm_utils_ip4_get_default_prefix (guint32 ip);
+
+gboolean nm_utils_ip_is_site_local (int addr_family,
+ const void *address);
+
+/*****************************************************************************/
+
+gboolean nm_utils_parse_inaddr (const char *text,
+ int family,
+ char **out_addr);
+
+gboolean nm_utils_parse_inaddr_prefix (const char *text,
+ int family,
+ char **out_addr,
+ int *out_prefix);
+
gint64 _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback);
gint _nm_utils_ascii_str_to_bool (const char *str,
@@ -31,6 +167,53 @@ gint _nm_utils_ascii_str_to_bool (const char *str,
/*****************************************************************************/
+#define _nm_g_slice_free_fcn_define(mem_size) \
+static inline void \
+_nm_g_slice_free_fcn_##mem_size (gpointer mem_block) \
+{ \
+ g_slice_free1 (mem_size, mem_block); \
+}
+
+_nm_g_slice_free_fcn_define (1)
+_nm_g_slice_free_fcn_define (2)
+_nm_g_slice_free_fcn_define (4)
+_nm_g_slice_free_fcn_define (8)
+_nm_g_slice_free_fcn_define (16)
+
+#define _nm_g_slice_free_fcn1(mem_size) \
+ ({ \
+ void (*_fcn) (gpointer); \
+ \
+ /* If mem_size is a compile time constant, the compiler
+ * will be able to optimize this. Hence, you don't want
+ * to call this with a non-constant size argument. */ \
+ switch (mem_size) { \
+ case 1: _fcn = _nm_g_slice_free_fcn_1; break; \
+ case 2: _fcn = _nm_g_slice_free_fcn_2; break; \
+ case 4: _fcn = _nm_g_slice_free_fcn_4; break; \
+ case 8: _fcn = _nm_g_slice_free_fcn_8; break; \
+ case 16: _fcn = _nm_g_slice_free_fcn_16; break; \
+ default: g_assert_not_reached (); _fcn = NULL; break; \
+ } \
+ _fcn; \
+ })
+
+/**
+ * nm_g_slice_free_fcn:
+ * @type: type argument for sizeof() operator that you would
+ * pass to g_slice_new().
+ *
+ * Returns: a function pointer with GDestroyNotify signature
+ * for g_slice_free(type,*).
+ *
+ * Only certain types are implemented. You'll get an assertion
+ * using the wrong type. */
+#define nm_g_slice_free_fcn(type) (_nm_g_slice_free_fcn1 (sizeof (type)))
+
+#define nm_g_slice_free_fcn_gint64 (nm_g_slice_free_fcn (gint64))
+
+/*****************************************************************************/
+
/**
* NMUtilsError:
* @NM_UTILS_ERROR_UNKNOWN: unknown or unclassified error
@@ -39,10 +222,12 @@ gint _nm_utils_ascii_str_to_bool (const char *str,
* error reason. Depending on the usage, this might indicate a bug because
* usually the target object should stay alive as long as there are pending
* operations.
+ * @NM_UTILS_ERROR_INVALID_ARGUMENT: invalid argument.
*/
typedef enum {
NM_UTILS_ERROR_UNKNOWN = 0, /*< nick=Unknown >*/
NM_UTILS_ERROR_CANCELLED_DISPOSING, /*< nick=CancelledDisposing >*/
+ NM_UTILS_ERROR_INVALID_ARGUMENT, /*< nick=InvalidArgument >*/
} NMUtilsError;
#define NM_UTILS_ERROR (nm_utils_error_quark ())
@@ -61,6 +246,25 @@ gboolean nm_g_object_set_property (GObject *object,
const GValue *value,
GError **error);
+GParamSpec *nm_g_object_class_find_property_from_gtype (GType gtype,
+ const char *property_name);
+
+/*****************************************************************************/
+
+typedef enum {
+ NM_UTILS_STR_UTF8_SAFE_FLAG_NONE = 0,
+ NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL = 0x0001,
+ NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII = 0x0002,
+} NMUtilsStrUtf8SafeFlags;
+
+const char *nm_utils_str_utf8safe_escape (const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free);
+const char *nm_utils_str_utf8safe_unescape (const char *str, char **to_free);
+
+char *nm_utils_str_utf8safe_escape_cp (const char *str, NMUtilsStrUtf8SafeFlags flags);
+char *nm_utils_str_utf8safe_unescape_cp (const char *str);
+
+char *nm_utils_str_utf8safe_escape_take (char *str, NMUtilsStrUtf8SafeFlags flags);
+
/*****************************************************************************/
#endif /* __NM_SHARED_UTILS_H__ */
diff --git a/shared/nm-utils/nm-test-utils.h b/shared/nm-utils/nm-test-utils.h
index 64604e38..f7a87aae 100644
--- a/shared/nm-utils/nm-test-utils.h
+++ b/shared/nm-utils/nm-test-utils.h
@@ -41,7 +41,7 @@
* NMTST_SEED_RAND environment variable:
* Tests that use random numbers from nmtst_get_rand() get seeded randomly at each start.
* You can specify the seed by setting NMTST_SEED_RAND. Also, tests will print the seed
- * to stdout, so that you know the choosen seed.
+ * to stdout, so that you know the chosen seed.
*
*
* NMTST_DEBUG environment variable:
@@ -82,7 +82,8 @@
* Whether long-running tests are enabled is determined as follows (highest priority first):
* - specifying the value in NMTST_DEBUG has highest priority
* - respect g_test_quick(), if the command line contains '-mslow', '-mquick', '-mthorough'.
- * - use compile time default
+ * - use compile time default (CFLAGS=-DNMTST_TEST_QUICK=TRUE)
+ * - enable slow tests by default
*
* "p=PATH"|"s=PATH": passes the path to g_test_init() as "-p" and "-s", respectively.
* Unfortunately, these options conflict with "--tap" which our makefile passes to the
@@ -137,12 +138,13 @@
#define NMTST_WAIT(max_wait_ms, wait) \
({ \
gboolean _not_expired = TRUE; \
- gint64 _nmtst_end, _nmtst_max_wait_us = (max_wait_ms) * 1000L; \
+ const gint64 nmtst_wait_start_us = g_get_monotonic_time (); \
+ const gint64 nmtst_wait_duration_us = (max_wait_ms) * 1000L; \
+ const gint64 nmtst_wait_end_us = nmtst_wait_start_us + nmtst_wait_duration_us; \
\
- _nmtst_end = g_get_monotonic_time () + _nmtst_max_wait_us; \
while (TRUE) { \
{ wait }; \
- if (g_get_monotonic_time () > _nmtst_end) { \
+ if (g_get_monotonic_time () > nmtst_wait_end_us) { \
_not_expired = FALSE; \
break; \
} \
@@ -198,7 +200,7 @@ _nmtst_exit (void) \
}
-inline static gboolean
+static inline gboolean
nmtst_initialized (void)
{
return !!__nmtst_internal.rand0;
@@ -219,7 +221,7 @@ nmtst_initialized (void)
*
* The caller must g_free() the returned argv array.
**/
-inline static char **
+static inline char **
nmtst_str_split (char *str, const char *delimiters)
{
const char *d;
@@ -265,7 +267,7 @@ BREAK_INNER_LOOPS:
/* free instances allocated by nmtst (especially nmtst_init()) on shutdown
* to release memory. After nmtst_free(), the test is uninitialized again. */
-inline static void
+static inline void
nmtst_free (void)
{
if (!nmtst_initialized ())
@@ -280,7 +282,16 @@ nmtst_free (void)
memset (&__nmtst_internal, 0, sizeof (__nmtst_internal));
}
-inline static void
+static inline void
+_nmtst_log_handler (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer user_data)
+{
+ g_print ("%s\n", message);
+}
+
+static inline void
__nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_level, const char *log_domains, gboolean *out_set_logging)
{
const char *nmtst_debug;
@@ -589,24 +600,29 @@ __nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_
g_assert_no_error (error);
}
#endif
+
+ g_log_set_handler (G_LOG_DOMAIN,
+ G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
+ _nmtst_log_handler,
+ NULL);
}
#ifndef _NMTST_INSIDE_CORE
-inline static void
+static inline void
nmtst_init (int *argc, char ***argv, gboolean assert_logging)
{
__nmtst_init (argc, argv, assert_logging, NULL, NULL, NULL);
}
#endif
-inline static gboolean
+static inline gboolean
nmtst_is_debug (void)
{
g_assert (nmtst_initialized ());
return __nmtst_internal.is_debug;
}
-inline static gboolean
+static inline gboolean
nmtst_test_quick (void)
{
g_assert (nmtst_initialized ());
@@ -647,16 +663,21 @@ nmtst_test_quick (void)
typedef struct _NmtstTestData NmtstTestData;
-typedef void (*NmtstTestDataRelease) (const NmtstTestData *test_data);
+typedef void (*NmtstTestHandler) (const NmtstTestData *test_data);
struct _NmtstTestData {
- const char *testpath;
- NmtstTestDataRelease fcn_release;
+ union {
+ const char *testpath;
+ char *_testpath;
+ };
gsize n_args;
- gpointer args[1];
+ gpointer *args;
+ NmtstTestHandler _func_setup;
+ GTestDataFunc _func_test;
+ NmtstTestHandler _func_teardown;
};
-inline static void
+static inline void
_nmtst_test_data_unpack (const NmtstTestData *test_data, gsize n_args, ...)
{
gsize i;
@@ -670,39 +691,56 @@ _nmtst_test_data_unpack (const NmtstTestData *test_data, gsize n_args, ...)
for (i = 0; i < n_args; i++) {
p = va_arg (ap, gpointer *);
- g_assert (p);
- *p = test_data->args[i];
+ if (p)
+ *p = test_data->args[i];
}
va_end (ap);
}
#define nmtst_test_data_unpack(test_data, ...) _nmtst_test_data_unpack(test_data, NM_NARG (__VA_ARGS__), ##__VA_ARGS__)
-inline static void
+static inline void
_nmtst_test_data_free (gpointer data)
{
NmtstTestData *test_data = data;
g_assert (test_data);
- if (test_data->fcn_release)
- test_data->fcn_release (test_data);
-
- g_free ((gpointer) test_data->testpath);
+ g_free (test_data->_testpath);
g_free (test_data);
}
-inline static void
-_nmtst_add_test_func_full (const char *testpath, GTestDataFunc test_func, NmtstTestDataRelease fcn_release, gsize n_args, ...)
+static inline void
+_nmtst_test_run (gconstpointer data)
+{
+ const NmtstTestData *test_data = data;
+
+ if (test_data->_func_setup)
+ test_data->_func_setup (test_data);
+
+ test_data->_func_test (test_data);
+
+ if (test_data->_func_teardown)
+ test_data->_func_teardown (test_data);
+}
+
+static inline void
+_nmtst_add_test_func_full (const char *testpath, GTestDataFunc func_test, NmtstTestHandler func_setup, NmtstTestHandler func_teardown, gsize n_args, ...)
{
gsize i;
NmtstTestData *data;
va_list ap;
- data = g_malloc (G_STRUCT_OFFSET (NmtstTestData, args) + sizeof (gpointer) * (n_args + 1));
+ g_assert (testpath && testpath[0]);
+ g_assert (func_test);
+
+ data = g_malloc0 (sizeof (NmtstTestData) + (sizeof (gpointer) * (n_args + 1)));
- data->testpath = g_strdup (testpath);
- data->fcn_release = fcn_release;
+ data->_testpath = g_strdup (testpath);
+ data->_func_test = func_test;
+ data->_func_setup = func_setup;
+ data->_func_teardown = func_teardown;
data->n_args = n_args;
+ data->args = (gpointer) &data[1];
va_start (ap, n_args);
for (i = 0; i < n_args; i++)
data->args[i] = va_arg (ap, gpointer);
@@ -711,22 +749,22 @@ _nmtst_add_test_func_full (const char *testpath, GTestDataFunc test_func, NmtstT
g_test_add_data_func_full (testpath,
data,
- test_func,
+ _nmtst_test_run,
_nmtst_test_data_free);
}
-#define nmtst_add_test_func_full(testpath, test_func, fcn_release, ...) _nmtst_add_test_func_full(testpath, test_func, fcn_release, NM_NARG (__VA_ARGS__), ##__VA_ARGS__)
-#define nmtst_add_test_func(testpath, test_func, ...) nmtst_add_test_func_full(testpath, test_func, NULL, ##__VA_ARGS__)
+#define nmtst_add_test_func_full(testpath, func_test, func_setup, func_teardown, ...) _nmtst_add_test_func_full(testpath, func_test, func_setup, func_teardown, NM_NARG (__VA_ARGS__), ##__VA_ARGS__)
+#define nmtst_add_test_func(testpath, func_test, ...) nmtst_add_test_func_full(testpath, func_test, NULL, NULL, ##__VA_ARGS__)
/*****************************************************************************/
-inline static GRand *
+static inline GRand *
nmtst_get_rand0 (void)
{
g_assert (nmtst_initialized ());
return __nmtst_internal.rand0;
}
-inline static GRand *
+static inline GRand *
nmtst_get_rand (void)
{
g_assert (nmtst_initialized ());
@@ -757,13 +795,13 @@ nmtst_get_rand (void)
return __nmtst_internal.rand;
}
-inline static guint32
+static inline guint32
nmtst_get_rand_int (void)
{
return g_rand_int (nmtst_get_rand ());
}
-inline static gpointer
+static inline gpointer
nmtst_rand_buf (GRand *rand, gpointer buffer, gsize buffer_length)
{
guint32 v;
@@ -791,7 +829,7 @@ nmtst_rand_buf (GRand *rand, gpointer buffer, gsize buffer_length)
return buffer;
}
-inline static void *
+static inline void *
nmtst_rand_perm (GRand *rand, void *dst, const void *src, gsize elmt_size, gsize n_elmt)
{
gsize i, j;
@@ -832,9 +870,34 @@ nmtst_rand_perm (GRand *rand, void *dst, const void *src, gsize elmt_size, gsize
return dst;
}
+static inline GSList *
+nmtst_rand_perm_gslist (GRand *rand, GSList *list)
+{
+ GSList *result;
+ guint l;
+
+ if (!rand)
+ rand = nmtst_get_rand ();
+
+ /* no need for an efficient implementation :) */
+
+ result = 0;
+ for (l = g_slist_length (list); l > 0; l--) {
+ GSList *tmp;
+
+ tmp = g_slist_nth (list, g_rand_int (rand) % l);
+ g_assert (tmp);
+
+ list = g_slist_remove_link (list, tmp);
+ result = g_slist_concat (tmp, result);
+ }
+ g_assert (!list);
+ return result;
+}
+
/*****************************************************************************/
-inline static gboolean
+static inline gboolean
_nmtst_main_loop_run_timeout (gpointer user_data)
{
GMainLoop **p_loop = user_data;
@@ -848,7 +911,7 @@ _nmtst_main_loop_run_timeout (gpointer user_data)
return G_SOURCE_REMOVE;
}
-inline static gboolean
+static inline gboolean
nmtst_main_loop_run (GMainLoop *loop, int timeout_ms)
{
GSource *source = NULL;
@@ -869,7 +932,7 @@ nmtst_main_loop_run (GMainLoop *loop, int timeout_ms)
return loopx != NULL;
}
-inline static void
+static inline void
_nmtst_main_loop_quit_on_notify (GObject *object, GParamSpec *pspec, gpointer user_data)
{
GMainLoop *loop = user_data;
@@ -883,14 +946,14 @@ _nmtst_main_loop_quit_on_notify (GObject *object, GParamSpec *pspec, gpointer us
/*****************************************************************************/
-inline static const char *
+static inline const char *
nmtst_get_sudo_cmd (void)
{
g_assert (nmtst_initialized ());
return __nmtst_internal.sudo_cmd;
}
-inline static void
+static inline void
nmtst_reexec_sudo (void)
{
char *str;
@@ -920,7 +983,7 @@ nmtst_reexec_sudo (void)
/*****************************************************************************/
-inline static gsize
+static inline gsize
nmtst_find_all_indexes (gpointer *elements,
gsize n_elements,
gpointer *needles,
@@ -962,7 +1025,7 @@ next:
/*****************************************************************************/
#define __define_nmtst_static(NUM,SIZE) \
-inline static const char * \
+static inline const char * \
nmtst_static_##SIZE##_##NUM (const char *str) \
{ \
gsize l; \
@@ -979,7 +1042,11 @@ __define_nmtst_static(02, 1024)
__define_nmtst_static(03, 1024)
#undef __define_nmtst_static
-inline static const char *
+#define NMTST_UUID_INIT(uuid) \
+ gs_free char *_nmtst_hidden_##uuid = nm_utils_uuid_generate (); \
+ const char *const uuid = _nmtst_hidden_##uuid
+
+static inline const char *
nmtst_uuid_generate (void)
{
static char u[37];
@@ -1010,7 +1077,7 @@ nmtst_uuid_generate (void)
g_error ("%s:%d: Expects \"%s\" but got \"%s\"", __FILE__, __LINE__, __substr, __str); \
} G_STMT_END
-inline static guint32
+static inline guint32
nmtst_inet4_from_string (const char *str)
{
guint32 addr;
@@ -1026,7 +1093,7 @@ nmtst_inet4_from_string (const char *str)
return addr;
}
-inline static const struct in6_addr *
+static inline const struct in6_addr *
nmtst_inet6_from_string (const char *str)
{
static struct in6_addr addr;
@@ -1042,7 +1109,7 @@ nmtst_inet6_from_string (const char *str)
return &addr;
}
-inline static void
+static inline void
_nmtst_assert_ip4_address (const char *file, int line, in_addr_t addr, const char *str_expected)
{
if (nmtst_inet4_from_string (str_expected) != addr) {
@@ -1055,7 +1122,7 @@ _nmtst_assert_ip4_address (const char *file, int line, in_addr_t addr, const cha
}
#define nmtst_assert_ip4_address(addr, str_expected) _nmtst_assert_ip4_address (__FILE__, __LINE__, addr, str_expected)
-inline static void
+static inline void
_nmtst_assert_ip6_address (const char *file, int line, const struct in6_addr *addr, const char *str_expected)
{
struct in6_addr any = in6addr_any;
@@ -1075,9 +1142,9 @@ _nmtst_assert_ip6_address (const char *file, int line, const struct in6_addr *ad
#define nmtst_spawn_sync(working_directory, standard_out, standard_err, assert_exit_status, ...) \
__nmtst_spawn_sync (working_directory, standard_out, standard_err, assert_exit_status, ##__VA_ARGS__, NULL)
-inline static gint
+static inline gint
__nmtst_spawn_sync (const char *working_directory, char **standard_out, char **standard_err, int assert_exit_status, ...) G_GNUC_NULL_TERMINATED;
-inline static gint
+static inline gint
__nmtst_spawn_sync (const char *working_directory, char **standard_out, char **standard_err, int assert_exit_status, ...)
{
gint exit_status = 0;
@@ -1125,7 +1192,7 @@ __nmtst_spawn_sync (const char *working_directory, char **standard_out, char **s
/*****************************************************************************/
-inline static char *
+static inline char *
nmtst_file_resolve_relative_path (const char *rel, const char *cwd)
{
gs_free char *cwd_free = NULL;
@@ -1140,7 +1207,72 @@ nmtst_file_resolve_relative_path (const char *rel, const char *cwd)
return g_build_filename (cwd, rel, NULL);
}
-inline static void
+static inline char *
+nmtst_file_get_contents (const char *filename)
+{
+ GError *error = NULL;
+ gboolean success;
+ char *contents = NULL;
+ gsize len;
+
+ success = g_file_get_contents (filename, &contents, &len, &error);
+ nmtst_assert_success (success && contents, error);
+ g_assert_cmpint (strlen (contents), ==, len);
+ return contents;
+}
+
+#define nmtst_file_set_contents(filename, content) \
+ G_STMT_START { \
+ GError *_error = NULL; \
+ gboolean _success; \
+ \
+ _success = g_file_set_contents ((filename), (content), -1, &_error); \
+ nmtst_assert_success (_success, _error); \
+ } G_STMT_END
+
+/*****************************************************************************/
+
+static inline void
+nmtst_file_unlink_if_exists (const char *name)
+{
+ int errsv;
+
+ g_assert (name && name[0]);
+
+ if (unlink (name) != 0) {
+ errsv = errno;
+ if (errsv != ENOENT)
+ g_error ("nmtst_file_unlink_if_exists(%s): failed with %s", name, strerror (errsv));
+ }
+}
+
+static inline void
+nmtst_file_unlink (const char *name)
+{
+ int errsv;
+
+ g_assert (name && name[0]);
+
+ if (unlink (name) != 0) {
+ errsv = errno;
+ g_error ("nmtst_file_unlink(%s): failed with %s", name, strerror (errsv));
+ }
+}
+
+static inline void
+_nmtst_auto_unlinkfile (char **p_name)
+{
+ if (*p_name) {
+ nmtst_file_unlink (*p_name);
+ nm_clear_g_free (p_name);
+ }
+}
+
+#define nmtst_auto_unlinkfile nm_auto(_nmtst_auto_unlinkfile)
+
+/*****************************************************************************/
+
+static inline void
_nmtst_assert_resolve_relative_path_equals (const char *f1, const char *f2, const char *file, int line)
{
gs_free char *p1 = NULL, *p2 = NULL;
@@ -1159,7 +1291,7 @@ _nmtst_assert_resolve_relative_path_equals (const char *f1, const char *f2, cons
/*****************************************************************************/
#ifdef NM_SETTING_IP_CONFIG_H
-inline static void
+static inline void
nmtst_setting_ip_config_add_address (NMSettingIPConfig *s_ip,
const char *address,
guint prefix)
@@ -1182,7 +1314,7 @@ nmtst_setting_ip_config_add_address (NMSettingIPConfig *s_ip,
nm_ip_address_unref (addr);
}
-inline static void
+static inline void
nmtst_setting_ip_config_add_route (NMSettingIPConfig *s_ip,
const char *dest,
guint prefix,
@@ -1206,11 +1338,55 @@ nmtst_setting_ip_config_add_route (NMSettingIPConfig *s_ip,
g_assert (nm_setting_ip_config_add_route (s_ip, route));
nm_ip_route_unref (route);
}
+
+static inline void
+nmtst_assert_route_attribute_string (NMIPRoute *route, const char *name, const char *value)
+{
+ GVariant *variant;
+
+ variant = nm_ip_route_get_attribute (route, name);
+ g_assert (variant);
+ g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING));
+ g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, value);
+}
+
+static inline void
+nmtst_assert_route_attribute_byte (NMIPRoute *route, const char *name, guchar value)
+{
+ GVariant *variant;
+
+ variant = nm_ip_route_get_attribute (route, name);
+ g_assert (variant);
+ g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTE));
+ g_assert_cmpint (g_variant_get_byte (variant), ==, value);
+}
+
+static inline void
+nmtst_assert_route_attribute_uint32 (NMIPRoute *route, const char *name, guint32 value)
+{
+ GVariant *variant;
+
+ variant = nm_ip_route_get_attribute (route, name);
+ g_assert (variant);
+ g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32));
+ g_assert_cmpint (g_variant_get_uint32 (variant), ==, value);
+}
+
+static inline void
+nmtst_assert_route_attribute_boolean (NMIPRoute *route, const char *name, gboolean value)
+{
+ GVariant *variant;
+
+ variant = nm_ip_route_get_attribute (route, name);
+ g_assert (variant);
+ g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN));
+ g_assert_cmpint (g_variant_get_boolean (variant), ==, value);
+}
#endif /* NM_SETTING_IP_CONFIG_H */
#if (defined(__NM_SIMPLE_CONNECTION_H__) && defined(__NM_SETTING_CONNECTION_H__)) || (defined(NM_CONNECTION_H))
-inline static NMConnection *
+static inline NMConnection *
nmtst_clone_connection (NMConnection *connection)
{
g_assert (NM_IS_CONNECTION (connection));
@@ -1222,7 +1398,7 @@ nmtst_clone_connection (NMConnection *connection)
#endif
}
-inline static NMConnection *
+static inline NMConnection *
nmtst_create_minimal_connection (const char *id, const char *uuid, const char *type, NMSettingConnection **out_s_con)
{
NMConnection *con;
@@ -1275,7 +1451,7 @@ nmtst_create_minimal_connection (const char *id, const char *uuid, const char *t
return con;
}
-inline static gboolean
+static inline gboolean
_nmtst_connection_normalize_v (NMConnection *connection, va_list args)
{
GError *error = NULL;
@@ -1305,7 +1481,7 @@ _nmtst_connection_normalize_v (NMConnection *connection, va_list args)
return was_modified;
}
-inline static gboolean
+static inline gboolean
_nmtst_connection_normalize (NMConnection *connection, ...)
{
gboolean was_modified;
@@ -1320,7 +1496,7 @@ _nmtst_connection_normalize (NMConnection *connection, ...)
#define nmtst_connection_normalize(connection, ...) \
_nmtst_connection_normalize(connection, ##__VA_ARGS__, NULL)
-inline static NMConnection *
+static inline NMConnection *
_nmtst_connection_duplicate_and_normalize (NMConnection *connection, ...)
{
gboolean was_modified;
@@ -1337,7 +1513,7 @@ _nmtst_connection_duplicate_and_normalize (NMConnection *connection, ...)
#define nmtst_connection_duplicate_and_normalize(connection, ...) \
_nmtst_connection_duplicate_and_normalize(connection, ##__VA_ARGS__, NULL)
-inline static void
+static inline void
nmtst_assert_connection_equals (NMConnection *a, gboolean normalize_a, NMConnection *b, gboolean normalize_b)
{
gboolean compare;
@@ -1396,7 +1572,7 @@ nmtst_assert_connection_equals (NMConnection *a, gboolean normalize_a, NMConnect
g_assert (compare);
}
-inline static void
+static inline void
nmtst_assert_connection_verifies (NMConnection *con)
{
/* assert that the connection does verify, it might be normaliziable or not */
@@ -1410,7 +1586,7 @@ nmtst_assert_connection_verifies (NMConnection *con)
g_assert (success);
}
-inline static void
+static inline void
nmtst_assert_connection_verifies_without_normalization (NMConnection *con)
{
/* assert that the connection verifies and does not need any normalization */
@@ -1430,7 +1606,7 @@ nmtst_assert_connection_verifies_without_normalization (NMConnection *con)
g_assert (!was_modified);
}
-inline static void
+static inline void
nmtst_assert_connection_verifies_and_normalizable (NMConnection *con)
{
/* assert that the connection does verify, but normalization still modifies it */
@@ -1452,7 +1628,7 @@ nmtst_assert_connection_verifies_and_normalizable (NMConnection *con)
nmtst_assert_connection_verifies_without_normalization (clone);
}
-inline static void
+static inline void
nmtst_assert_connection_verifies_after_normalization (NMConnection *con,
GQuark expect_error_domain,
gint expect_error_code)
@@ -1479,7 +1655,7 @@ nmtst_assert_connection_verifies_after_normalization (NMConnection *con,
nmtst_assert_connection_verifies_without_normalization (clone);
}
-inline static void
+static inline void
nmtst_assert_connection_unnormalizable (NMConnection *con,
GQuark expect_error_domain,
gint expect_error_code)
@@ -1506,7 +1682,7 @@ nmtst_assert_connection_unnormalizable (NMConnection *con,
g_clear_error (&error);
}
-inline static void
+static inline void
nmtst_assert_setting_verifies (NMSetting *setting)
{
/* assert that the setting verifies without an error */
@@ -1521,7 +1697,7 @@ nmtst_assert_setting_verifies (NMSetting *setting)
g_assert (success);
}
-inline static void
+static inline void
nmtst_assert_setting_verify_fails (NMSetting *setting,
GQuark expect_error_domain,
gint expect_error_code)
@@ -1576,9 +1752,10 @@ nmtst_assert_hwaddr_equals (gconstpointer hwaddr1, gssize hwaddr1_len, const cha
nmtst_assert_hwaddr_equals (hwaddr1, hwaddr1_len, expected, __FILE__, __LINE__)
#endif
+
#if defined(__NM_SIMPLE_CONNECTION_H__) && defined(__NM_SETTING_CONNECTION_H__) && defined(__NM_KEYFILE_INTERNAL_H__)
-inline static NMConnection *
+static inline NMConnection *
nmtst_create_connection_from_keyfile (const char *keyfile_str, const char *keyfile_name, const char *base_dir)
{
GKeyFile *keyfile;
@@ -1608,7 +1785,7 @@ nmtst_create_connection_from_keyfile (const char *keyfile_str, const char *keyfi
#ifdef __NM_CONNECTION_H__
-inline static GVariant *
+static inline GVariant *
_nmtst_variant_new_vardict (int dummy, ...)
{
GVariantBuilder builder;