diff options
Diffstat (limited to 'shared/nm-utils/nm-macros-internal.h')
| -rw-r--r-- | shared/nm-utils/nm-macros-internal.h | 276 |
1 files changed, 262 insertions, 14 deletions
diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h index 5fe4bc50..d9dab83d 100644 --- a/shared/nm-utils/nm-macros-internal.h +++ b/shared/nm-utils/nm-macros-internal.h @@ -26,20 +26,41 @@ #include <stdlib.h> #include <errno.h> -#include "nm-glib.h" +#define _nm_packed __attribute__ ((packed)) +#define _nm_unused __attribute__ ((unused)) +#define _nm_pure __attribute__ ((pure)) +#define _nm_const __attribute__ ((const)) +#define _nm_printf(a,b) __attribute__ ((__format__ (__printf__, a, b))) +#define _nm_align(s) __attribute__ ((aligned (s))) +#define _nm_alignof(type) __alignof (type) +#define _nm_alignas(type) _nm_align (_nm_alignof (type)) + +/*****************************************************************************/ + +#ifdef thread_local +#define _nm_thread_local thread_local +/* + * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__ + * see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769 + */ +#elif __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16)) +#define _nm_thread_local _Thread_local +#else +#define _nm_thread_local __thread +#endif /*****************************************************************************/ -#define _nm_packed __attribute__ ((packed)) -#define _nm_unused __attribute__ ((unused)) -#define _nm_pure __attribute__ ((pure)) -#define _nm_const __attribute__ ((const)) -#define _nm_printf(a,b) __attribute__ ((__format__ (__printf__, a, b))) +#include "nm-glib.h" + +/*****************************************************************************/ #define nm_offsetofend(t,m) (G_STRUCT_OFFSET (t,m) + sizeof (((t *) NULL)->m)) #define nm_auto(fcn) __attribute__ ((cleanup(fcn))) +static inline int nm_close (int fd); + /** * nm_auto_free: * @@ -56,6 +77,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) @@ -69,7 +98,7 @@ _nm_auto_close_impl (int *pfd) if (*pfd >= 0) { int errsv = errno; - (void) close (*pfd); + (void) nm_close (*pfd); errno = errsv; } } @@ -201,6 +230,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")); @@ -217,6 +263,47 @@ 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 + +#if _NM_CC_SUPPORT_GENERIC +/* returns @value, if the type of @value matches @type. + * This requires support for C11 _Generic(). If no support is + * present, this returns @value directly. + * + * It's useful to check the let the compiler ensure that @value is + * of a certain type. */ +#define _NM_ENSURE_TYPE(type, value) (_Generic ((value), type: (value))) +#else +#define _NM_ENSURE_TYPE(type, value) (value) +#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__) @@ -395,6 +482,16 @@ fcn (void) \ /*****************************************************************************/ +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) { @@ -487,7 +584,7 @@ _notify (obj_type *obj, _PropertyEnums prop) \ /* 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, result_cmd) \ +#define __NM_GET_PRIVATE(self, type, is_check, addrop) \ ({ \ /* preserve the const-ness of self. Unfortunately, that * way, @self cannot be a void pointer */ \ @@ -497,11 +594,11 @@ _notify (obj_type *obj, _PropertyEnums prop) \ _nm_unused const type *const _self2 = (_self); \ \ nm_assert (is_check (_self)); \ - ( result_cmd ); \ + ( addrop ( _NM_CONSTCAST (type, _self)->_priv) ); \ }) -#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(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) \ ({ \ @@ -540,6 +637,36 @@ nm_g_object_unref (gpointer obj) g_object_unref (obj); } +/* Assigns GObject @obj to destination @pdst, and takes an additional ref. + * The previous value of @pdst is unrefed. + * + * It makes sure to first increase the ref-count of @obj, and handles %NULL + * @obj correctly. + * */ +#define nm_g_object_ref_set(pp, obj) \ + ({ \ + typeof (*(pp)) *const _pp = (pp); \ + typeof (**_pp) *const _obj = (obj); \ + typeof (**_pp) *_p; \ + gboolean _changed = FALSE; \ + \ + if ( _pp \ + && ((_p = *_pp) != _obj)) { \ + if (_obj) { \ + nm_assert (G_IS_OBJECT (_obj)); \ + g_object_ref (_obj); \ + } \ + if (_p) { \ + nm_assert (G_IS_OBJECT (_p)); \ + *_pp = NULL; \ + g_object_unref (_p); \ + } \ + *_pp = _obj; \ + _changed = TRUE; \ + } \ + _changed; \ + }) + /* basically, replaces * g_clear_pointer (&location, g_free) * with @@ -552,13 +679,32 @@ nm_g_object_unref (gpointer obj) #define nm_clear_g_free(pp) \ ({ \ typeof (*(pp)) *_pp = (pp); \ - typeof (**_pp) *_p = *_pp; \ + typeof (**_pp) *_p; \ + gboolean _changed = FALSE; \ \ - if (_p) { \ + if ( _pp \ + && (_p = *_pp)) { \ *_pp = NULL; \ g_free (_p); \ + _changed = TRUE; \ + } \ + _changed; \ + }) + +#define nm_clear_g_object(pp) \ + ({ \ + typeof (*(pp)) *_pp = (pp); \ + typeof (**_pp) *_p; \ + gboolean _changed = FALSE; \ + \ + if ( _pp \ + && (_p = *_pp)) { \ + nm_assert (G_IS_OBJECT (_p)); \ + *_pp = NULL; \ + g_object_unref (_p); \ + _changed = TRUE; \ } \ - !!_p; \ + _changed; \ }) static inline gboolean @@ -620,6 +766,50 @@ nm_clear_g_cancellable (GCancellable **cancellable) /*****************************************************************************/ +#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; \ + }) + +/*****************************************************************************/ + /* 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) \ @@ -686,6 +876,33 @@ nm_strstrip (char *str) return str ? g_strstrip (str) : NULL; } +static inline const char * +nm_strstrip_avoid_copy (const char *str, char **str_free) +{ + gsize l; + char *s; + + nm_assert (str_free && !*str_free); + + if (!str) + return NULL; + + str = nm_str_skip_leading_spaces (str); + l = strlen (str); + if ( l == 0 + || !g_ascii_isspace (str[l - 1])) + return str; + while ( l > 0 + && g_ascii_isspace (str[l - 1])) + l--; + + s = g_new (char, l + 1); + memcpy (s, str, l); + s[l] = '\0'; + *str_free = s; + return s; +} + /* g_ptr_array_sort()'s compare function takes pointers to the * value. Thus, you cannot use strcmp directly. You can use * nm_strcmp_p(). @@ -934,4 +1151,35 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro) /*****************************************************************************/ +static inline int +nm_steal_fd (int *p_fd) +{ + int fd; + + if ( p_fd + && ((fd = *p_fd) >= 0)) { + *p_fd = -1; + return fd; + } + return -1; +} + +/** + * nm_close: + * + * Like close() but throws an assertion if the input fd is + * invalid. Closing an invalid fd is a programming error, so + * it's better to catch it early. + */ +static inline int +nm_close (int fd) +{ + if (fd >= 0) { + if (close (fd) == 0) + return 0; + nm_assert (errno != EBADF); + } + return -1; +} + #endif /* __NM_MACROS_INTERNAL_H__ */ |