diff --git a/Makefile.am b/Makefile.am index cfcc27c4dd..1db61f3695 100644 --- a/Makefile.am +++ b/Makefile.am @@ -414,6 +414,7 @@ libnm_core_lib_h_pub_real = \ libnm_core_lib_h_pub_mkenums = \ libnm-core/nm-core-enum-types.h libnm_core_lib_h_priv = \ + shared/nm-utils/nm-enum-utils.h \ shared/nm-utils/nm-shared-utils.h \ shared/nm-utils/nm-udev-utils.h \ shared/nm-meta-setting.h \ @@ -427,6 +428,7 @@ libnm_core_lib_h_priv = \ libnm-core/nm-setting-private.h \ libnm-core/nm-utils-private.h libnm_core_lib_c_real = \ + shared/nm-utils/nm-enum-utils.c \ shared/nm-utils/nm-shared-utils.c \ shared/nm-utils/nm-udev-utils.c \ shared/nm-meta-setting.c \ diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index ac292bfc18..176c0600f9 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -204,8 +204,6 @@ gboolean _nm_utils_check_module_file (const char *name, gpointer user_data, GError **error); -char *_nm_utils_enum_to_str_full (GType type, int value, const char *sep); - #define NM_UTILS_UUID_TYPE_LEGACY 0 #define NM_UTILS_UUID_TYPE_VARIANT3 1 diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 56f9497f2a..5c5b94c667 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -37,6 +37,7 @@ #include #endif +#include "nm-utils/nm-enum-utils.h" #include "nm-common-macros.h" #include "nm-utils-private.h" #include "nm-setting-private.h" @@ -4249,291 +4250,6 @@ 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 -_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) -{ - GTypeClass *class; - char *ret; - - 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); - - if (G_IS_ENUM_CLASS (class)) { - GEnumValue *enum_value; - - enum_value = g_enum_get_value (G_ENUM_CLASS (class), value); - 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 (""); - unsigned uvalue = (unsigned) value; - - flags_separator = flags_separator ?: " "; - - do { - flags_value = g_flags_get_first_value (G_FLAGS_CLASS (class), uvalue); - if (str->len) - g_string_append (str, flags_separator); - if ( !flags_value - || !_enum_is_valid_flags_nick (flags_value->value_nick)) { - if (uvalue) - g_string_append_printf (str, "0x%x", uvalue); - break; - } - 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; -} - -/** - * nm_utils_enum_to_str: - * @type: the %GType of the enum - * @value: the value to be translated - * - * Converts an enum value to its string representation. If the enum is a - * %G_TYPE_FLAGS the function returns a comma-separated list of matching values. - * If the value has no corresponding string representation, it is converted - * to a number. For enums it is converted to a decimal number, for flags - * to an (unsigned) hex number. - * - * Returns: a newly allocated string or %NULL - * - * Since: 1.2 - */ -char * -nm_utils_enum_to_str (GType type, int value) -{ - return _nm_utils_enum_to_str_full (type, value, ", "); -} - -/** - * nm_utils_enum_from_str: - * @type: the %GType of the enum - * @str: the input string - * @out_value: (out) (allow-none): the output value - * @err_token: (out) (allow-none) (transfer full): location to store the first unrecognized token - * - * Converts a string to the matching enum value. - * - * If the enum is a %G_TYPE_FLAGS the function returns the logical OR of values - * matching the comma-separated tokens in the string; if an unknown token is found - * the function returns %FALSE and stores a pointer to a newly allocated string - * containing the unrecognized token in @err_token. - * - * Returns: %TRUE if the conversion was successful, %FALSE otherwise - * - * Since: 1.2 - */ -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 *str_clone = NULL; - char *s; - gint64 v64; - - g_return_val_if_fail (str, FALSE); - - 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; - - 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 { - 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; - 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 { - flags_value = g_flags_get_value_by_nick (G_FLAGS_CLASS (class), s); - if (!flags_value) { - ret = FALSE; - break; - } - uvalue |= flags_value->value; - } - } - - 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); - g_type_class_unref (class); - return ret; -} - -/** - * nm_utils_enum_get_values: - * @type: the %GType of the enum - * @from: the first element to be returned - * @to: the last element to be returned - * - * Returns the list of possible values for a given enum. - * - * Returns: (transfer container): a NULL-terminated dynamically-allocated array of static strings - * or %NULL on error - * - * Since: 1.2 - */ -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 (); - - if (G_IS_ENUM_CLASS (class)) { - GEnumClass *enum_class = G_ENUM_CLASS (class); - 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 (class)) { - GFlagsClass *flags_class = G_FLAGS_CLASS (class); - GFlagsValue *flags_value; - - for (i = 0; i < flags_class->n_values; i++) { - flags_value = &flags_class->values[i]; - 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); - g_ptr_array_free (array, TRUE); - g_return_val_if_reached (NULL); - } - - g_type_class_unref (class); - g_ptr_array_add (array, NULL); - - return (const char **) g_ptr_array_free (array, FALSE); -} - #if WITH_JANSSON /** * nm_utils_is_json_object: diff --git a/shared/nm-utils/nm-enum-utils.c b/shared/nm-utils/nm-enum-utils.c new file mode 100644 index 0000000000..5b62a26910 --- /dev/null +++ b/shared/nm-utils/nm-enum-utils.c @@ -0,0 +1,311 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-enum-utils.h" + +/*****************************************************************************/ + +#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 +_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) +{ + GTypeClass *class; + char *ret; + + 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); + + if (G_IS_ENUM_CLASS (class)) { + GEnumValue *enum_value; + + enum_value = g_enum_get_value (G_ENUM_CLASS (class), value); + 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 (""); + unsigned uvalue = (unsigned) value; + + flags_separator = flags_separator ?: " "; + + do { + flags_value = g_flags_get_first_value (G_FLAGS_CLASS (class), uvalue); + if (str->len) + g_string_append (str, flags_separator); + if ( !flags_value + || !_enum_is_valid_flags_nick (flags_value->value_nick)) { + if (uvalue) + g_string_append_printf (str, "0x%x", uvalue); + break; + } + 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; +} + +/** + * nm_utils_enum_to_str: + * @type: the %GType of the enum + * @value: the value to be translated + * + * Converts an enum value to its string representation. If the enum is a + * %G_TYPE_FLAGS the function returns a comma-separated list of matching values. + * If the value has no corresponding string representation, it is converted + * to a number. For enums it is converted to a decimal number, for flags + * to an (unsigned) hex number. + * + * Returns: a newly allocated string or %NULL + * + * Since: 1.2 + */ +char * +nm_utils_enum_to_str (GType type, int value) +{ + return _nm_utils_enum_to_str_full (type, value, ", "); +} + +/** + * nm_utils_enum_from_str: + * @type: the %GType of the enum + * @str: the input string + * @out_value: (out) (allow-none): the output value + * @err_token: (out) (allow-none) (transfer full): location to store the first unrecognized token + * + * Converts a string to the matching enum value. + * + * If the enum is a %G_TYPE_FLAGS the function returns the logical OR of values + * matching the comma-separated tokens in the string; if an unknown token is found + * the function returns %FALSE and stores a pointer to a newly allocated string + * containing the unrecognized token in @err_token. + * + * Returns: %TRUE if the conversion was successful, %FALSE otherwise + * + * Since: 1.2 + */ +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 *str_clone = NULL; + char *s; + gint64 v64; + + g_return_val_if_fail (str, FALSE); + + 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; + + 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 { + 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; + 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 { + flags_value = g_flags_get_value_by_nick (G_FLAGS_CLASS (class), s); + if (!flags_value) { + ret = FALSE; + break; + } + uvalue |= flags_value->value; + } + } + + 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); + g_type_class_unref (class); + return ret; +} + +/** + * nm_utils_enum_get_values: + * @type: the %GType of the enum + * @from: the first element to be returned + * @to: the last element to be returned + * + * Returns the list of possible values for a given enum. + * + * Returns: (transfer container): a NULL-terminated dynamically-allocated array of static strings + * or %NULL on error + * + * Since: 1.2 + */ +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 (); + + if (G_IS_ENUM_CLASS (class)) { + GEnumClass *enum_class = G_ENUM_CLASS (class); + 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 (class)) { + GFlagsClass *flags_class = G_FLAGS_CLASS (class); + GFlagsValue *flags_value; + + for (i = 0; i < flags_class->n_values; i++) { + flags_value = &flags_class->values[i]; + 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); + g_ptr_array_free (array, TRUE); + g_return_val_if_reached (NULL); + } + + g_type_class_unref (class); + g_ptr_array_add (array, NULL); + + return (const char **) g_ptr_array_free (array, FALSE); +} diff --git a/shared/nm-utils/nm-enum-utils.h b/shared/nm-utils/nm-enum-utils.h new file mode 100644 index 0000000000..6f8d4924ea --- /dev/null +++ b/shared/nm-utils/nm-enum-utils.h @@ -0,0 +1,34 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2017 Red Hat, Inc. + */ + +#ifndef __NM_ENUM_UTILS_H__ +#define __NM_ENUM_UTILS_H__ + +/*****************************************************************************/ + +char *_nm_utils_enum_to_str_full (GType type, int value, const char *sep); +char *nm_utils_enum_to_str (GType type, int value); +gboolean nm_utils_enum_from_str (GType type, const char *str, int *out_value, char **err_token); +const char **nm_utils_enum_get_values (GType type, gint from, gint to); + +/*****************************************************************************/ + +#endif /* __NM_ENUM_UTILS_H__ */ diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 01e666356e..8aa6b9e8f0 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -32,6 +32,7 @@ #include #include +#include "nm-utils/nm-enum-utils.h" #include "nm-manager.h" #include "nm-setting-connection.h" #include "nm-setting-wired.h"