GSettings: new <schema> tags 'extends', 'list-of'
authorRyan Lortie <desrt@desrt.ca>
Tue, 29 Jun 2010 18:41:04 +0000 (14:41 -0400)
committerRyan Lortie <desrt@desrt.ca>
Tue, 29 Jun 2010 19:58:35 +0000 (15:58 -0400)
Add support for extends='' and list-of='' tags to the <schema> element.
The attributes are parsed and some sanity-checking is done but currently
nothing happens as a result.

Add some tests.

12 files changed:
gio/gschema-compile.c
gio/tests/Makefile.am
gio/tests/gschema-compile.c
gio/tests/schema-tests/extend-missing.gschema.xml [new file with mode: 0644]
gio/tests/schema-tests/extend-nonlist.gschema.xml [new file with mode: 0644]
gio/tests/schema-tests/extend-self.gschema.xml [new file with mode: 0644]
gio/tests/schema-tests/extend-wrong-list-indirect.gschema.xml [new file with mode: 0644]
gio/tests/schema-tests/extend-wrong-list.gschema.xml [new file with mode: 0644]
gio/tests/schema-tests/extending.gschema.xml [new file with mode: 0644]
gio/tests/schema-tests/key-in-list-indirect.gschema.xml [new file with mode: 0644]
gio/tests/schema-tests/key-in-list.gschema.xml [new file with mode: 0644]
gio/tests/schema-tests/list-of-missing.gschema.xml [new file with mode: 0644]

index 3ec2621..004a3b1 100644 (file)
@@ -671,23 +671,34 @@ is_valid_keyname (const gchar  *key,
 }
 
 /* Handling of <schema> {{{1 */
-typedef struct
+typedef struct _SchemaState SchemaState;
+struct _SchemaState
 {
-  gchar      *path;
-  gchar      *gettext_domain;
+  SchemaState *extends;
+
+  gchar       *path;
+  gchar       *gettext_domain;
+  gchar       *extends_name;
+  gchar       *list_of;
 
-  GHashTable *keys;
-} SchemaState;
+  GHashTable  *keys;
+};
 
 static SchemaState *
 schema_state_new (const gchar  *path,
-                  const gchar  *gettext_domain)
+                  const gchar  *gettext_domain,
+                  SchemaState  *extends,
+                  const gchar  *extends_name,
+                  const gchar  *list_of)
 {
   SchemaState *state;
 
   state = g_slice_new (SchemaState);
   state->path = g_strdup (path);
   state->gettext_domain = g_strdup (gettext_domain);
+  state->extends = extends;
+  state->extends_name = g_strdup (extends_name);
+  state->list_of = g_strdup (list_of);
   state->keys = g_hash_table_new_full (g_str_hash, g_str_equal,
                                        g_free, key_state_free);
 
@@ -740,6 +751,14 @@ schema_state_add_key (SchemaState  *state,
   GString *enum_data;
   KeyState *key;
 
+  if (state->list_of)
+    {
+      g_set_error_literal (error, G_MARKUP_ERROR,
+                           G_MARKUP_ERROR_INVALID_CONTENT,
+                           "can not add keys to a list-of schema");
+      return NULL;
+    }
+
   if (!is_valid_keyname (name, error))
     return NULL;
 
@@ -809,13 +828,34 @@ typedef struct
   GString     *string;                  /* non-NULL when accepting text */
 } ParseState;
 
+static gboolean
+is_subclass (const gchar *class_name,
+             const gchar *possible_parent,
+             GHashTable  *schema_table)
+{
+  SchemaState *class;
+
+  if (strcmp (class_name, possible_parent) == 0)
+    return TRUE;
+
+  class = g_hash_table_lookup (schema_table, class_name);
+  g_assert (class != NULL);
+
+  return class->extends_name &&
+         is_subclass (class->extends_name, possible_parent, schema_table);
+}
+
 static void
 parse_state_start_schema (ParseState  *state,
                           const gchar  *id,
                           const gchar  *path,
                           const gchar  *gettext_domain,
+                          const gchar  *extends_name,
+                          const gchar  *list_of,
                           GError      **error)
 {
+  SchemaState *extends;
+
   if (g_hash_table_lookup (state->schema_table, id))
     {
       g_set_error (error, G_MARKUP_ERROR,
@@ -824,6 +864,66 @@ parse_state_start_schema (ParseState  *state,
       return;
     }
 
+  if (extends_name)
+    {
+      extends = g_hash_table_lookup (state->schema_table, extends_name);
+
+      if (extends == NULL)
+        {
+          g_set_error (error, G_MARKUP_ERROR,
+                       G_MARKUP_ERROR_INVALID_CONTENT,
+                       "<schema id='%s'> extends not yet "
+                       "existing schema '%s'", id, extends_name);
+          return;
+        }
+    }
+  else
+    extends = NULL;
+
+  if (list_of)
+    {
+      if (!g_hash_table_lookup (state->schema_table, list_of))
+        {
+          g_set_error (error, G_MARKUP_ERROR,
+                       G_MARKUP_ERROR_INVALID_CONTENT,
+                       "<schema id='%s'> is list of not yet "
+                       "existing schema '%s'", id, list_of);
+          return;
+        }
+    }
+
+  if (extends)
+    {
+      if (list_of)
+        {
+          if (extends->list_of == NULL)
+            {
+              g_set_error (error, G_MARKUP_ERROR,
+                           G_MARKUP_ERROR_INVALID_CONTENT,
+                           "<schema id='%s'> is a list, extending "
+                           "<schema id='%s'> which is not a list",
+                           id, extends_name);
+              return;
+            }
+
+          if (!is_subclass (list_of, extends->list_of, state->schema_table))
+            {
+              g_set_error (error, G_MARKUP_ERROR,
+                           G_MARKUP_ERROR_INVALID_CONTENT,
+                           "<schema id='%s' list-of='%s'> extends <schema "
+                           "id='%s' list-of='%s'> but '%s' does not extend '%s'",
+                           id, list_of, extends_name, extends->list_of,
+                           list_of, extends->list_of);
+              return;
+            }
+        }
+      else
+        /* by default we are a list of the same thing that the schema
+         * we are extending is a list of (which might be nothing)
+         */
+        list_of = extends->list_of;
+    }
+
   if (path && !(g_str_has_prefix (path, "/") && g_str_has_suffix (path, "/")))
     {
       g_set_error (error, G_MARKUP_ERROR,
@@ -833,7 +933,8 @@ parse_state_start_schema (ParseState  *state,
       return;
     }
 
-  state->schema_state = schema_state_new (path, gettext_domain);
+  state->schema_state = schema_state_new (path, gettext_domain,
+                                          extends, extends_name, list_of);
   g_hash_table_insert (state->schema_table, g_strdup (id),
                        state->schema_state);
 }
@@ -900,11 +1001,14 @@ start_element (GMarkupParseContext  *context,
     {
       if (strcmp (element_name, "schema") == 0)
         {
-          const gchar *id, *path, *gettext_domain;
+          const gchar *id, *path, *gettext_domain, *extends, *list_of;
           if (COLLECT (STRING, "id", &id,
                        OPTIONAL | STRING, "path", &path,
-                       OPTIONAL | STRING, "gettext-domain", &gettext_domain))
-            parse_state_start_schema (state, id, path, gettext_domain, error);
+                       OPTIONAL | STRING, "gettext-domain", &gettext_domain,
+                       OPTIONAL | STRING, "extends", &extends,
+                       OPTIONAL | STRING, "list-of", &list_of))
+            parse_state_start_schema (state, id, path, gettext_domain,
+                                      extends, list_of, error);
           return;
         }
 
index 4cfbb6e..4ddf0d3 100644 (file)
@@ -302,9 +302,18 @@ schema_tests = \
        schema-tests/enum-with-repeated-alias.gschema.xml               \
        schema-tests/enum-with-shadow-alias.gschema.xml                 \
        schema-tests/enum.gschema.xml                                   \
+       schema-tests/extend-missing.gschema.xml                         \
+       schema-tests/extend-nonlist.gschema.xml                         \
+       schema-tests/extend-self.gschema.xml                            \
+       schema-tests/extend-wrong-list-indirect.gschema.xml             \
+       schema-tests/extend-wrong-list.gschema.xml                      \
+       schema-tests/extending.gschema.xml                              \
        schema-tests/from-docs.gschema.xml                              \
        schema-tests/incomplete-list.gschema.xml                        \
        schema-tests/invalid-path.gschema.xml                           \
+       schema-tests/key-in-list-indirect.gschema.xml                   \
+       schema-tests/key-in-list.gschema.xml                            \
+       schema-tests/list-of-missing.gschema.xml                        \
        schema-tests/missing-quotes.gschema.xml                         \
        schema-tests/no-default.gschema.xml                             \
        schema-tests/overflow.gschema.xml                               \
@@ -320,7 +329,6 @@ schema_tests = \
        schema-tests/range.gschema.xml                                  \
        schema-tests/wrong-category.gschema.xml
 
-
 EXTRA_DIST += \
        socket-common.c                 \
        org.gtk.test.gschema            \
index 48d0ffb..c3961d1 100644 (file)
@@ -92,7 +92,16 @@ static const SchemaTest tests[] = {
   { "range-default-low",            NULL, "*<default> is not contained in the specified range*" },
   { "range-default-high",           NULL, "*<default> is not contained in the specified range*" },
   { "range-parse-error",            NULL, "*invalid character in number*"                       },
-  { "from-docs",                    NULL, NULL                                                  }
+  { "from-docs",                    NULL, NULL                                                  },
+  { "extending",                    NULL, NULL                                                  },
+  { "extend-missing",               NULL, "*extends not yet existing schema*"                   },
+  { "extend-nonlist",               NULL, "*which is not a list*"                               },
+  { "extend-self",                  NULL, "*not yet existing*"                                  },
+  { "extend-wrong-list-indirect",   NULL, "*'y' does not extend 'x'*"                           },
+  { "extend-wrong-list",            NULL, "*'y' does not extend 'x'*"                           },
+  { "key-in-list-indirect",         NULL, "*can not add keys to a list*"                        },
+  { "key-in-list",                  NULL, "*can not add keys to a list*"                        },
+  { "list-of-missing",              NULL, "*is list of not yet existing schema*"                }
 };
 
 int
diff --git a/gio/tests/schema-tests/extend-missing.gschema.xml b/gio/tests/schema-tests/extend-missing.gschema.xml
new file mode 100644 (file)
index 0000000..675803a
--- /dev/null
@@ -0,0 +1,3 @@
+<schemalist>
+  <schema id='a' extends='x'/>
+</schemalist>
diff --git a/gio/tests/schema-tests/extend-nonlist.gschema.xml b/gio/tests/schema-tests/extend-nonlist.gschema.xml
new file mode 100644 (file)
index 0000000..7008cee
--- /dev/null
@@ -0,0 +1,4 @@
+<schemalist>
+  <schema id='a'/> <schema id='x'/>
+  <schema id='b' list-of='x' extends='a'/>
+</schemalist>
diff --git a/gio/tests/schema-tests/extend-self.gschema.xml b/gio/tests/schema-tests/extend-self.gschema.xml
new file mode 100644 (file)
index 0000000..f5b0c3d
--- /dev/null
@@ -0,0 +1,3 @@
+<schemalist>
+  <schema id='a' extends='a'/>
+</schemalist>
diff --git a/gio/tests/schema-tests/extend-wrong-list-indirect.gschema.xml b/gio/tests/schema-tests/extend-wrong-list-indirect.gschema.xml
new file mode 100644 (file)
index 0000000..a336db7
--- /dev/null
@@ -0,0 +1,6 @@
+<schemalist>
+  <schema id='x'/> <schema id='y'/>
+  <schema id='lx' list-of='x'/>
+  <schema id='lx2' extends='lx'/>
+  <schema id='ly' extends='lx2' list-of='y'/>
+</schemalist>
diff --git a/gio/tests/schema-tests/extend-wrong-list.gschema.xml b/gio/tests/schema-tests/extend-wrong-list.gschema.xml
new file mode 100644 (file)
index 0000000..4232dc2
--- /dev/null
@@ -0,0 +1,5 @@
+<schemalist>
+  <schema id='x'/> <schema id='y'/>
+  <schema id='lx' list-of='x'/>
+  <schema id='ly' extends='lx' list-of='y'/>
+</schemalist>
diff --git a/gio/tests/schema-tests/extending.gschema.xml b/gio/tests/schema-tests/extending.gschema.xml
new file mode 100644 (file)
index 0000000..98882c7
--- /dev/null
@@ -0,0 +1,21 @@
+<schemalist>
+  <!-- c extends b extends a -->
+  <schema id='a'/>
+  <schema id='b' extends='a'/>
+  <schema id='c' extends='b'/>
+
+  <!-- lists of each -->
+  <schema id='la' list-of='a'/>
+  <schema id='lb' list-of='b'/>
+  <schema id='lc' list-of='c'/>
+
+  <!-- extend 'la', override the list-of to 'b' -->
+  <schema id='lb-la' list-of='b' extends='la'/>
+
+  <!-- extend 'la', override the list-of to 'c' -->
+  <schema id='lc-la' list-of='c' extends='la'/>
+  <!-- extend 'lb', override the list-of to 'c' -->
+  <schema id='lc-lb' list-of='c' extends='lb'/>
+  <!-- extend 'lb-la', override the list-of to 'c' -->
+  <schema id='lc-lb-la' list-of='c' extends='lb-la'/>
+</schemalist>
diff --git a/gio/tests/schema-tests/key-in-list-indirect.gschema.xml b/gio/tests/schema-tests/key-in-list-indirect.gschema.xml
new file mode 100644 (file)
index 0000000..6f0bea1
--- /dev/null
@@ -0,0 +1,8 @@
+<schemalist>
+  <schema id='y'/>
+  <schema id='x' list-of='y'/>
+
+  <schema id='z' extends='x'>
+    <key name='foo' type='s'/>
+  </schema>
+</schemalist>
diff --git a/gio/tests/schema-tests/key-in-list.gschema.xml b/gio/tests/schema-tests/key-in-list.gschema.xml
new file mode 100644 (file)
index 0000000..e2a967a
--- /dev/null
@@ -0,0 +1,6 @@
+<schemalist>
+  <schema id='y'/>
+  <schema id='x' list-of='y'>
+    <key name='foo' type='s'/>
+  </schema>
+</schemalist>
diff --git a/gio/tests/schema-tests/list-of-missing.gschema.xml b/gio/tests/schema-tests/list-of-missing.gschema.xml
new file mode 100644 (file)
index 0000000..f5ef476
--- /dev/null
@@ -0,0 +1,3 @@
+<schemalist>
+  <schema id='a' list-of='x'/>
+</schemalist>