diff options
Diffstat (limited to 'shared/nm-utils/nm-enum-utils.c')
| -rw-r--r-- | shared/nm-utils/nm-enum-utils.c | 181 |
1 files changed, 128 insertions, 53 deletions
diff --git a/shared/nm-utils/nm-enum-utils.c b/shared/nm-utils/nm-enum-utils.c index 70a8b415..023f8385 100644 --- a/shared/nm-utils/nm-enum-utils.c +++ b/shared/nm-utils/nm-enum-utils.c @@ -27,6 +27,62 @@ #define IS_FLAGS_SEPARATOR(ch) (NM_IN_SET ((ch), ' ', '\t', ',', '\n', '\r')) +static void +_ASSERT_enum_values_info (GType type, + const NMUtilsEnumValueInfo *value_infos) +{ +#if NM_MORE_ASSERTS > 5 + nm_auto_unref_gtypeclass GTypeClass *klass = NULL; + gs_unref_hashtable GHashTable *ht = NULL; + + klass = g_type_class_ref (type); + + g_assert (G_IS_ENUM_CLASS (klass) || G_IS_FLAGS_CLASS (klass)); + + if (!value_infos) + return; + + ht = g_hash_table_new (g_str_hash, g_str_equal); + + for (; value_infos->nick; value_infos++) { + + g_assert (value_infos->nick[0]); + + /* duplicate nicks make no sense!! */ + g_assert (!g_hash_table_contains (ht, value_infos->nick)); + g_hash_table_add (ht, (gpointer) value_infos->nick); + + if (G_IS_ENUM_CLASS (klass)) { + GEnumValue *enum_value; + + enum_value = g_enum_get_value_by_nick (G_ENUM_CLASS (klass), value_infos->nick); + if (enum_value) { + /* we do allow specifying the same name via @value_infos and @type. + * That might make sense, if @type comes from a library where older versions + * of the library don't yet support the value. In this case, the caller can + * provide the nick via @value_infos, to support the older library version. + * And then, when actually running against a newer library version where + * @type knows the nick, we have this situation. + * + * However, what never is allowed, is to use a name (nick) to re-number + * the value. That is, if both @value_infos and @type contain a particular + * nick, their numeric values must agree as well. + */ + g_assert (enum_value->value == value_infos->value); + } + } else { + GFlagsValue *flags_value; + + flags_value = g_flags_get_value_by_nick (G_FLAGS_CLASS (klass), value_infos->nick); + if (flags_value) { + /* see ENUM case above. */ + g_assert (flags_value->value == (guint) value_infos->value); + } + } + } +#endif +} + static gboolean _is_hex_string (const char *str) { @@ -64,36 +120,65 @@ _enum_is_valid_flags_nick (const char *str) char * _nm_utils_enum_to_str_full (GType type, int value, - const char *flags_separator) + const char *flags_separator, + const NMUtilsEnumValueInfo *value_infos) { - GTypeClass *class; - char *ret; + nm_auto_unref_gtypeclass GTypeClass *klass = NULL; + + _ASSERT_enum_values_info (type, value_infos); if ( flags_separator && ( !flags_separator[0] || NM_STRCHAR_ANY (flags_separator, ch, !IS_FLAGS_SEPARATOR (ch)))) g_return_val_if_reached (NULL); - class = g_type_class_ref (type); + klass = g_type_class_ref (type); - if (G_IS_ENUM_CLASS (class)) { + if (G_IS_ENUM_CLASS (klass)) { GEnumValue *enum_value; - enum_value = g_enum_get_value (G_ENUM_CLASS (class), value); + for ( ; value_infos && value_infos->nick; value_infos++) { + if (value_infos->value == value) + return g_strdup (value_infos->nick); + } + + enum_value = g_enum_get_value (G_ENUM_CLASS (klass), value); if ( !enum_value || !_enum_is_valid_enum_nick (enum_value->value_nick)) - ret = g_strdup_printf ("%d", value); + return g_strdup_printf ("%d", value); else - ret = strdup (enum_value->value_nick); - } else if (G_IS_FLAGS_CLASS (class)) { + return g_strdup (enum_value->value_nick); + } else if (G_IS_FLAGS_CLASS (klass)) { GFlagsValue *flags_value; GString *str = g_string_new (""); unsigned uvalue = (unsigned) value; flags_separator = flags_separator ?: " "; + for ( ; value_infos && value_infos->nick; value_infos++) { + + nm_assert (_enum_is_valid_flags_nick (value_infos->nick)); + + if (uvalue == 0) { + if (value_infos->value != 0) + continue; + } else { + if (!NM_FLAGS_ALL (uvalue, (unsigned) value_infos->value)) + continue; + } + + if (str->len) + g_string_append (str, flags_separator); + g_string_append (str, value_infos->nick); + uvalue &= ~((unsigned) value_infos->value); + if (uvalue == 0) { + /* we printed all flags. Done. */ + goto flags_done; + } + } + do { - flags_value = g_flags_get_first_value (G_FLAGS_CLASS (class), uvalue); + flags_value = g_flags_get_first_value (G_FLAGS_CLASS (klass), uvalue); if (str->len) g_string_append (str, flags_separator); if ( !flags_value @@ -105,12 +190,12 @@ _nm_utils_enum_to_str_full (GType type, g_string_append (str, flags_value->value_nick); uvalue &= ~flags_value->value; } while (uvalue); - ret = g_string_free (str, FALSE); - } else - g_return_val_if_reached (NULL); - g_type_class_unref (class); - return ret; +flags_done: + return g_string_free (str, FALSE); + } + + g_return_val_if_reached (NULL); } static const NMUtilsEnumValueInfo * @@ -132,7 +217,7 @@ _nm_utils_enum_from_str_full (GType type, char **err_token, const NMUtilsEnumValueInfo *value_infos) { - GTypeClass *class; + GTypeClass *klass; gboolean ret = FALSE; int value = 0; gs_free char *str_clone = NULL; @@ -142,13 +227,15 @@ _nm_utils_enum_from_str_full (GType type, g_return_val_if_fail (str, FALSE); + _ASSERT_enum_values_info (type, value_infos); + str_clone = strdup (str); s = nm_str_skip_leading_spaces (str_clone); g_strchomp (s); - class = g_type_class_ref (type); + klass = g_type_class_ref (type); - if (G_IS_ENUM_CLASS (class)) { + if (G_IS_ENUM_CLASS (klass)) { GEnumValue *enum_value; if (s[0]) { @@ -164,21 +251,15 @@ _nm_utils_enum_from_str_full (GType type, value = (int) v64; ret = TRUE; } - } else { - enum_value = g_enum_get_value_by_nick (G_ENUM_CLASS (class), s); - if (enum_value) { - value = enum_value->value; - ret = TRUE; - } else { - nick = _find_value_info (value_infos, s); - if (nick) { - value = nick->value; - ret = TRUE; - } - } + } else if ((nick = _find_value_info (value_infos, s))) { + value = nick->value; + ret = TRUE; + } else if ((enum_value = g_enum_get_value_by_nick (G_ENUM_CLASS (klass), s))) { + value = enum_value->value; + ret = TRUE; } } - } else if (G_IS_FLAGS_CLASS (class)) { + } else if (G_IS_FLAGS_CLASS (klass)) { GFlagsValue *flags_value; unsigned uvalue = 0; @@ -209,19 +290,13 @@ _nm_utils_enum_from_str_full (GType type, break; } uvalue |= (unsigned) v64; - } else { - flags_value = g_flags_get_value_by_nick (G_FLAGS_CLASS (class), s); - if (flags_value) - uvalue |= flags_value->value; - else { - nick = _find_value_info (value_infos, s); - if (nick) - uvalue = (unsigned) nick->value; - else { - ret = FALSE; - break; - } - } + } else if ((nick = _find_value_info (value_infos, s))) + uvalue |= (unsigned) nick->value; + else if ((flags_value = g_flags_get_value_by_nick (G_FLAGS_CLASS (klass), s))) + uvalue |= flags_value->value; + else { + ret = FALSE; + break; } } @@ -234,23 +309,23 @@ _nm_utils_enum_from_str_full (GType type, NM_SET_OUT (err_token, !ret && s[0] ? g_strdup (s) : NULL); NM_SET_OUT (out_value, ret ? value : 0); - g_type_class_unref (class); + g_type_class_unref (klass); return ret; } const char ** _nm_utils_enum_get_values (GType type, gint from, gint to) { - GTypeClass *class; + GTypeClass *klass; GPtrArray *array; gint i; char sbuf[64]; - class = g_type_class_ref (type); + klass = g_type_class_ref (type); array = g_ptr_array_new (); - if (G_IS_ENUM_CLASS (class)) { - GEnumClass *enum_class = G_ENUM_CLASS (class); + if (G_IS_ENUM_CLASS (klass)) { + GEnumClass *enum_class = G_ENUM_CLASS (klass); GEnumValue *enum_value; for (i = 0; i < enum_class->n_values; i++) { @@ -262,8 +337,8 @@ _nm_utils_enum_get_values (GType type, gint from, gint to) g_ptr_array_add (array, (gpointer) g_intern_string (nm_sprintf_buf (sbuf, "%d", enum_value->value))); } } - } else if (G_IS_FLAGS_CLASS (class)) { - GFlagsClass *flags_class = G_FLAGS_CLASS (class); + } else if (G_IS_FLAGS_CLASS (klass)) { + GFlagsClass *flags_class = G_FLAGS_CLASS (klass); GFlagsValue *flags_value; for (i = 0; i < flags_class->n_values; i++) { @@ -276,12 +351,12 @@ _nm_utils_enum_get_values (GType type, gint from, gint to) } } } else { - g_type_class_unref (class); + g_type_class_unref (klass); g_ptr_array_free (array, TRUE); g_return_val_if_reached (NULL); } - g_type_class_unref (class); + g_type_class_unref (klass); g_ptr_array_add (array, NULL); return (const char **) g_ptr_array_free (array, FALSE); |