diff options
author | Thomas Haller <thaller@redhat.com> | 2017-02-20 11:59:38 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-02-20 13:45:32 +0100 |
commit | 1525b447146fb6f8f726d66862c2daa5ae48409c (patch) | |
tree | f8e3e228db21087a47c086532ea64336920874cc | |
parent | 8950d1836245f2ddc0a63b4ef49050a47246c3ec (diff) | |
download | NetworkManager-1525b447146fb6f8f726d66862c2daa5ae48409c.tar.gz |
utils: support unknown numeric values in nm_utils_enum_to_str() and nm_utils_enum_from_str()
- for nm_utils_enum_to_str(), whenever encounter a numeric value
that has no expression as enum/flag, encode the value numerically.
For enums, encode it as decimal. For flags, encode it as hexadecimal
(with 0x prefix).
Also check that an existing value_nick cannot be wrongly interpreted
as a integer, and if they would, encode them instead as integers only.
- Likewise, in nm_utils_enum_from_str() accept numerical values
and for nm_utils_enum_get_values() return enum nicks that look
like numeric values in their numeric form only.
- In nm_utils_enum_from_str(), don't use g_strsplit(), but clone the
string only once and manipulate it inplace.
- Accept '\n' and '\r' as additional delimiters for flags.
- For consistency, also return an err_token for enum types. If the caller
doesn't care about that, he should simply not pass the out-argument.
-rw-r--r-- | libnm-core/nm-utils.c | 158 | ||||
-rw-r--r-- | libnm-core/tests/test-general-enums.h | 4 | ||||
-rw-r--r-- | libnm-core/tests/test-general.c | 19 |
3 files changed, 133 insertions, 48 deletions
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 75581699ab..f9dd4b1be2 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -4249,13 +4249,45 @@ int _nm_utils_dns_option_find_idx (GPtrArray *array, const char *option) return -1; } +#define IS_FLAGS_SEPARATOR(ch) (NM_IN_SET ((ch), ' ', '\t', ',', '\n', '\r')) + +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 +_enum_is_valid_enum_nick (const char *str) +{ + return str[0] + && !NM_STRCHAR_ANY (str, ch, g_ascii_isspace (ch)) + && !NM_STRCHAR_ALL (str, ch, g_ascii_isdigit (ch)); +} + +static gboolean +_enum_is_valid_flags_nick (const char *str) +{ + return str[0] + && !NM_STRCHAR_ANY (str, ch, IS_FLAGS_SEPARATOR (ch)) + && !_is_hex_string (str); +} + char * -_nm_utils_enum_to_str_full (GType type, int value, const char *sep) +_nm_utils_enum_to_str_full (GType type, + int value, + const char *flags_separator) { GTypeClass *class; char *ret; - g_return_val_if_fail (sep, NULL); + 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); @@ -4263,23 +4295,28 @@ _nm_utils_enum_to_str_full (GType type, int value, const char *sep) GEnumValue *enum_value; enum_value = g_enum_get_value (G_ENUM_CLASS (class), value); - ret = enum_value ? strdup (enum_value->value_nick) : NULL; + if ( !enum_value + || !_enum_is_valid_enum_nick (enum_value->value_nick)) + ret = g_strdup_printf ("%d", value); + else + ret = strdup (enum_value->value_nick); } else if (G_IS_FLAGS_CLASS (class)) { GFlagsValue *flags_value; GString *str = g_string_new (""); - gboolean first = TRUE; + + flags_separator = flags_separator ?: " "; while (value) { flags_value = g_flags_get_first_value (G_FLAGS_CLASS (class), value); - if (!flags_value) + if (str->len) + g_string_append (str, flags_separator); + if ( !flags_value + || !_enum_is_valid_flags_nick (flags_value->value_nick)) { + g_string_append_printf (str, "0x%x", (unsigned) value); break; - - if (!first) - g_string_append (str, sep); + } g_string_append (str, flags_value->value_nick); - value &= ~flags_value->value; - first = FALSE; } ret = g_string_free (str, FALSE); } else @@ -4327,55 +4364,83 @@ nm_utils_enum_to_str (GType type, int value) * * Since: 1.2 */ -gboolean nm_utils_enum_from_str (GType type, const char *str, - int *out_value, char **err_token) +gboolean +nm_utils_enum_from_str (GType type, const char *str, + int *out_value, char **err_token) { GTypeClass *class; gboolean ret = FALSE; int value = 0; - gs_free char *stripped = NULL; + gs_free char *str_clone = NULL; + char *s; + gint64 v64; g_return_val_if_fail (str, FALSE); - stripped = g_strstrip (strdup (str)); + + str_clone = strdup (str); + s = nm_str_skip_leading_spaces (str_clone); + g_strchomp (s); + class = g_type_class_ref (type); if (G_IS_ENUM_CLASS (class)) { GEnumValue *enum_value; - enum_value = g_enum_get_value_by_nick (G_ENUM_CLASS (class), stripped); - if (enum_value) { - value = enum_value->value; - ret = TRUE; + if (s[0]) { + if (NM_STRCHAR_ALL (s, ch, g_ascii_isdigit (ch))) { + v64 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXINT, -1); + if (v64 != -1) { + 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 if (G_IS_FLAGS_CLASS (class)) { GFlagsValue *flags_value; - gs_strfreev char **strv = NULL; - int i; - strv = g_strsplit_set (stripped, " \t,", 0); - for (i = 0; strv[i]; i++) { - if (!strv[i][0]) - continue; + ret = TRUE; + while (s[0]) { + char *s_end; - flags_value = g_flags_get_value_by_nick (G_FLAGS_CLASS (class), strv[i]); - if (!flags_value) - break; + for (s_end = s; s_end[0]; s_end++) { + if (IS_FLAGS_SEPARATOR (s_end[0])) { + s_end[0] = '\0'; + s_end++; + break; + } + } - value |= flags_value->value; - } + 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; + } + value |= (int) v64; + } else { + flags_value = g_flags_get_value_by_nick (G_FLAGS_CLASS (class), s); + if (!flags_value) { + ret = FALSE; + break; + } + value |= flags_value->value; + } + } - if (strv[i]) { - if (err_token) - *err_token = strdup (strv[i]); - value = 0; - } else - ret = TRUE; + s = s_end; + } } else g_return_val_if_reached (FALSE); - if (out_value) - *out_value = value; - + 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); return ret; } @@ -4398,6 +4463,7 @@ const char **nm_utils_enum_get_values (GType type, gint from, gint to) GTypeClass *class; GPtrArray *array; gint i; + char sbuf[64]; class = g_type_class_ref (type); array = g_ptr_array_new (); @@ -4408,8 +4474,12 @@ const char **nm_utils_enum_get_values (GType type, gint from, gint to) for (i = 0; i < enum_class->n_values; i++) { enum_value = &enum_class->values[i]; - if (enum_value->value >= from && enum_value->value <= to) - g_ptr_array_add (array, (gpointer) enum_value->value_nick); + 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 (class)) { GFlagsClass *flags_class = G_FLAGS_CLASS (class); @@ -4417,8 +4487,12 @@ const char **nm_utils_enum_get_values (GType type, gint from, gint to) for (i = 0; i < flags_class->n_values; i++) { flags_value = &flags_class->values[i]; - if (flags_value->value >= from && flags_value->value <= to) - g_ptr_array_add (array, (gpointer) flags_value->value_nick); + if (flags_value->value >= from && flags_value->value <= 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 (class); diff --git a/libnm-core/tests/test-general-enums.h b/libnm-core/tests/test-general-enums.h index d06d6e39ff..8aa3f99fd1 100644 --- a/libnm-core/tests/test-general-enums.h +++ b/libnm-core/tests/test-general-enums.h @@ -27,6 +27,8 @@ typedef enum { NM_TEST_GENERAL_BOOL_ENUM_MAYBE = 2, NM_TEST_GENERAL_BOOL_ENUM_UNKNOWN = 3, NM_TEST_GENERAL_BOOL_ENUM_INVALID = 4, /*< skip >*/ + NM_TEST_GENERAL_BOOL_ENUM_67 = 67, + NM_TEST_GENERAL_BOOL_ENUM_46 = 64, } NMTestGeneralBoolEnum; typedef enum { @@ -34,6 +36,8 @@ typedef enum { NM_TEST_GENERAL_META_FLAGS_FOO = (1 << 0), NM_TEST_GENERAL_META_FLAGS_BAR = (1 << 1), NM_TEST_GENERAL_META_FLAGS_BAZ = (1 << 2), + NM_TEST_GENERAL_META_FLAGS_0x8 = (1 << 3), + NM_TEST_GENERAL_META_FLAGS_0x4 = (1 << 4), } NMTestGeneralMetaFlags; typedef enum { /*< flags >*/ diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index b9fef8da6a..073850b4e5 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -5142,25 +5142,30 @@ static void test_nm_utils_enum (void) test_nm_utils_enum_to_str_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_YES, "yes"); test_nm_utils_enum_to_str_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_UNKNOWN, "unknown"); - test_nm_utils_enum_to_str_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_INVALID, NULL); + test_nm_utils_enum_to_str_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_INVALID, "4"); + test_nm_utils_enum_to_str_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_67, "67"); + test_nm_utils_enum_to_str_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_46, "64"); test_nm_utils_enum_to_str_do (meta_flags, NM_TEST_GENERAL_META_FLAGS_NONE, ""); test_nm_utils_enum_to_str_do (meta_flags, NM_TEST_GENERAL_META_FLAGS_BAZ, "baz"); test_nm_utils_enum_to_str_do (meta_flags, NM_TEST_GENERAL_META_FLAGS_FOO | NM_TEST_GENERAL_META_FLAGS_BAR | NM_TEST_GENERAL_META_FLAGS_BAZ, "foo, bar, baz"); + test_nm_utils_enum_to_str_do (meta_flags, 0xFF, "foo, bar, baz, 0xf8"); + test_nm_utils_enum_to_str_do (meta_flags, NM_TEST_GENERAL_META_FLAGS_0x8, "0x8"); + test_nm_utils_enum_to_str_do (meta_flags, NM_TEST_GENERAL_META_FLAGS_0x4, "0x10"); test_nm_utils_enum_to_str_do (color_flags, NM_TEST_GENERAL_COLOR_FLAGS_RED, "red"); - test_nm_utils_enum_to_str_do (color_flags, NM_TEST_GENERAL_COLOR_FLAGS_WHITE, ""); + test_nm_utils_enum_to_str_do (color_flags, NM_TEST_GENERAL_COLOR_FLAGS_WHITE, "0x1"); test_nm_utils_enum_to_str_do (color_flags, NM_TEST_GENERAL_COLOR_FLAGS_RED | NM_TEST_GENERAL_COLOR_FLAGS_GREEN, "red, green"); test_nm_utils_enum_from_str_do (bool_enum, "", FALSE, 0, NULL); test_nm_utils_enum_from_str_do (bool_enum, " ", FALSE, 0, NULL); - test_nm_utils_enum_from_str_do (bool_enum, "invalid", FALSE, 0, NULL); + test_nm_utils_enum_from_str_do (bool_enum, "invalid", FALSE, 0, "invalid"); test_nm_utils_enum_from_str_do (bool_enum, "yes", TRUE, NM_TEST_GENERAL_BOOL_ENUM_YES, NULL); test_nm_utils_enum_from_str_do (bool_enum, "no", TRUE, NM_TEST_GENERAL_BOOL_ENUM_NO, NULL); - test_nm_utils_enum_from_str_do (bool_enum, "yes,no", FALSE, 0, NULL); + test_nm_utils_enum_from_str_do (bool_enum, "yes,no", FALSE, 0, "yes,no"); test_nm_utils_enum_from_str_do (meta_flags, "", TRUE, 0, NULL); test_nm_utils_enum_from_str_do (meta_flags, " ", TRUE, 0, NULL); @@ -5172,16 +5177,18 @@ static void test_nm_utils_enum (void) test_nm_utils_enum_from_str_do (meta_flags, "foo,,bar", TRUE, NM_TEST_GENERAL_META_FLAGS_FOO | NM_TEST_GENERAL_META_FLAGS_BAR, NULL); test_nm_utils_enum_from_str_do (meta_flags, "foo,baz,quux,bar", FALSE, 0, "quux"); + test_nm_utils_enum_from_str_do (meta_flags, "foo,0x6", TRUE, NM_TEST_GENERAL_META_FLAGS_FOO | 0x6, NULL); + test_nm_utils_enum_from_str_do (meta_flags, "0x30,0x08,foo", TRUE, 0x39, NULL); test_nm_utils_enum_from_str_do (color_flags, "green", TRUE, NM_TEST_GENERAL_COLOR_FLAGS_GREEN, NULL); test_nm_utils_enum_from_str_do (color_flags, "blue,red", TRUE, NM_TEST_GENERAL_COLOR_FLAGS_BLUE | NM_TEST_GENERAL_COLOR_FLAGS_RED, NULL); test_nm_utils_enum_from_str_do (color_flags, "blue,white", FALSE, 0, "white"); - test_nm_utils_enum_get_values_do (bool_enum, 0, G_MAXINT, "no,yes,maybe,unknown"); + test_nm_utils_enum_get_values_do (bool_enum, 0, G_MAXINT, "no,yes,maybe,unknown,67,64"); test_nm_utils_enum_get_values_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_YES, NM_TEST_GENERAL_BOOL_ENUM_MAYBE, "yes,maybe"); - test_nm_utils_enum_get_values_do (meta_flags, 0, G_MAXINT, "none,foo,bar,baz"); + test_nm_utils_enum_get_values_do (meta_flags, 0, G_MAXINT, "none,foo,bar,baz,0x8,0x10"); test_nm_utils_enum_get_values_do (color_flags, 0, G_MAXINT, "blue,red,green"); } |