NetworkManager/shared/nm-glib-aux/nm-enum-utils.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

351 lines
12 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: LGPL-2.1+ */
/*
* Copyright (C) 2017 Red Hat, Inc.
*/
#include "nm-default.h"
#include "nm-enum-utils.h"
shared: use NMStrBuf in _nm_utils_enum_to_str_full() Just for showcase and to hit the code from the unit-tests that we have. Also, just to show, the following runs about 25 % faster than before, which isn't bad for such a simple replacement. { GType gtype = nm_test_general_color_flags_get_type (); const int N_RUN = 1000000; int i_run; guint8 c = 0; for (i_run = 0; i_run < N_RUN; i_run++) { gs_free char *str = NULL; str = _nm_utils_enum_to_str_full (gtype, i_run % 10, ",", NULL); c += str[0]; } return c % 3; } $ perf stat -r 200 -B libnm-core/tests/test-general Before: Performance counter stats for 'libnm-core/tests/test-general' (200 runs): 204.48 msec task-clock:u # 0.997 CPUs utilized ( +- 0.53% ) 0 context-switches:u # 0.000 K/sec 0 cpu-migrations:u # 0.000 K/sec 267 page-faults:u # 0.001 M/sec ( +- 0.05% ) 702,987,494 cycles:u # 3.438 GHz ( +- 0.54% ) 1,698,874,415 instructions:u # 2.42 insn per cycle ( +- 0.00% ) 410,394,229 branches:u # 2006.970 M/sec ( +- 0.00% ) 1,770,484 branch-misses:u # 0.43% of all branches ( +- 0.40% ) 0.20502 +- 0.00108 seconds time elapsed ( +- 0.53% ) After: Performance counter stats for 'libnm-core/tests/test-general' (200 runs): 155.71 msec task-clock:u # 0.996 CPUs utilized ( +- 0.50% ) 0 context-switches:u # 0.000 K/sec 0 cpu-migrations:u # 0.000 K/sec 266 page-faults:u # 0.002 M/sec ( +- 0.05% ) 539,994,118 cycles:u # 3.468 GHz ( +- 0.49% ) 1,116,016,733 instructions:u # 2.07 insn per cycle ( +- 0.00% ) 283,974,158 branches:u # 1823.760 M/sec ( +- 0.00% ) 1,377,786 branch-misses:u # 0.49% of all branches ( +- 0.43% ) 0.156255 +- 0.000786 seconds time elapsed ( +- 0.50% )
2018-11-14 15:42:27 +00:00
#include "nm-str-buf.h"
/*****************************************************************************/
#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.
*
* 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)
{
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)
{
return str[0] && NM_STRCHAR_ALL(&str[0], ch, g_ascii_isdigit(ch));
}
static gboolean
_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);
}
static gboolean
_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);
}
char *
_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;
shared: use NMStrBuf in _nm_utils_enum_to_str_full() Just for showcase and to hit the code from the unit-tests that we have. Also, just to show, the following runs about 25 % faster than before, which isn't bad for such a simple replacement. { GType gtype = nm_test_general_color_flags_get_type (); const int N_RUN = 1000000; int i_run; guint8 c = 0; for (i_run = 0; i_run < N_RUN; i_run++) { gs_free char *str = NULL; str = _nm_utils_enum_to_str_full (gtype, i_run % 10, ",", NULL); c += str[0]; } return c % 3; } $ perf stat -r 200 -B libnm-core/tests/test-general Before: Performance counter stats for 'libnm-core/tests/test-general' (200 runs): 204.48 msec task-clock:u # 0.997 CPUs utilized ( +- 0.53% ) 0 context-switches:u # 0.000 K/sec 0 cpu-migrations:u # 0.000 K/sec 267 page-faults:u # 0.001 M/sec ( +- 0.05% ) 702,987,494 cycles:u # 3.438 GHz ( +- 0.54% ) 1,698,874,415 instructions:u # 2.42 insn per cycle ( +- 0.00% ) 410,394,229 branches:u # 2006.970 M/sec ( +- 0.00% ) 1,770,484 branch-misses:u # 0.43% of all branches ( +- 0.40% ) 0.20502 +- 0.00108 seconds time elapsed ( +- 0.53% ) After: Performance counter stats for 'libnm-core/tests/test-general' (200 runs): 155.71 msec task-clock:u # 0.996 CPUs utilized ( +- 0.50% ) 0 context-switches:u # 0.000 K/sec 0 cpu-migrations:u # 0.000 K/sec 266 page-faults:u # 0.002 M/sec ( +- 0.05% ) 539,994,118 cycles:u # 3.468 GHz ( +- 0.49% ) 1,116,016,733 instructions:u # 2.07 insn per cycle ( +- 0.00% ) 283,974,158 branches:u # 1823.760 M/sec ( +- 0.00% ) 1,377,786 branch-misses:u # 0.49% of all branches ( +- 0.43% ) 0.156255 +- 0.000786 seconds time elapsed ( +- 0.50% )
2018-11-14 15:42:27 +00:00
GFlagsValue *flags_value;
NMStrBuf strbuf;
flags_separator = flags_separator ?: " ";
shared: use NMStrBuf in _nm_utils_enum_to_str_full() Just for showcase and to hit the code from the unit-tests that we have. Also, just to show, the following runs about 25 % faster than before, which isn't bad for such a simple replacement. { GType gtype = nm_test_general_color_flags_get_type (); const int N_RUN = 1000000; int i_run; guint8 c = 0; for (i_run = 0; i_run < N_RUN; i_run++) { gs_free char *str = NULL; str = _nm_utils_enum_to_str_full (gtype, i_run % 10, ",", NULL); c += str[0]; } return c % 3; } $ perf stat -r 200 -B libnm-core/tests/test-general Before: Performance counter stats for 'libnm-core/tests/test-general' (200 runs): 204.48 msec task-clock:u # 0.997 CPUs utilized ( +- 0.53% ) 0 context-switches:u # 0.000 K/sec 0 cpu-migrations:u # 0.000 K/sec 267 page-faults:u # 0.001 M/sec ( +- 0.05% ) 702,987,494 cycles:u # 3.438 GHz ( +- 0.54% ) 1,698,874,415 instructions:u # 2.42 insn per cycle ( +- 0.00% ) 410,394,229 branches:u # 2006.970 M/sec ( +- 0.00% ) 1,770,484 branch-misses:u # 0.43% of all branches ( +- 0.40% ) 0.20502 +- 0.00108 seconds time elapsed ( +- 0.53% ) After: Performance counter stats for 'libnm-core/tests/test-general' (200 runs): 155.71 msec task-clock:u # 0.996 CPUs utilized ( +- 0.50% ) 0 context-switches:u # 0.000 K/sec 0 cpu-migrations:u # 0.000 K/sec 266 page-faults:u # 0.002 M/sec ( +- 0.05% ) 539,994,118 cycles:u # 3.468 GHz ( +- 0.49% ) 1,116,016,733 instructions:u # 2.07 insn per cycle ( +- 0.00% ) 283,974,158 branches:u # 1823.760 M/sec ( +- 0.00% ) 1,377,786 branch-misses:u # 0.49% of all branches ( +- 0.43% ) 0.156255 +- 0.000786 seconds time elapsed ( +- 0.50% )
2018-11-14 15:42:27 +00:00
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;
}
shared: use NMStrBuf in _nm_utils_enum_to_str_full() Just for showcase and to hit the code from the unit-tests that we have. Also, just to show, the following runs about 25 % faster than before, which isn't bad for such a simple replacement. { GType gtype = nm_test_general_color_flags_get_type (); const int N_RUN = 1000000; int i_run; guint8 c = 0; for (i_run = 0; i_run < N_RUN; i_run++) { gs_free char *str = NULL; str = _nm_utils_enum_to_str_full (gtype, i_run % 10, ",", NULL); c += str[0]; } return c % 3; } $ perf stat -r 200 -B libnm-core/tests/test-general Before: Performance counter stats for 'libnm-core/tests/test-general' (200 runs): 204.48 msec task-clock:u # 0.997 CPUs utilized ( +- 0.53% ) 0 context-switches:u # 0.000 K/sec 0 cpu-migrations:u # 0.000 K/sec 267 page-faults:u # 0.001 M/sec ( +- 0.05% ) 702,987,494 cycles:u # 3.438 GHz ( +- 0.54% ) 1,698,874,415 instructions:u # 2.42 insn per cycle ( +- 0.00% ) 410,394,229 branches:u # 2006.970 M/sec ( +- 0.00% ) 1,770,484 branch-misses:u # 0.43% of all branches ( +- 0.40% ) 0.20502 +- 0.00108 seconds time elapsed ( +- 0.53% ) After: Performance counter stats for 'libnm-core/tests/test-general' (200 runs): 155.71 msec task-clock:u # 0.996 CPUs utilized ( +- 0.50% ) 0 context-switches:u # 0.000 K/sec 0 cpu-migrations:u # 0.000 K/sec 266 page-faults:u # 0.002 M/sec ( +- 0.05% ) 539,994,118 cycles:u # 3.468 GHz ( +- 0.49% ) 1,116,016,733 instructions:u # 2.07 insn per cycle ( +- 0.00% ) 283,974,158 branches:u # 1823.760 M/sec ( +- 0.00% ) 1,377,786 branch-misses:u # 0.49% of all branches ( +- 0.43% ) 0.156255 +- 0.000786 seconds time elapsed ( +- 0.50% )
2018-11-14 15:42:27 +00:00
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);
shared: use NMStrBuf in _nm_utils_enum_to_str_full() Just for showcase and to hit the code from the unit-tests that we have. Also, just to show, the following runs about 25 % faster than before, which isn't bad for such a simple replacement. { GType gtype = nm_test_general_color_flags_get_type (); const int N_RUN = 1000000; int i_run; guint8 c = 0; for (i_run = 0; i_run < N_RUN; i_run++) { gs_free char *str = NULL; str = _nm_utils_enum_to_str_full (gtype, i_run % 10, ",", NULL); c += str[0]; } return c % 3; } $ perf stat -r 200 -B libnm-core/tests/test-general Before: Performance counter stats for 'libnm-core/tests/test-general' (200 runs): 204.48 msec task-clock:u # 0.997 CPUs utilized ( +- 0.53% ) 0 context-switches:u # 0.000 K/sec 0 cpu-migrations:u # 0.000 K/sec 267 page-faults:u # 0.001 M/sec ( +- 0.05% ) 702,987,494 cycles:u # 3.438 GHz ( +- 0.54% ) 1,698,874,415 instructions:u # 2.42 insn per cycle ( +- 0.00% ) 410,394,229 branches:u # 2006.970 M/sec ( +- 0.00% ) 1,770,484 branch-misses:u # 0.43% of all branches ( +- 0.40% ) 0.20502 +- 0.00108 seconds time elapsed ( +- 0.53% ) After: Performance counter stats for 'libnm-core/tests/test-general' (200 runs): 155.71 msec task-clock:u # 0.996 CPUs utilized ( +- 0.50% ) 0 context-switches:u # 0.000 K/sec 0 cpu-migrations:u # 0.000 K/sec 266 page-faults:u # 0.002 M/sec ( +- 0.05% ) 539,994,118 cycles:u # 3.468 GHz ( +- 0.49% ) 1,116,016,733 instructions:u # 2.07 insn per cycle ( +- 0.00% ) 283,974,158 branches:u # 1823.760 M/sec ( +- 0.00% ) 1,377,786 branch-misses:u # 0.49% of all branches ( +- 0.43% ) 0.156255 +- 0.000786 seconds time elapsed ( +- 0.50% )
2018-11-14 15:42:27 +00:00
if (strbuf.len)
nm_str_buf_append(&strbuf, flags_separator);
if (!flags_value || !_enum_is_valid_flags_nick(flags_value->value_nick)) {
if (uvalue)
shared: use NMStrBuf in _nm_utils_enum_to_str_full() Just for showcase and to hit the code from the unit-tests that we have. Also, just to show, the following runs about 25 % faster than before, which isn't bad for such a simple replacement. { GType gtype = nm_test_general_color_flags_get_type (); const int N_RUN = 1000000; int i_run; guint8 c = 0; for (i_run = 0; i_run < N_RUN; i_run++) { gs_free char *str = NULL; str = _nm_utils_enum_to_str_full (gtype, i_run % 10, ",", NULL); c += str[0]; } return c % 3; } $ perf stat -r 200 -B libnm-core/tests/test-general Before: Performance counter stats for 'libnm-core/tests/test-general' (200 runs): 204.48 msec task-clock:u # 0.997 CPUs utilized ( +- 0.53% ) 0 context-switches:u # 0.000 K/sec 0 cpu-migrations:u # 0.000 K/sec 267 page-faults:u # 0.001 M/sec ( +- 0.05% ) 702,987,494 cycles:u # 3.438 GHz ( +- 0.54% ) 1,698,874,415 instructions:u # 2.42 insn per cycle ( +- 0.00% ) 410,394,229 branches:u # 2006.970 M/sec ( +- 0.00% ) 1,770,484 branch-misses:u # 0.43% of all branches ( +- 0.40% ) 0.20502 +- 0.00108 seconds time elapsed ( +- 0.53% ) After: Performance counter stats for 'libnm-core/tests/test-general' (200 runs): 155.71 msec task-clock:u # 0.996 CPUs utilized ( +- 0.50% ) 0 context-switches:u # 0.000 K/sec 0 cpu-migrations:u # 0.000 K/sec 266 page-faults:u # 0.002 M/sec ( +- 0.05% ) 539,994,118 cycles:u # 3.468 GHz ( +- 0.49% ) 1,116,016,733 instructions:u # 2.07 insn per cycle ( +- 0.00% ) 283,974,158 branches:u # 1823.760 M/sec ( +- 0.00% ) 1,377,786 branch-misses:u # 0.49% of all branches ( +- 0.43% ) 0.156255 +- 0.000786 seconds time elapsed ( +- 0.50% )
2018-11-14 15:42:27 +00:00
nm_str_buf_append_printf(&strbuf, "0x%x", uvalue);
break;
}
shared: use NMStrBuf in _nm_utils_enum_to_str_full() Just for showcase and to hit the code from the unit-tests that we have. Also, just to show, the following runs about 25 % faster than before, which isn't bad for such a simple replacement. { GType gtype = nm_test_general_color_flags_get_type (); const int N_RUN = 1000000; int i_run; guint8 c = 0; for (i_run = 0; i_run < N_RUN; i_run++) { gs_free char *str = NULL; str = _nm_utils_enum_to_str_full (gtype, i_run % 10, ",", NULL); c += str[0]; } return c % 3; } $ perf stat -r 200 -B libnm-core/tests/test-general Before: Performance counter stats for 'libnm-core/tests/test-general' (200 runs): 204.48 msec task-clock:u # 0.997 CPUs utilized ( +- 0.53% ) 0 context-switches:u # 0.000 K/sec 0 cpu-migrations:u # 0.000 K/sec 267 page-faults:u # 0.001 M/sec ( +- 0.05% ) 702,987,494 cycles:u # 3.438 GHz ( +- 0.54% ) 1,698,874,415 instructions:u # 2.42 insn per cycle ( +- 0.00% ) 410,394,229 branches:u # 2006.970 M/sec ( +- 0.00% ) 1,770,484 branch-misses:u # 0.43% of all branches ( +- 0.40% ) 0.20502 +- 0.00108 seconds time elapsed ( +- 0.53% ) After: Performance counter stats for 'libnm-core/tests/test-general' (200 runs): 155.71 msec task-clock:u # 0.996 CPUs utilized ( +- 0.50% ) 0 context-switches:u # 0.000 K/sec 0 cpu-migrations:u # 0.000 K/sec 266 page-faults:u # 0.002 M/sec ( +- 0.05% ) 539,994,118 cycles:u # 3.468 GHz ( +- 0.49% ) 1,116,016,733 instructions:u # 2.07 insn per cycle ( +- 0.00% ) 283,974,158 branches:u # 1823.760 M/sec ( +- 0.00% ) 1,377,786 branch-misses:u # 0.49% of all branches ( +- 0.43% ) 0.156255 +- 0.000786 seconds time elapsed ( +- 0.50% )
2018-11-14 15:42:27 +00:00
nm_str_buf_append(&strbuf, flags_value->value_nick);
uvalue &= ~flags_value->value;
} while (uvalue);
flags_done:
shared: use NMStrBuf in _nm_utils_enum_to_str_full() Just for showcase and to hit the code from the unit-tests that we have. Also, just to show, the following runs about 25 % faster than before, which isn't bad for such a simple replacement. { GType gtype = nm_test_general_color_flags_get_type (); const int N_RUN = 1000000; int i_run; guint8 c = 0; for (i_run = 0; i_run < N_RUN; i_run++) { gs_free char *str = NULL; str = _nm_utils_enum_to_str_full (gtype, i_run % 10, ",", NULL); c += str[0]; } return c % 3; } $ perf stat -r 200 -B libnm-core/tests/test-general Before: Performance counter stats for 'libnm-core/tests/test-general' (200 runs): 204.48 msec task-clock:u # 0.997 CPUs utilized ( +- 0.53% ) 0 context-switches:u # 0.000 K/sec 0 cpu-migrations:u # 0.000 K/sec 267 page-faults:u # 0.001 M/sec ( +- 0.05% ) 702,987,494 cycles:u # 3.438 GHz ( +- 0.54% ) 1,698,874,415 instructions:u # 2.42 insn per cycle ( +- 0.00% ) 410,394,229 branches:u # 2006.970 M/sec ( +- 0.00% ) 1,770,484 branch-misses:u # 0.43% of all branches ( +- 0.40% ) 0.20502 +- 0.00108 seconds time elapsed ( +- 0.53% ) After: Performance counter stats for 'libnm-core/tests/test-general' (200 runs): 155.71 msec task-clock:u # 0.996 CPUs utilized ( +- 0.50% ) 0 context-switches:u # 0.000 K/sec 0 cpu-migrations:u # 0.000 K/sec 266 page-faults:u # 0.002 M/sec ( +- 0.05% ) 539,994,118 cycles:u # 3.468 GHz ( +- 0.49% ) 1,116,016,733 instructions:u # 2.07 insn per cycle ( +- 0.00% ) 283,974,158 branches:u # 1823.760 M/sec ( +- 0.00% ) 1,377,786 branch-misses:u # 0.49% of all branches ( +- 0.43% ) 0.156255 +- 0.000786 seconds time elapsed ( +- 0.50% )
2018-11-14 15:42:27 +00:00
return nm_str_buf_finalize(&strbuf, NULL);
}
g_return_val_if_reached(NULL);
}
static const NMUtilsEnumValueInfo *
_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;
}
gboolean
_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;
}
const char **
_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);
}