summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2021-01-14 17:46:21 +0100
committerThomas Haller <thaller@redhat.com>2021-01-14 18:16:23 +0100
commit25dc831cfdef81211cc60f53c1fcc84f2d057c2f (patch)
tree077416285d1ed9be267b242f71eb5ab809bb9499
parent37290c2ba5428d23f68a65d30dc6081f137ed632 (diff)
downloadNetworkManager-th/enum-from-str-fix-signed.tar.gz
shared: fix _nm_utils_enum_from_str_full() for negative enum valuesth/enum-from-str-fix-signed
Enums can also be negative (contrary to Flags). Fix the parsing. $ nmcli connection modify "$PROFILE" connection.llmnr -1 Error: failed to modify connection.llmnr: invalid option '-1', use one of [default,no,resolve,yes].
-rw-r--r--libnm-core/tests/test-general.c14
-rw-r--r--shared/nm-glib-aux/nm-enum-utils.c51
2 files changed, 49 insertions, 16 deletions
diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c
index f89aea9718..4b44472e2f 100644
--- a/libnm-core/tests/test-general.c
+++ b/libnm-core/tests/test-general.c
@@ -8805,6 +8805,20 @@ test_nm_utils_enum(void)
NULL,
color_value_infos);
+ _test_nm_utils_enum_from_str_do_full(NM_TYPE_SETTING_CONNECTION_LLMNR,
+ "-1",
+ TRUE,
+ -1,
+ NULL,
+ NULL);
+
+ _test_nm_utils_enum_from_str_do_full(NM_TYPE_SETTING_CONNECTION_LLMNR,
+ "-0x1",
+ TRUE,
+ -1,
+ NULL,
+ NULL);
+
_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,
diff --git a/shared/nm-glib-aux/nm-enum-utils.c b/shared/nm-glib-aux/nm-enum-utils.c
index 279eeaeb5b..9b778d6ba5 100644
--- a/shared/nm-glib-aux/nm-enum-utils.c
+++ b/shared/nm-glib-aux/nm-enum-utils.c
@@ -76,30 +76,34 @@ _ASSERT_enum_values_info(GType type, const NMUtilsEnumValueInfo *value_infos)
}
static gboolean
-_is_hex_string(const char *str)
+_is_hex_string(const char *str, gboolean allow_sign)
{
+ if (allow_sign && str[0] == '-')
+ 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)
+_is_dec_string(const char *str, gboolean allow_sign)
{
+ if (allow_sign && str[0] == '-')
+ 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);
+ return str[0] && !NM_STRCHAR_ANY(str, ch, g_ascii_isspace(ch)) && !_is_dec_string(str, TRUE)
+ && !_is_hex_string(str, TRUE);
}
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);
+ return str[0] && !NM_STRCHAR_ANY(str, ch, IS_FLAGS_SEPARATOR(ch)) && !_is_dec_string(str, FALSE)
+ && !_is_hex_string(str, FALSE);
}
char *
@@ -220,16 +224,31 @@ _nm_utils_enum_from_str_full(GType type,
if (G_IS_ENUM_CLASS(klass)) {
GEnumValue *enum_value;
+ G_STATIC_ASSERT(G_MAXINT < G_MAXINT64);
+ G_STATIC_ASSERT(G_MININT > G_MININT64);
+
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;
+ if (_is_hex_string(s, TRUE)) {
+ if (s[0] == '-') {
+ v64 = _nm_utils_ascii_str_to_int64(&s[3],
+ 16,
+ -((gint64) G_MAXINT),
+ -((gint64) G_MININT),
+ G_MAXINT64);
+ if (v64 != G_MAXINT64) {
+ value = (int) (-v64);
+ ret = TRUE;
+ }
+ } else {
+ v64 = _nm_utils_ascii_str_to_int64(&s[2], 16, G_MININT, G_MAXINT, G_MAXINT64);
+ if (v64 != G_MAXINT64) {
+ 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) {
+ } else if (_is_dec_string(s, TRUE)) {
+ v64 = _nm_utils_ascii_str_to_int64(s, 10, G_MININT, G_MAXINT, G_MAXINT64);
+ if (v64 != G_MAXINT64) {
value = (int) v64;
ret = TRUE;
}
@@ -258,14 +277,14 @@ _nm_utils_enum_from_str_full(GType type,
}
if (s[0]) {
- if (_is_hex_string(s)) {
+ if (_is_hex_string(s, FALSE)) {
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)) {
+ } else if (_is_dec_string(s, FALSE)) {
v64 = _nm_utils_ascii_str_to_int64(s, 10, 0, G_MAXUINT, -1);
if (v64 == -1) {
ret = FALSE;