[ALIAS_POINTER] Support for alias to pointers
[gnome.gobject-introspection] / girepository / girparser.c
index 97e3a1e..c8a13aa 100644 (file)
 #include "girmodule.h"
 #include "girnode.h"
 #include "gtypelib.h"
+#include "config.h"
+
+#if defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS)
+# include <execinfo.h>
+#endif
 
 struct _GIrParser
 {
@@ -36,37 +41,39 @@ struct _GIrParser
 
 typedef enum
 {
-  STATE_START,    
-  STATE_END,        
-  STATE_REPOSITORY, 
-  STATE_INCLUDE,  
-  STATE_NAMESPACE,  
-  STATE_ENUM,      /* 5 */    
-  STATE_BITFIELD,  
-  STATE_FUNCTION,   
-  STATE_FUNCTION_RETURN, 
-  STATE_FUNCTION_PARAMETERS,
-  STATE_FUNCTION_PARAMETER,  /* 10 */
-  STATE_CLASS,  
+  STATE_START,
+  STATE_END,
+  STATE_REPOSITORY,
+  STATE_INCLUDE,
+  STATE_PACKAGE,
+  STATE_NAMESPACE, /* 5 */
+  STATE_ENUM,
+  STATE_BITFIELD,
+  STATE_FUNCTION,
+  STATE_FUNCTION_RETURN,
+  STATE_FUNCTION_PARAMETERS, /* 10 */
+  STATE_FUNCTION_PARAMETER,
+  STATE_CLASS,
   STATE_CLASS_FIELD,
   STATE_CLASS_PROPERTY,
-  STATE_INTERFACE,
-  STATE_INTERFACE_PROPERTY,   /* 15 */
+  STATE_INTERFACE, /* 15 */
+  STATE_INTERFACE_PROPERTY,
   STATE_INTERFACE_FIELD,
-  STATE_IMPLEMENTS, 
+  STATE_IMPLEMENTS,
   STATE_PREREQUISITE,
-  STATE_BOXED,  
-  STATE_BOXED_FIELD, /* 20 */
-  STATE_STRUCT,   
+  STATE_BOXED,   /* 20 */
+  STATE_BOXED_FIELD,
+  STATE_STRUCT,
   STATE_STRUCT_FIELD,
-  STATE_ERRORDOMAIN, 
-  STATE_UNION,
-  STATE_UNION_FIELD, /* 25 */
-  STATE_NAMESPACE_CONSTANT, 
-  STATE_CLASS_CONSTANT, 
+  STATE_ERRORDOMAIN,
+  STATE_UNION, /* 25 */
+  STATE_UNION_FIELD,
+  STATE_NAMESPACE_CONSTANT,
+  STATE_CLASS_CONSTANT,
   STATE_INTERFACE_CONSTANT,
   STATE_ALIAS,
   STATE_TYPE,
+  STATE_ATTRIBUTE,
   STATE_UNKNOWN
 } ParseState;
 
@@ -86,6 +93,7 @@ struct _ParseContext
   GHashTable *disguised_structures;
 
   const char *namespace;
+  const char *c_prefix;
   GIrModule *current_module;
   GSList *node_stack;
   GIrNode *current_typed;
@@ -93,6 +101,7 @@ struct _ParseContext
   GList *type_stack;
   GList *type_parameters;
   int type_depth;
+  gboolean in_embedded_type;
 };
 #define CURRENT_NODE(ctx) ((GIrNode *)((ctx)->node_stack->data))
 
@@ -115,7 +124,7 @@ static void cleanup               (GMarkupParseContext *context,
                                   GError              *error,
                                   gpointer             user_data);
 
-static GMarkupParser markup_parser = 
+static GMarkupParser markup_parser =
 {
   start_element_handler,
   end_element_handler,
@@ -132,7 +141,7 @@ start_alias (GMarkupParseContext *context,
             ParseContext        *ctx,
             GError             **error);
 
-static const gchar *find_attribute (const gchar  *name, 
+static const gchar *find_attribute (const gchar  *name,
                                    const gchar **attribute_names,
                                    const gchar **attribute_values);
 
@@ -179,7 +188,7 @@ firstpass_start_element_handler (GMarkupParseContext *context,
 {
   ParseContext *ctx = user_data;
 
-  if (strcmp (element_name, "alias") == 0) 
+  if (strcmp (element_name, "alias") == 0)
     {
       start_alias (context, element_name, attribute_names, attribute_values,
                   ctx, error);
@@ -210,7 +219,7 @@ firstpass_end_element_handler (GMarkupParseContext *context,
 {
 }
 
-static GMarkupParser firstpass_parser = 
+static GMarkupParser firstpass_parser =
 {
   firstpass_start_element_handler,
   firstpass_end_element_handler,
@@ -221,21 +230,17 @@ static GMarkupParser firstpass_parser =
 
 static char *
 locate_gir (GIrParser  *parser,
-           const char *name,
-           const char *version)
+           const char *girname)
 {
   const gchar *const *datadirs;
   const gchar *const *dir;
-  char *girname;
   char *path = NULL;
-      
+
   datadirs = g_get_system_data_dirs ();
-      
-  girname = g_strdup_printf ("%s-%s.gir", name, version);
-  
+
   if (parser->includes != NULL)
     {
-      for (dir = (const gchar *const *)parser->includes; *dir; dir++) 
+      for (dir = (const gchar *const *)parser->includes; *dir; dir++)
        {
          path = g_build_filename (*dir, girname, NULL);
          if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
@@ -244,16 +249,20 @@ locate_gir (GIrParser  *parser,
          path = NULL;
        }
     }
-  for (dir = datadirs; *dir; dir++) 
+  for (dir = datadirs; *dir; dir++)
     {
-      path = g_build_filename (*dir, "gir-1.0", girname, NULL);
+      path = g_build_filename (*dir, GIR_SUFFIX, girname, NULL);
       if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
        return path;
       g_free (path);
       path = NULL;
     }
-  g_free (girname);
-  return path;
+
+  path = g_build_filename (GIR_DIR, girname, NULL);
+  if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
+    return path;
+  g_free (path);
+  return NULL;
 }
 
 #define MISSING_ATTRIBUTE(ctx,error,element,attribute)                         \
@@ -272,9 +281,8 @@ backtrace_stderr (void)
 {
 #if defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS)
   void *array[50];
-  int size;
+  int size, i;
   char **strings;
-  size_t i;
 
   size = backtrace (array, 50);
   strings = (char**) backtrace_symbols (array, size);
@@ -284,7 +292,7 @@ backtrace_stderr (void)
   for (i = 0; i < size; i++)
     fprintf (stderr, "%s\n", strings[i]);
 
-  fprintf (stderr, "--- END BACKTRACE ---\n", size);
+  fprintf (stderr, "--- END BACKTRACE ---\n");
 
   free (strings);
 #endif
@@ -292,16 +300,16 @@ backtrace_stderr (void)
 
 
 static const gchar *
-find_attribute (const gchar  *name, 
+find_attribute (const gchar  *name,
                const gchar **attribute_names,
                const gchar **attribute_values)
 {
   gint i;
-  
+
   for (i = 0; attribute_names[i] != NULL; i++)
     if (strcmp (attribute_names[i], name) == 0)
       return attribute_values[i];
-  
+
   return 0;
 }
 
@@ -317,10 +325,10 @@ static GIrNode *
 pop_node (ParseContext *ctx)
 {
   g_assert (ctx->node_stack != 0);
-  
+
   GSList *top = ctx->node_stack;
   GIrNode *node = top->data;
-  
+
   g_debug ("popping node %d %s", node->type, node->name);
   ctx->node_stack = top->next;
   g_slist_free_1 (top);
@@ -357,6 +365,8 @@ static BasicTypeInfo basic_types[] = {
     { "uint32",   GI_TYPE_TAG_UINT32,  0 },
     { "int64",    GI_TYPE_TAG_INT64,   0 },
     { "uint64",   GI_TYPE_TAG_UINT64,  0 },
+    { "short",    GI_TYPE_TAG_SHORT,   0 },
+    { "ushort",   GI_TYPE_TAG_USHORT,  0 },
     { "int",      GI_TYPE_TAG_INT,     0 },
     { "uint",     GI_TYPE_TAG_UINT,    0 },
     { "long",     GI_TYPE_TAG_LONG,    0 },
@@ -369,21 +379,21 @@ static BasicTypeInfo basic_types[] = {
     { "double",   GI_TYPE_TAG_DOUBLE,  0 },
     { "time_t",   GI_TYPE_TAG_TIME_T,  0 },
     { "GType",    GI_TYPE_TAG_GTYPE,   0 },
-    { "utf8",     GI_TYPE_TAG_UTF8,    1 },  
+    { "utf8",     GI_TYPE_TAG_UTF8,    1 },
     { "filename", GI_TYPE_TAG_FILENAME,1 },
-};  
+};
 
 static const BasicTypeInfo *
 parse_basic (const char *str)
 {
   gint i;
   gint n_basic = G_N_ELEMENTS (basic_types);
-  
+
   for (i = 0; i < n_basic; i++)
     {
       if (g_str_has_prefix (str, basic_types[i].str))
        return &(basic_types[i]);
-    }  
+    }
   return NULL;
 }
 
@@ -391,21 +401,21 @@ static GIrNodeType *
 parse_type_internal (const gchar *str, char **next, gboolean in_glib,
                     gboolean in_gobject)
 {
-  const BasicTypeInfo *basic;  
+  const BasicTypeInfo *basic;
   GIrNodeType *type;
   char *temporary_type = NULL;
-  
+
   type = (GIrNodeType *)g_ir_node_new (G_IR_NODE_TYPE);
-  
+
   type->unparsed = g_strdup (str);
 
   /* See comment below on GLib.List handling */
-  if (in_gobject && strcmp (str, "Type") == 0) 
+  if (in_gobject && strcmp (str, "Type") == 0)
     {
       temporary_type = g_strdup ("GLib.Type");
       str = temporary_type;
     }
-  
+
   basic = parse_basic (str);
   if (basic != NULL)
     {
@@ -419,7 +429,7 @@ parse_type_internal (const gchar *str, char **next, gboolean in_glib,
     {
       /* If we're inside GLib, handle "List" etc. by prefixing with
        * "GLib." so the parsing code below doesn't have to get more
-       * special. 
+       * special.
        */
       if (g_str_has_prefix (str, "List<") ||
          strcmp (str, "List") == 0)
@@ -485,12 +495,12 @@ parse_type_internal (const gchar *str, char **next, gboolean in_glib,
       type->is_error = TRUE;
       type->is_pointer = TRUE;
       str += strlen ("Error");
-      
+
       if (*str == '<')
        {
          (str)++;
          char *tmp, *end;
-         
+
          end = strchr (str, '>');
          tmp = g_strndup (str, end - str);
          type->errors = g_strsplit (tmp, ",", 0);
@@ -499,23 +509,34 @@ parse_type_internal (const gchar *str, char **next, gboolean in_glib,
          str = end;
        }
     }
-  else 
+  else
     {
       type->tag = GI_TYPE_TAG_INTERFACE;
-      type->is_interface = TRUE; 
+      type->is_interface = TRUE;
       const char *start = str;
 
       /* must be an interface type */
-      while (g_ascii_isalnum (*str) || 
-            *str == '.' || 
-            *str == '-' || 
+      while (g_ascii_isalnum (*str) ||
+            *str == '.' ||
+            *str == '-' ||
             *str == '_' ||
             *str == ':')
        (str)++;
 
       type->interface = g_strndup (start, str - start);
+      /* 
+         The alias code can return pointers for typedefs.
+        since the type reader code does not catch this,
+         it has to be set here.
+      */
+      if (strchr(start, '*')) 
+        {
+          g_debug("Adding type as interface (pointer) %s ", type->interface); 
+          type->is_pointer = TRUE;
+        }
     }
-  
+
   if (next)
     *next = (char*)str;
   g_assert (type->tag >= 0 && type->tag <= GI_TYPE_TAG_ERROR);
@@ -524,18 +545,20 @@ parse_type_internal (const gchar *str, char **next, gboolean in_glib,
 
 /* error: */
   g_ir_node_free ((GIrNode *)type);
-  g_free (temporary_type);  
+  g_free (temporary_type);
   return NULL;
 }
 
 static const char *
-resolve_aliases (ParseContext *ctx, const gchar *type)
+resolve_aliases (ParseContext *ctx, const gchar *type, gboolean *is_pointer)
 {
   gpointer orig;
   gpointer value;
   GSList *seen_values = NULL;
   const gchar *lookup;
-  gchar *prefixed;
+  gchar *prefixed, *lookup_copy;
+  char *star_pos;
+    
 
   if (strchr (type, '.') == NULL)
     {
@@ -547,24 +570,43 @@ resolve_aliases (ParseContext *ctx, const gchar *type)
       lookup = type;
       prefixed = NULL;
     }
-
+   /*
+    Since target could be a name + '*'
+    we need to duplicate the lookup value always
+    and free it later..
+  */
+  star_pos = strchr(lookup, '*');
+  if (star_pos) 
+    *is_pointer = TRUE;
+    
+  lookup_copy = g_strndup(lookup, star_pos ? (gsize) (star_pos - lookup) : strlen(lookup));
+  
   seen_values = g_slist_prepend (seen_values, (char*)lookup);
-  while (g_hash_table_lookup_extended (ctx->current_module->aliases, lookup, &orig, &value))
+  while (g_hash_table_lookup_extended (ctx->current_module->aliases, lookup_copy, &orig, &value))
     {
       g_debug ("Resolved: %s => %s\n", lookup, (char*)value);
       lookup = value;
+      /* prevent looping forever.. */
       if (g_slist_find_custom (seen_values, lookup,
                               (GCompareFunc)strcmp) != NULL)
        break;
       seen_values = g_slist_prepend (seen_values, (gchar*)lookup);
+        
+      g_free(lookup_copy);
+      star_pos = strchr(lookup, '*');
+      if (star_pos)
+        *is_pointer = TRUE;
+      lookup_copy = g_strndup(lookup, star_pos ? (gsize) (star_pos - lookup) : strlen(lookup));
     }
+  g_free(lookup_copy);  
   g_slist_free (seen_values);
 
   if (lookup == prefixed)
     lookup = type;
 
   g_free (prefixed);
-  
+
   return lookup;
 }
 
@@ -588,9 +630,9 @@ is_disguised_structure (ParseContext *ctx, const gchar *type)
 
   result = g_hash_table_lookup (ctx->current_module->disguised_structures,
                                lookup) != NULL;
-  
+
   g_free (prefixed);
-  
+
   return result;
 }
 
@@ -600,18 +642,23 @@ parse_type (ParseContext *ctx, const gchar *type)
   GIrNodeType *node;
   const BasicTypeInfo *basic;
   gboolean in_glib, in_gobject;
-
+  gboolean is_pointer = FALSE;
+    
   in_glib = strcmp (ctx->namespace, "GLib") == 0;
   in_gobject = strcmp (ctx->namespace, "GObject") == 0;
 
   /* Do not search aliases for basic types */
   basic = parse_basic (type);
   if (basic == NULL)
-    type = resolve_aliases (ctx, type);
+    type = resolve_aliases (ctx, type, &is_pointer);
 
   node = parse_type_internal (type, NULL, in_glib, in_gobject);
-  if (node)
-    g_debug ("Parsed type: %s => %d", type, node->tag);
+  if (node) 
+    {
+      g_debug ("Parsed type: %s => %d", type, node->tag);
+      /* Overlay is_pointer if it get's set */
+      node->is_pointer = node->is_pointer || is_pointer;
+    } 
   else
     g_critical ("Failed to parse type: '%s'", type);
 
@@ -640,7 +687,7 @@ start_glib_boxed (GMarkupParseContext *context,
   typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
   typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
   deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
-  
+
   if (name == NULL)
     {
       MISSING_ATTRIBUTE (context, error, element_name, "glib:name");
@@ -658,7 +705,7 @@ start_glib_boxed (GMarkupParseContext *context,
     }
 
   boxed = (GIrNodeBoxed *) g_ir_node_new (G_IR_NODE_BOXED);
-         
+
   ((GIrNode *)boxed)->name = g_strdup (name);
   boxed->gtype_name = g_strdup (typename);
   boxed->gtype_init = g_strdup (typeinit);
@@ -666,11 +713,11 @@ start_glib_boxed (GMarkupParseContext *context,
     boxed->deprecated = TRUE;
   else
     boxed->deprecated = FALSE;
-         
+
   push_node (ctx, (GIrNode *)boxed);
-  ctx->current_module->entries = 
+  ctx->current_module->entries =
     g_list_append (ctx->current_module->entries, boxed);
-  
+
   state_switch (ctx, STATE_BOXED);
 
   return TRUE;
@@ -690,7 +737,7 @@ start_function (GMarkupParseContext *context,
   const gchar *throws;
   GIrNodeFunction *function;
   gboolean found = FALSE;
-  
+
   switch (ctx->state)
     {
     case STATE_NAMESPACE:
@@ -710,6 +757,10 @@ start_function (GMarkupParseContext *context,
               strcmp (element_name, "method") == 0 ||
               strcmp (element_name, "callback") == 0);
       break;
+    case STATE_STRUCT_FIELD:
+      ctx->in_embedded_type = TRUE;
+      found = (found || strcmp (element_name, "callback") == 0);
+      break;
     default:
       break;
     }
@@ -721,7 +772,7 @@ start_function (GMarkupParseContext *context,
   symbol = find_attribute ("c:identifier", attribute_names, attribute_values);
   deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
   throws = find_attribute ("throws", attribute_names, attribute_values);
-      
+
   if (name == NULL)
     {
       MISSING_ATTRIBUTE (context, error, element_name, "name");
@@ -734,7 +785,7 @@ start_function (GMarkupParseContext *context,
     }
 
   function = (GIrNodeFunction *) g_ir_node_new (G_IR_NODE_FUNCTION);
-      
+
   ((GIrNode *)function)->name = g_strdup (name);
   function->symbol = g_strdup (symbol);
   function->parameters = NULL;
@@ -742,12 +793,12 @@ start_function (GMarkupParseContext *context,
     function->deprecated = TRUE;
   else
     function->deprecated = FALSE;
-  
+
   if (strcmp (element_name, "method") == 0 ||
       strcmp (element_name, "constructor") == 0)
     {
       function->is_method = TRUE;
-      
+
       if (strcmp (element_name, "constructor") == 0)
        function->is_constructor = TRUE;
       else
@@ -770,8 +821,15 @@ start_function (GMarkupParseContext *context,
 
   if (ctx->node_stack == NULL)
     {
-      ctx->current_module->entries = 
-       g_list_append (ctx->current_module->entries, function);       
+      ctx->current_module->entries =
+       g_list_append (ctx->current_module->entries, function);
+    }
+  else if (ctx->current_typed)
+    {
+      GIrNodeField *field;
+
+      field = (GIrNodeField *)ctx->current_typed;
+      field->callback = function;
     }
   else
     switch (CURRENT_NODE (ctx)->type)
@@ -780,7 +838,7 @@ start_function (GMarkupParseContext *context,
       case G_IR_NODE_OBJECT:
        {
          GIrNodeInterface *iface;
-         
+
          iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
          iface->members = g_list_append (iface->members, function);
        }
@@ -788,7 +846,7 @@ start_function (GMarkupParseContext *context,
       case G_IR_NODE_BOXED:
        {
          GIrNodeBoxed *boxed;
-         
+
          boxed = (GIrNodeBoxed *)CURRENT_NODE (ctx);
          boxed->members = g_list_append (boxed->members, function);
        }
@@ -796,14 +854,14 @@ start_function (GMarkupParseContext *context,
       case G_IR_NODE_STRUCT:
        {
          GIrNodeStruct *struct_;
-         
+
          struct_ = (GIrNodeStruct *)CURRENT_NODE (ctx);
          struct_->members = g_list_append (struct_->members, function);                }
        break;
       case G_IR_NODE_UNION:
        {
          GIrNodeUnion *union_;
-         
+
          union_ = (GIrNodeUnion *)CURRENT_NODE (ctx);
          union_->members = g_list_append (union_->members, function);
        }
@@ -811,19 +869,22 @@ start_function (GMarkupParseContext *context,
       default:
        g_assert_not_reached ();
       }
-  
+
   push_node(ctx, (GIrNode *)function);
   state_switch (ctx, STATE_FUNCTION);
-  
+
   return TRUE;
 }
 
 static void
-parse_param_transfer (GIrNodeParam *param, const gchar *transfer)
+parse_param_transfer (GIrNodeParam *param, const gchar *transfer, const gchar *name)
 {
   if (transfer == NULL)
   {
-    g_warning ("required attribute 'transfer-ownership' missing");
+    if (!name)
+      g_warning ("required attribute 'transfer-ownership' missing");
+    else
+      g_warning ("required attribute 'transfer-ownership' for function '%s'", name);
   }
   else if (strcmp (transfer, "none") == 0)
     {
@@ -865,7 +926,7 @@ start_parameter (GMarkupParseContext *context,
   const gchar *closure;
   const gchar *destroy;
   GIrNodeParam *param;
-      
+
   if (!(strcmp (element_name, "parameter") == 0 &&
        ctx->state == STATE_FUNCTION_PARAMETERS))
     return FALSE;
@@ -880,7 +941,7 @@ start_parameter (GMarkupParseContext *context,
   scope = find_attribute ("scope", attribute_names, attribute_values);
   closure = find_attribute ("closure", attribute_names, attribute_values);
   destroy = find_attribute ("destroy", attribute_names, attribute_values);
-  
+
   if (name == NULL)
     name = "unknown";
 
@@ -927,24 +988,22 @@ start_parameter (GMarkupParseContext *context,
   else
     param->allow_none = FALSE;
 
-  parse_param_transfer (param, transfer);
+  parse_param_transfer (param, transfer, name);
 
   if (scope && strcmp (scope, "call") == 0)
     param->scope = GI_SCOPE_TYPE_CALL;
-  else if (scope && strcmp (scope, "object") == 0)
-    param->scope = GI_SCOPE_TYPE_OBJECT;
   else if (scope && strcmp (scope, "async") == 0)
     param->scope = GI_SCOPE_TYPE_ASYNC;
   else if (scope && strcmp (scope, "notified") == 0)
     param->scope = GI_SCOPE_TYPE_NOTIFIED;
   else
     param->scope = GI_SCOPE_TYPE_INVALID;
-  
+
   param->closure = closure ? atoi (closure) : -1;
   param->destroy = destroy ? atoi (destroy) : -1;
-  
+
   ((GIrNode *)param)->name = g_strdup (name);
-         
+
   switch (CURRENT_NODE (ctx)->type)
     {
     case G_IR_NODE_FUNCTION:
@@ -967,7 +1026,7 @@ start_parameter (GMarkupParseContext *context,
     case G_IR_NODE_VFUNC:
       {
        GIrNodeVFunc *vfunc;
-               
+
        vfunc = (GIrNodeVFunc *)CURRENT_NODE (ctx);
        vfunc->parameters = g_list_append (vfunc->parameters, param);
       }
@@ -1005,16 +1064,16 @@ start_field (GMarkupParseContext *context,
     default:
       return FALSE;
     }
-  
+
   if (strcmp (element_name, "field") != 0)
     return FALSE;
-  
+
   name = find_attribute ("name", attribute_names, attribute_values);
   readable = find_attribute ("readable", attribute_names, attribute_values);
   writable = find_attribute ("writable", attribute_names, attribute_values);
   bits = find_attribute ("bits", attribute_names, attribute_values);
   branch = find_attribute ("branch", attribute_names, attribute_values);
-  
+
   if (name == NULL)
     {
       MISSING_ATTRIBUTE (context, error, element_name, "name");
@@ -1029,18 +1088,18 @@ start_field (GMarkupParseContext *context,
    */
   field->readable = readable == NULL || strcmp (readable, "0") == 0;
   field->writable = writable != NULL && strcmp (writable, "1") == 0;
-  
+
   if (bits)
     field->bits = atoi (bits);
   else
     field->bits = 0;
-  
+
   switch (CURRENT_NODE (ctx)->type)
     {
     case G_IR_NODE_OBJECT:
       {
        GIrNodeInterface *iface;
-       
+
        iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
        iface->members = g_list_append (iface->members, field);
        state_switch (ctx, STATE_CLASS_FIELD);
@@ -1049,7 +1108,7 @@ start_field (GMarkupParseContext *context,
     case G_IR_NODE_INTERFACE:
       {
        GIrNodeInterface *iface;
-       
+
        iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
        iface->members = g_list_append (iface->members, field);
        state_switch (ctx, STATE_INTERFACE_FIELD);
@@ -1058,7 +1117,7 @@ start_field (GMarkupParseContext *context,
     case G_IR_NODE_BOXED:
       {
        GIrNodeBoxed *boxed;
-       
+
        boxed = (GIrNodeBoxed *)CURRENT_NODE (ctx);
                boxed->members = g_list_append (boxed->members, field);
                state_switch (ctx, STATE_BOXED_FIELD);
@@ -1067,7 +1126,7 @@ start_field (GMarkupParseContext *context,
     case G_IR_NODE_STRUCT:
       {
        GIrNodeStruct *struct_;
-       
+
        struct_ = (GIrNodeStruct *)CURRENT_NODE (ctx);
        struct_->members = g_list_append (struct_->members, field);
        state_switch (ctx, STATE_STRUCT_FIELD);
@@ -1076,19 +1135,19 @@ start_field (GMarkupParseContext *context,
     case G_IR_NODE_UNION:
       {
        GIrNodeUnion *union_;
-       
+
        union_ = (GIrNodeUnion *)CURRENT_NODE (ctx);
        union_->members = g_list_append (union_->members, field);
        if (branch)
          {
            GIrNodeConstant *constant;
-           
+
            constant = (GIrNodeConstant *) g_ir_node_new (G_IR_NODE_CONSTANT);
            ((GIrNode *)constant)->name = g_strdup (name);
-           constant->value = g_strdup (branch);          
+           constant->value = g_strdup (branch);
            constant->type = union_->discriminator_type;
            constant->deprecated = FALSE;
-           
+
            union_->discriminators = g_list_append (union_->discriminators, constant);
          }
        state_switch (ctx, STATE_UNION_FIELD);
@@ -1097,7 +1156,7 @@ start_field (GMarkupParseContext *context,
     default:
       g_assert_not_reached ();
     }
-  
+
   return TRUE;
 }
 
@@ -1160,18 +1219,18 @@ start_enum (GMarkupParseContext *context,
       const gchar *typename;
       const gchar *typeinit;
       const gchar *deprecated;
-      
+
       name = find_attribute ("name", attribute_names, attribute_values);
       typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
       typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
       deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
-      
+
       if (name == NULL)
        MISSING_ATTRIBUTE (context, error, element_name, "name");
-      else 
-       {             
+      else
+       {
          GIrNodeEnum *enum_;
-         
+
          if (strcmp (element_name, "enumeration") == 0)
            enum_ = (GIrNodeEnum *) g_ir_node_new (G_IR_NODE_ENUM);
          else
@@ -1185,12 +1244,12 @@ start_enum (GMarkupParseContext *context,
            enum_->deprecated = FALSE;
 
          push_node (ctx, (GIrNode *) enum_);
-         ctx->current_module->entries = 
-           g_list_append (ctx->current_module->entries, enum_);              
-         
+         ctx->current_module->entries =
+           g_list_append (ctx->current_module->entries, enum_);
+
          state_switch (ctx, STATE_ENUM);
        }
-      
+
       return TRUE;
     }
   return FALSE;
@@ -1213,25 +1272,25 @@ start_property (GMarkupParseContext *context,
       const gchar *writable;
       const gchar *construct;
       const gchar *construct_only;
-      
+
       name = find_attribute ("name", attribute_names, attribute_values);
       readable = find_attribute ("readable", attribute_names, attribute_values);
       writable = find_attribute ("writable", attribute_names, attribute_values);
       construct = find_attribute ("construct", attribute_names, attribute_values);
       construct_only = find_attribute ("construct-only", attribute_names, attribute_values);
-      
+
       if (name == NULL)
        MISSING_ATTRIBUTE (context, error, element_name, "name");
-      else 
-       {             
+      else
+       {
          GIrNodeProperty *property;
          GIrNodeInterface *iface;
-         
+
          property = (GIrNodeProperty *) g_ir_node_new (G_IR_NODE_PROPERTY);
          ctx->current_typed = (GIrNode*) property;
 
          ((GIrNode *)property)->name = g_strdup (name);
-         
+
          /* Assume properties are readable */
          if (readable == NULL || strcmp (readable, "1") == 0)
            property->readable = TRUE;
@@ -1260,7 +1319,7 @@ start_property (GMarkupParseContext *context,
          else
            g_assert_not_reached ();
        }
-      
+
       return TRUE;
     }
   return FALSE;
@@ -1270,7 +1329,7 @@ static gint
 parse_value (const gchar *str)
 {
   gchar *shift_op;
+
   /* FIXME just a quick hack */
   shift_op = strstr (str, "<<");
 
@@ -1280,7 +1339,7 @@ parse_value (const gchar *str)
 
       base = strtol (str, NULL, 10);
       shift = strtol (shift_op + 3, NULL, 10);
-      
+
       return base << shift;
     }
   else
@@ -1303,24 +1362,24 @@ start_member (GMarkupParseContext *context,
       const gchar *name;
       const gchar *value;
       const gchar *deprecated;
-      
+
       name = find_attribute ("name", attribute_names, attribute_values);
       value = find_attribute ("value", attribute_names, attribute_values);
       deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
-      
+
       if (name == NULL)
        MISSING_ATTRIBUTE (context, error, element_name, "name");
-      else 
-       {             
+      else
+       {
          GIrNodeEnum *enum_;
          GIrNodeValue *value_;
 
          value_ = (GIrNodeValue *) g_ir_node_new (G_IR_NODE_VALUE);
 
          ((GIrNode *)value_)->name = g_strdup (name);
-         
+
          value_->value = parse_value (value);
-         
+
          if (deprecated)
            value_->deprecated = TRUE;
          else
@@ -1329,7 +1388,7 @@ start_member (GMarkupParseContext *context,
          enum_ = (GIrNodeEnum *)CURRENT_NODE (ctx);
          enum_->values = g_list_append (enum_->values, value_);
        }
-      
+
       return TRUE;
     }
   return FALSE;
@@ -1351,17 +1410,17 @@ start_constant (GMarkupParseContext *context,
       const gchar *name;
       const gchar *value;
       const gchar *deprecated;
-      
+
       name = find_attribute ("name", attribute_names, attribute_values);
       value = find_attribute ("value", attribute_names, attribute_values);
       deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
-      
+
       if (name == NULL)
        MISSING_ATTRIBUTE (context, error, element_name, "name");
       else if (value == NULL)
        MISSING_ATTRIBUTE (context, error, element_name, "value");
-      else 
-       {             
+      else
+       {
          GIrNodeConstant *constant;
 
          constant = (GIrNodeConstant *) g_ir_node_new (G_IR_NODE_CONSTANT);
@@ -1379,7 +1438,7 @@ start_constant (GMarkupParseContext *context,
          if (ctx->state == STATE_NAMESPACE)
            {
              push_node (ctx, (GIrNode *) constant);
-             ctx->current_module->entries = 
+             ctx->current_module->entries =
                g_list_append (ctx->current_module->entries, constant);
            }
          else
@@ -1406,7 +1465,7 @@ start_constant (GMarkupParseContext *context,
              break;
            }
        }
-      
+
       return TRUE;
     }
   return FALSE;
@@ -1427,20 +1486,20 @@ start_errordomain (GMarkupParseContext *context,
       const gchar *getquark;
       const gchar *codes;
       const gchar *deprecated;
-      
+
       name = find_attribute ("name", attribute_names, attribute_values);
       getquark = find_attribute ("get-quark", attribute_names, attribute_values);
       codes = find_attribute ("codes", attribute_names, attribute_values);
       deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
-      
+
       if (name == NULL)
        MISSING_ATTRIBUTE (context, error, element_name, "name");
       else if (getquark == NULL)
        MISSING_ATTRIBUTE (context, error, element_name, "getquark");
       else if (codes == NULL)
        MISSING_ATTRIBUTE (context, error, element_name, "codes");
-      else 
-       {             
+      else
+       {
          GIrNodeErrorDomain *domain;
 
          domain = (GIrNodeErrorDomain *) g_ir_node_new (G_IR_NODE_ERROR_DOMAIN);
@@ -1455,12 +1514,12 @@ start_errordomain (GMarkupParseContext *context,
            domain->deprecated = FALSE;
 
          push_node (ctx, (GIrNode *) domain);
-         ctx->current_module->entries = 
+         ctx->current_module->entries =
            g_list_append (ctx->current_module->entries, domain);
 
          state_switch (ctx, STATE_ERRORDOMAIN);
        }
-      
+
       return TRUE;
     }
   return FALSE;
@@ -1481,12 +1540,14 @@ start_interface (GMarkupParseContext *context,
       const gchar *typename;
       const gchar *typeinit;
       const gchar *deprecated;
-      
+      const gchar *glib_type_struct;
+
       name = find_attribute ("name", attribute_names, attribute_values);
       typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
       typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
+      glib_type_struct = find_attribute ("glib:type-struct", attribute_names, attribute_values);
       deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
-      
+
       if (name == NULL)
        MISSING_ATTRIBUTE (context, error, element_name, "name");
       else if (typename == NULL)
@@ -1501,19 +1562,20 @@ start_interface (GMarkupParseContext *context,
          ((GIrNode *)iface)->name = g_strdup (name);
          iface->gtype_name = g_strdup (typename);
          iface->gtype_init = g_strdup (typeinit);
+          iface->glib_type_struct = g_strdup (glib_type_struct);
          if (deprecated)
            iface->deprecated = TRUE;
          else
            iface->deprecated = FALSE;
-         
+
          push_node (ctx, (GIrNode *) iface);
-         ctx->current_module->entries = 
-           g_list_append (ctx->current_module->entries, iface);              
-         
+         ctx->current_module->entries =
+           g_list_append (ctx->current_module->entries, iface);
+
          state_switch (ctx, STATE_INTERFACE);
-         
+
        }
-      
+
       return TRUE;
     }
   return FALSE;
@@ -1532,20 +1594,20 @@ start_class (GMarkupParseContext *context,
     {
       const gchar *name;
       const gchar *parent;
-      const gchar *class_struct;      
+      const gchar *glib_type_struct;
       const gchar *typename;
       const gchar *typeinit;
       const gchar *deprecated;
       const gchar *abstract;
-      
+
       name = find_attribute ("name", attribute_names, attribute_values);
       parent = find_attribute ("parent", attribute_names, attribute_values);
-      class_struct = find_attribute ("glib:class-struct", attribute_names, attribute_values);      
+      glib_type_struct = find_attribute ("glib:type-struct", attribute_names, attribute_values);
       typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
       typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
       deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
       abstract = find_attribute ("abstract", attribute_names, attribute_values);
-      
+
       if (name == NULL)
        MISSING_ATTRIBUTE (context, error, element_name, "name");
       else if (typename == NULL)
@@ -1561,7 +1623,7 @@ start_class (GMarkupParseContext *context,
          iface->gtype_name = g_strdup (typename);
          iface->gtype_init = g_strdup (typeinit);
          iface->parent = g_strdup (parent);
-         iface->class_struct = g_strdup (class_struct);
+         iface->glib_type_struct = g_strdup (glib_type_struct);
          if (deprecated)
            iface->deprecated = TRUE;
          else
@@ -1570,12 +1632,12 @@ start_class (GMarkupParseContext *context,
          iface->abstract = abstract && strcmp (abstract, "1") == 0;
 
          push_node (ctx, (GIrNode *) iface);
-         ctx->current_module->entries = 
-           g_list_append (ctx->current_module->entries, iface);              
-         
+         ctx->current_module->entries =
+           g_list_append (ctx->current_module->entries, iface);
+
          state_switch (ctx, STATE_CLASS);
        }
-      
+
       return TRUE;
     }
   return  FALSE;
@@ -1601,14 +1663,14 @@ start_type (GMarkupParseContext *context,
   if (!(is_array || is_varargs || (strcmp (element_name, "type") == 0)))
     return FALSE;
 
-  if (ctx->state == STATE_TYPE) 
+  if (ctx->state == STATE_TYPE)
     {
       ctx->type_depth++;
       ctx->type_stack = g_list_prepend (ctx->type_stack, ctx->type_parameters);
       ctx->type_parameters = NULL;
-    } 
+    }
   else if (ctx->state == STATE_FUNCTION_PARAMETER ||
-          ctx->state == STATE_FUNCTION_RETURN || 
+          ctx->state == STATE_FUNCTION_RETURN ||
           ctx->state == STATE_STRUCT_FIELD ||
           ctx->state == STATE_UNION_FIELD ||
           ctx->state == STATE_CLASS_PROPERTY ||
@@ -1680,7 +1742,7 @@ start_type (GMarkupParseContext *context,
   if (is_varargs)
     return TRUE;
 
-  if (is_array) 
+  if (is_array)
     {
       const char *zero;
       const char *len;
@@ -1691,17 +1753,23 @@ start_type (GMarkupParseContext *context,
       typenode->tag = GI_TYPE_TAG_ARRAY;
       typenode->is_pointer = TRUE;
       typenode->is_array = TRUE;
-      
+
       zero = find_attribute ("zero-terminated", attribute_names, attribute_values);
       len = find_attribute ("length", attribute_names, attribute_values);
       size = find_attribute ("fixed-size", attribute_names, attribute_values);
-      
+
       typenode->zero_terminated = !(zero && strcmp (zero, "1") != 0);
       typenode->has_length = len != NULL;
       typenode->length = typenode->has_length ? atoi (len) : -1;
-      
+
       typenode->has_size = size != NULL;
       typenode->size = typenode->has_size ? atoi (size) : -1;
+
+      if (zero)
+        typenode->zero_terminated = strcmp(zero, "1") == 0;
+      else
+        /* If neither zero-terminated nor length nor fixed-size is given, assume zero-terminated. */
+        typenode->zero_terminated = !(typenode->has_length || typenode->has_size);
     }
   else
     {
@@ -1710,7 +1778,7 @@ start_type (GMarkupParseContext *context,
 
       if (name == NULL)
        MISSING_ATTRIBUTE (context, error, element_name, "name");
-      
+
       pointer_depth = 0;
       ctype = find_attribute ("c:type", attribute_names, attribute_values);
       if (ctype != NULL)
@@ -1719,12 +1787,12 @@ start_type (GMarkupParseContext *context,
           while (cp > ctype && *cp-- == '*')
             pointer_depth++;
         }
-      
+
       if (ctx->current_typed->type == G_IR_NODE_PARAM &&
           ((GIrNodeParam *)ctx->current_typed)->out &&
           pointer_depth > 0)
         pointer_depth--;
-      
+
       typenode = parse_type (ctx, name);
 
       /* A 'disguised' structure is one where the c:type is a typedef that
@@ -1739,7 +1807,7 @@ start_type (GMarkupParseContext *context,
     }
 
   ctx->type_parameters = g_list_append (ctx->type_parameters, typenode);
-  
+
   return TRUE;
 }
 
@@ -1802,7 +1870,7 @@ end_type_top (ParseContext *ctx)
     }
   g_list_free (ctx->type_parameters);
 
- out:  
+ out:
   ctx->type_depth = 0;
   ctx->type_parameters = NULL;
   ctx->current_typed = NULL;
@@ -1860,6 +1928,44 @@ end_type (ParseContext *ctx)
     }
 }
 
+static gboolean
+start_attribute (GMarkupParseContext *context,
+                 const gchar         *element_name,
+                 const gchar        **attribute_names,
+                 const gchar        **attribute_values,
+                 ParseContext       *ctx,
+                 GError             **error)
+{
+  const gchar *name;
+  const gchar *value;
+  GIrNode *curnode;
+
+  if (strcmp (element_name, "attribute") != 0 || ctx->node_stack == NULL)
+    return FALSE;
+
+  name = find_attribute ("name", attribute_names, attribute_values);
+  value = find_attribute ("value", attribute_names, attribute_values);
+
+  if (name == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "name");
+      return FALSE;
+    }
+  if (value == NULL)
+    {
+      MISSING_ATTRIBUTE (context, error, element_name, "value");
+      return FALSE;
+    }
+
+  state_switch (ctx, STATE_ATTRIBUTE);
+
+  curnode = CURRENT_NODE (ctx);
+
+  g_hash_table_insert (curnode->attributes, g_strdup (name), g_strdup (value));
+
+  return TRUE;
+}
+
 static gboolean
 start_return_value (GMarkupParseContext *context,
                    const gchar         *element_name,
@@ -1884,7 +1990,7 @@ start_return_value (GMarkupParseContext *context,
       state_switch (ctx, STATE_FUNCTION_RETURN);
 
       transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values);
-      parse_param_transfer (param, transfer);
+      parse_param_transfer (param, transfer, NULL);
 
       switch (CURRENT_NODE (ctx)->type)
        {
@@ -1910,7 +2016,7 @@ start_return_value (GMarkupParseContext *context,
        default:
          g_assert_not_reached ();
        }
-      
+
       return TRUE;
     }
 
@@ -1933,14 +2039,14 @@ start_implements (GMarkupParseContext *context,
     return FALSE;
 
   state_switch (ctx, STATE_IMPLEMENTS);
-  
+
   name = find_attribute ("name", attribute_names, attribute_values);
   if (name == NULL)
     {
       MISSING_ATTRIBUTE (context, error, element_name, "name");
       return FALSE;
     }
-      
+
   iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
   iface->interfaces = g_list_append (iface->interfaces, g_strdup (name));
 
@@ -1955,7 +2061,7 @@ start_glib_signal (GMarkupParseContext *context,
                   ParseContext       *ctx,
                   GError             **error)
 {
-  if (strcmp (element_name, "glib:signal") == 0 && 
+  if (strcmp (element_name, "glib:signal") == 0 &&
       (ctx->state == STATE_CLASS ||
        ctx->state == STATE_INTERFACE))
     {
@@ -1966,7 +2072,7 @@ start_glib_signal (GMarkupParseContext *context,
       const gchar *action;
       const gchar *no_hooks;
       const gchar *has_class_closure;
-      
+
       name = find_attribute ("name", attribute_names, attribute_values);
       when = find_attribute ("when", attribute_names, attribute_values);
       no_recurse = find_attribute ("no-recurse", attribute_names, attribute_values);
@@ -1974,7 +2080,7 @@ start_glib_signal (GMarkupParseContext *context,
       action = find_attribute ("action", attribute_names, attribute_values);
       no_hooks = find_attribute ("no-hooks", attribute_names, attribute_values);
       has_class_closure = find_attribute ("has-class-closure", attribute_names, attribute_values);
-      
+
       if (name == NULL)
        MISSING_ATTRIBUTE (context, error, element_name, "name");
       else
@@ -1983,9 +2089,9 @@ start_glib_signal (GMarkupParseContext *context,
          GIrNodeSignal *signal;
 
          signal = (GIrNodeSignal *)g_ir_node_new (G_IR_NODE_SIGNAL);
-         
+
          ((GIrNode *)signal)->name = g_strdup (name);
-         
+
          signal->run_first = FALSE;
          signal->run_last = FALSE;
          signal->run_cleanup = FALSE;
@@ -1993,9 +2099,9 @@ start_glib_signal (GMarkupParseContext *context,
            signal->run_last = TRUE;
          else if (strcmp (when, "FIRST") == 0)
            signal->run_first = TRUE;
-         else 
+         else
            signal->run_cleanup = TRUE;
-         
+
          if (no_recurse && strcmp (no_recurse, "1") == 0)
            signal->no_recurse = TRUE;
          else
@@ -2023,7 +2129,7 @@ start_glib_signal (GMarkupParseContext *context,
          push_node (ctx, (GIrNode *)signal);
          state_switch (ctx, STATE_FUNCTION);
        }
-      
+
       return TRUE;
     }
   return FALSE;
@@ -2037,7 +2143,7 @@ start_vfunc (GMarkupParseContext *context,
             ParseContext       *ctx,
             GError             **error)
 {
-  if (strcmp (element_name, "vfunc") == 0 && 
+  if (strcmp (element_name, "virtual-method") == 0 &&
       (ctx->state == STATE_CLASS ||
        ctx->state == STATE_INTERFACE))
     {
@@ -2046,13 +2152,15 @@ start_vfunc (GMarkupParseContext *context,
       const gchar *override;
       const gchar *is_class_closure;
       const gchar *offset;
-      
+      const gchar *invoker;
+
       name = find_attribute ("name", attribute_names, attribute_values);
-      must_chain_up = find_attribute ("must-chain-up", attribute_names, attribute_values);       
+      must_chain_up = find_attribute ("must-chain-up", attribute_names, attribute_values);
       override = find_attribute ("override", attribute_names, attribute_values);
       is_class_closure = find_attribute ("is-class-closure", attribute_names, attribute_values);
       offset = find_attribute ("offset", attribute_names, attribute_values);
-      
+      invoker = find_attribute ("invoker", attribute_names, attribute_values);
+
       if (name == NULL)
        MISSING_ATTRIBUTE (context, error, element_name, "name");
       else
@@ -2061,7 +2169,7 @@ start_vfunc (GMarkupParseContext *context,
          GIrNodeVFunc *vfunc;
 
          vfunc = (GIrNodeVFunc *)g_ir_node_new (G_IR_NODE_VFUNC);
-         
+
          ((GIrNode *)vfunc)->name = g_strdup (name);
 
          if (must_chain_up && strcmp (must_chain_up, "1") == 0)
@@ -2084,24 +2192,26 @@ start_vfunc (GMarkupParseContext *context,
              vfunc->must_be_implemented = FALSE;
              vfunc->must_not_be_implemented = FALSE;
            }
-         
+
          if (is_class_closure && strcmp (is_class_closure, "1") == 0)
            vfunc->is_class_closure = TRUE;
          else
            vfunc->is_class_closure = FALSE;
-         
+
          if (offset)
            vfunc->offset = atoi (offset);
          else
            vfunc->offset = 0;
 
+         vfunc->invoker = g_strdup (invoker);
+
          iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
          iface->members = g_list_append (iface->members, vfunc);
 
          push_node (ctx, (GIrNode *)vfunc);
          state_switch (ctx, STATE_FUNCTION);
        }
-      
+
       return TRUE;
     }
   return FALSE;
@@ -2116,7 +2226,7 @@ start_struct (GMarkupParseContext *context,
              ParseContext       *ctx,
              GError             **error)
 {
-  if (strcmp (element_name, "record") == 0 && 
+  if (strcmp (element_name, "record") == 0 &&
       (ctx->state == STATE_NAMESPACE ||
        ctx->state == STATE_UNION ||
        ctx->state == STATE_STRUCT ||
@@ -2127,15 +2237,17 @@ start_struct (GMarkupParseContext *context,
       const gchar *disguised;
       const gchar *gtype_name;
       const gchar *gtype_init;
-      const gchar *gclass_struct;
+      const gchar *gtype_struct;
+      const gchar *foreign;
       GIrNodeStruct *struct_;
-      
+
       name = find_attribute ("name", attribute_names, attribute_values);
       deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
       disguised = find_attribute ("disguised", attribute_names, attribute_values);
       gtype_name = find_attribute ("glib:type-name", attribute_names, attribute_values);
       gtype_init = find_attribute ("glib:get-type", attribute_names, attribute_values);
-      gclass_struct = find_attribute ("glib:is-class-struct-for", attribute_names, attribute_values);      
+      gtype_struct = find_attribute ("glib:is-gtype-struct-for", attribute_names, attribute_values);
+      foreign = find_attribute ("foreign", attribute_names, attribute_values);
 
       if (name == NULL && ctx->node_stack == NULL)
        {
@@ -2154,7 +2266,7 @@ start_struct (GMarkupParseContext *context,
        }
 
       struct_ = (GIrNodeStruct *) g_ir_node_new (G_IR_NODE_STRUCT);
-      
+
       ((GIrNode *)struct_)->name = g_strdup (name ? name : "");
       if (deprecated)
        struct_->deprecated = TRUE;
@@ -2163,23 +2275,25 @@ start_struct (GMarkupParseContext *context,
 
       if (disguised && strcmp (disguised, "1") == 0)
        struct_->disguised = TRUE;
-      
-      struct_->is_gclass_struct = gclass_struct != NULL;
+
+      struct_->is_gtype_struct = gtype_struct != NULL;
 
       struct_->gtype_name = g_strdup (gtype_name);
       struct_->gtype_init = g_strdup (gtype_init);
 
+      struct_->foreign = (g_strcmp0 (foreign, "1") == 0);
+
       if (ctx->node_stack == NULL)
-        ctx->current_module->entries = 
+        ctx->current_module->entries =
           g_list_append (ctx->current_module->entries, struct_);
       push_node (ctx, (GIrNode *)struct_);
-      
+
       state_switch (ctx, STATE_STRUCT);
       return TRUE;
     }
   return FALSE;
 }
-  
+
 
 static gboolean
 start_union (GMarkupParseContext *context,
@@ -2199,12 +2313,12 @@ start_union (GMarkupParseContext *context,
       const gchar *deprecated;
       const gchar *typename;
       const gchar *typeinit;
-      
+
       name = find_attribute ("name", attribute_names, attribute_values);
       deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
       typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
       typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
-      
+
       if (name == NULL && ctx->node_stack == NULL)
        MISSING_ATTRIBUTE (context, error, element_name, "name");
       else
@@ -2212,7 +2326,7 @@ start_union (GMarkupParseContext *context,
          GIrNodeUnion *union_;
 
          union_ = (GIrNodeUnion *) g_ir_node_new (G_IR_NODE_UNION);
-         
+
          ((GIrNode *)union_)->name = g_strdup (name ? name : "");
          union_->gtype_name = g_strdup (typename);
          union_->gtype_init = g_strdup (typeinit);
@@ -2222,10 +2336,10 @@ start_union (GMarkupParseContext *context,
            union_->deprecated = FALSE;
 
           if (ctx->node_stack == NULL)
-            ctx->current_module->entries = 
+            ctx->current_module->entries =
               g_list_append (ctx->current_module->entries, union_);
          push_node (ctx, (GIrNode *)union_);
-         
+
          state_switch (ctx, STATE_UNION);
        }
       return TRUE;
@@ -2246,7 +2360,7 @@ start_discriminator (GMarkupParseContext *context,
     {
       const gchar *type;
       const gchar *offset;
-      
+
       type = find_attribute ("type", attribute_names, attribute_values);
       offset = find_attribute ("offset", attribute_names, attribute_values);
       if (type == NULL)
@@ -2254,12 +2368,12 @@ start_discriminator (GMarkupParseContext *context,
       else if (offset == NULL)
        MISSING_ATTRIBUTE (context, error, element_name, "offset");
        {
-         ((GIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_type 
+         ((GIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_type
            = parse_type (ctx, type);
-         ((GIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_offset 
+         ((GIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_offset
            = atoi (offset);
        }
-      
+
       return TRUE;
     }
 
@@ -2275,7 +2389,7 @@ parse_include (GMarkupParseContext *context,
 {
   gchar *buffer;
   gsize length;
-  char *girpath;
+  gchar *girpath, *girname;
   gboolean success = FALSE;
   GList *modules;
   GList *l;
@@ -2304,17 +2418,20 @@ parse_include (GMarkupParseContext *context,
        }
     }
 
-  girpath = locate_gir (ctx->parser, name, version);
+  girname = g_strdup_printf ("%s-%s.gir", name, version);
+  girpath = locate_gir (ctx->parser, girname);
 
   if (girpath == NULL)
     {
       g_set_error (error,
                   G_MARKUP_ERROR,
                   G_MARKUP_ERROR_INVALID_CONTENT,
-                  "Could not find GIR file '%s.gir'; check XDG_DATA_DIRS or use --includedir",
-                  name);
+                  "Could not find GIR file '%s'; check XDG_DATA_DIRS or use --includedir",
+                  girname);
+      g_free (girname);
       return FALSE;
     }
+  g_free (girname);
 
   g_debug ("Parsing include %s", girpath);
 
@@ -2335,7 +2452,7 @@ parse_include (GMarkupParseContext *context,
 
   return success;
 }
-  
+
 extern GLogLevelFlags logged_levels;
 
 static void
@@ -2367,10 +2484,10 @@ start_element_handler (GMarkupParseContext *context,
       g_string_free (tags, TRUE);
     }
 
-  switch (element_name[0]) 
+  switch (element_name[0])
     {
     case 'a':
-      if (ctx->state == STATE_NAMESPACE && strcmp (element_name, "alias") == 0) 
+      if (ctx->state == STATE_NAMESPACE && strcmp (element_name, "alias") == 0)
        {
          state_switch (ctx, STATE_ALIAS);
          goto out;
@@ -2379,15 +2496,19 @@ start_element_handler (GMarkupParseContext *context,
                      attribute_names, attribute_values,
                      ctx, error))
        goto out;
+      else if (start_attribute (context, element_name,
+                                attribute_names, attribute_values,
+                                ctx, error))
+        goto out;
       break;
     case 'b':
-      if (start_enum (context, element_name, 
+      if (start_enum (context, element_name,
                      attribute_names, attribute_values,
                      ctx, error))
        goto out;
       break;
     case 'c':
-      if (start_function (context, element_name, 
+      if (start_function (context, element_name,
                          attribute_names, attribute_values,
                          ctx, error))
        goto out;
@@ -2395,36 +2516,36 @@ start_element_handler (GMarkupParseContext *context,
                               attribute_names, attribute_values,
                               ctx, error))
        goto out;
-      else if (start_class (context, element_name, 
+      else if (start_class (context, element_name,
                            attribute_names, attribute_values,
                            ctx, error))
        goto out;
       break;
 
     case 'd':
-      if (start_discriminator (context, element_name, 
+      if (start_discriminator (context, element_name,
                               attribute_names, attribute_values,
                               ctx, error))
        goto out;
       break;
 
     case 'e':
-      if (start_enum (context, element_name, 
+      if (start_enum (context, element_name,
                      attribute_names, attribute_values,
                      ctx, error))
        goto out;
-      else if (start_errordomain (context, element_name, 
+      else if (start_errordomain (context, element_name,
                      attribute_names, attribute_values,
                      ctx, error))
        goto out;
       break;
 
     case 'f':
-      if (start_function (context, element_name, 
+      if (start_function (context, element_name,
                          attribute_names, attribute_values,
                          ctx, error))
        goto out;
-      else if (start_field (context, element_name, 
+      else if (start_field (context, element_name,
                            attribute_names, attribute_values,
                            ctx, error))
        goto out;
@@ -2472,7 +2593,7 @@ start_element_handler (GMarkupParseContext *context,
          state_switch (ctx, STATE_INCLUDE);
          goto out;
        }
-      if (start_interface (context, element_name, 
+      if (start_interface (context, element_name,
                           attribute_names, attribute_values,
                           ctx, error))
        goto out;
@@ -2483,11 +2604,11 @@ start_element_handler (GMarkupParseContext *context,
       break;
 
     case 'm':
-      if (start_function (context, element_name, 
+      if (start_function (context, element_name,
                          attribute_names, attribute_values,
                          ctx, error))
        goto out;
-      else if (start_member (context, element_name, 
+      else if (start_member (context, element_name,
                          attribute_names, attribute_values,
                          ctx, error))
        goto out;
@@ -2496,7 +2617,7 @@ start_element_handler (GMarkupParseContext *context,
     case 'n':
       if (strcmp (element_name, "namespace") == 0 && ctx->state == STATE_REPOSITORY)
        {
-         const gchar *name, *version, *shared_library;
+         const gchar *name, *version, *shared_library, *cprefix;
 
          if (ctx->current_module != NULL)
            {
@@ -2510,6 +2631,7 @@ start_element_handler (GMarkupParseContext *context,
          name = find_attribute ("name", attribute_names, attribute_values);
          version = find_attribute ("version", attribute_names, attribute_values);
          shared_library = find_attribute ("shared-library", attribute_names, attribute_values);
+         cprefix = find_attribute ("c:prefix", attribute_names, attribute_values);
 
          if (name == NULL)
            MISSING_ATTRIBUTE (context, error, element_name, "name");
@@ -2526,7 +2648,7 @@ start_element_handler (GMarkupParseContext *context,
                             "<namespace/> name element '%s' doesn't match file name '%s'",
                             name, ctx->namespace);
 
-             ctx->current_module = g_ir_module_new (name, version, shared_library);
+             ctx->current_module = g_ir_module_new (name, version, shared_library, cprefix);
 
              ctx->current_module->aliases = ctx->aliases;
              ctx->aliases = NULL;
@@ -2576,7 +2698,7 @@ start_element_handler (GMarkupParseContext *context,
          if (name == NULL)
            MISSING_ATTRIBUTE (context, error, element_name, "name");
          else
-           {  
+           {
              GIrNodeInterface *iface;
 
              iface = (GIrNodeInterface *)CURRENT_NODE(ctx);
@@ -2584,6 +2706,12 @@ start_element_handler (GMarkupParseContext *context,
            }
          goto out;
        }
+      else if (strcmp (element_name, "package") == 0 &&
+          ctx->state == STATE_REPOSITORY)
+        {
+          state_switch (ctx, STATE_PACKAGE);
+          goto out;
+        }
       break;
 
     case 'r':
@@ -2592,7 +2720,7 @@ start_element_handler (GMarkupParseContext *context,
          const gchar *version;
 
          version = find_attribute ("version", attribute_names, attribute_values);
-         
+
          if (version == NULL)
            MISSING_ATTRIBUTE (context, error, element_name, "version");
          else if (strcmp (version, "1.0") != 0)
@@ -2603,17 +2731,17 @@ start_element_handler (GMarkupParseContext *context,
                         version);
          else
            state_switch (ctx, STATE_REPOSITORY);
-         
+
          goto out;
        }
       else if (start_return_value (context, element_name,
                                   attribute_names, attribute_values,
                                   ctx, error))
-       goto out;      
+       goto out;
       else if (start_struct (context, element_name,
                             attribute_names, attribute_values,
                             ctx, error))
-       goto out;      
+       goto out;
       break;
 
     case 'u':
@@ -2651,9 +2779,9 @@ start_element_handler (GMarkupParseContext *context,
     {
       ctx->unknown_depth += 1;
     }
-  
- out: ;
-  if (*error) 
+
+ out:
+  if (*error)
     {
       g_markup_parse_context_get_position (context, &line_number, &char_number);
 
@@ -2666,7 +2794,7 @@ static gboolean
 require_one_of_end_elements (GMarkupParseContext *context,
                             ParseContext        *ctx,
                             const char          *actual_name,
-                            GError             **error, 
+                            GError             **error,
                             ...)
 {
   va_list args;
@@ -2676,7 +2804,7 @@ require_one_of_end_elements (GMarkupParseContext *context,
 
   va_start (args, error);
 
-  while ((expected = va_arg (args, const char*)) != NULL) 
+  while ((expected = va_arg (args, const char*)) != NULL)
     {
       if (strcmp (expected, actual_name) == 0)
        {
@@ -2695,7 +2823,7 @@ require_one_of_end_elements (GMarkupParseContext *context,
               G_MARKUP_ERROR,
               G_MARKUP_ERROR_INVALID_CONTENT,
               "Unexpected end tag '%s' on line %d char %d; current state=%d",
-              actual_name, 
+              actual_name,
               line_number, char_number, ctx->state);
   backtrace_stderr();
   return FALSE;
@@ -2712,7 +2840,7 @@ state_switch_end_struct_or_union (GMarkupParseContext *context,
     {
       state_switch (ctx, STATE_NAMESPACE);
     }
-  else 
+  else
     {
       if (CURRENT_NODE (ctx)->type == G_IR_NODE_STRUCT)
         state_switch (ctx, STATE_STRUCT);
@@ -2774,6 +2902,13 @@ end_element_handler (GMarkupParseContext *context,
         }
       break;
 
+    case STATE_PACKAGE:
+      if (require_end_element (context, ctx, "package", element_name, error))
+        {
+          state_switch (ctx, STATE_REPOSITORY);
+        }
+      break;
+
     case STATE_NAMESPACE:
       if (require_end_element (context, ctx, "namespace", element_name, error))
        {
@@ -2821,11 +2956,17 @@ end_element_handler (GMarkupParseContext *context,
          {
            state_switch (ctx, STATE_NAMESPACE);
          }
-       else 
+       else
          {
-           if (CURRENT_NODE (ctx)->type == G_IR_NODE_INTERFACE)
+            g_debug("case STATE_FUNCTION %d", CURRENT_NODE (ctx)->type);
+            if (ctx->in_embedded_type)
+              {
+                ctx->in_embedded_type = FALSE;
+                state_switch (ctx, STATE_STRUCT_FIELD);
+              }
+           else if (CURRENT_NODE (ctx)->type == G_IR_NODE_INTERFACE)
              state_switch (ctx, STATE_INTERFACE);
-           else if (CURRENT_NODE (ctx)->type == G_IR_NODE_OBJECT) 
+           else if (CURRENT_NODE (ctx)->type == G_IR_NODE_OBJECT)
              state_switch (ctx, STATE_CLASS);
            else if (CURRENT_NODE (ctx)->type == G_IR_NODE_BOXED)
              state_switch (ctx, STATE_BOXED);
@@ -2911,8 +3052,8 @@ end_element_handler (GMarkupParseContext *context,
     case STATE_ENUM:
       if (strcmp ("member", element_name) == 0)
        break;
-      else if (require_one_of_end_elements (context, ctx, 
-                                           element_name, error, "enumeration", 
+      else if (require_one_of_end_elements (context, ctx,
+                                           element_name, error, "enumeration",
                                            "bitfield", NULL))
        {
          pop_node (ctx);
@@ -2985,10 +3126,10 @@ end_element_handler (GMarkupParseContext *context,
        break;
       if (require_end_element (context, ctx, "constant", element_name, error))
        {
-         pop_node (ctx);
          switch (ctx->state)
            {
            case STATE_NAMESPACE_CONSTANT:
+                 pop_node (ctx);
              state_switch (ctx, STATE_NAMESPACE);
              break;
            case STATE_CLASS_CONSTANT:
@@ -3010,6 +3151,13 @@ end_element_handler (GMarkupParseContext *context,
          end_type (ctx);
          break;
        }
+    case STATE_ATTRIBUTE:
+      if (strcmp ("attribute", element_name) == 0)
+        {
+          state_switch (ctx, ctx->prev_state);
+        }
+      break;
+
     case STATE_UNKNOWN:
       ctx->unknown_depth -= 1;
       if (ctx->unknown_depth == 0)
@@ -3020,10 +3168,10 @@ end_element_handler (GMarkupParseContext *context,
     }
 }
 
-static void 
+static void
 text_handler (GMarkupParseContext *context,
              const gchar         *text,
-             gsize                text_len,  
+             gsize                text_len,
              gpointer             user_data,
              GError             **error)
 {
@@ -3042,25 +3190,25 @@ cleanup (GMarkupParseContext *context,
     g_ir_module_free (m->data);
   g_list_free (ctx->modules);
   ctx->modules = NULL;
-  
+
   ctx->current_module = NULL;
 }
 
 static GList *
-post_filter_toplevel_varargs_functions (GList *list, 
+post_filter_toplevel_varargs_functions (GList *list,
                                        GList **varargs_callbacks_out)
 {
   GList *iter;
   GList *varargs_callbacks = *varargs_callbacks_out;
-  
+
   iter = list;
   while (iter)
     {
       GList *link = iter;
       GIrNode *node = iter->data;
-      
+
       iter = iter->next;
-      
+
       if (node->type == G_IR_NODE_FUNCTION)
        {
          if (((GIrNodeFunction*)node)->is_varargs)
@@ -3078,20 +3226,42 @@ post_filter_toplevel_varargs_functions (GList *list,
            }
        }
     }
-  
+
   *varargs_callbacks_out = varargs_callbacks;
-  
+
   return list;
 }
 
+
+/* 
+  quick look up of node in the list..
+  return null, or a pointer to the list item..
+ */
+static GList *
+node_find_in_list(GList *list, const char *name)
+{
+  GList *link;
+  for (link = list;
+       link;
+       link = link->next)
+    {
+      if (!strcmp (name, ((GIrNode *)link->data)->name))
+       return link;
+    }
+  return NULL;
+}
+
+
+
 static GList *
 post_filter_varargs_functions (GList *list, GList ** varargs_callbacks_out)
 {
   GList *iter;
   GList *varargs_callbacks;
-  
+
   list = post_filter_toplevel_varargs_functions (list, varargs_callbacks_out);
-  
+
   varargs_callbacks = *varargs_callbacks_out;
 
   iter = list;
@@ -3099,45 +3269,82 @@ post_filter_varargs_functions (GList *list, GList ** varargs_callbacks_out)
     {
       GList *link = iter;
       GIrNode *node = iter->data;
-      
+
       iter = iter->next;
-      
+
       if (node->type == G_IR_NODE_FUNCTION)
        {
          GList *param;
          gboolean function_done = FALSE;
-         
+
          for (param = ((GIrNodeFunction *)node)->parameters;
               param;
               param = param->next)
            {
              GIrNodeParam *node = (GIrNodeParam *)param->data;
-             
+
              if (function_done)
                break;
 
              if (node->type->is_interface)
                {
-                 GList *callback;
-                 for (callback = varargs_callbacks;
-                      callback;
-                      callback = callback->next)
-                   {
-                     if (!strcmp (node->type->interface,
-                                  ((GIrNode *)varargs_callbacks->data)->name))
-                       {
-                         list = g_list_delete_link (list, link);
-                         function_done = TRUE;
-                         break;
-                       }
-                   }
+       
+                 GList *callback = node_find_in_list(
+                                       varargs_callbacks, 
+                                       node->type->interface);
+                 if (callback)
+                    {
+                      list = g_list_delete_link (list, link);
+                      function_done = TRUE;
+                    }
+                    
                }
            }
        }
+
+       if (node->type == G_IR_NODE_FIELD)
+          {
+           /*
+               this is a field, if the member is a blacklisted callback, 
+               then we need to flag it as to be generated as a void*
+            */
+           GIrNodeField *fnode = (GIrNodeField *)node;
+           GIrNodeType * tnode;
+           GList *match;
+
+           if (!fnode->type)
+              continue;
+           
+           tnode = (GIrNodeType *)fnode->type;
+            /* field is not an interface. */
+           if (!tnode->is_interface)
+             continue;
+             
+           match = node_find_in_list(
+                       varargs_callbacks, tnode->interface);
+
+            if (!match)
+             continue;
+
+           /*
+               we now have a field which is pointing to an blacklisted callback.
+              so need modify the type so it points to void* and
+               is not read/or writable.
+            */
+           fnode->readable = FALSE;
+           fnode->writable = FALSE;
+           
+           tnode->tag          = GI_TYPE_TAG_VOID;
+           tnode->is_interface = FALSE;
+           tnode->is_pointer   = TRUE;
+           tnode->is_basic     = TRUE;
+         }
+
+        
     }
-  
+
   *varargs_callbacks_out = varargs_callbacks;
-  
+
   return list;
 }
 
@@ -3146,18 +3353,18 @@ post_filter (GIrModule *module)
 {
   GList *iter;
   GList *varargs_callbacks = NULL;
-  
+
   module->entries = post_filter_varargs_functions (module->entries,
                                                   &varargs_callbacks);
   iter = module->entries;
   while (iter)
     {
       GIrNode *node = iter->data;
-      
+
       iter = iter->next;
-      
-      if (node->type == G_IR_NODE_OBJECT || 
-         node->type == G_IR_NODE_INTERFACE) 
+
+      if (node->type == G_IR_NODE_OBJECT ||
+         node->type == G_IR_NODE_INTERFACE)
        {
          GIrNodeInterface *iface = (GIrNodeInterface*)node;
          iface->members = post_filter_varargs_functions (iface->members,
@@ -3188,12 +3395,15 @@ post_filter (GIrModule *module)
 /**
  * g_ir_parser_parse_string:
  * @parser: a #GIrParser
+ * @namespace: the namespace of the string
+ * @buffer: the data containing the XML
+ * @length: length of the data
  * @error: return location for a #GError, or %NULL
  *
  * Parse a string that holds a complete GIR XML file, and return a list of a
  * a #GirModule for each &lt;namespace/&gt; element within the file.
  *
- * @returns: a newly allocated list of #GIrModule. The modules themselves
+ * Returns: a newly allocated list of #GIrModule. The modules themselves
  *  are owned by the #GIrParser and will be freed along with the parser.
  */
 GList *
@@ -3225,7 +3435,7 @@ g_ir_parser_parse_string (GIrParser           *parser,
     goto out;
 
   g_markup_parse_context_free (context);
-  
+
   context = g_markup_parse_context_new (&markup_parser, 0, &ctx, NULL);
   if (!g_markup_parse_context_parse (context, buffer, length, error))
     goto out;
@@ -3249,21 +3459,22 @@ g_ir_parser_parse_string (GIrParser           *parser,
        g_hash_table_destroy (ctx.disguised_structures);
       g_list_free (ctx.include_modules);
     }
-  
+
   g_markup_parse_context_free (context);
-  
+
   return ctx.modules;
 }
 
 /**
  * g_ir_parser_parse_file:
  * @parser: a #GIrParser
+ * @filename: filename to parse
  * @error: return location for a #GError, or %NULL
  *
  * Parse GIR XML file, and return a list of a a #GirModule for each
  * &lt;namespace/&gt; element within the file.
  *
- * @returns: a newly allocated list of #GIrModule. The modules themselves
+ * Returns: a newly allocated list of #GIrModule. The modules themselves
  *  are owned by the #GIrParser and will be freed along with the parser.
  */
 GList *
@@ -3304,10 +3515,10 @@ g_ir_parser_parse_file (GIrParser   *parser,
 
   if (!g_file_get_contents (filename, &buffer, &length, error))
     return NULL;
-  
+
   modules = g_ir_parser_parse_string (parser, namespace, buffer, length, error);
 
-  for (iter = modules; iter; iter = iter->next) 
+  for (iter = modules; iter; iter = iter->next)
     {
       post_filter ((GIrModule*)iter->data);
     }