summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Lortie <desrt@desrt.ca>2010-10-02 22:42:02 -0400
committerRyan Lortie <desrt@desrt.ca>2010-10-02 22:42:02 -0400
commitd2c06994402ee30e989efb9e912d3abd16ca0e10 (patch)
tree5d6f480344c8e58941b7b620d7ef0aee25d3005a
parent1fee36f72bdbf87d585222e864cb8494e7156ee0 (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.symbols1
-rw-r--r--gio/gsettings.h1
-rw-r--r--gio/gsettingsschema.c126
-rw-r--r--gio/tests/gsettings.c7
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",