[glib/gsettings] GSettingsSchema: support for uncached schemas



commit c08f3a5bcdfb41db831ca23892007b8ef1941a43
Author: Ryan Lortie <desrt desrt ca>
Date:   Fri Oct 2 16:44:02 2009 -0400

    GSettingsSchema: support for uncached schemas

 gio/gsettingsschema.c |  161 +++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 143 insertions(+), 18 deletions(-)
---
diff --git a/gio/gsettingsschema.c b/gio/gsettingsschema.c
index 02c1c04..5131fdd 100644
--- a/gio/gsettingsschema.c
+++ b/gio/gsettingsschema.c
@@ -10,6 +10,7 @@
 
 #include "gsettingsschema.h"
 
+#include <sys/stat.h>
 #include <string.h>
 
 #include "gioalias.h"
@@ -25,38 +26,152 @@ struct _GSettingsSchemaPrivate
   GVariant *children;
 };
 
+gint g_settings_schema_n_dirs;
+GVariant **g_settings_schema_caches;
+gchar **g_settings_schema_dirs;
+
 static void
-g_settings_schema_init (GSettingsSchema *schema)
+g_settings_schema_initialise_directories (void)
 {
-  schema->priv = G_TYPE_INSTANCE_GET_PRIVATE (schema,
-                                              G_TYPE_SETTINGS_SCHEMA,
-                                              GSettingsSchemaPrivate);
+  const GVariantType *cache_type;
+  const char * const *data_dirs;
+  GVariant **caches;
+  gchar **dirs;
+  gint i, n;
+
+  /* we want to do the following:
+   *
+   *   - set g_settings_schema_n_dirs to the number of valid schema dirs
+   *
+   *   - set g_settings_schema_caches to an array with 'n_dirs'
+   *     elements.  if a given element is non-NULL then it points to the
+   *     GVariant for that schema directory's cache.  if NULL, the cache
+   *     is invalid.
+   *
+   *   - set g_settings_schema_dirs to an array of size n where n is one
+   *     more than the largest index in g_settings_schema_caches that
+   *     contains NULL.  for every NULL in g_setings_schema_caches, the
+   *     entry of the same index in this array will contain the
+   *     path of a schema directory to check for uncached schemas.
+   */
+
+  cache_type = G_VARIANT_TYPE ("a{s(asmsa{s(sv)}a{ss})}");
+  data_dirs = g_get_system_data_dirs ();
+
+  caches = NULL;
+  dirs = NULL;
+
+  for (n = i = 0; data_dirs[i]; i++)
+    {
+      struct stat dirbuf, cachebuf;
+      gchar *path, *cachepath;
+     
+      path = g_strdup_printf ("%s/%s", data_dirs[i], "gsettings/schemas");
+      if (stat (path, &dirbuf) || !S_ISDIR (dirbuf.st_mode) < 0)
+        {
+          g_free (path);
+          continue;
+        }
+
+      cachepath = g_strdup_printf ("%s/schemas-cache", path);
+      if (stat (cachepath, &cachebuf) < 0)
+        {
+          g_free (cachepath);
+          cachepath = NULL;
+        }
+      else
+        {
+          if (cachebuf.st_mtime < dirbuf.st_mtime)
+            {
+              g_free (cachepath);
+              cachepath = NULL;
+            }
+        }
+
+      caches = g_renew (GVariant *, caches, n + 1);
+      caches[n] = cachepath ?
+                  g_variant_from_file (cache_type, cachepath, 0, NULL) :
+                  NULL;
+      g_free (cachepath);
+
+      if (caches[n] == NULL)
+        {
+          dirs = g_renew (gchar *, dirs, i + 1);
+          dirs[n] = path;
+        }
+      else
+        g_free (path);
+
+      n++;
+    }
+  g_settings_schema_n_dirs = n;
+  g_settings_schema_caches = caches;
+  g_settings_schema_dirs = dirs;
 }
 
-GSettingsSchema *
-g_settings_schema_new (const gchar *schema_name)
+static GVariant *
+g_settings_schema_compile (const gchar *filename)
 {
-  static GVariant *schemas;
-  GSettingsSchema *schema;
+  g_print ("compiling %s\n", filename);
+  return NULL;
+}
+
+static GVariant *
+g_settings_schema_scan_dir (const gchar *directory,
+                            const gchar *schema_name)
+{
+  gint directory_length;
+  gint name_length;
   GVariant *value;
+  gchar *path;
+  gint end;
+
+  directory_length = strlen (directory);
+  name_length = strlen (schema_name);
 
-  if G_UNLIKELY (g_once_init_enter ((gsize *) &schemas))
+  path = g_malloc (directory_length + 1 + name_length + 1  +  7  +  1);
+                 /*       directory   /   schema_name   .  schemas  \0 */
+  memcpy (path, directory, directory_length);
+  path[directory_length] = '/';
+  memcpy (path + directory_length + 1, schema_name, name_length);
+  end = directory_length + 1 + name_length;
+
+  while (value == NULL)
     {
-      GError *error = NULL;
-      GVariant *tmp;
+      strcpy (path + end, ".schemas");
 
-      tmp = g_variant_from_file (G_VARIANT_TYPE ("a{s(asmsa{s(sv)}a{ss})}"),
-                                 GSETTINGS_SCHEMAS_DIR "/schemas-cache", 0,
-                                 &error);
+      while (path[--end] != '.' && end > directory_length + 1);
 
-      if G_UNLIKELY (tmp == NULL)
-        g_error ("open schema file: %s\n", error->message);
+      /* don't allow looking for TLD-named files (like 'org.schemas') */
+      if (path[end] != '.')
+        break;
 
-      g_once_init_leave ((gsize *) &schemas, (gsize) tmp);
+      value = g_settings_schema_compile (path);
     }
 
+  g_free (path);
+
+  return value;
+}
+
+GSettingsSchema *
+g_settings_schema_new (const gchar *schema_name)
+{
+  GSettingsSchema *schema;
+  GVariant *value = NULL;
+  gint i;
+
   schema = g_object_new (G_TYPE_SETTINGS_SCHEMA, NULL);
-  value = g_variant_lookup_value (schemas, schema_name);
+
+  for (i = 0; value == NULL && i < g_settings_schema_n_dirs; i++)
+    {
+      if (g_settings_schema_caches[i] != NULL)
+        value = g_variant_lookup_value (g_settings_schema_caches[i],
+                                        schema_name);
+      else
+        value = g_settings_schema_scan_dir (g_settings_schema_dirs[i],
+                                            schema_name);
+    }
 
   if (value == NULL)
     g_error ("Invalid schema name '%s'", schema_name);
@@ -79,12 +194,22 @@ g_settings_schema_finalize (GObject *object)
 }
 
 static void
+g_settings_schema_init (GSettingsSchema *schema)
+{
+  schema->priv = G_TYPE_INSTANCE_GET_PRIVATE (schema,
+                                              G_TYPE_SETTINGS_SCHEMA,
+                                              GSettingsSchemaPrivate);
+}
+
+static void
 g_settings_schema_class_init (GSettingsSchemaClass *class)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (class);
 
   g_type_class_add_private (class, sizeof (GSettingsSchemaPrivate));
 
+  g_settings_schema_initialise_directories ();
+
   object_class->finalize = g_settings_schema_finalize;
 }
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]