diff options
author | Thomas Haller <thaller@redhat.com> | 2017-09-07 17:45:21 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-09-07 18:11:54 +0200 |
commit | 61ab0224c54d1c52e5e46e6d08228f82eab3a390 (patch) | |
tree | f4daeea34d8058f24ab34544876cd0928b5a527b /shared | |
parent | 83e798d9eff577aa2f7f1f8f2f3fb2601e41b359 (diff) | |
download | network-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.h | 25 | ||||
-rw-r--r-- | shared/nm-utils/nm-macros-internal.h | 468 | ||||
-rw-r--r-- | shared/nm-utils/nm-shared-utils.c | 446 | ||||
-rw-r--r-- | shared/nm-utils/nm-shared-utils.h | 204 | ||||
-rw-r--r-- | shared/nm-utils/nm-test-utils.h | 317 |
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; |