Bug 560250 - Fully parse included modules
authorOwen Taylor <otaylor@src.gnome.org>
Tue, 11 Nov 2008 00:48:17 +0000 (00:48 +0000)
committerOwen Taylor <otaylor@src.gnome.org>
Tue, 11 Nov 2008 00:48:17 +0000 (00:48 +0000)
For some things, like computing structure offsets to put into the typelib
we need more than just the aliases from included modules. Do a completel
parse of included modules and store in module->included_modules.

Also add g_ir_find_node() to find node information from within the
active set of modules and their includes.

svn path=/trunk/; revision=874

girepository/girmodule.c
girepository/girmodule.h
girepository/girnode.c
girepository/girnode.h
girepository/girparser.c

index d7ca37b..91cc02d 100644 (file)
@@ -62,6 +62,10 @@ g_ir_module_free (GIrModule *module)
   g_list_free (module->entries);
   /* Don't free dependencies, we inherit that from the parser */
 
+  /* FIXME: we leak the included modules themelves; they may be shared
+   * between multiple modules, so we would need refcounting */
+  g_list_free (module->include_modules);
+
   g_free (module);
 }
 
index 56c7d46..5008c4e 100644 (file)
@@ -36,6 +36,7 @@ struct _GIrModule
   gchar *shared_library;
   GList *dependencies;
   GList *entries;
+  GList *include_modules;
 };
 
 GIrModule *g_ir_module_new            (const gchar *name,
index 632d5c3..b7f0cb2 100644 (file)
@@ -1070,6 +1070,92 @@ find_entry (GIrModule   *module,
   return idx;
 }
 
+static GIrNode *
+find_name_in_module (GIrModule   *module,
+                    const gchar *name)
+{
+  GList *l;
+
+  for (l = module->entries; l; l = l->next)
+    {
+      GIrNode *node = (GIrNode *)l->data;
+
+      if (strcmp (node->name, name) == 0)
+       return node;
+    }
+
+  return NULL;
+}
+
+gboolean
+g_ir_find_node (GIrModule  *module,
+               GList      *modules,
+               const char *name,
+               GIrNode   **node_out,
+               GIrModule **module_out)
+{
+  char **names = g_strsplit (name, ".", 0);
+  gint n_names = g_strv_length (names);
+  GIrNode *node = NULL;
+  GList *l;
+
+  if (n_names == 0)
+    {
+      g_warning ("Name can't be empty");
+      goto out;
+    }
+
+  if (n_names > 2)
+    {
+      g_warning ("Too many name parts in '%s'", name);
+      goto out;
+    }
+
+  if (n_names == 1)
+    {
+      *module_out = module;
+      node = find_name_in_module (module, names[0]);
+    }
+  else if (strcmp (names[0], module->name) == 0)
+    {
+      *module_out = module;
+      node = find_name_in_module (module, names[1]);
+    }
+  else
+    {
+      for (l = module->include_modules; l; l = l->next)
+       {
+         GIrModule *m = l->data;
+
+         if (strcmp (names[0], m->name) == 0)
+           {
+             *module_out = m;
+             node = find_name_in_module (m, names[1]);
+             goto out;
+           }
+       }
+
+      for (l = modules; l; l = l->next)
+       {
+         GIrModule *m = l->data;
+
+         if (strcmp (names[0], m->name) == 0)
+           {
+             *module_out = m;
+             node = find_name_in_module (m, names[1]);
+             goto out;
+           }
+       }
+    }
+
+ out:
+  g_strfreev (names);
+
+  *node_out = node;
+
+  return node != NULL;
+}
+
 static void
 serialize_type (GIrModule    *module, 
                GList        *modules,
index a0dd9ee..bc24a11 100644 (file)
@@ -23,6 +23,8 @@
 
 #include <glib.h>
 
+#include "girmodule.h"
+
 G_BEGIN_DECLS
 
 typedef struct _GIrNode GIrNode; 
@@ -340,6 +342,12 @@ guint32   write_string              (const gchar *str,
 const gchar * g_ir_node_param_direction_string (GIrNodeParam * node);
 const gchar * g_ir_node_type_to_string         (GIrNodeTypeId type);
 
+gboolean g_ir_find_node (GIrModule  *module,
+                        GList      *modules,
+                        const char *name,
+                        GIrNode   **node_out,
+                        GIrModule **module_out);
+
 G_END_DECLS
 
 #endif  /* __G_IR_NODE_H__ */
index 50085c4..9221bb5 100644 (file)
@@ -72,6 +72,7 @@ struct _ParseContext
   const char * const*includes;
   
   GList *modules;
+  GList *include_modules;
   gboolean prefix_aliases;
   GList *dependencies;
   GHashTable *aliases;
@@ -87,6 +88,34 @@ struct _ParseContext
   int type_depth;
 };
 
+static void start_element_handler (GMarkupParseContext *context,
+                                  const gchar         *element_name,
+                                  const gchar        **attribute_names,
+                                  const gchar        **attribute_values,
+                                  gpointer             user_data,
+                                  GError             **error);
+static void end_element_handler   (GMarkupParseContext *context,
+                                  const gchar         *element_name,
+                                  gpointer             user_data,
+                                  GError             **error);
+static void text_handler          (GMarkupParseContext *context,
+                                  const gchar         *text,
+                                  gsize                text_len,
+                                  gpointer             user_data,
+                                  GError             **error);
+static void cleanup               (GMarkupParseContext *context,
+                                  GError              *error,
+                                  gpointer             user_data);
+
+static GMarkupParser parser = 
+{
+  start_element_handler,
+  end_element_handler,
+  text_handler,
+  NULL,
+  cleanup
+};
+
 static gboolean
 start_alias (GMarkupParseContext *context,
             const gchar         *element_name,
@@ -2116,7 +2145,31 @@ parse_include (GMarkupParseContext *context,
   gchar *buffer;
   gsize length;
   char *girpath;
-  
+  gboolean success = FALSE;
+  GList *l;
+
+  for (l = ctx->include_modules; l; l = l->next)
+    {
+      GIrModule *m = l->data;
+
+      if (strcmp (m->name, name) == 0)
+       {
+         if (strcmp (m->version, version) == 0)
+           {
+             return TRUE;
+           }
+         else
+           {
+             g_set_error (error,
+                          G_MARKUP_ERROR,
+                          G_MARKUP_ERROR_INVALID_CONTENT,
+                          "Module '%s' imported with conflicting versions '%s' and '%s'",
+                          name, m->version, version);
+             return FALSE;
+           }
+       }
+    }
+
   girpath = locate_gir (name, version, ctx->includes);
 
   if (girpath == NULL)
@@ -2147,21 +2200,32 @@ parse_include (GMarkupParseContext *context,
   sub_ctx.type_depth = 0;
 
   context = g_markup_parse_context_new (&firstpass_parser, 0, &sub_ctx, NULL);
-         
+
   if (!g_markup_parse_context_parse (context, buffer, length, error))
-    {
-      g_free (buffer);
-      return FALSE;
-    }
-         
+    goto out;
+
   if (!g_markup_parse_context_end_parse (context, error))
-    {
-      g_free (buffer);
-      return FALSE;
-    }
-         
+    goto out;
+
   g_markup_parse_context_free (context);
-  return TRUE;
+
+  context = g_markup_parse_context_new (&parser, 0, &sub_ctx, NULL);
+  if (!g_markup_parse_context_parse (context, buffer, length, error))
+    goto out;
+
+  if (!g_markup_parse_context_end_parse (context, error))
+    goto out;
+
+  success = TRUE;
+
+ out:
+  ctx->include_modules = g_list_concat (ctx->include_modules,
+                                       sub_ctx.modules);
+
+  g_markup_parse_context_free (context);
+  g_free (buffer);
+
+  return success;
 }
   
 extern GLogLevelFlags logged_levels;
@@ -2358,6 +2422,7 @@ start_element_handler (GMarkupParseContext *context,
              ctx->current_module = g_ir_module_new (name, version, shared_library);
              ctx->modules = g_list_append (ctx->modules, ctx->current_module);
              ctx->current_module->dependencies = ctx->dependencies;
+             ctx->current_module->include_modules = g_list_copy (ctx->include_modules);
 
              state_switch (ctx, STATE_NAMESPACE);
              goto out;
@@ -2819,15 +2884,6 @@ cleanup (GMarkupParseContext *context,
   ctx->current_module = NULL;
 }
 
-static GMarkupParser parser = 
-{
-  start_element_handler,
-  end_element_handler,
-  text_handler,
-  NULL,
-  cleanup
-};
-
 static GList *
 post_filter_varargs_functions (GList *list)
 {