GNOME Bugzilla – Bug 327198
Add g_key_file_[gs]et_enum
Last modified: 2013-02-03 02:13:26 UTC
Glib has this nice enumeration types. Therefore I'd like to see the following two functions for storing and retreiving enum values beeing added to glib: void g_key_file_set_enum( GKeyFile *key_file, const gchar *group_name, const gchar *key, GType enum_type, gint value) { g_return_if_fail(NULL != key_file); g_return_if_fail(NULL != key); GEnumClass *enum_class = G_ENUM_CLASS(g_type_class_peek(enum_type)); g_return_if_fail(NULL != enum_class); GEnumValue *enum_value = g_enum_get_value(enum_class, value); g_return_if_fail(NULL != enum_value); g_key_file_set_string(key_file, group_name, key, enum_value->value_nick); } gint g_key_file_get_enum( GKeyFile *key_file, const gchar *group_name, const gchar *key, GType enum_type, GError **error) { g_return_val_if_fail(NULL != key_file, -1); g_return_val_if_fail(NULL != key, -1); GEnumClass *enum_class = G_ENUM_CLASS(g_type_class_peek(enum_type)); g_return_val_if_fail(NULL != enum_class, -1); gchar *nick = g_key_file_get_string(key_file, group_name, key, error); gint result = -1; if (NULL != nick) { GEnumValue *enum_value = g_enum_get_value_by_nick(enum_class, nick); if (NULL == enum_value) { g_propagate_error(error, g_error_new( G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_PARSE, _("Invalid value for %s enumeration: '%s'"), g_type_name(enum_type), nick)); } else { result = enum_value->value; } } return result; }
Duh: Error message in g_key_file_get_enum should be: _("Key file contains key '%s' in group '%s' which has value that cannot be " "interpreted."), key, group_name instead of: _("Invalid value for %s enumeration: '%s'"), g_type_name(enum_type), nick)
This would be very useful - +1. This way users could have preferences that have the name of the enum, instead of e.g. an integer that maps to the enum values. Could this be included soon?
I tried adding this, but unfortunately this means we'd have to pull all of GObject into GLib... and I unless this is possible we'd have to hand-write all the enum checking code.... :-(
If you do this, it's always good to allow the value to be a list where the first understood enum value is used; then it's possible to write a config file that works with both old and new versions of the app when the enum is extended. (by having "NEWER_ENUM_VALUE,OLDER_ENUM_VALUE" as the setting)
I need similar functionality in GOption. I went on and implemented one in pango. The problem is that GOption and GKeyFile are in glib, while enums/flags are in gobject. I added this function to pango, which may be of greater interest: /** * pango_parse_enum: * @type: enum type to parse, eg. %PANGO_TYPE_ELLIPSIZE_MODE. * @str: string to parse. May be %NULL. * @value: integer to store the result in, or %NULL. * @warn: if %TRUE, issue a g_warning() on bad input. * @possible_values: place to store list of possible values on failure, or %NULL. * * Parses an enum type and stored the result in @value. * * If @str does not match the nick name of any of the possible values for the * enum, %FALSE is returned, a warning is issued if @warn is %TRUE, and a * string representing the list of possible values is stored in * @possible_values. The list is slash-separated, eg. * "none/start/middle/end". If failed and @possible_values is not %NULL, * returned string should be freed using g_free(). * * Return value: %TRUE if @str was successfully parsed. * * Since: 1.16 **/ gboolean pango_parse_enum (GType type, const char *str, int *value, gboolean warn, char **possible_values) { GEnumClass *class = NULL; gboolean ret = TRUE; GEnumValue *v = NULL; class = g_type_class_ref (type); if (G_LIKELY (str)) v = g_enum_get_value_by_nick (class, str); if (v) { if (G_LIKELY (value)) *value = v->value; } else { ret = FALSE; if (warn || possible_values) { int i; GString *s = g_string_new (NULL); for (i = 0, v = g_enum_get_value (class, i); v; i++ , v = g_enum_get_value (class, i)) { if (i) g_string_append_c (s, '/'); g_string_append (s, v->value_nick); } if (warn) g_warning ("%s must be one of %s", G_ENUM_CLASS_TYPE_NAME(class), s->str); if (possible_values) *possible_values = s->str; g_string_free (s, possible_values ? FALSE : TRUE); } } g_type_class_unref (class); return ret; }
(In reply to comment #5) Didn't understand the purpose of your post initially, but you are right: As neither GKeyFile nor GOptions can support enums directly we should have at least this convenience API in the gobject library. Just wondering if that function shouldn't be split into two pieces: g_parse_enum and g_enum_describe_values, as I didn't understand the purpose of possible_values initially.
It's unfortunate that enums cannot be supported by GKeyFile. I don't exactly see the use of the enum parsing in the context of the feature request. There is no need to enumerate and save all values just for config file handling.
Perhaps the relevant functions can be put in libgobject?
closing some old bugs