diff --git a/gio/gsettings.c b/gio/gsettings.c index 539c30364..a7c86ad4b 100644 --- a/gio/gsettings.c +++ b/gio/gsettings.c @@ -33,9 +33,6 @@ #include "gsettings-mapping.h" #include "gsettingsschema-internal.h" -#include - - #include "strinfo.c" /** @@ -854,112 +851,7 @@ g_settings_new_with_backend_and_path (const gchar *schema, NULL); } -/* Internal read/write utilities, enum/flags conversion, validation {{{1 */ -typedef struct -{ - GSettingsSchema *schema; - const gchar *name; - - guint is_flags : 1; - guint is_enum : 1; - - const guint32 *strinfo; - gsize strinfo_length; - - const gchar *unparsed; - gchar lc_char; - - const GVariantType *type; - GVariant *minimum, *maximum; - GVariant *default_value; -} GSettingsSchemaKey; - -static inline void -endian_fixup (GVariant **value) -{ -#if G_BYTE_ORDER == G_BIG_ENDIAN - GVariant *tmp; - - tmp = g_variant_byteswap (*value); - g_variant_unref (*value); - *value = tmp; -#endif -} - -static void -g_settings_schema_key_init (GSettingsSchemaKey *key, - GSettingsSchema *schema, - const gchar *name) -{ - GVariantIter *iter; - GVariant *data; - guchar code; - - memset (key, 0, sizeof *key); - - iter = g_settings_schema_get_value (schema, name); - - key->schema = g_settings_schema_ref (schema); - key->default_value = g_variant_iter_next_value (iter); - endian_fixup (&key->default_value); - key->type = g_variant_get_type (key->default_value); - key->name = g_intern_string (name); - - while (g_variant_iter_next (iter, "(y*)", &code, &data)) - { - switch (code) - { - case 'l': - /* translation requested */ - g_variant_get (data, "(y&s)", &key->lc_char, &key->unparsed); - break; - - case 'e': - /* enumerated types... */ - key->is_enum = TRUE; - goto choice; - - case 'f': - /* flags... */ - key->is_flags = TRUE; - goto choice; - - choice: case 'c': - /* ..., choices, aliases */ - key->strinfo = g_variant_get_fixed_array (data, &key->strinfo_length, sizeof (guint32)); - break; - - case 'r': - g_variant_get (data, "(**)", &key->minimum, &key->maximum); - endian_fixup (&key->minimum); - endian_fixup (&key->maximum); - break; - - default: - g_warning ("unknown schema extension '%c'", code); - break; - } - - g_variant_unref (data); - } - - g_variant_iter_free (iter); -} - -static void -g_settings_schema_key_clear (GSettingsSchemaKey *key) -{ - if (key->minimum) - g_variant_unref (key->minimum); - - if (key->maximum) - g_variant_unref (key->maximum); - - g_variant_unref (key->default_value); - - g_settings_schema_unref (key->schema); -} - +/* Internal read/write utilities {{{1 */ static gboolean g_settings_write_to_backend (GSettings *settings, GSettingsSchemaKey *key, @@ -975,94 +867,6 @@ g_settings_write_to_backend (GSettings *settings, return success; } -static gboolean -g_settings_schema_key_type_check (GSettingsSchemaKey *key, - GVariant *value) -{ - g_return_val_if_fail (value != NULL, FALSE); - - return g_variant_is_of_type (value, key->type); -} - -static gboolean -g_settings_schema_key_range_check (GSettingsSchemaKey *key, - GVariant *value) -{ - if (key->minimum == NULL && key->strinfo == NULL) - return TRUE; - - if (g_variant_is_container (value)) - { - gboolean ok = TRUE; - GVariantIter iter; - GVariant *child; - - g_variant_iter_init (&iter, value); - while (ok && (child = g_variant_iter_next_value (&iter))) - { - ok = g_settings_schema_key_range_check (key, child); - g_variant_unref (child); - } - - return ok; - } - - if (key->minimum) - { - return g_variant_compare (key->minimum, value) <= 0 && - g_variant_compare (value, key->maximum) <= 0; - } - - return strinfo_is_string_valid (key->strinfo, key->strinfo_length, - g_variant_get_string (value, NULL)); -} - -static GVariant * -g_settings_schema_key_range_fixup (GSettingsSchemaKey *key, - GVariant *value) -{ - const gchar *target; - - if (g_settings_schema_key_range_check (key, value)) - return g_variant_ref (value); - - if (key->strinfo == NULL) - return NULL; - - if (g_variant_is_container (value)) - { - GVariantBuilder builder; - GVariantIter iter; - GVariant *child; - - g_variant_iter_init (&iter, value); - g_variant_builder_init (&builder, g_variant_get_type (value)); - - while ((child = g_variant_iter_next_value (&iter))) - { - GVariant *fixed; - - fixed = g_settings_schema_key_range_fixup (key, child); - g_variant_unref (child); - - if (fixed == NULL) - { - g_variant_builder_clear (&builder); - return NULL; - } - - g_variant_builder_add_value (&builder, fixed); - g_variant_unref (fixed); - } - - return g_variant_ref_sink (g_variant_builder_end (&builder)); - } - - target = strinfo_string_from_alias (key->strinfo, key->strinfo_length, - g_variant_get_string (value, NULL)); - return target ? g_variant_ref_sink (g_variant_new_string (target)) : NULL; -} - static GVariant * g_settings_read_from_backend (GSettings *settings, GSettingsSchemaKey *key) @@ -1086,141 +890,6 @@ g_settings_read_from_backend (GSettings *settings, return fixup; } -static GVariant * -g_settings_schema_key_get_translated_default (GSettingsSchemaKey *key) -{ - const gchar *translated; - GError *error = NULL; - const gchar *domain; - GVariant *value; - - domain = g_settings_schema_get_gettext_domain (key->schema); - - if (key->lc_char == '\0') - /* translation not requested for this key */ - return NULL; - - if (key->lc_char == 't') - translated = g_dcgettext (domain, key->unparsed, LC_TIME); - else - translated = g_dgettext (domain, key->unparsed); - - if (translated == key->unparsed) - /* the default value was not translated */ - return NULL; - - /* try to parse the translation of the unparsed default */ - value = g_variant_parse (key->type, translated, NULL, NULL, &error); - - if (value == NULL) - { - g_warning ("Failed to parse translated string `%s' for " - "key `%s' in schema `%s': %s", key->unparsed, key->name, - g_settings_schema_get_name (key->schema), error->message); - g_warning ("Using untranslated default instead."); - g_error_free (error); - } - - else if (!g_settings_schema_key_range_check (key, value)) - { - g_warning ("Translated default `%s' for key `%s' in schema `%s' " - "is outside of valid range", key->unparsed, key->name, - g_settings_schema_get_name (key->schema)); - g_variant_unref (value); - value = NULL; - } - - return value; -} - -static gint -g_settings_schema_key_to_enum (GSettingsSchemaKey *key, - GVariant *value) -{ - gboolean it_worked; - guint result; - - it_worked = strinfo_enum_from_string (key->strinfo, key->strinfo_length, - g_variant_get_string (value, NULL), - &result); - - /* 'value' can only come from the backend after being filtered for validity, - * from the translation after being filtered for validity, or from the schema - * itself (which the schema compiler checks for validity). If this assertion - * fails then it's really a bug in GSettings or the schema compiler... - */ - g_assert (it_worked); - - return result; -} - -static GVariant * -g_settings_schema_key_from_enum (GSettingsSchemaKey *key, - gint value) -{ - const gchar *string; - - string = strinfo_string_from_enum (key->strinfo, key->strinfo_length, value); - - if (string == NULL) - return NULL; - - return g_variant_new_string (string); -} - -static guint -g_settings_schema_key_to_flags (GSettingsSchemaKey *key, - GVariant *value) -{ - GVariantIter iter; - const gchar *flag; - guint result; - - result = 0; - g_variant_iter_init (&iter, value); - while (g_variant_iter_next (&iter, "&s", &flag)) - { - gboolean it_worked; - guint flag_value; - - it_worked = strinfo_enum_from_string (key->strinfo, key->strinfo_length, flag, &flag_value); - /* as in g_settings_to_enum() */ - g_assert (it_worked); - - result |= flag_value; - } - - return result; -} - -static GVariant * -g_settings_schema_key_from_flags (GSettingsSchemaKey *key, - guint value) -{ - GVariantBuilder builder; - gint i; - - g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); - - for (i = 0; i < 32; i++) - if (value & (1u << i)) - { - const gchar *string; - - string = strinfo_string_from_enum (key->strinfo, key->strinfo_length, 1u << i); - - if (string == NULL) - { - g_variant_builder_clear (&builder); - return NULL; - } - - g_variant_builder_add (&builder, "s", string); - } - - return g_variant_builder_end (&builder); -} - /* Public Get/Set API {{{1 (get, get_value, set, set_value, get_mapped) */ /** * g_settings_get_value: diff --git a/gio/gsettingsschema-internal.h b/gio/gsettingsschema-internal.h index 2c3880150..ef4875a17 100644 --- a/gio/gsettingsschema-internal.h +++ b/gio/gsettingsschema-internal.h @@ -24,6 +24,25 @@ typedef struct _GSettingsSchema GSettingsSchema; +typedef struct +{ + GSettingsSchema *schema; + const gchar *name; + + guint is_flags : 1; + guint is_enum : 1; + + const guint32 *strinfo; + gsize strinfo_length; + + const gchar *unparsed; + gchar lc_char; + + const GVariantType *type; + GVariant *minimum, *maximum; + GVariant *default_value; +} GSettingsSchemaKey; + G_GNUC_INTERNAL GSettingsSchema * g_settings_schema_new (const gchar *name); G_GNUC_INTERNAL @@ -49,4 +68,35 @@ G_GNUC_INTERNAL const gchar * g_settings_schema_get_string (GSettingsSchema *schema, const gchar *key); +G_GNUC_INTERNAL +void g_settings_schema_key_init (GSettingsSchemaKey *key, + GSettingsSchema *schema, + const gchar *name); +G_GNUC_INTERNAL +void g_settings_schema_key_clear (GSettingsSchemaKey *key); +G_GNUC_INTERNAL +gboolean g_settings_schema_key_type_check (GSettingsSchemaKey *key, + GVariant *value); +G_GNUC_INTERNAL +gboolean g_settings_schema_key_range_check (GSettingsSchemaKey *key, + GVariant *value); +G_GNUC_INTERNAL +GVariant * g_settings_schema_key_range_fixup (GSettingsSchemaKey *key, + GVariant *value); +G_GNUC_INTERNAL +GVariant * g_settings_schema_key_get_translated_default (GSettingsSchemaKey *key); + +G_GNUC_INTERNAL +gint g_settings_schema_key_to_enum (GSettingsSchemaKey *key, + GVariant *value); +G_GNUC_INTERNAL +GVariant * g_settings_schema_key_from_enum (GSettingsSchemaKey *key, + gint value); +G_GNUC_INTERNAL +guint g_settings_schema_key_to_flags (GSettingsSchemaKey *key, + GVariant *value); +G_GNUC_INTERNAL +GVariant * g_settings_schema_key_from_flags (GSettingsSchemaKey *key, + guint value); + #endif /* __G_SETTINGS_SCHEMA_INTERNAL_H__ */ diff --git a/gio/gsettingsschema.c b/gio/gsettingsschema.c index 315a690cc..b79477ce2 100644 --- a/gio/gsettingsschema.c +++ b/gio/gsettingsschema.c @@ -23,8 +23,10 @@ #include "gsettings.h" #include "gvdb/gvdb-reader.h" +#include "strinfo.c" #include +#include struct _GSettingsSchema { @@ -362,3 +364,313 @@ g_settings_schema_get_name (GSettingsSchema *schema) { return schema->name; } + +static inline void +endian_fixup (GVariant **value) +{ +#if G_BYTE_ORDER == G_BIG_ENDIAN + GVariant *tmp; + + tmp = g_variant_byteswap (*value); + g_variant_unref (*value); + *value = tmp; +#endif +} + +void +g_settings_schema_key_init (GSettingsSchemaKey *key, + GSettingsSchema *schema, + const gchar *name) +{ + GVariantIter *iter; + GVariant *data; + guchar code; + + memset (key, 0, sizeof *key); + + iter = g_settings_schema_get_value (schema, name); + + key->schema = g_settings_schema_ref (schema); + key->default_value = g_variant_iter_next_value (iter); + endian_fixup (&key->default_value); + key->type = g_variant_get_type (key->default_value); + key->name = g_intern_string (name); + + while (g_variant_iter_next (iter, "(y*)", &code, &data)) + { + switch (code) + { + case 'l': + /* translation requested */ + g_variant_get (data, "(y&s)", &key->lc_char, &key->unparsed); + break; + + case 'e': + /* enumerated types... */ + key->is_enum = TRUE; + goto choice; + + case 'f': + /* flags... */ + key->is_flags = TRUE; + goto choice; + + choice: case 'c': + /* ..., choices, aliases */ + key->strinfo = g_variant_get_fixed_array (data, &key->strinfo_length, sizeof (guint32)); + break; + + case 'r': + g_variant_get (data, "(**)", &key->minimum, &key->maximum); + endian_fixup (&key->minimum); + endian_fixup (&key->maximum); + break; + + default: + g_warning ("unknown schema extension '%c'", code); + break; + } + + g_variant_unref (data); + } + + g_variant_iter_free (iter); +} + +void +g_settings_schema_key_clear (GSettingsSchemaKey *key) +{ + if (key->minimum) + g_variant_unref (key->minimum); + + if (key->maximum) + g_variant_unref (key->maximum); + + g_variant_unref (key->default_value); + + g_settings_schema_unref (key->schema); +} + +gboolean +g_settings_schema_key_type_check (GSettingsSchemaKey *key, + GVariant *value) +{ + g_return_val_if_fail (value != NULL, FALSE); + + return g_variant_is_of_type (value, key->type); +} + +gboolean +g_settings_schema_key_range_check (GSettingsSchemaKey *key, + GVariant *value) +{ + if (key->minimum == NULL && key->strinfo == NULL) + return TRUE; + + if (g_variant_is_container (value)) + { + gboolean ok = TRUE; + GVariantIter iter; + GVariant *child; + + g_variant_iter_init (&iter, value); + while (ok && (child = g_variant_iter_next_value (&iter))) + { + ok = g_settings_schema_key_range_check (key, child); + g_variant_unref (child); + } + + return ok; + } + + if (key->minimum) + { + return g_variant_compare (key->minimum, value) <= 0 && + g_variant_compare (value, key->maximum) <= 0; + } + + return strinfo_is_string_valid (key->strinfo, key->strinfo_length, + g_variant_get_string (value, NULL)); +} + +GVariant * +g_settings_schema_key_range_fixup (GSettingsSchemaKey *key, + GVariant *value) +{ + const gchar *target; + + if (g_settings_schema_key_range_check (key, value)) + return g_variant_ref (value); + + if (key->strinfo == NULL) + return NULL; + + if (g_variant_is_container (value)) + { + GVariantBuilder builder; + GVariantIter iter; + GVariant *child; + + g_variant_iter_init (&iter, value); + g_variant_builder_init (&builder, g_variant_get_type (value)); + + while ((child = g_variant_iter_next_value (&iter))) + { + GVariant *fixed; + + fixed = g_settings_schema_key_range_fixup (key, child); + g_variant_unref (child); + + if (fixed == NULL) + { + g_variant_builder_clear (&builder); + return NULL; + } + + g_variant_builder_add_value (&builder, fixed); + g_variant_unref (fixed); + } + + return g_variant_ref_sink (g_variant_builder_end (&builder)); + } + + target = strinfo_string_from_alias (key->strinfo, key->strinfo_length, + g_variant_get_string (value, NULL)); + return target ? g_variant_ref_sink (g_variant_new_string (target)) : NULL; +} + + +GVariant * +g_settings_schema_key_get_translated_default (GSettingsSchemaKey *key) +{ + const gchar *translated; + GError *error = NULL; + const gchar *domain; + GVariant *value; + + domain = g_settings_schema_get_gettext_domain (key->schema); + + if (key->lc_char == '\0') + /* translation not requested for this key */ + return NULL; + + if (key->lc_char == 't') + translated = g_dcgettext (domain, key->unparsed, LC_TIME); + else + translated = g_dgettext (domain, key->unparsed); + + if (translated == key->unparsed) + /* the default value was not translated */ + return NULL; + + /* try to parse the translation of the unparsed default */ + value = g_variant_parse (key->type, translated, NULL, NULL, &error); + + if (value == NULL) + { + g_warning ("Failed to parse translated string `%s' for " + "key `%s' in schema `%s': %s", key->unparsed, key->name, + g_settings_schema_get_name (key->schema), error->message); + g_warning ("Using untranslated default instead."); + g_error_free (error); + } + + else if (!g_settings_schema_key_range_check (key, value)) + { + g_warning ("Translated default `%s' for key `%s' in schema `%s' " + "is outside of valid range", key->unparsed, key->name, + g_settings_schema_get_name (key->schema)); + g_variant_unref (value); + value = NULL; + } + + return value; +} + +gint +g_settings_schema_key_to_enum (GSettingsSchemaKey *key, + GVariant *value) +{ + gboolean it_worked; + guint result; + + it_worked = strinfo_enum_from_string (key->strinfo, key->strinfo_length, + g_variant_get_string (value, NULL), + &result); + + /* 'value' can only come from the backend after being filtered for validity, + * from the translation after being filtered for validity, or from the schema + * itself (which the schema compiler checks for validity). If this assertion + * fails then it's really a bug in GSettings or the schema compiler... + */ + g_assert (it_worked); + + return result; +} + +GVariant * +g_settings_schema_key_from_enum (GSettingsSchemaKey *key, + gint value) +{ + const gchar *string; + + string = strinfo_string_from_enum (key->strinfo, key->strinfo_length, value); + + if (string == NULL) + return NULL; + + return g_variant_new_string (string); +} + +guint +g_settings_schema_key_to_flags (GSettingsSchemaKey *key, + GVariant *value) +{ + GVariantIter iter; + const gchar *flag; + guint result; + + result = 0; + g_variant_iter_init (&iter, value); + while (g_variant_iter_next (&iter, "&s", &flag)) + { + gboolean it_worked; + guint flag_value; + + it_worked = strinfo_enum_from_string (key->strinfo, key->strinfo_length, flag, &flag_value); + /* as in g_settings_to_enum() */ + g_assert (it_worked); + + result |= flag_value; + } + + return result; +} + +GVariant * +g_settings_schema_key_from_flags (GSettingsSchemaKey *key, + guint value) +{ + GVariantBuilder builder; + gint i; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); + + for (i = 0; i < 32; i++) + if (value & (1u << i)) + { + const gchar *string; + + string = strinfo_string_from_enum (key->strinfo, key->strinfo_length, 1u << i); + + if (string == NULL) + { + g_variant_builder_clear (&builder); + return NULL; + } + + g_variant_builder_add (&builder, "s", string); + } + + return g_variant_builder_end (&builder); +}