summary refs log tree commit diff
path: root/shared/nm-glib-aux/nm-enum-utils.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2020-10-05 22:27:18 +0200
committerMichael Biebl <biebl@debian.org>2020-10-05 22:27:18 +0200
commitaafc1dbe4712c86189bbc1d4d54ad8cb4c69be7e (patch)
treea2a9bb4d007339a0b1304540388230ccedac32bd /shared/nm-glib-aux/nm-enum-utils.c
parente7b44ef4c80907346ec7492a09c45277459924fc (diff)
New upstream version 1.27.90 upstream/1.27.90
Diffstat (limited to 'shared/nm-glib-aux/nm-enum-utils.c')
-rw-r--r--shared/nm-glib-aux/nm-enum-utils.c604
1 files changed, 298 insertions, 306 deletions
diff --git a/shared/nm-glib-aux/nm-enum-utils.c b/shared/nm-glib-aux/nm-enum-utils.c
index 854eda6e..5292755d 100644
--- a/shared/nm-glib-aux/nm-enum-utils.c
+++ b/shared/nm-glib-aux/nm-enum-utils.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: LGPL-2.1+
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /*
  * Copyright (C) 2017 Red Hat, Inc.
  */
@@ -10,349 +10,341 @@
 
 /*****************************************************************************/
 
-#define IS_FLAGS_SEPARATOR(ch)  (NM_IN_SET ((ch), ' ', '\t', ',', '\n', '\r'))
+#define IS_FLAGS_SEPARATOR(ch) (NM_IN_SET((ch), ' ', '\t', ',', '\n', '\r'))
 
 static void
-_ASSERT_enum_values_info (GType type,
-                          const NMUtilsEnumValueInfo *value_infos)
+_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.
-				 *
-				 * Another reason for specifying a nick both in @value_infos and @type,
-				 * is to specify an alias which is not used with highest preference. For
-				 * example, if you add an alias "disabled" for "none" (both numerically
-				 * equal), then the first alias in @value_infos will be preferred over
-				 * the name from @type. So, to still use "none" as preferred name, you may
-				 * explicitly specify the "none" alias in @value_infos before "disabled".
-				 *
-				 * 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.
-				 * Allowing this, would be very confusing, because the name would have a different
-				 * value from the regular GLib GEnum API.
-				 */
-				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);
-			}
-		}
-	}
+    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.
+                 *
+                 * Another reason for specifying a nick both in @value_infos and @type,
+                 * is to specify an alias which is not used with highest preference. For
+                 * example, if you add an alias "disabled" for "none" (both numerically
+                 * equal), then the first alias in @value_infos will be preferred over
+                 * the name from @type. So, to still use "none" as preferred name, you may
+                 * explicitly specify the "none" alias in @value_infos before "disabled".
+                 *
+                 * 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.
+                 * Allowing this, would be very confusing, because the name would have a different
+                 * value from the regular GLib GEnum API.
+                 */
+                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)
+_is_hex_string(const char *str)
 {
-	return    str[0] == '0'
-	       && str[1] == 'x'
-	       && str[2]
-	       && NM_STRCHAR_ALL (&str[2], ch, g_ascii_isxdigit (ch));
+    return str[0] == '0' && str[1] == 'x' && str[2]
+           && NM_STRCHAR_ALL(&str[2], ch, g_ascii_isxdigit(ch));
 }
 
 static gboolean
-_is_dec_string (const char *str)
+_is_dec_string(const char *str)
 {
-	return    str[0]
-	       && NM_STRCHAR_ALL (&str[0], ch, g_ascii_isdigit (ch));
+    return str[0] && NM_STRCHAR_ALL(&str[0], ch, g_ascii_isdigit(ch));
 }
 
 static gboolean
-_enum_is_valid_enum_nick (const char *str)
+_enum_is_valid_enum_nick(const char *str)
 {
-	return    str[0]
-	       && !NM_STRCHAR_ANY (str, ch, g_ascii_isspace (ch))
-	       && !_is_dec_string (str)
-	       && !_is_hex_string (str);
+    return str[0] && !NM_STRCHAR_ANY(str, ch, g_ascii_isspace(ch)) && !_is_dec_string(str)
+           && !_is_hex_string(str);
 }
 
 static gboolean
-_enum_is_valid_flags_nick (const char *str)
+_enum_is_valid_flags_nick(const char *str)
 {
-	return    str[0]
-	       && !NM_STRCHAR_ANY (str, ch, IS_FLAGS_SEPARATOR (ch))
-	       && !_is_dec_string (str)
-	       && !_is_hex_string (str);
+    return str[0] && !NM_STRCHAR_ANY(str, ch, IS_FLAGS_SEPARATOR(ch)) && !_is_dec_string(str)
+           && !_is_hex_string(str);
 }
 
 char *
-_nm_utils_enum_to_str_full (GType type,
-                            int value,
-                            const char *flags_separator,
-                            const NMUtilsEnumValueInfo *value_infos)
+_nm_utils_enum_to_str_full(GType                       type,
+                           int                         value,
+                           const char *                flags_separator,
+                           const NMUtilsEnumValueInfo *value_infos)
 {
-	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);
-
-	klass = g_type_class_ref (type);
-
-	if (G_IS_ENUM_CLASS (klass)) {
-		GEnumValue *enum_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))
-			return g_strdup_printf ("%d", value);
-		else
-			return g_strdup (enum_value->value_nick);
-	} else if (G_IS_FLAGS_CLASS (klass)) {
-		unsigned uvalue = (unsigned) value;
-		GFlagsValue *flags_value;
-		NMStrBuf strbuf;
-
-		flags_separator = flags_separator ?: " ";
-
-		nm_str_buf_init (&strbuf, 16, FALSE);
-
-		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 (strbuf.len)
-				nm_str_buf_append (&strbuf, flags_separator);
-			nm_str_buf_append (&strbuf, 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 (klass), uvalue);
-			if (strbuf.len)
-				nm_str_buf_append (&strbuf, flags_separator);
-			if (   !flags_value
-			    || !_enum_is_valid_flags_nick (flags_value->value_nick)) {
-				if (uvalue)
-					nm_str_buf_append_printf (&strbuf, "0x%x", uvalue);
-				break;
-			}
-			nm_str_buf_append (&strbuf, flags_value->value_nick);
-			uvalue &= ~flags_value->value;
-		} while (uvalue);
+    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);
+
+    klass = g_type_class_ref(type);
+
+    if (G_IS_ENUM_CLASS(klass)) {
+        GEnumValue *enum_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))
+            return g_strdup_printf("%d", value);
+        else
+            return g_strdup(enum_value->value_nick);
+    } else if (G_IS_FLAGS_CLASS(klass)) {
+        unsigned     uvalue = (unsigned) value;
+        GFlagsValue *flags_value;
+        NMStrBuf     strbuf;
+
+        flags_separator = flags_separator ?: " ";
+
+        nm_str_buf_init(&strbuf, 16, FALSE);
+
+        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 (strbuf.len)
+                nm_str_buf_append(&strbuf, flags_separator);
+            nm_str_buf_append(&strbuf, 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(klass), uvalue);
+            if (strbuf.len)
+                nm_str_buf_append(&strbuf, flags_separator);
+            if (!flags_value || !_enum_is_valid_flags_nick(flags_value->value_nick)) {
+                if (uvalue)
+                    nm_str_buf_append_printf(&strbuf, "0x%x", uvalue);
+                break;
+            }
+            nm_str_buf_append(&strbuf, flags_value->value_nick);
+            uvalue &= ~flags_value->value;
+        } while (uvalue);
 
 flags_done:
-		return nm_str_buf_finalize (&strbuf, NULL);
-	}
+        return nm_str_buf_finalize(&strbuf, NULL);
+    }
 
-	g_return_val_if_reached (NULL);
+    g_return_val_if_reached(NULL);
 }
 
 static const NMUtilsEnumValueInfo *
-_find_value_info (const NMUtilsEnumValueInfo *value_infos, const char *needle)
+_find_value_info(const NMUtilsEnumValueInfo *value_infos, const char *needle)
 {
-	if (value_infos) {
-		for (; value_infos->nick; value_infos++) {
-			if (nm_streq (needle, value_infos->nick))
-				return value_infos;
-		}
-	}
-	return NULL;
+    if (value_infos) {
+        for (; value_infos->nick; value_infos++) {
+            if (nm_streq(needle, value_infos->nick))
+                return value_infos;
+        }
+    }
+    return NULL;
 }
 
 gboolean
-_nm_utils_enum_from_str_full (GType type,
-                              const char *str,
-                              int *out_value,
-                              char **err_token,
-                              const NMUtilsEnumValueInfo *value_infos)
+_nm_utils_enum_from_str_full(GType                       type,
+                             const char *                str,
+                             int *                       out_value,
+                             char **                     err_token,
+                             const NMUtilsEnumValueInfo *value_infos)
 {
-	nm_auto_unref_gtypeclass GTypeClass *klass = NULL;
-	gboolean ret = FALSE;
-	int value = 0;
-	gs_free char *str_clone = NULL;
-	char *s;
-	gint64 v64;
-	const NMUtilsEnumValueInfo *nick;
-
-	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);
-
-	klass = g_type_class_ref (type);
-
-	if (G_IS_ENUM_CLASS (klass)) {
-		GEnumValue *enum_value;
-
-		if (s[0]) {
-			if (_is_hex_string (s)) {
-				v64 = _nm_utils_ascii_str_to_int64 (s, 16, 0, G_MAXUINT, -1);
-				if (v64 != -1) {
-					value = (int) v64;
-					ret = TRUE;
-				}
-			} else if (_is_dec_string (s)) {
-				v64 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXUINT, -1);
-				if (v64 != -1) {
-					value = (int) v64;
-					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 (klass)) {
-		GFlagsValue *flags_value;
-		unsigned uvalue = 0;
-
-		ret = TRUE;
-		while (s[0]) {
-			char *s_end;
-
-			for (s_end = s; s_end[0]; s_end++) {
-				if (IS_FLAGS_SEPARATOR (s_end[0])) {
-					s_end[0] = '\0';
-					s_end++;
-					break;
-				}
-			}
-
-			if (s[0]) {
-				if (_is_hex_string (s)) {
-					v64 = _nm_utils_ascii_str_to_int64 (&s[2], 16, 0, G_MAXUINT, -1);
-					if (v64 == -1) {
-						ret = FALSE;
-						break;
-					}
-					uvalue |= (unsigned) v64;
-				} else if (_is_dec_string (s)) {
-					v64 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXUINT, -1);
-					if (v64 == -1) {
-						ret = FALSE;
-						break;
-					}
-					uvalue |= (unsigned) v64;
-				} 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;
-				}
-			}
-
-			s = s_end;
-		}
-
-		value = (int) uvalue;
-	} else
-		g_return_val_if_reached (FALSE);
-
-	NM_SET_OUT (err_token, !ret && s[0] ? g_strdup (s) : NULL);
-	NM_SET_OUT (out_value, ret ? value : 0);
-	return ret;
+    nm_auto_unref_gtypeclass GTypeClass *klass     = NULL;
+    gboolean                             ret       = FALSE;
+    int                                  value     = 0;
+    gs_free char *                       str_clone = NULL;
+    char *                               s;
+    gint64                               v64;
+    const NMUtilsEnumValueInfo *         nick;
+
+    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);
+
+    klass = g_type_class_ref(type);
+
+    if (G_IS_ENUM_CLASS(klass)) {
+        GEnumValue *enum_value;
+
+        if (s[0]) {
+            if (_is_hex_string(s)) {
+                v64 = _nm_utils_ascii_str_to_int64(s, 16, 0, G_MAXUINT, -1);
+                if (v64 != -1) {
+                    value = (int) v64;
+                    ret   = TRUE;
+                }
+            } else if (_is_dec_string(s)) {
+                v64 = _nm_utils_ascii_str_to_int64(s, 10, 0, G_MAXUINT, -1);
+                if (v64 != -1) {
+                    value = (int) v64;
+                    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(klass)) {
+        GFlagsValue *flags_value;
+        unsigned     uvalue = 0;
+
+        ret = TRUE;
+        while (s[0]) {
+            char *s_end;
+
+            for (s_end = s; s_end[0]; s_end++) {
+                if (IS_FLAGS_SEPARATOR(s_end[0])) {
+                    s_end[0] = '\0';
+                    s_end++;
+                    break;
+                }
+            }
+
+            if (s[0]) {
+                if (_is_hex_string(s)) {
+                    v64 = _nm_utils_ascii_str_to_int64(&s[2], 16, 0, G_MAXUINT, -1);
+                    if (v64 == -1) {
+                        ret = FALSE;
+                        break;
+                    }
+                    uvalue |= (unsigned) v64;
+                } else if (_is_dec_string(s)) {
+                    v64 = _nm_utils_ascii_str_to_int64(s, 10, 0, G_MAXUINT, -1);
+                    if (v64 == -1) {
+                        ret = FALSE;
+                        break;
+                    }
+                    uvalue |= (unsigned) v64;
+                } 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;
+                }
+            }
+
+            s = s_end;
+        }
+
+        value = (int) uvalue;
+    } else
+        g_return_val_if_reached(FALSE);
+
+    NM_SET_OUT(err_token, !ret && s[0] ? g_strdup(s) : NULL);
+    NM_SET_OUT(out_value, ret ? value : 0);
+    return ret;
 }
 
 const char **
-_nm_utils_enum_get_values (GType type, int from, int to)
+_nm_utils_enum_get_values(GType type, int from, int to)
 {
-	GTypeClass *klass;
-	GPtrArray *array;
-	int i;
-	char sbuf[64];
-
-	klass = g_type_class_ref (type);
-	array = g_ptr_array_new ();
-
-	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++) {
-			enum_value = &enum_class->values[i];
-			if (enum_value->value >= from && enum_value->value <= to) {
-				if (_enum_is_valid_enum_nick (enum_value->value_nick))
-					g_ptr_array_add (array, (gpointer) enum_value->value_nick);
-				else
-					g_ptr_array_add (array, (gpointer) g_intern_string (nm_sprintf_buf (sbuf, "%d", enum_value->value)));
-			}
-		}
-	} 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++) {
-			flags_value = &flags_class->values[i];
-			if (flags_value->value >= (guint) from && flags_value->value <= (guint) to) {
-				if (_enum_is_valid_flags_nick (flags_value->value_nick))
-					g_ptr_array_add (array, (gpointer) flags_value->value_nick);
-				else
-					g_ptr_array_add (array, (gpointer) g_intern_string (nm_sprintf_buf (sbuf, "0x%x", (unsigned) flags_value->value)));
-			}
-		}
-	} else {
-		g_type_class_unref (klass);
-		g_ptr_array_free (array, TRUE);
-		g_return_val_if_reached (NULL);
-	}
-
-	g_type_class_unref (klass);
-	g_ptr_array_add (array, NULL);
-
-	return (const char **) g_ptr_array_free (array, FALSE);
+    GTypeClass *klass;
+    GPtrArray * array;
+    int         i;
+    char        sbuf[64];
+
+    klass = g_type_class_ref(type);
+    array = g_ptr_array_new();
+
+    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++) {
+            enum_value = &enum_class->values[i];
+            if (enum_value->value >= from && enum_value->value <= to) {
+                if (_enum_is_valid_enum_nick(enum_value->value_nick))
+                    g_ptr_array_add(array, (gpointer) enum_value->value_nick);
+                else
+                    g_ptr_array_add(
+                        array,
+                        (gpointer) g_intern_string(nm_sprintf_buf(sbuf, "%d", enum_value->value)));
+            }
+        }
+    } 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++) {
+            flags_value = &flags_class->values[i];
+            if (flags_value->value >= (guint) from && flags_value->value <= (guint) to) {
+                if (_enum_is_valid_flags_nick(flags_value->value_nick))
+                    g_ptr_array_add(array, (gpointer) flags_value->value_nick);
+                else
+                    g_ptr_array_add(
+                        array,
+                        (gpointer) g_intern_string(
+                            nm_sprintf_buf(sbuf, "0x%x", (unsigned) flags_value->value)));
+            }
+        }
+    } else {
+        g_type_class_unref(klass);
+        g_ptr_array_free(array, TRUE);
+        g_return_val_if_reached(NULL);
+    }
+
+    g_type_class_unref(klass);
+    g_ptr_array_add(array, NULL);
+
+    return (const char **) g_ptr_array_free(array, FALSE);
 }