diff options
author | Ryan Lortie <desrt@desrt.ca> | 2010-10-02 22:42:02 -0400 |
---|---|---|
committer | Ryan Lortie <desrt@desrt.ca> | 2010-10-02 22:42:02 -0400 |
commit | d2c06994402ee30e989efb9e912d3abd16ca0e10 (patch) | |
tree | 5d6f480344c8e58941b7b620d7ef0aee25d3005a | |
parent | 1fee36f72bdbf87d585222e864cb8494e7156ee0 (diff) |
Clean up g_settings_list_schemas()
In its previous form, g_settings_list_schemas() was not useful as a tool
to prevent aborts due to using g_settings_new() with an invalid schema
name. This is because g_settings_list_scheams() also listed relocatable
schemas, and calling g_settings_new() for those would abort just the
same as if you called it for a non-existent schema.
Modify g_settings_list_schemas() so that it only returns schemas for
which it is safe to call g_settings_new(). Add another call for sake of
completeness: g_settings_list_relocatable_schemas().
-rw-r--r-- | gio/gio.symbols | 1 | ||||
-rw-r--r-- | gio/gsettings.h | 1 | ||||
-rw-r--r-- | gio/gsettingsschema.c | 126 | ||||
-rw-r--r-- | gio/tests/gsettings.c | 7 |
4 files changed, 103 insertions, 32 deletions
diff --git a/gio/gio.symbols b/gio/gio.symbols index 0e33f614b..29378f4bd 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -1520,6 +1520,7 @@ g_keyfile_settings_backend_new #if IN_HEADER(__G_SETTINGS_H__) #if IN_FILE(__G_SETTINGS_SCHEMA_C__) g_settings_list_schemas +g_settings_list_relocatable_schemas #endif #if IN_FILE(__G_SETTINGS_C__) diff --git a/gio/gsettings.h b/gio/gsettings.h index 0ee4399ef..2b4e2f6fc 100644 --- a/gio/gsettings.h +++ b/gio/gsettings.h @@ -71,6 +71,7 @@ struct _GSettings GType g_settings_get_type (void); const gchar * const * g_settings_list_schemas (void); +const gchar * const * g_settings_list_relocatable_schemas (void); GSettings * g_settings_new (const gchar *schema); GSettings * g_settings_new_with_path (const gchar *schema, const gchar *path); diff --git a/gio/gsettingsschema.c b/gio/gsettingsschema.c index 053b94e72..6411f4f1d 100644 --- a/gio/gsettingsschema.c +++ b/gio/gsettingsschema.c @@ -83,65 +83,129 @@ initialise_schema_sources (void) } } -static void -add_item (gpointer key, - gpointer value, - gpointer user_data) +static gboolean +steal_item (gpointer key, + gpointer value, + gpointer user_data) { gchar ***ptr = user_data; *(*ptr)++ = (gchar *) key; + + return TRUE; } -/** - * g_settings_list_schemas: - * @returns: a list of the schemas installed on the system - * - * Returns: (element-type utf8) (transfer none): a list of GSettings schemas that are available. The list - * must not be modified or freed. - **/ -const gchar * const * -g_settings_list_schemas (void) -{ - static gsize schema_list; +static const gchar * const *non_relocatable_schema_list; +static const gchar * const *relocatable_schema_list; +static gsize schema_lists_initialised; - if (g_once_init_enter (&schema_list)) +static void +ensure_schema_lists (void) +{ + if (g_once_init_enter (&schema_lists_initialised)) { - GHashTable *builder; + GHashTable *single, *reloc; + const gchar **ptr; GSList *source; gchar **list; - gchar **ptr; gint i; initialise_schema_sources (); - builder = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + /* We use hash tables to avoid duplicate listings for schemas that + * appear in more than one file. + */ + single = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + reloc = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); for (source = schema_sources; source; source = source->next) { list = gvdb_table_list (source->data, ""); - if (list) - { - for (i = 0; list[i]; i++) - g_hash_table_insert (builder, list[i], NULL); + g_assert (list != NULL); - /* not strfreev: we stole the strings into the hashtable */ - g_free (list); + for (i = 0; list[i]; i++) + { + if (!g_hash_table_lookup (single, list[i]) && + !g_hash_table_lookup (reloc, list[i])) + { + GvdbTable *table; + + table = gvdb_table_get_table (source->data, list[i]); + g_assert (table != NULL); + + if (gvdb_table_has_value (table, ".path")) + g_hash_table_insert (single, g_strdup (list[i]), NULL); + else + g_hash_table_insert (reloc, g_strdup (list[i]), NULL); + } } + + g_strfreev (list); } - ptr = list = g_new (gchar *, g_hash_table_size (builder) + 1); - g_hash_table_foreach (builder, add_item, &ptr); + ptr = g_new (const gchar *, g_hash_table_size (single) + 1); + non_relocatable_schema_list = ptr; + g_hash_table_foreach_steal (single, steal_item, &ptr); + g_hash_table_unref (single); *ptr = NULL; - g_hash_table_steal_all (builder); - g_hash_table_unref (builder); + ptr = g_new (const gchar *, g_hash_table_size (reloc) + 1); + relocatable_schema_list = ptr; + g_hash_table_foreach_steal (reloc, steal_item, &ptr); + g_hash_table_unref (reloc); + *ptr = NULL; - g_once_init_leave (&schema_list, (gsize) list); + g_once_init_leave (&schema_lists_initialised, TRUE); } +} + +/** + * g_settings_list_schemas: + * + * Gets a list of the #GSettings schemas installed on the system. The + * returned list is exactly the list of schemas for which you may call + * g_settings_new() without adverse effects. + * + * This function does not list the schemas that do not provide their own + * paths (ie: schemas for which you must use + * g_settings_new_with_path()). See + * g_settings_list_relocatable_schemas() for that. + * + * Returns: (element-type utf8) (transfer none): a list of #GSettings + * schemas that are available. The list must not be modified or + * freed. + **/ +const gchar * const * +g_settings_list_schemas (void) +{ + ensure_schema_lists (); + + return non_relocatable_schema_list; +} + +/** + * g_settings_list_relocatable_schemas: + * + * Gets a list of the relocatable #GSettings schemas installed on the + * system. These are schemas that do not provide their own path. It is + * usual to instantiate these schemas directly, but if you want to you + * can use g_settings_new_with_path() to specify the path. + * + * The output of this function, tTaken together with the output of + * g_settings_list_schemas() represents the complete list of all + * installed schemas. + * + * Returns: (element-type utf8) (transfer none): a list of relocatable + * #GSettings schemas that are available. The list must not be + * modified or freed. + **/ +const gchar * const * +g_settings_list_relocatable_schemas (void) +{ + ensure_schema_lists (); - return (const gchar **) schema_list; + return relocatable_schema_list; } static void diff --git a/gio/tests/gsettings.c b/gio/tests/gsettings.c index fdadf9633..3313d38a6 100644 --- a/gio/tests/gsettings.c +++ b/gio/tests/gsettings.c @@ -1765,12 +1765,17 @@ static void test_list_schemas (void) { const gchar * const *schemas; + const gchar * const *relocs; + relocs = g_settings_list_relocatable_schemas (); schemas = g_settings_list_schemas (); + g_assert (strv_set_equal ((gchar **)relocs, + "org.gtk.test.no-path", + NULL)); + g_assert (strv_set_equal ((gchar **)schemas, "org.gtk.test", - "org.gtk.test.no-path", "org.gtk.test.basic-types", "org.gtk.test.complex-types", "org.gtk.test.localized", |