diff options
Diffstat (limited to 'src/libnm-glib-aux/nm-shared-utils.h')
| -rw-r--r-- | src/libnm-glib-aux/nm-shared-utils.h | 532 |
1 files changed, 380 insertions, 152 deletions
diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h index dcf37cd3..8dd53dcf 100644 --- a/src/libnm-glib-aux/nm-shared-utils.h +++ b/src/libnm-glib-aux/nm-shared-utils.h @@ -18,6 +18,7 @@ typedef enum _nm_packed { NM_OPTION_BOOL_TRUE = 1, } NMOptionBool; +#define nm_assert_is_bool(value) nm_assert(NM_IN_SET((value), 0, 1)) #define nm_assert_is_ternary(value) nm_assert(NM_IN_SET((value), -1, 0, 1)) /*****************************************************************************/ @@ -35,19 +36,19 @@ pid_t nm_utils_gettid(void); gboolean _nm_assert_on_main_thread(void); #if NM_MORE_ASSERTS > 5 - #define NM_ASSERT_ON_MAIN_THREAD() \ - G_STMT_START \ - { \ - nm_assert(_nm_assert_on_main_thread()); \ - } \ - G_STMT_END +#define NM_ASSERT_ON_MAIN_THREAD() \ + G_STMT_START \ + { \ + nm_assert(_nm_assert_on_main_thread()); \ + } \ + G_STMT_END #else - #define NM_ASSERT_ON_MAIN_THREAD() \ - G_STMT_START \ - { \ - ; \ - } \ - G_STMT_END +#define NM_ASSERT_ON_MAIN_THREAD() \ + G_STMT_START \ + { \ + ; \ + } \ + G_STMT_END #endif /*****************************************************************************/ @@ -79,20 +80,20 @@ _NM_INT_NOT_NEGATIVE(gssize val) * Together with the G_STATIC_ASSERT(), we make sure that this is always satisfied. */ G_STATIC_ASSERT(sizeof(int) == sizeof(gint32)); #if _NM_CC_SUPPORT_GENERIC - #define _NM_INT_LE_MAXINT32(value) \ - ({ \ - _nm_unused typeof(value) _value = (value); \ - \ - _Generic((value), int : TRUE); \ - }) +#define _NM_INT_LE_MAXINT32(value) \ + ({ \ + _nm_unused typeof(value) _value = (value); \ + \ + _Generic((value), int : TRUE); \ + }) #else - #define _NM_INT_LE_MAXINT32(value) \ - ({ \ - _nm_unused typeof(value) _value = (value); \ - _nm_unused const int * _p_value = &_value; \ - \ - TRUE; \ - }) +#define _NM_INT_LE_MAXINT32(value) \ + ({ \ + _nm_unused typeof(value) _value = (value); \ + _nm_unused const int * _p_value = &_value; \ + \ + TRUE; \ + }) #endif /*****************************************************************************/ @@ -247,7 +248,6 @@ extern const NMIPAddr nm_ip_addr_zero; static inline int nm_ip_addr_cmp(int addr_family, gconstpointer a, gconstpointer b) { - nm_assert_addr_family(addr_family); nm_assert(a); nm_assert(b); @@ -264,20 +264,27 @@ static inline gboolean nm_ip_addr_is_null(int addr_family, gconstpointer addr) { nm_assert(addr); - if (addr_family == AF_INET6) - return IN6_IS_ADDR_UNSPECIFIED((const struct in6_addr *) addr); - nm_assert(addr_family == AF_INET); - return ((const struct in_addr *) addr)->s_addr == 0; + + if (NM_IS_IPv4(addr_family)) { + in_addr_t t; + + /* also for in_addr_t type (AF_INET), we accept that the pointer might + * be unaligned. */ + memcpy(&t, addr, sizeof(t)); + return t == 0; + } + + return IN6_IS_ADDR_UNSPECIFIED((const struct in6_addr *) addr); } static inline void nm_ip_addr_set(int addr_family, gpointer dst, gconstpointer src) { - nm_assert_addr_family(addr_family); nm_assert(dst); nm_assert(src); - memcpy(dst, src, NM_IS_IPv4(addr_family) ? sizeof(in_addr_t) : sizeof(struct in6_addr)); + /* this MUST use memcpy() (or similar means) to support unaligned src/dst pointers. */ + memcpy(dst, src, nm_utils_addr_family_to_size(addr_family)); } static inline NMIPAddr @@ -308,6 +315,9 @@ gboolean nm_ip_addr_set_from_untrusted(int addr_family, gsize src_len, int * out_addr_family); +gboolean +nm_ip_addr_set_from_variant(int addr_family, gpointer dst, GVariant *variant, int *out_addr_family); + static inline gboolean nm_ip4_addr_is_localhost(in_addr_t addr4) { @@ -365,8 +375,8 @@ typedef struct _NMUtilsIPv6IfaceId { } \ } -void nm_utils_ipv6_addr_set_interface_identifier(struct in6_addr * addr, - const NMUtilsIPv6IfaceId iid); +void nm_utils_ipv6_addr_set_interface_identifier(struct in6_addr * addr, + const NMUtilsIPv6IfaceId *iid); void nm_utils_ipv6_interface_identifier_get_from_addr(NMUtilsIPv6IfaceId * iid, const struct in6_addr *addr); @@ -374,7 +384,7 @@ void nm_utils_ipv6_interface_identifier_get_from_addr(NMUtilsIPv6IfaceId * iid gboolean nm_utils_ipv6_interface_identifier_get_from_token(NMUtilsIPv6IfaceId *iid, const char * token); -const char *nm_utils_inet6_interface_identifier_to_token(NMUtilsIPv6IfaceId iid, +const char *nm_utils_inet6_interface_identifier_to_token(const NMUtilsIPv6IfaceId *iid, char buf[static INET6_ADDRSTRLEN]); gboolean nm_utils_get_ipv6_interface_identifier(NMLinkType link_type, @@ -559,25 +569,25 @@ extern const void *const _NM_PTRARRAY_EMPTY[1]; #define NM_STRV_EMPTY_CC() NM_PTRARRAY_EMPTY(const char *) static inline void -_nm_utils_strbuf_init(char *buf, gsize len, char **p_buf_ptr, gsize *p_buf_len) +nm_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) \ +#define nm_strbuf_init_arr(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)); \ + nm_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); -void nm_utils_strbuf_append_bin(char **buf, gsize *len, gconstpointer str, gsize str_len); -void nm_utils_strbuf_seek_end(char **buf, gsize *len); +void nm_strbuf_append(char **buf, gsize *len, const char *format, ...) _nm_printf(3, 4); +void nm_strbuf_append_c(char **buf, gsize *len, char c); +void nm_strbuf_append_str(char **buf, gsize *len, const char *str); +void nm_strbuf_append_bin(char **buf, gsize *len, gconstpointer str, gsize str_len); +void nm_strbuf_seek_end(char **buf, gsize *len); const char *nm_strquote(char *buf, gsize buf_len, const char *str); @@ -589,24 +599,25 @@ nm_utils_is_separator(const char c) /*****************************************************************************/ -GBytes *nm_gbytes_get_empty(void); +GBytes *nm_g_bytes_get_empty(void); GBytes *nm_g_bytes_new_from_str(const char *str); +GBytes *nm_g_bytes_new_from_variant_ay(GVariant *var); static inline gboolean -nm_gbytes_equal0(GBytes *a, GBytes *b) +nm_g_bytes_equal0(const GBytes *a, const GBytes *b) { return a == b || (a && b && g_bytes_equal(a, b)); } -gboolean nm_utils_gbytes_equal_mem(GBytes *bytes, gconstpointer mem_data, gsize mem_len); +gboolean nm_g_bytes_equal_mem(GBytes *bytes, gconstpointer mem_data, gsize mem_len); -GVariant *nm_utils_gbytes_to_variant_ay(GBytes *bytes); +GVariant *nm_g_bytes_to_variant_ay(const GBytes *bytes); -GHashTable *nm_utils_strdict_clone(GHashTable *src); +GHashTable *nm_strdict_clone(GHashTable *src); -GVariant *nm_utils_strdict_to_variant_ass(GHashTable *strdict); -GVariant *nm_utils_strdict_to_variant_asv(GHashTable *strdict); +GVariant *nm_strdict_to_variant_ass(GHashTable *strdict); +GVariant *nm_strdict_to_variant_asv(GHashTable *strdict); /*****************************************************************************/ @@ -650,95 +661,105 @@ int nm_utils_dbus_path_cmp(const char *dbus_path_a, const char *dbus_path_b); /*****************************************************************************/ typedef enum { - NM_UTILS_STRSPLIT_SET_FLAGS_NONE = 0, + NM_STRSPLIT_SET_FLAGS_NONE = 0, /* by default, strsplit will coalesce consecutive delimiters and remove * them from the result. If this flag is present, empty values are preserved * and returned. * - * When combined with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP, if a value gets + * When combined with %NM_STRSPLIT_SET_FLAGS_STRSTRIP, if a value gets * empty after strstrip(), it also gets removed. */ - NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY = (1u << 0), + NM_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY = (1u << 0), - /* %NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING means that delimiters prefixed + /* %NM_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING means that delimiters prefixed * by a backslash are not treated as a separator. Such delimiters and their escape * character are copied to the current word without unescaping them. In general, - * nm_utils_strsplit_set_full() does not remove any backslash escape characters + * nm_strsplit_set_full() does not remove any backslash escape characters * and does no unescaping. It only considers them for skipping to split at * an escaped delimiter. * - * If this is combined with (or implied by %NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED), then + * If this is combined with (or implied by %NM_STRSPLIT_SET_FLAGS_ESCAPED), then * the backslash escapes are removed from the result. */ - NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING = (1u << 1), + NM_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING = (1u << 1), /* If flag is set, does the same as g_strstrip() on the returned tokens. * This will remove leading and trailing ascii whitespaces (g_ascii_isspace() * and NM_ASCII_SPACES). * - * - when combined with !%NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY, + * - when combined with !%NM_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY, * empty tokens will be removed (and %NULL will be returned if that * results in an empty string array). - * - when combined with %NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING, + * - when combined with %NM_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING, * trailing whitespace escaped by backslash are not stripped. */ - NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP = (1u << 2), + NM_STRSPLIT_SET_FLAGS_STRSTRIP = (1u << 2), - /* This implies %NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING. + /* This implies %NM_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING. * * This will do a final run over all tokens and remove all backslash * escape characters that * - precede a delimiter. * - precede a backslash. - * - precede a whitespace (only with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP). + * - precede a whitespace (only with %NM_STRSPLIT_SET_FLAGS_STRSTRIP). * - * Note that with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP, it is only + * Note that with %NM_STRSPLIT_SET_FLAGS_STRSTRIP, it is only * necessary to escape the very last whitespace (if the delimiters * are not whitespace themself). So, technically, it would be sufficient * to only unescape a backslash before the last whitespace and the user * still could express everything. However, such a rule would be complicated - * to understand, so when using backslash escaping with nm_utils_strsplit_set_full(), + * to understand, so when using backslash escaping with nm_strsplit_set_full(), * then all characters (including backslash) are treated verbatim, except: * * - "\\$DELIMITER" (escaped delimiter) * - "\\\\" (escaped backslash) - * - "\\$SPACE" (escaped space) (only with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP). + * - "\\$SPACE" (escaped space) (only with %NM_STRSPLIT_SET_FLAGS_STRSTRIP). * * Note that all other escapes like "\\n" or "\\001" are left alone. * That makes the escaping/unescaping rules simple. Also, for the most part * a text is just taken as-is, with little additional rules. Only backslashes * need extra care, and then only if they proceed one of the relevant characters. */ - NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED = (1u << 3), + NM_STRSPLIT_SET_FLAGS_ESCAPED = (1u << 3), } NMUtilsStrsplitSetFlags; const char ** -nm_utils_strsplit_set_full(const char *str, const char *delimiter, NMUtilsStrsplitSetFlags flags); +nm_strsplit_set_full(const char *str, const char *delimiter, NMUtilsStrsplitSetFlags flags); static inline const char ** -nm_utils_strsplit_set_with_empty(const char *str, const char *delimiters) +nm_strsplit_set_with_empty(const char *str, const char *delimiters) { /* this returns the same result as g_strsplit_set(str, delimiters, -1), except * it does not deep-clone the strv array. * Also, for @str == "", this returns %NULL while g_strsplit_set() would return * an empty strv array. */ - return nm_utils_strsplit_set_full(str, delimiters, NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY); + return nm_strsplit_set_full(str, delimiters, NM_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY); } static inline const char ** -nm_utils_strsplit_set(const char *str, const char *delimiters) +nm_strsplit_set(const char *str, const char *delimiters) { - return nm_utils_strsplit_set_full(str, delimiters, NM_UTILS_STRSPLIT_SET_FLAGS_NONE); + return nm_strsplit_set_full(str, delimiters, NM_STRSPLIT_SET_FLAGS_NONE); } -gssize nm_utils_strv_find_first(char **list, gssize len, const char *needle); +gssize _nm_strv_find_first(const char *const *list, gssize len, const char *needle); + +#define nm_strv_find_first(list, len, needle) \ + _nm_strv_find_first(NM_CAST_STRV_CC(list), (len), (needle)) gboolean nm_strv_has_duplicate(const char *const *list, gssize len, gboolean is_sorted); -char **_nm_utils_strv_cleanup(char ** strv, - gboolean strip_whitespace, - gboolean skip_empty, - gboolean skip_repeated); +const char **nm_strv_cleanup_const(const char **strv, gboolean skip_empty, gboolean skip_repeated); + +char **nm_strv_cleanup(char ** strv, + gboolean strip_whitespace, + gboolean skip_empty, + gboolean skip_repeated); + +gboolean nm_strv_is_same_unordered(const char *const *strv1, + gssize len1, + const char *const *strv2, + gssize len2); /*****************************************************************************/ @@ -753,10 +774,9 @@ nm_copy_func_g_strdup(gconstpointer arg, gpointer user_data) static inline const char ** nm_utils_escaped_tokens_split(const char *str, const char *delimiters) { - return nm_utils_strsplit_set_full(str, - delimiters, - NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED - | NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP); + return nm_strsplit_set_full(str, + delimiters, + NM_STRSPLIT_SET_FLAGS_ESCAPED | NM_STRSPLIT_SET_FLAGS_STRSTRIP); } typedef enum { @@ -879,10 +899,10 @@ char **nm_utils_strsplit_quoted(const char *str); static inline const char ** nm_utils_escaped_tokens_options_split_list(const char *str) { - return nm_utils_strsplit_set_full(str, - ",", - NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP - | NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING); + return nm_strsplit_set_full(str, + ",", + NM_STRSPLIT_SET_FLAGS_STRSTRIP + | NM_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING); } void nm_utils_escaped_tokens_options_split(char *str, const char **out_key, const char **out_val); @@ -1033,7 +1053,7 @@ int _nm_utils_ascii_str_to_bool(const char *str, int default_value); /*****************************************************************************/ -extern char _nm_utils_to_string_buffer[2096]; +extern _nm_thread_local char _nm_utils_to_string_buffer[2096]; void nm_utils_to_string_buffer_init(char **buf, gsize *len); gboolean nm_utils_to_string_buffer_init_null(gconstpointer obj, char **buf, gsize *len); @@ -1069,16 +1089,12 @@ const char *nm_utils_flags2str(const NMUtilsFlags2StrDesc *descs, /*****************************************************************************/ #define NM_UTILS_ENUM2STR(v, n) \ - (void) 0; \ -case v: \ - s = "" n ""; \ - break; \ - (void) 0 + case v: \ + s = "" n ""; \ + break; #define NM_UTILS_ENUM2STR_IGNORE(v) \ - (void) 0; \ -case v: \ - break; \ - (void) 0 + case v: \ + break; #define NM_UTILS_ENUM2STR_DEFINE_FULL(fcn_name, lookup_type, int_fmt, ...) \ const char *fcn_name(lookup_type val, char *buf, gsize len) \ @@ -1087,7 +1103,7 @@ case v: \ if (len) { \ const char *s = NULL; \ switch (val) { \ - (void) 0, __VA_ARGS__(void) 0; \ + NM_VA_ARGS_JOIN(, __VA_ARGS__) \ }; \ if (s) \ g_strlcpy(buf, s, len); \ @@ -1107,14 +1123,26 @@ case v: \ static inline void _nm_g_slice_free_fcn_##mem_size(gpointer mem_block) \ { \ g_slice_free1(mem_size, mem_block); \ - } + } \ + _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON -_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(10) _nm_g_slice_free_fcn_define(12) - _nm_g_slice_free_fcn_define(16) _nm_g_slice_free_fcn_define(32) +_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(10); +_nm_g_slice_free_fcn_define(12); +_nm_g_slice_free_fcn_define(16); +_nm_g_slice_free_fcn_define(32); + +_nm_warn_unused_result static inline GDestroyNotify +_nm_get_warn_unused_result_gdestroynotify(GDestroyNotify f) +{ + return f; +} #define nm_g_slice_free_fcn1(mem_size) \ - ({ \ + _nm_get_warn_unused_result_gdestroynotify(({ \ void (*_fcn)(gpointer); \ \ /* If mem_size is a compile time constant, the compiler @@ -1153,8 +1181,9 @@ _nm_g_slice_free_fcn_define(1) _nm_g_slice_free_fcn_define(2) _nm_g_slice_free_f _fcn = NULL; \ break; \ } \ + \ _fcn; \ - }) + })) /** * nm_g_slice_free_fcn: @@ -1185,7 +1214,8 @@ _nm_g_slice_free_fcn_define(1) _nm_g_slice_free_fcn_define(2) _nm_g_slice_free_f _error && _error->domain == (err_domain) && NM_IN_SET(_error->code, __VA_ARGS__); \ }) - static inline void nm_g_set_error_take(GError **error, GError *error_take) +static inline void +nm_g_set_error_take(GError **error, GError *error_take) { if (!error_take) g_return_if_reached(); @@ -1420,21 +1450,41 @@ GParamSpec *nm_g_object_class_find_property_from_gtype(GType gtype, const char * ((const _c_type *) _param_spec); \ }) +#define _NM_G_PARAM_SPEC_CAST_IS_A(param_spec, _value_type, _c_type) \ + ({ \ + const GParamSpec *const _param_spec = (param_spec); \ + \ + nm_assert(!_param_spec || g_type_is_a(_param_spec->value_type, _value_type)); \ + ((const _c_type *) _param_spec); \ + }) + #define NM_G_PARAM_SPEC_CAST_BOOLEAN(param_spec) \ _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_BOOLEAN, GParamSpecBoolean) +#define NM_G_PARAM_SPEC_CAST_INT(param_spec) \ + _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_INT, GParamSpecInt) #define NM_G_PARAM_SPEC_CAST_UINT(param_spec) \ _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_UINT, GParamSpecUInt) #define NM_G_PARAM_SPEC_CAST_UINT64(param_spec) \ _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_UINT64, GParamSpecUInt64) +#define NM_G_PARAM_SPEC_CAST_ENUM(param_spec) \ + _NM_G_PARAM_SPEC_CAST_IS_A(param_spec, G_TYPE_ENUM, GParamSpecEnum) +#define NM_G_PARAM_SPEC_CAST_FLAGS(param_spec) \ + _NM_G_PARAM_SPEC_CAST_IS_A(param_spec, G_TYPE_FLAGS, GParamSpecFlags) #define NM_G_PARAM_SPEC_CAST_STRING(param_spec) \ _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_STRING, GParamSpecString) #define NM_G_PARAM_SPEC_GET_DEFAULT_BOOLEAN(param_spec) \ (NM_G_PARAM_SPEC_CAST_BOOLEAN(NM_ENSURE_NOT_NULL(param_spec))->default_value) +#define NM_G_PARAM_SPEC_GET_DEFAULT_INT(param_spec) \ + (NM_G_PARAM_SPEC_CAST_INT(NM_ENSURE_NOT_NULL(param_spec))->default_value) #define NM_G_PARAM_SPEC_GET_DEFAULT_UINT(param_spec) \ (NM_G_PARAM_SPEC_CAST_UINT(NM_ENSURE_NOT_NULL(param_spec))->default_value) #define NM_G_PARAM_SPEC_GET_DEFAULT_UINT64(param_spec) \ (NM_G_PARAM_SPEC_CAST_UINT64(NM_ENSURE_NOT_NULL(param_spec))->default_value) +#define NM_G_PARAM_SPEC_GET_DEFAULT_ENUM(param_spec) \ + (NM_G_PARAM_SPEC_CAST_ENUM(NM_ENSURE_NOT_NULL(param_spec))->default_value) +#define NM_G_PARAM_SPEC_GET_DEFAULT_FLAGS(param_spec) \ + (NM_G_PARAM_SPEC_CAST_FLAGS(NM_ENSURE_NOT_NULL(param_spec))->default_value) #define NM_G_PARAM_SPEC_GET_DEFAULT_STRING(param_spec) \ (NM_G_PARAM_SPEC_CAST_STRING(NM_ENSURE_NOT_NULL(param_spec))->default_value) @@ -1498,10 +1548,17 @@ char *nm_utils_str_utf8safe_escape_take(char *str, NMUtilsStrUtf8SafeFlags flags GVariant *nm_g_variant_singleton_b(gboolean value); GVariant *nm_g_variant_singleton_u_0(void); +GVariant *nm_g_variant_singleton_i_0(void); GVariant *nm_g_variant_singleton_s_empty(void); +GVariant *nm_g_variant_singleton_au(void); +GVariant *nm_g_variant_singleton_aay(void); +GVariant *nm_g_variant_singleton_as(void); GVariant *nm_g_variant_singleton_aLsvI(void); GVariant *nm_g_variant_singleton_aLsaLsvII(void); GVariant *nm_g_variant_singleton_aaLsvI(void); +GVariant *nm_g_variant_singleton_ao(void); + +GVariant *nm_g_variant_maybe_singleton_i(gint32 v); static inline void nm_g_variant_unref_floating(GVariant *var) @@ -1599,6 +1656,19 @@ nm_g_variant_builder_add_sv_str(GVariantBuilder *builder, const char *key, const static inline void nm_g_source_destroy_and_unref(GSource *source) { + /* Note that calling g_source_destroy() on a currently attached source, + * will destroy the user-data of the callback right away (and not only + * during the last g_source_unref()). + * + * It also means, that if the user data itself has the reference to the + * source, then this will lead to crash: + * + * g_source_destroy(user_data->my_source); + * // ups, user_data was destroyed (if source was attached). + * g_source_unref(user_data->my_source); + * + * nm_g_source_destroy_and_unref() and nm_clear_g_source_inst() does not + * suffer from this problem. */ g_source_destroy(source); g_source_unref(source); } @@ -1673,19 +1743,25 @@ GSource *nm_g_timeout_source_new_seconds(guint timeout_sec, gpointer user_data, GDestroyNotify destroy_notify); -GSource * - nm_g_unix_fd_source_new(int fd, - GIOCondition io_condition, - int priority, - gboolean (*source_func)(int fd, GIOCondition condition, gpointer user_data), - gpointer user_data, - GDestroyNotify destroy_notify); +GSource *nm_g_unix_fd_source_new(int fd, + GIOCondition io_condition, + int priority, + GUnixFDSourceFunc source_func, + gpointer user_data, + GDestroyNotify destroy_notify); + GSource *nm_g_unix_signal_source_new(int signum, int priority, GSourceFunc handler, gpointer user_data, GDestroyNotify notify); +GSource *nm_g_child_watch_source_new(GPid pid, + int priority, + GChildWatchFunc handler, + gpointer user_data, + GDestroyNotify notify); + static inline GSource * nm_g_source_attach(GSource *source, GMainContext *context) { @@ -1693,10 +1769,25 @@ nm_g_source_attach(GSource *source, GMainContext *context) return source; } +static inline void +nm_g_idle_add(GSourceFunc func, gpointer user_data) +{ + /* g_idle_add() is discouraged because it relies on the guint source IDs. + * + * Usually, you would want to use nm_g_idle_add_source() which returns a GSource* + * instance. + * + * However, if you don't care to ever call g_source_remove() on the source ID, then + * g_idle_add() is fine. But our checkpatch script would complain about it. In + * that case use nm_g_idle_add(), which makes it clear that you really want to + * use g_idle_add() and ignore the source ID. */ + g_idle_add(func, user_data); +} + static inline GSource * nm_g_idle_add_source(GSourceFunc func, gpointer user_data) { - /* G convenience function to attach a new timeout source to the default GMainContext. + /* A convenience function to attach a new timeout source to the default GMainContext. * In that sense it's very similar to g_idle_add() except that it returns a * reference to the new source. */ return nm_g_source_attach(nm_g_idle_source_new(G_PRIORITY_DEFAULT, func, user_data, NULL), @@ -1706,7 +1797,7 @@ nm_g_idle_add_source(GSourceFunc func, gpointer user_data) static inline GSource * nm_g_timeout_add_source(guint timeout_msec, GSourceFunc func, gpointer user_data) { - /* G convenience function to attach a new timeout source to the default GMainContext. + /* A convenience function to attach a new timeout source to the default GMainContext. * In that sense it's very similar to g_timeout_add() except that it returns a * reference to the new source. */ return nm_g_source_attach( @@ -1715,9 +1806,9 @@ nm_g_timeout_add_source(guint timeout_msec, GSourceFunc func, gpointer user_data } static inline GSource * -nm_g_timeout_add_source_seconds(guint timeout_sec, GSourceFunc func, gpointer user_data) +nm_g_timeout_add_seconds_source(guint timeout_sec, GSourceFunc func, gpointer user_data) { - /* G convenience function to attach a new timeout source to the default GMainContext. + /* A convenience function to attach a new timeout source to the default GMainContext. * In that sense it's very similar to g_timeout_add_seconds() except that it returns a * reference to the new source. */ return nm_g_source_attach( @@ -1746,6 +1837,36 @@ nm_g_timeout_add_source_approx(guint timeout_msec, return nm_g_source_attach(source, NULL); } +static inline GSource * +nm_g_unix_fd_add_source(int fd, + GIOCondition condition, + GUnixFDSourceFunc function, + gpointer user_data) +{ + /* A convenience function to attach a new unix-fd source to the default GMainContext. + * In that sense it's very similar to g_unix_fd_add() except that it returns a + * reference to the new source. */ + return nm_g_source_attach( + nm_g_unix_fd_source_new(fd, condition, G_PRIORITY_DEFAULT, function, user_data, NULL), + NULL); +} + +static inline GSource * +nm_g_unix_signal_add_source(int signum, GSourceFunc handler, gpointer user_data) +{ + return nm_g_source_attach( + nm_g_unix_signal_source_new(signum, G_PRIORITY_DEFAULT, handler, user_data, NULL), + NULL); +} + +static inline GSource * +nm_g_child_watch_add_source(GPid pid, GChildWatchFunc handler, gpointer user_data) +{ + return nm_g_source_attach( + nm_g_child_watch_source_new(pid, G_PRIORITY_DEFAULT, handler, user_data, NULL), + NULL); +} + NM_AUTO_DEFINE_FCN0(GMainContext *, _nm_auto_unref_gmaincontext, g_main_context_unref); #define nm_auto_unref_gmaincontext nm_auto(_nm_auto_unref_gmaincontext) @@ -1801,6 +1922,16 @@ nm_g_main_context_push_thread_default_if_necessary(GMainContext *context) return context; } +static inline void +nm_g_main_context_iterate_ready(GMainContext *context) +{ + while (g_main_context_iteration(context, FALSE)) { + ; + } +} + +void nm_g_main_context_iterate_for_msec(GMainContext *context, guint timeout_msec); + /*****************************************************************************/ static inline int @@ -1893,7 +2024,7 @@ gpointer *nm_utils_hash_values_to_array(GHashTable * hash, guint * out_len); static inline const char ** -nm_utils_strdict_get_keys(const GHashTable *hash, gboolean sorted, guint *out_length) +nm_strdict_get_keys(const GHashTable *hash, gboolean sorted, guint *out_length) { return (const char **) nm_utils_hash_keys_to_array((GHashTable *) hash, sorted ? nm_strcmp_p_with_data : NULL, @@ -1924,26 +2055,26 @@ int nm_utils_hashtable_cmp(const GHashTable *a, GCompareDataFunc cmp_values, gpointer user_data); -char **nm_utils_strv_make_deep_copied(const char **strv); +char **nm_strv_make_deep_copied(const char **strv); -char **nm_utils_strv_make_deep_copied_n(const char **strv, gsize len); +char **nm_strv_make_deep_copied_n(const char **strv, gsize len); static inline char ** -nm_utils_strv_make_deep_copied_nonnull(const char **strv) +nm_strv_make_deep_copied_nonnull(const char **strv) { - return nm_utils_strv_make_deep_copied(strv) ?: g_new0(char *, 1); + return nm_strv_make_deep_copied(strv) ?: g_new0(char *, 1); } -char **_nm_utils_strv_dup(const char *const *strv, gssize len, gboolean deep_copied); +char **_nm_strv_dup(const char *const *strv, gssize len, gboolean deep_copied); -#define nm_utils_strv_dup(strv, len, deep_copied) \ - _nm_utils_strv_dup(NM_CAST_STRV_CC(strv), (len), (deep_copied)) +#define nm_strv_dup(strv, len, deep_copied) \ + _nm_strv_dup(NM_CAST_STRV_CC(strv), (len), (deep_copied)) -const char **_nm_utils_strv_dup_packed(const char *const *strv, gssize len); +const char **_nm_strv_dup_packed(const char *const *strv, gssize len); -#define nm_utils_strv_dup_packed(strv, len) _nm_utils_strv_dup_packed(NM_CAST_STRV_CC(strv), (len)) +#define nm_strv_dup_packed(strv, len) _nm_strv_dup_packed(NM_CAST_STRV_CC(strv), (len)) -#define nm_utils_strv_dup_shallow_maybe_a(alloca_maxlen, strv, len, to_free) \ +#define nm_strv_dup_shallow_maybe_a(alloca_maxlen, strv, len, to_free) \ ({ \ const char *const *const _strv = NM_CAST_STRV_CC(strv); \ const gssize _len = (len); \ @@ -1994,6 +2125,28 @@ nm_g_array_unref(GArray *arr) g_array_unref(arr); } +#define nm_g_array_first(arr, type) \ + ({ \ + GArray *const _arr = (arr); \ + guint _len; \ + \ + nm_assert(_arr); \ + _len = _arr->len; \ + nm_assert(_len > 0); \ + &g_array_index(arr, type, 0); \ + }) + +#define nm_g_array_last(arr, type) \ + ({ \ + GArray *const _arr = (arr); \ + guint _len; \ + \ + nm_assert(_arr); \ + _len = _arr->len; \ + nm_assert(_len > 0); \ + &g_array_index(arr, type, _len - 1u); \ + }) + #define nm_g_array_append_new(arr, type) \ ({ \ GArray *const _arr = (arr); \ @@ -2091,17 +2244,17 @@ GPtrArray *_nm_g_ptr_array_copy(GPtrArray * array, * Note that the @element_free_func MUST correspond to free function set in @array. */ #if GLIB_CHECK_VERSION(2, 62, 0) - #define nm_g_ptr_array_copy(array, func, user_data, element_free_func) \ - ({ \ - _nm_unused GDestroyNotify const _element_free_func = (element_free_func); \ - \ - G_GNUC_BEGIN_IGNORE_DEPRECATIONS; \ - g_ptr_array_copy((array), (func), (user_data)); \ - G_GNUC_END_IGNORE_DEPRECATIONS; \ - }) +#define nm_g_ptr_array_copy(array, func, user_data, element_free_func) \ + ({ \ + _nm_unused GDestroyNotify const _element_free_func = (element_free_func); \ + \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; \ + g_ptr_array_copy((array), (func), (user_data)); \ + G_GNUC_END_IGNORE_DEPRECATIONS; \ + }) #else - #define nm_g_ptr_array_copy(array, func, user_data, element_free_func) \ - _nm_g_ptr_array_copy((array), (func), (user_data), (element_free_func)) +#define nm_g_ptr_array_copy(array, func, user_data, element_free_func) \ + _nm_g_ptr_array_copy((array), (func), (user_data), (element_free_func)) #endif /*****************************************************************************/ @@ -2165,7 +2318,7 @@ gssize nm_utils_ptrarray_find_binary_search_range(gconstpointer * list, gssize * out_idx_first, gssize * out_idx_last); -#define nm_utils_strv_find_binary_search(strv, len, needle) \ +#define nm_strv_find_binary_search(strv, len, needle) \ ({ \ const char *const *const _strv = NM_CAST_STRV_CC(strv); \ const gsize _len = (len); \ @@ -2192,16 +2345,89 @@ gssize nm_utils_ptrarray_find_first(gconstpointer *list, gssize len, gconstpoint /*****************************************************************************/ -void _nm_utils_strv_sort(const char **strv, gssize len); -#define nm_utils_strv_sort(strv, len) _nm_utils_strv_sort(NM_CAST_STRV_MC(strv), len) +void _nm_strv_sort(const char **strv, gssize len); +#define nm_strv_sort(strv, len) _nm_strv_sort(NM_CAST_STRV_MC(strv), len) + +int _nm_strv_cmp_n(const char *const *strv1, gssize len1, const char *const *strv2, gssize len2); + +#define nm_strv_cmp_n(strv1, len1, strv2, len2) \ + _nm_strv_cmp_n(NM_CAST_STRV_CC(strv1), (len1), NM_CAST_STRV_CC(strv2), (len2)) + +/* This is like nm_strv_cmp_n(). The difference is that a NULL strv array (strv=NULL,len=-1) + * is treated the same as an empty one (with len=0). */ +#define nm_strv_cmp_n_null(strv1, len1, strv2, len2) \ + ({ \ + const char *const *const _strv1 = NM_CAST_STRV_CC(strv1); \ + const char *const *const _strv2 = NM_CAST_STRV_CC(strv2); \ + const gssize _len1 = (len1); \ + const gssize _len2 = (len2); \ + \ + _nm_strv_cmp_n(_strv1, \ + (_len1 >= 0 ? _len1 : (_strv1 ? -1 : 0)), \ + _strv2, \ + (_len2 >= 0 ? _len2 : (_strv2 ? -1 : 0))); \ + }) + +#define nm_strv_equal_n(strv1, len1, strv2, len2) \ + (nm_strv_cmp_n((strv1), (len1), (strv2), (len2)) == 0) -int -_nm_utils_strv_cmp_n(const char *const *strv1, gssize len1, const char *const *strv2, gssize len2); +#define nm_strv_equal(strv1, strv2) nm_strv_equal_n((strv1), -1, (strv2), -1) -#define nm_utils_strv_cmp_n(strv1, len1, strv2, len2) \ - _nm_utils_strv_cmp_n(NM_CAST_STRV_CC(strv1), (len1), NM_CAST_STRV_CC(strv2), (len2)) +#define nm_strv_equal_n_null(strv1, len1, strv2, len2) \ + (nm_strv_cmp_n_null((strv1), (len1), (strv2), (len2)) == 0) -#define nm_utils_strv_equal(strv1, strv2) (nm_utils_strv_cmp_n((strv1), -1, (strv2), -1) == 0) +/*****************************************************************************/ + +/* nm_arr_insert_at() does @arr[@idx] = @value, but first memmove's + * the elements @arr[@idx..@len-1] one element up. That means, @arr currently + * has @len valid elements, but it must have space for one more element, + * which will be overwritten. + * + * The use case is to have a sorted array (nm_strv_find_binary_search()) and + * to insert the element at he desired index. The caller must make sure that + * @len is large enough to contain one more element. */ +#define nm_arr_insert_at(arr, len, idx, value) \ + G_STMT_START \ + { \ + typeof(*(arr)) *const _arr = (arr); \ + typeof(len) _len = (len); \ + typeof(idx) _idx = (idx); \ + const gsize _len2 = (_len); \ + const gsize _idx2 = (_idx); \ + \ + nm_assert(_arr); \ + nm_assert(_NM_INT_NOT_NEGATIVE(_len)); \ + nm_assert(_NM_INT_NOT_NEGATIVE(_idx)); \ + nm_assert(_idx <= _len); \ + \ + if (_idx2 != _len2) \ + memmove(&_arr[_idx2 + 1u], &_arr[_idx2], sizeof(_arr[0]) * (_len2 - _idx2)); \ + \ + _arr[_idx2] = (value); \ + } \ + G_STMT_END + +/* nm_arr_remove_at() removes the element at arr[idx], by memmove'ing + * the elements from arr[idx+1..len-1] down. All it does is one memmove(), + * if there is anything to move. */ +#define nm_arr_remove_at(arr, len, idx) \ + G_STMT_START \ + { \ + typeof(*(arr)) *const _arr = (arr); \ + typeof(len) _len = (len); \ + typeof(idx) _idx = (idx); \ + const gsize _len2 = (_len); \ + const gsize _idx2 = (_idx); \ + \ + nm_assert(_arr); \ + nm_assert(_len > 0); \ + nm_assert(_NM_INT_NOT_NEGATIVE(_idx)); \ + nm_assert(_idx < _len); \ + \ + if (_idx2 != _len2 - 1u) \ + memmove(&_arr[_idx2], &_arr[_idx2 + 1u], sizeof(_arr[0]) * ((_len2 - 1u) - _idx2)); \ + } \ + G_STMT_END /*****************************************************************************/ @@ -2406,7 +2632,7 @@ nm_strv_ptrarray_find_first(const GPtrArray *strv, const char *str) { if (!strv) return -1; - return nm_utils_strv_find_first((char **) strv->pdata, strv->len, str); + return nm_strv_find_first((const char *const *) strv->pdata, strv->len, str); } static inline gboolean @@ -2418,14 +2644,14 @@ nm_strv_ptrarray_contains(const GPtrArray *strv, const char *str) static inline int nm_strv_ptrarray_cmp(const GPtrArray *a, const GPtrArray *b) { - /* nm_utils_strv_cmp_n() will treat NULL and empty arrays the same. + /* nm_strv_cmp_n() will treat NULL and empty arrays the same. * That means, an empty strv array can both be represented by NULL * and an array of length zero. * If you need to distinguish between these case, do that yourself. */ - return nm_utils_strv_cmp_n((const char *const *) nm_g_ptr_array_pdata(a), - nm_g_ptr_array_len(a), - (const char *const *) nm_g_ptr_array_pdata(b), - nm_g_ptr_array_len(b)); + return nm_strv_cmp_n((const char *const *) nm_g_ptr_array_pdata(a), + nm_g_ptr_array_len(a), + (const char *const *) nm_g_ptr_array_pdata(b), + nm_g_ptr_array_len(b)); } /*****************************************************************************/ @@ -2750,7 +2976,7 @@ guint nm_utils_parse_debug_string(const char *string, const GDebugKey *keys, gui /*****************************************************************************/ static inline gboolean -nm_utils_strdup_reset(char **dst, const char *src) +nm_strdup_reset(char **dst, const char *src) { char *old; @@ -2765,12 +2991,12 @@ nm_utils_strdup_reset(char **dst, const char *src) } static inline gboolean -nm_utils_strdup_reset_take(char **dst, char *src) +nm_strdup_reset_take(char **dst, char *src) { char *old; nm_assert(dst); - nm_assert(src != *dst); + nm_assert(!src || src != *dst); if (nm_streq0(*dst, src)) { if (src) @@ -2854,7 +3080,7 @@ nm_strvarray_get_strv_non_empty_dup(GArray *arr, guint *length) NM_SET_OUT(length, arr->len); strv = &g_array_index(arr, const char *, 0); - return nm_utils_strv_dup(strv, arr->len, TRUE); + return nm_strv_dup(strv, arr->len, TRUE); } static inline const char *const * @@ -2988,6 +3214,8 @@ void nm_crypto_md5_hash(const guint8 *salt, char *nm_utils_get_process_exit_status_desc(int status); +gboolean nm_utils_validate_hostname(const char *hostname); + /*****************************************************************************/ void nm_utils_thread_local_register_destroy(gpointer tls_data, GDestroyNotify destroy_notify); |