Expand aliases when generating typelibs
[gnome.gobject-introspection] / girepository / girparser.c
1 /* GObject introspection: A parser for the XML GIR format
2  *
3  * Copyright (C) 2008 Philip Van Hoof
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdio.h>
24
25 #include <glib.h>
26 #include "girmodule.h"
27 #include "girnode.h"
28 #include "gtypelib.h"
29
30 typedef enum
31 {
32   STATE_START,    
33   STATE_END,        
34   STATE_REPOSITORY, 
35   STATE_INCLUDE,  
36   STATE_NAMESPACE,  
37   STATE_ENUM,      /* 5 */    
38   STATE_BITFIELD,  
39   STATE_FUNCTION,   
40   STATE_FUNCTION_RETURN, 
41   STATE_FUNCTION_PARAMETERS,
42   STATE_FUNCTION_PARAMETER,  /* 10 */
43   STATE_CLASS,  
44   STATE_CLASS_FIELD,
45   STATE_CLASS_PROPERTY,
46   STATE_INTERFACE,
47   STATE_INTERFACE_PROPERTY,   /* 15 */
48   STATE_INTERFACE_FIELD,
49   STATE_IMPLEMENTS, 
50   STATE_REQUIRES,
51   STATE_BOXED,  
52   STATE_BOXED_FIELD, /* 20 */
53   STATE_STRUCT,   
54   STATE_STRUCT_FIELD,
55   STATE_ERRORDOMAIN, 
56   STATE_UNION,
57   STATE_UNION_FIELD, /* 25 */
58   STATE_NAMESPACE_CONSTANT, 
59   STATE_CLASS_CONSTANT, 
60   STATE_INTERFACE_CONSTANT,
61   STATE_ALIAS,
62   STATE_TYPE,
63 } ParseState;
64
65 typedef struct _ParseContext ParseContext;
66 struct _ParseContext
67 {
68   ParseState state;
69   ParseState prev_state;
70
71   const char **includes;
72   
73   GList *modules;
74   gboolean prefix_aliases;
75   GHashTable *aliases;
76
77   const char *namespace;
78   GIrModule *current_module;
79   GIrNode *current_node;
80   GIrNode *current_typed;
81   int type_depth;
82 };
83
84 static gboolean
85 start_alias (GMarkupParseContext *context,
86              const gchar         *element_name,
87              const gchar        **attribute_names,
88              const gchar        **attribute_values,
89              ParseContext        *ctx,
90              GError             **error);
91
92 static void
93 firstpass_start_element_handler (GMarkupParseContext *context,
94                                  const gchar         *element_name,
95                                  const gchar        **attribute_names,
96                                  const gchar        **attribute_values,
97                                  gpointer             user_data,
98                                  GError             **error)
99 {
100   ParseContext *ctx = user_data;
101
102   if (strcmp (element_name, "alias") == 0) 
103     {
104       start_alias (context, element_name, attribute_names, attribute_values,
105                    ctx, error);
106     }
107 }
108
109 static void
110 firstpass_end_element_handler (GMarkupParseContext *context,
111                                const gchar         *element_name,
112                                gpointer             user_data,
113                                GError             **error)
114 {
115   ParseContext *ctx = user_data;
116
117 }
118
119 static GMarkupParser firstpass_parser = 
120 {
121   firstpass_start_element_handler,
122   firstpass_end_element_handler,
123   NULL,
124   NULL,
125   NULL,
126 };
127
128 static char *
129 locate_gir (const char *name, const char **extra_paths)
130 {
131   const gchar *const *datadirs;
132   const gchar *const *dir;
133   char *girname;
134   char *path = NULL;
135   GSList *link;
136   gboolean firstpass = TRUE;
137       
138   datadirs = g_get_system_data_dirs ();
139       
140   girname = g_strdup_printf ("%s.gir", name);
141   
142   for (dir = datadirs; *dir; dir++) 
143     {
144       path = g_build_filename (*dir, "gir", girname, NULL);
145       if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
146         return path;
147       g_free (path);
148       path = NULL;
149       if (firstpass && !*dir)
150         {
151           firstpass = FALSE;
152           dir = extra_paths;
153         }
154     }
155   g_free (girname);
156   return path;
157 }
158
159 #define MISSING_ATTRIBUTE(ctx,error,element,attribute)                          \
160   do {                                                                          \
161     int line_number, char_number;                                                \
162     g_markup_parse_context_get_position (context, &line_number, &char_number);  \
163     g_set_error (error,                                                         \
164                  G_MARKUP_ERROR,                                                \
165                  G_MARKUP_ERROR_INVALID_CONTENT,                                \
166                  "Line %d, character %d: The attribute '%s' on the element '%s' must be specified",    \
167                  line_number, char_number, attribute, element);         \
168   } while (0)
169
170 static void
171 backtrace_stderr (void)
172 {
173 #ifndef _WIN32
174   void *array[50];
175   int size;
176   char **strings;
177   size_t i;
178
179   size = backtrace (array, 50);
180   strings = (char**) backtrace_symbols (array, size);
181
182   fprintf (stderr, "--- BACKTRACE (%zd frames) ---\n", size);
183
184   for (i = 0; i < size; i++)
185     fprintf (stderr, "%s\n", strings[i]);
186
187   fprintf (stderr, "--- END BACKTRACE ---\n", size);
188
189   free (strings);
190 #endif
191 }
192
193
194 static const gchar *
195 find_attribute (const gchar  *name, 
196                 const gchar **attribute_names,
197                 const gchar **attribute_values)
198 {
199   gint i;
200   
201   for (i = 0; attribute_names[i] != NULL; i++)
202     if (strcmp (attribute_names[i], name) == 0)
203       return attribute_values[i];
204   
205   return 0;
206 }
207
208 static void
209 state_switch (ParseContext *ctx, ParseState newstate)
210 {
211   g_debug ("State: %d", newstate);
212   ctx->prev_state = ctx->state;
213   ctx->state = newstate;
214 }
215
216 static GIrNodeType * parse_type_internal (gchar *str, gchar **rest);
217
218 static GIrNodeType *
219 create_pointer ()
220 {
221   char *pointer = g_strdup ("any");
222   char *pointer_rest;
223   GIrNodeType *ret = parse_type_internal (pointer, &pointer_rest);
224   g_free (pointer);
225   return ret;
226 }
227
228 static GIrNodeType *
229 parse_type_internal (gchar *str, gchar **rest)
230 {
231   gint i;
232
233   static struct {
234     const gchar *str;
235     gint tag;
236     gboolean pointer;
237   } basic[] = {
238     { "none",     GI_TYPE_TAG_VOID,    0 },
239     { "any",      GI_TYPE_TAG_VOID,    1 },
240
241     { "bool",     GI_TYPE_TAG_BOOLEAN, 0 },
242     { "char",     GI_TYPE_TAG_INT8,    0 },
243     { "int8",     GI_TYPE_TAG_INT8,    0 },
244     { "uint8",    GI_TYPE_TAG_UINT8,   0 },
245     { "int16",    GI_TYPE_TAG_INT16,   0 },
246     { "uint16",   GI_TYPE_TAG_UINT16,  0 },
247     { "int32",    GI_TYPE_TAG_INT32,   0 },
248     { "uint32",   GI_TYPE_TAG_UINT32,  0 },
249     { "int64",    GI_TYPE_TAG_INT64,   0 },
250     { "uint64",   GI_TYPE_TAG_UINT64,  0 },
251     { "int",      GI_TYPE_TAG_INT,     0 },
252     { "uint",     GI_TYPE_TAG_UINT,    0 },
253     { "long",     GI_TYPE_TAG_LONG,    0 },
254     { "ulong",    GI_TYPE_TAG_ULONG,   0 },
255     { "ssize_t",  GI_TYPE_TAG_SSIZE,   0 },
256     { "ssize",    GI_TYPE_TAG_SSIZE,   0 },
257     { "size_t",   GI_TYPE_TAG_SIZE,    0 },
258     { "size",     GI_TYPE_TAG_SIZE,    0 },
259     { "float",    GI_TYPE_TAG_FLOAT,   0 },
260     { "double",   GI_TYPE_TAG_DOUBLE,  0 },
261     { "utf8",     GI_TYPE_TAG_UTF8,    1 },  
262     { "filename", GI_TYPE_TAG_FILENAME,1 },
263
264     /* FIXME: merge - do we still want this? */
265     { "string",   GI_TYPE_TAG_UTF8,  1 },
266
267     /* FIXME: Remove these */
268     { "void",     GI_TYPE_TAG_VOID,    0 },
269     { "int8_t",   GI_TYPE_TAG_INT8,    0 },
270     { "uint8_t",  GI_TYPE_TAG_UINT8,   0 },
271     { "int16_t",  GI_TYPE_TAG_INT16,   0 },
272     { "uint16_t", GI_TYPE_TAG_UINT16,  0 },
273     { "int32_t",  GI_TYPE_TAG_INT32,   0 },
274     { "uint32_t", GI_TYPE_TAG_UINT32,  0 },
275     { "int64_t",  GI_TYPE_TAG_INT64,   0 },
276     { "uint64_t", GI_TYPE_TAG_UINT64,  0 },
277     { "gpointer", GI_TYPE_TAG_VOID,    1 },
278     { "gboolean", GI_TYPE_TAG_BOOLEAN, 0 },
279     { "gchar",    GI_TYPE_TAG_INT8,    0 },
280     { "guchar",   GI_TYPE_TAG_UINT8,   0 },
281     { "gunichar", GI_TYPE_TAG_UINT32,  0 },
282     { "gint",     GI_TYPE_TAG_INT,     0 },
283     { "guint",    GI_TYPE_TAG_UINT,    0 },
284     { "gshort",   GI_TYPE_TAG_INT16,   0 },
285     { "gushort",  GI_TYPE_TAG_UINT16,  0 },
286     { "gint8",    GI_TYPE_TAG_INT8,    0 },
287     { "guint8",   GI_TYPE_TAG_UINT8,   0 },
288     { "gint16",   GI_TYPE_TAG_INT16,   0 },
289     { "guint16",  GI_TYPE_TAG_UINT16,  0 },
290     { "gint32",   GI_TYPE_TAG_INT32,   0 },
291     { "guint32",  GI_TYPE_TAG_UINT32,  0 },
292     { "gint64",   GI_TYPE_TAG_INT64,   0 },
293     { "guint64",  GI_TYPE_TAG_UINT64,  0 },
294     { "glong",    GI_TYPE_TAG_LONG,    0 },
295     { "gulong",   GI_TYPE_TAG_ULONG,   0 },
296     { "gssize",   GI_TYPE_TAG_SSIZE,   0 },
297     { "gsize",    GI_TYPE_TAG_SIZE,    0 },
298     { "gfloat",   GI_TYPE_TAG_FLOAT,   0 },
299     { "gdouble",  GI_TYPE_TAG_DOUBLE,  0 },
300     { "gchar*",   GI_TYPE_TAG_UTF8,    1 }
301   };  
302
303   gint n_basic = G_N_ELEMENTS (basic);
304   gchar *start, *end;
305   
306   GIrNodeType *type;
307   
308   type = (GIrNodeType *)g_ir_node_new (G_IR_NODE_TYPE);
309   
310   str = g_strstrip (str);
311
312   type->unparsed = g_strdup (str);
313  
314   *rest = str;
315   for (i = 0; i < n_basic; i++)
316     {
317       if (g_str_has_prefix (*rest, basic[i].str))
318         {
319           type->is_basic = TRUE;
320           type->tag = basic[i].tag;
321           type->is_pointer = basic[i].pointer;
322
323           *rest += strlen(basic[i].str);
324           *rest = g_strchug (*rest);
325           if (**rest == '*' && !type->is_pointer)
326             {
327               type->is_pointer = TRUE;
328               (*rest)++;
329             }
330
331           break;
332         }
333     }
334
335   if (i < n_basic)
336     /* found a basic type */;
337   else if (g_str_has_prefix (*rest, "GList") ||
338            g_str_has_prefix (*rest, "GSList"))
339     {
340       if (g_str_has_prefix (*rest, "GList"))
341         {
342           type->tag = GI_TYPE_TAG_GLIST;
343           type->is_glist = TRUE;
344           type->is_pointer = TRUE;
345           *rest += strlen ("GList");
346         }
347       else
348         {
349           type->tag = GI_TYPE_TAG_GSLIST;
350           type->is_gslist = TRUE;
351           type->is_pointer = TRUE;
352           *rest += strlen ("GSList");
353         }
354       
355       *rest = g_strchug (*rest);
356       
357       if (**rest == '<')
358         {
359           (*rest)++;
360           
361           type->parameter_type1 = parse_type_internal (*rest, rest);
362           if (type->parameter_type1 == NULL)
363             goto error;
364           
365           *rest = g_strchug (*rest);
366           
367           if ((*rest)[0] != '>')
368             goto error;
369           (*rest)++;
370         }
371       else
372         {
373           type->parameter_type1 = create_pointer ();
374         }
375     }
376   else if (g_str_has_prefix (*rest, "GHashTable"))
377     {
378       type->tag = GI_TYPE_TAG_GHASH;
379       type->is_ghashtable = TRUE;
380       type->is_pointer = TRUE;
381       *rest += strlen ("GHashTable");
382       
383       *rest = g_strchug (*rest);
384       
385       if (**rest == '<')
386         {
387           (*rest)++;
388       
389           type->parameter_type1 = parse_type_internal (*rest, rest);
390           if (type->parameter_type1 == NULL)
391             goto error;
392       
393           *rest = g_strchug (*rest);
394           
395           if ((*rest)[0] != ',')
396             goto error;
397           (*rest)++;
398           
399           type->parameter_type2 = parse_type_internal (*rest, rest);
400           if (type->parameter_type2 == NULL)
401             goto error;
402       
403           if ((*rest)[0] != '>')
404             goto error;
405           (*rest)++;
406         }
407       else
408         {
409           type->parameter_type1 = create_pointer ();
410           type->parameter_type2 = create_pointer ();
411         }
412
413     }
414   else if (g_str_has_prefix (*rest, "GError"))
415     {
416       type->tag = GI_TYPE_TAG_ERROR;
417       type->is_error = TRUE;
418       type->is_pointer = TRUE;
419       *rest += strlen ("GError");
420       
421       *rest = g_strchug (*rest);
422       
423       if (**rest == '<')
424         {
425           (*rest)++;
426           
427           end = strchr (*rest, '>');
428           str = g_strndup (*rest, end - *rest);
429           type->errors = g_strsplit (str, ",", 0);
430           g_free (str);
431           
432           *rest = end + 1;
433         }
434     }
435   else 
436     {
437       type->tag = GI_TYPE_TAG_INTERFACE;
438       type->is_interface = TRUE; 
439       start = *rest;
440
441       /* must be an interface type */
442       while (g_ascii_isalnum (**rest) || 
443              **rest == '.' || 
444              **rest == '-' || 
445              **rest == '_' ||
446              **rest == ':')
447         (*rest)++;
448
449       type->interface = g_strndup (start, *rest - start);
450
451       *rest = g_strchug (*rest);
452       if (**rest == '*')
453         {
454           type->is_pointer = TRUE;
455           (*rest)++;
456         }
457     }
458   
459   *rest = g_strchug (*rest);
460   if (g_str_has_prefix (*rest, "["))
461     {
462       GIrNodeType *array;
463
464       array = (GIrNodeType *)g_ir_node_new (G_IR_NODE_TYPE);
465
466       array->tag = GI_TYPE_TAG_ARRAY;
467       array->is_pointer = TRUE;
468       array->is_array = TRUE;
469       
470       array->parameter_type1 = type;
471
472       array->zero_terminated = FALSE;
473       array->has_length = FALSE;
474       array->length = 0;
475
476       if (!g_str_has_prefix (*rest, "[]"))
477         {
478           gchar *end, *str, **opts;
479           
480           end = strchr (*rest, ']');
481           str = g_strndup (*rest + 1, (end - *rest) - 1); 
482           opts = g_strsplit (str, ",", 0);
483           
484           *rest = end + 1;
485
486           for (i = 0; opts[i]; i++)
487             {
488               gchar **vals;
489               
490               vals = g_strsplit (opts[i], "=", 0);
491
492               if (strcmp (vals[0], "zero-terminated") == 0)
493                 array->zero_terminated = (strcmp (vals[1], "1") == 0);
494               else if (strcmp (vals[0], "length") == 0)
495                 {
496                   array->has_length = TRUE;
497                   array->length = atoi (vals[1]);
498                 }
499
500               g_strfreev (vals);
501             }
502
503           g_free (str);
504           g_strfreev (opts);
505         }
506               
507       type = array;
508     }
509
510   g_assert (type->tag >= 0 && type->tag <= GI_TYPE_TAG_ERROR);
511   return type;
512
513  error:
514   g_ir_node_free ((GIrNode *)type);
515   
516   return NULL;
517 }
518
519 static const char *
520 resolve_aliases (ParseContext *ctx, const gchar *type)
521 {
522   gpointer orig;
523   gpointer value;
524   GSList *seen_values = NULL;
525
526   seen_values = g_slist_prepend (seen_values, (char*)type);
527   while (g_hash_table_lookup_extended (ctx->aliases, type, &orig, &value))
528     {
529       g_debug ("Resolved: %s => %s", type, value);
530       type = value;
531       if (g_slist_find_custom (seen_values, type,
532                                (GCompareFunc)strcmp) != NULL)
533         break;
534       seen_values = g_slist_prepend (seen_values, (gchar*)type);
535     }
536   g_slist_free (seen_values);
537   return type;
538 }
539
540 static GIrNodeType *
541 parse_type (ParseContext *ctx, const gchar *type)
542 {
543   gchar *str;
544   gchar *rest;
545   GIrNodeType *node;
546   
547   type = resolve_aliases (ctx, type);
548   str = g_strdup (type);
549   node = parse_type_internal (str, &rest);
550   g_free (str);
551   g_debug ("Parsed type: %s => %d", type, node->tag);
552
553   return node;
554 }
555
556 static gboolean
557 start_glib_boxed (GMarkupParseContext *context,
558                   const gchar         *element_name,
559                   const gchar        **attribute_names,
560                   const gchar        **attribute_values,
561                   ParseContext        *ctx,
562                   GError             **error)
563 {
564   const gchar *name;
565   const gchar *typename;
566   const gchar *typeinit;
567   const gchar *deprecated;
568   GIrNodeBoxed *boxed;
569
570   if (!(strcmp (element_name, "glib:boxed") == 0 &&
571         ctx->state == STATE_NAMESPACE))
572     return FALSE;
573
574   name = find_attribute ("glib:name", attribute_names, attribute_values);
575   typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
576   typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
577   deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
578   
579   if (name == NULL)
580     {
581       MISSING_ATTRIBUTE (context, error, element_name, "glib:name");
582       return FALSE;
583     }
584   else if (typename == NULL)
585     {
586       MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name");
587       return FALSE;
588     }
589   else if (typeinit == NULL)
590     {
591       MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
592       return FALSE;
593     }
594
595   boxed = (GIrNodeBoxed *) g_ir_node_new (G_IR_NODE_BOXED);
596           
597   ((GIrNode *)boxed)->name = g_strdup (name);
598   boxed->gtype_name = g_strdup (typename);
599   boxed->gtype_init = g_strdup (typeinit);
600   if (deprecated && strcmp (deprecated, "1") == 0)
601     boxed->deprecated = TRUE;
602   else
603     boxed->deprecated = FALSE;
604           
605   ctx->current_node = (GIrNode *)boxed;
606   ctx->current_module->entries = 
607     g_list_append (ctx->current_module->entries, boxed);
608   
609   state_switch (ctx, STATE_BOXED);
610
611   return TRUE;
612 }
613
614 static gboolean
615 start_function (GMarkupParseContext *context,
616                 const gchar         *element_name,
617                 const gchar        **attribute_names,
618                 const gchar        **attribute_values,
619                 ParseContext        *ctx,
620                 GError             **error)
621 {
622   const gchar *name;
623   const gchar *symbol;
624   const gchar *deprecated;
625   GIrNodeFunction *function;
626   gboolean found = FALSE;
627   
628   switch (ctx->state)
629     {
630     case STATE_NAMESPACE:
631       found = (strcmp (element_name, "function") == 0 ||
632                strcmp (element_name, "callback") == 0);
633       break;
634     case STATE_CLASS:
635     case STATE_BOXED:
636     case STATE_STRUCT:
637     case STATE_UNION:
638       found = strcmp (element_name, "constructor") == 0;
639       /* fallthrough */
640     case STATE_INTERFACE:
641       found = (found ||
642                strcmp (element_name, "method") == 0 ||
643                strcmp (element_name, "callback") == 0);
644       break;
645     default:
646       break;
647     }
648
649   if (!found)
650     return FALSE;
651
652   name = find_attribute ("name", attribute_names, attribute_values);
653   symbol = find_attribute ("c:identifier", attribute_names, attribute_values);
654   deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
655       
656   if (name == NULL)
657     {
658       MISSING_ATTRIBUTE (context, error, element_name, "name");
659       return FALSE;
660     }
661   else if (strcmp (element_name, "callback") != 0 && symbol == NULL)
662     {
663       MISSING_ATTRIBUTE (context, error, element_name, "c:identifier");
664       return FALSE;
665     }
666
667   function = (GIrNodeFunction *) g_ir_node_new (G_IR_NODE_FUNCTION);
668       
669   ((GIrNode *)function)->name = g_strdup (name);
670   function->symbol = g_strdup (symbol);
671   function->parameters = NULL;
672   if (deprecated && strcmp (deprecated, "1") == 0)
673     function->deprecated = TRUE;
674   else
675     function->deprecated = FALSE;
676   
677   if (strcmp (element_name, "method") == 0 ||
678       strcmp (element_name, "constructor") == 0)
679     {
680       function->is_method = TRUE;
681       
682       if (strcmp (element_name, "constructor") == 0)
683         function->is_constructor = TRUE;
684       else
685         function->is_constructor = FALSE;
686     }
687   else
688     {
689       function->is_method = FALSE;
690       function->is_setter = FALSE;
691       function->is_getter = FALSE;
692       function->is_constructor = FALSE;
693       if (strcmp (element_name, "callback") == 0)
694         ((GIrNode *)function)->type = G_IR_NODE_CALLBACK;
695     }
696           
697   if (ctx->current_node == NULL)
698     {
699       ctx->current_module->entries = 
700         g_list_append (ctx->current_module->entries, function);       
701     }
702   else
703     switch (ctx->current_node->type)
704       {
705       case G_IR_NODE_INTERFACE:
706       case G_IR_NODE_OBJECT:
707         {
708           GIrNodeInterface *iface;
709           
710           iface = (GIrNodeInterface *)ctx->current_node;
711           iface->members = g_list_append (iface->members, function);
712         }
713         break;
714       case G_IR_NODE_BOXED:
715         {
716           GIrNodeBoxed *boxed;
717           
718           boxed = (GIrNodeBoxed *)ctx->current_node;
719           boxed->members = g_list_append (boxed->members, function);
720         }
721         break;
722       case G_IR_NODE_STRUCT:
723         {
724           GIrNodeStruct *struct_;
725           
726           struct_ = (GIrNodeStruct *)ctx->current_node;
727           struct_->members = g_list_append (struct_->members, function);                }
728         break;
729       case G_IR_NODE_UNION:
730         {
731           GIrNodeUnion *union_;
732           
733           union_ = (GIrNodeUnion *)ctx->current_node;
734           union_->members = g_list_append (union_->members, function);
735         }
736         break;
737       default:
738         g_assert_not_reached ();
739       }
740   
741   ctx->current_node = (GIrNode *)function;
742   state_switch (ctx, STATE_FUNCTION);
743   
744   return TRUE;
745 }
746
747 static gboolean
748 start_parameter (GMarkupParseContext *context,
749                  const gchar         *element_name,
750                  const gchar        **attribute_names,
751                  const gchar        **attribute_values,
752                  ParseContext        *ctx,
753                  GError             **error)
754 {
755   const gchar *name;
756   const gchar *direction;
757   const gchar *retval;
758   const gchar *dipper;
759   const gchar *optional;
760   const gchar *nullok;
761   const gchar *transfer;
762   GIrNodeParam *param;
763       
764   if (!(strcmp (element_name, "parameter") == 0 &&
765         ctx->state == STATE_FUNCTION_PARAMETERS))
766     return FALSE;
767
768   name = find_attribute ("name", attribute_names, attribute_values);
769   direction = find_attribute ("direction", attribute_names, attribute_values);
770   retval = find_attribute ("retval", attribute_names, attribute_values);
771   dipper = find_attribute ("dipper", attribute_names, attribute_values);
772   optional = find_attribute ("optional", attribute_names, attribute_values);
773   nullok = find_attribute ("null-ok", attribute_names, attribute_values);
774   transfer = find_attribute ("transfer", attribute_names, attribute_values);
775
776   if (name == NULL)
777     name = "unknown";
778
779   param = (GIrNodeParam *)g_ir_node_new (G_IR_NODE_PARAM);
780
781   ctx->current_typed = (GIrNode*) param;
782   ctx->current_typed->name = g_strdup (name);
783
784   state_switch (ctx, STATE_FUNCTION_PARAMETER);
785
786   if (direction && strcmp (direction, "out") == 0)
787     {
788       param->in = FALSE;
789       param->out = TRUE;
790     }
791   else if (direction && strcmp (direction, "inout") == 0)
792     {
793       param->in = TRUE;
794       param->out = TRUE;
795     }
796   else
797     {
798       param->in = TRUE;
799       param->out = FALSE;
800     }
801
802   if (retval && strcmp (retval, "1") == 0)
803     param->retval = TRUE;
804   else
805     param->retval = FALSE;
806
807   if (dipper && strcmp (dipper, "1") == 0)
808     param->dipper = TRUE;
809   else
810     param->dipper = FALSE;
811
812   if (optional && strcmp (optional, "1") == 0)
813     param->optional = TRUE;
814   else
815     param->optional = FALSE;
816
817   if (nullok && strcmp (nullok, "1") == 0)
818     param->null_ok = TRUE;
819   else
820     param->null_ok = FALSE;
821
822   if (transfer && strcmp (transfer, "none") == 0)
823     {
824       param->transfer = FALSE;
825       param->shallow_transfer = FALSE;
826     }
827   else if (transfer && strcmp (transfer, "shallow") == 0)
828     {
829       param->transfer = FALSE;
830       param->shallow_transfer = TRUE;
831     }
832   else 
833     {
834       if (transfer)
835         {
836           if (strcmp (transfer, "full") != 0)
837             g_warning ("Unknown transfer %s", transfer);
838           else
839             param->transfer = TRUE;
840         }
841       else if (param->in && !param->out)
842         param->transfer = FALSE;
843       else
844         param->transfer = TRUE;
845       param->shallow_transfer = FALSE;
846     }
847           
848   ((GIrNode *)param)->name = g_strdup (name);
849           
850   switch (ctx->current_node->type)
851     {
852     case G_IR_NODE_FUNCTION:
853     case G_IR_NODE_CALLBACK:
854       {
855         GIrNodeFunction *func;
856
857         func = (GIrNodeFunction *)ctx->current_node;
858         func->parameters = g_list_append (func->parameters, param);
859       }
860       break;
861     case G_IR_NODE_SIGNAL:
862       {
863         GIrNodeSignal *signal;
864
865         signal = (GIrNodeSignal *)ctx->current_node;
866         signal->parameters = g_list_append (signal->parameters, param);
867       }
868       break;
869     case G_IR_NODE_VFUNC:
870       {
871         GIrNodeVFunc *vfunc;
872                 
873         vfunc = (GIrNodeVFunc *)ctx->current_node;
874         vfunc->parameters = g_list_append (vfunc->parameters, param);
875       }
876       break;
877     default:
878       g_assert_not_reached ();
879     }
880
881   return TRUE;
882 }
883
884 static gboolean
885 start_field (GMarkupParseContext *context,
886              const gchar         *element_name,
887              const gchar        **attribute_names,
888              const gchar        **attribute_values,
889              ParseContext        *ctx,
890              GError             **error)
891 {
892   const gchar *name;
893   const gchar *readable;
894   const gchar *writable;
895   const gchar *bits;
896   const gchar *branch;
897   const gchar *offset;
898   GIrNodeField *field;
899
900   switch (ctx->state)
901     {
902     case STATE_CLASS:
903     case STATE_BOXED:
904     case STATE_STRUCT:
905     case STATE_UNION:
906     case STATE_INTERFACE:
907       break;
908     default:
909       return FALSE;
910     }
911   
912   if (strcmp (element_name, "field") != 0)
913     return FALSE;
914   
915   name = find_attribute ("name", attribute_names, attribute_values);
916   readable = find_attribute ("readable", attribute_names, attribute_values);
917   writable = find_attribute ("writable", attribute_names, attribute_values);
918   bits = find_attribute ("bits", attribute_names, attribute_values);
919   branch = find_attribute ("branch", attribute_names, attribute_values);
920   offset = find_attribute ("offset", attribute_names, attribute_values);
921   
922   if (name == NULL)
923     {
924       MISSING_ATTRIBUTE (context, error, element_name, "name");
925       return FALSE;
926     }
927
928   field = (GIrNodeField *)g_ir_node_new (G_IR_NODE_FIELD);
929   ctx->current_typed = (GIrNode*) field;
930   ((GIrNode *)field)->name = g_strdup (name);
931   if (readable && strcmp (readable, "1") == 0)
932     field->readable = TRUE;
933   else
934     field->readable = FALSE;
935   
936   if (writable && strcmp (writable, "1") == 0)
937     field->writable = TRUE;
938   else
939     field->writable = FALSE;
940   
941   if (bits)
942     field->bits = atoi (bits);
943   else
944     field->bits = 0;
945   
946   if (offset)
947     field->offset = atoi (offset);
948   else
949     field->offset = 0;
950   
951   switch (ctx->current_node->type)
952     {
953     case G_IR_NODE_OBJECT:
954       {
955         GIrNodeInterface *iface;
956         
957         iface = (GIrNodeInterface *)ctx->current_node;
958         iface->members = g_list_append (iface->members, field);
959         state_switch (ctx, STATE_CLASS_FIELD);
960       }
961       break;
962     case G_IR_NODE_INTERFACE:
963       {
964         GIrNodeInterface *iface;
965         
966         iface = (GIrNodeInterface *)ctx->current_node;
967         iface->members = g_list_append (iface->members, field);
968         state_switch (ctx, STATE_INTERFACE_FIELD);
969       }
970       break;
971     case G_IR_NODE_BOXED:
972       {
973         GIrNodeBoxed *boxed;
974         
975         boxed = (GIrNodeBoxed *)ctx->current_node;
976                 boxed->members = g_list_append (boxed->members, field);
977                 state_switch (ctx, STATE_BOXED_FIELD);
978       }
979       break;
980     case G_IR_NODE_STRUCT:
981       {
982         GIrNodeStruct *struct_;
983         
984         struct_ = (GIrNodeStruct *)ctx->current_node;
985         struct_->members = g_list_append (struct_->members, field);
986         state_switch (ctx, STATE_STRUCT_FIELD);
987       }
988       break;
989     case G_IR_NODE_UNION:
990       {
991         GIrNodeUnion *union_;
992         
993         union_ = (GIrNodeUnion *)ctx->current_node;
994         union_->members = g_list_append (union_->members, field);
995         if (branch)
996           {
997             GIrNodeConstant *constant;
998             
999             constant = (GIrNodeConstant *) g_ir_node_new (G_IR_NODE_CONSTANT);
1000             ((GIrNode *)constant)->name = g_strdup (name);
1001             constant->value = g_strdup (branch);          
1002             constant->type = union_->discriminator_type;
1003             constant->deprecated = FALSE;
1004             
1005             union_->discriminators = g_list_append (union_->discriminators, constant);
1006           }
1007         state_switch (ctx, STATE_UNION_FIELD);
1008       }
1009       break;
1010     default:
1011       g_assert_not_reached ();
1012     }
1013   
1014   return TRUE;
1015 }
1016
1017 static gboolean
1018 start_alias (GMarkupParseContext *context,
1019              const gchar         *element_name,
1020              const gchar        **attribute_names,
1021              const gchar        **attribute_values,
1022              ParseContext        *ctx,
1023              GError             **error)
1024 {
1025   const gchar *name;
1026   const gchar *target;
1027   const gchar *type;
1028   char *key;
1029   char *value;
1030
1031   name = find_attribute ("name", attribute_names, attribute_values);
1032   if (name == NULL)
1033     {
1034       MISSING_ATTRIBUTE (context, error, element_name, "name");
1035       return FALSE;
1036     }
1037
1038   target = find_attribute ("target", attribute_names, attribute_values);
1039   if (name == NULL)
1040     {
1041       MISSING_ATTRIBUTE (context, error, element_name, "target");
1042       return FALSE;
1043     }
1044
1045   if (ctx->prefix_aliases)
1046     key = g_strdup_printf ("%s.%s", ctx->namespace, name);
1047   else
1048     key = g_strdup (name);
1049   
1050   g_hash_table_insert (ctx->aliases, key, g_strdup (target));
1051
1052   return TRUE;
1053 }
1054
1055 static gboolean
1056 start_enum (GMarkupParseContext *context,
1057              const gchar         *element_name,
1058              const gchar        **attribute_names,
1059              const gchar        **attribute_values,
1060              ParseContext        *ctx,
1061              GError             **error)
1062 {
1063   if ((strcmp (element_name, "enumeration") == 0 && ctx->state == STATE_NAMESPACE) ||
1064       (strcmp (element_name, "bitfield") == 0 && ctx->state == STATE_NAMESPACE))
1065     {
1066       const gchar *name;
1067       const gchar *typename;
1068       const gchar *typeinit;
1069       const gchar *deprecated;
1070       
1071       name = find_attribute ("name", attribute_names, attribute_values);
1072       typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
1073       typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
1074       deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
1075       
1076       if (name == NULL)
1077         MISSING_ATTRIBUTE (context, error, element_name, "name");
1078       else 
1079         {             
1080           GIrNodeEnum *enum_;
1081           
1082           if (strcmp (element_name, "enumeration") == 0)
1083             enum_ = (GIrNodeEnum *) g_ir_node_new (G_IR_NODE_ENUM);
1084           else
1085             enum_ = (GIrNodeEnum *) g_ir_node_new (G_IR_NODE_FLAGS);
1086           ((GIrNode *)enum_)->name = g_strdup (name);
1087           enum_->gtype_name = g_strdup (typename);
1088           enum_->gtype_init = g_strdup (typeinit);
1089           if (deprecated && strcmp (deprecated, "1") == 0)
1090             enum_->deprecated = TRUE;
1091           else
1092             enum_->deprecated = FALSE;
1093
1094           ctx->current_node = (GIrNode *) enum_;
1095           ctx->current_module->entries = 
1096             g_list_append (ctx->current_module->entries, enum_);              
1097           
1098           state_switch (ctx, STATE_ENUM);
1099         }
1100       
1101       return TRUE;
1102     }
1103   return FALSE;
1104 }
1105
1106 static gboolean
1107 start_property (GMarkupParseContext *context,
1108                 const gchar         *element_name,
1109                 const gchar        **attribute_names,
1110                 const gchar        **attribute_values,
1111                 ParseContext        *ctx,
1112                 GError             **error)
1113 {
1114   if (strcmp (element_name, "property") == 0 &&
1115       (ctx->state == STATE_CLASS ||
1116        ctx->state == STATE_INTERFACE))
1117     {
1118       const gchar *name;
1119       const gchar *readable;
1120       const gchar *writable;
1121       const gchar *construct;
1122       const gchar *construct_only;
1123       
1124       name = find_attribute ("name", attribute_names, attribute_values);
1125       readable = find_attribute ("readable", attribute_names, attribute_values);
1126       writable = find_attribute ("writable", attribute_names, attribute_values);
1127       construct = find_attribute ("construct", attribute_names, attribute_values);
1128       construct_only = find_attribute ("construct-only", attribute_names, attribute_values);
1129       
1130       if (name == NULL)
1131         MISSING_ATTRIBUTE (context, error, element_name, "name");
1132       else 
1133         {             
1134           GIrNodeProperty *property;
1135           GIrNodeInterface *iface;
1136           
1137           property = (GIrNodeProperty *) g_ir_node_new (G_IR_NODE_PROPERTY);
1138           ctx->current_typed = (GIrNode*) property;
1139
1140           ((GIrNode *)property)->name = g_strdup (name);
1141           
1142           if (readable && strcmp (readable, "1") == 0)
1143             property->readable = TRUE;
1144           else
1145             property->readable = FALSE;
1146           if (writable && strcmp (writable, "1") == 0)
1147             property->writable = TRUE;
1148           else
1149             property->writable = FALSE;
1150           if (construct && strcmp (construct, "1") == 0)
1151             property->construct = TRUE;
1152           else
1153             property->construct = FALSE;
1154           if (construct_only && strcmp (construct_only, "1") == 0)
1155             property->construct_only = TRUE;
1156           else
1157             property->construct_only = FALSE;
1158
1159           iface = (GIrNodeInterface *)ctx->current_node;
1160           iface->members = g_list_append (iface->members, property);
1161
1162           if (ctx->state == STATE_CLASS)
1163             state_switch (ctx, STATE_CLASS_PROPERTY);
1164           else if (ctx->state == STATE_INTERFACE)
1165             state_switch (ctx, STATE_INTERFACE_PROPERTY);
1166           else
1167             g_assert_not_reached ();
1168         }
1169       
1170       return TRUE;
1171     }
1172   return FALSE;
1173 }
1174
1175 static gint
1176 parse_value (const gchar *str)
1177 {
1178   gchar *shift_op;
1179  
1180   /* FIXME just a quick hack */
1181   shift_op = strstr (str, "<<");
1182
1183   if (shift_op)
1184     {
1185       gint base, shift;
1186
1187       base = strtol (str, NULL, 10);
1188       shift = strtol (shift_op + 3, NULL, 10);
1189       
1190       return base << shift;
1191     }
1192   else
1193     return strtol (str, NULL, 10);
1194
1195   return 0;
1196 }
1197
1198 static gboolean
1199 start_member (GMarkupParseContext *context,
1200               const gchar         *element_name,
1201               const gchar        **attribute_names,
1202               const gchar        **attribute_values,
1203               ParseContext        *ctx,
1204               GError             **error)
1205 {
1206   if (strcmp (element_name, "member") == 0 &&
1207       ctx->state == STATE_ENUM)
1208     {
1209       const gchar *name;
1210       const gchar *value;
1211       const gchar *deprecated;
1212       
1213       name = find_attribute ("name", attribute_names, attribute_values);
1214       value = find_attribute ("value", attribute_names, attribute_values);
1215       deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
1216       
1217       if (name == NULL)
1218         MISSING_ATTRIBUTE (context, error, element_name, "name");
1219       else 
1220         {             
1221           GIrNodeEnum *enum_;
1222           GIrNodeValue *value_;
1223
1224           value_ = (GIrNodeValue *) g_ir_node_new (G_IR_NODE_VALUE);
1225
1226           ((GIrNode *)value_)->name = g_strdup (name);
1227           
1228           value_->value = parse_value (value);
1229           
1230           if (deprecated && strcmp (deprecated, "1") == 0)
1231             value_->deprecated = TRUE;
1232           else
1233             value_->deprecated = FALSE;
1234
1235           enum_ = (GIrNodeEnum *)ctx->current_node;
1236           enum_->values = g_list_append (enum_->values, value_);
1237         }
1238       
1239       return TRUE;
1240     }
1241   return FALSE;
1242 }
1243
1244 static gboolean
1245 start_constant (GMarkupParseContext *context,
1246                 const gchar         *element_name,
1247                 const gchar        **attribute_names,
1248                 const gchar        **attribute_values,
1249                 ParseContext        *ctx,
1250                 GError             **error)
1251 {
1252   if (strcmp (element_name, "constant") == 0 &&
1253       (ctx->state == STATE_NAMESPACE ||
1254        ctx->state == STATE_CLASS ||
1255        ctx->state == STATE_INTERFACE))
1256     {
1257       const gchar *name;
1258       const gchar *value;
1259       const gchar *deprecated;
1260       
1261       name = find_attribute ("name", attribute_names, attribute_values);
1262       value = find_attribute ("value", attribute_names, attribute_values);
1263       deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
1264       
1265       if (name == NULL)
1266         MISSING_ATTRIBUTE (context, error, element_name, "name");
1267       else if (value == NULL)
1268         MISSING_ATTRIBUTE (context, error, element_name, "value");
1269       else 
1270         {             
1271           GIrNodeConstant *constant;
1272
1273           constant = (GIrNodeConstant *) g_ir_node_new (G_IR_NODE_CONSTANT);
1274
1275           ((GIrNode *)constant)->name = g_strdup (name);
1276           constant->value = g_strdup (value);
1277
1278           ctx->current_typed = (GIrNode*) constant;
1279
1280           if (deprecated && strcmp (deprecated, "1") == 0)
1281             constant->deprecated = TRUE;
1282           else
1283             constant->deprecated = FALSE;
1284
1285           if (ctx->state == STATE_NAMESPACE)
1286             {
1287               ctx->current_node = (GIrNode *) constant;
1288               ctx->current_module->entries = 
1289                 g_list_append (ctx->current_module->entries, constant);
1290             }
1291           else
1292             {
1293               GIrNodeInterface *iface;
1294
1295               iface = (GIrNodeInterface *)ctx->current_node;
1296               iface->members = g_list_append (iface->members, constant);
1297             }
1298
1299           switch (ctx->state)
1300             {
1301             case STATE_NAMESPACE:
1302               state_switch (ctx, STATE_NAMESPACE_CONSTANT);
1303               break;
1304             case STATE_CLASS:
1305               state_switch (ctx, STATE_CLASS_CONSTANT);
1306               break;
1307             case STATE_INTERFACE:
1308               state_switch (ctx, STATE_INTERFACE_CONSTANT);
1309               break;
1310             default:
1311               g_assert_not_reached ();
1312               break;
1313             }
1314         }
1315       
1316       return TRUE;
1317     }
1318   return FALSE;
1319 }
1320
1321 static gboolean
1322 start_errordomain (GMarkupParseContext *context,
1323                    const gchar         *element_name,
1324                    const gchar        **attribute_names,
1325                    const gchar        **attribute_values,
1326                    ParseContext        *ctx,
1327                    GError             **error)
1328 {
1329   if (strcmp (element_name, "errordomain") == 0 &&
1330       ctx->state == STATE_NAMESPACE)
1331     {
1332       const gchar *name;
1333       const gchar *getquark;
1334       const gchar *codes;
1335       const gchar *deprecated;
1336       
1337       name = find_attribute ("name", attribute_names, attribute_values);
1338       getquark = find_attribute ("get-quark", attribute_names, attribute_values);
1339       codes = find_attribute ("codes", attribute_names, attribute_values);
1340       deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
1341       
1342       if (name == NULL)
1343         MISSING_ATTRIBUTE (context, error, element_name, "name");
1344       else if (getquark == NULL)
1345         MISSING_ATTRIBUTE (context, error, element_name, "getquark");
1346       else if (codes == NULL)
1347         MISSING_ATTRIBUTE (context, error, element_name, "codes");
1348       else 
1349         {             
1350           GIrNodeErrorDomain *domain;
1351
1352           domain = (GIrNodeErrorDomain *) g_ir_node_new (G_IR_NODE_ERROR_DOMAIN);
1353
1354           ((GIrNode *)domain)->name = g_strdup (name);
1355           domain->getquark = g_strdup (getquark);
1356           domain->codes = g_strdup (codes);
1357
1358           if (deprecated && strcmp (deprecated, "1") == 0)
1359             domain->deprecated = TRUE;
1360           else
1361             domain->deprecated = FALSE;
1362
1363           ctx->current_node = (GIrNode *) domain;
1364           ctx->current_module->entries = 
1365             g_list_append (ctx->current_module->entries, domain);
1366
1367           state_switch (ctx, STATE_ERRORDOMAIN);
1368         }
1369       
1370       return TRUE;
1371     }
1372   return FALSE;
1373 }
1374
1375 static gboolean
1376 start_interface (GMarkupParseContext *context,
1377                  const gchar         *element_name,
1378                  const gchar        **attribute_names,
1379                  const gchar        **attribute_values,
1380                  ParseContext        *ctx,
1381                  GError             **error)
1382 {
1383   if (strcmp (element_name, "interface") == 0 &&
1384       ctx->state == STATE_NAMESPACE)
1385     {
1386       const gchar *name;
1387       const gchar *typename;
1388       const gchar *typeinit;
1389       const gchar *deprecated;
1390       
1391       name = find_attribute ("name", attribute_names, attribute_values);
1392       typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
1393       typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
1394       deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
1395       
1396       if (name == NULL)
1397         MISSING_ATTRIBUTE (context, error, element_name, "name");
1398       else if (typename == NULL)
1399         MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name");
1400       else if (typeinit == NULL)
1401         MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
1402       else
1403         {
1404           GIrNodeInterface *iface;
1405
1406           iface = (GIrNodeInterface *) g_ir_node_new (G_IR_NODE_INTERFACE);
1407           ((GIrNode *)iface)->name = g_strdup (name);
1408           iface->gtype_name = g_strdup (typename);
1409           iface->gtype_init = g_strdup (typeinit);
1410           if (deprecated && strcmp (deprecated, "1") == 0)
1411             iface->deprecated = TRUE;
1412           else
1413             iface->deprecated = FALSE;
1414           
1415           ctx->current_node = (GIrNode *) iface;
1416           ctx->current_module->entries = 
1417             g_list_append (ctx->current_module->entries, iface);              
1418           
1419           state_switch (ctx, STATE_INTERFACE);
1420           
1421         }
1422       
1423       return TRUE;
1424     }
1425   return FALSE;
1426 }
1427
1428 static gboolean
1429 start_class (GMarkupParseContext *context,
1430               const gchar         *element_name,
1431               const gchar        **attribute_names,
1432               const gchar        **attribute_values,
1433               ParseContext        *ctx,
1434               GError             **error)
1435 {
1436   if (strcmp (element_name, "class") == 0 &&
1437       ctx->state == STATE_NAMESPACE)
1438     {
1439       const gchar *name;
1440       const gchar *parent;
1441       const gchar *typename;
1442       const gchar *typeinit;
1443       const gchar *deprecated;
1444       
1445       name = find_attribute ("name", attribute_names, attribute_values);
1446       parent = find_attribute ("parent", attribute_names, attribute_values);
1447       typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
1448       typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
1449       deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
1450       
1451       if (name == NULL)
1452         MISSING_ATTRIBUTE (context, error, element_name, "name");
1453       else if (typename == NULL)
1454         MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name");
1455       else if (typeinit == NULL && strcmp (typename, "GObject"))
1456         MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
1457       else
1458         {
1459           GIrNodeInterface *iface;
1460
1461           iface = (GIrNodeInterface *) g_ir_node_new (G_IR_NODE_OBJECT);
1462           ((GIrNode *)iface)->name = g_strdup (name);
1463           iface->gtype_name = g_strdup (typename);
1464           iface->gtype_init = g_strdup (typeinit);
1465           iface->parent = g_strdup (parent);
1466           if (deprecated && strcmp (deprecated, "1") == 0)
1467             iface->deprecated = TRUE;
1468           else
1469             iface->deprecated = FALSE;
1470           
1471           ctx->current_node = (GIrNode *) iface;
1472           ctx->current_module->entries = 
1473             g_list_append (ctx->current_module->entries, iface);              
1474           
1475           state_switch (ctx, STATE_CLASS);
1476         }
1477       
1478       return TRUE;
1479     }
1480   return  FALSE;
1481 }
1482
1483 static gboolean
1484 start_type (GMarkupParseContext *context,
1485             const gchar         *element_name,
1486             const gchar        **attribute_names,
1487             const gchar        **attribute_values,
1488             ParseContext       *ctx,
1489             GError             **error)
1490 {
1491   const gchar *name;
1492
1493   if (strcmp (element_name, "type") != 0)
1494     return FALSE;
1495
1496   if (ctx->state == STATE_TYPE)
1497     ctx->type_depth++;
1498   else if (ctx->state == STATE_FUNCTION_PARAMETER ||
1499            ctx->state == STATE_FUNCTION_RETURN || 
1500            ctx->state == STATE_STRUCT_FIELD ||
1501            ctx->state == STATE_UNION_FIELD ||
1502            ctx->state == STATE_CLASS_PROPERTY ||
1503            ctx->state == STATE_CLASS_FIELD ||
1504            ctx->state == STATE_INTERFACE_FIELD ||
1505            ctx->state == STATE_INTERFACE_PROPERTY ||
1506            ctx->state == STATE_BOXED_FIELD ||
1507            ctx->state == STATE_NAMESPACE_CONSTANT ||
1508            ctx->state == STATE_CLASS_CONSTANT ||
1509            ctx->state == STATE_INTERFACE_CONSTANT
1510            )
1511     {
1512       state_switch (ctx, STATE_TYPE);
1513       ctx->type_depth = 1;
1514     }
1515
1516   /* FIXME handle recursive types */
1517   if (ctx->type_depth > 1)
1518     return TRUE;
1519
1520   if (!ctx->current_typed)
1521     {
1522       g_set_error (error,
1523                    G_MARKUP_ERROR,
1524                    G_MARKUP_ERROR_INVALID_CONTENT,
1525                    "The element <type> is invalid here");
1526       return FALSE;
1527     }
1528   
1529   name = find_attribute ("name", attribute_names, attribute_values);
1530
1531   if (name == NULL)
1532     MISSING_ATTRIBUTE (context, error, element_name, "name");
1533   
1534   switch (ctx->current_typed->type)
1535     {
1536     case G_IR_NODE_PARAM:
1537       {
1538         GIrNodeParam *param = (GIrNodeParam *)ctx->current_typed;
1539         param->type = parse_type (ctx, name);
1540       }
1541       break;
1542     case G_IR_NODE_FIELD:
1543       {
1544         GIrNodeField *field = (GIrNodeField *)ctx->current_typed;
1545         field->type = parse_type (ctx, name);
1546       }
1547       break;
1548     case G_IR_NODE_PROPERTY:
1549       {
1550         GIrNodeProperty *property = (GIrNodeProperty *) ctx->current_typed;
1551         property->type = parse_type (ctx, name);
1552       }
1553       break;
1554     case G_IR_NODE_CONSTANT:
1555       {
1556         GIrNodeConstant *constant = (GIrNodeConstant *)ctx->current_typed;
1557         constant->type = parse_type (ctx, name);
1558       }
1559       break;
1560     default:
1561       g_printerr("current node is %d\n", ctx->current_node->type);
1562       g_assert_not_reached ();
1563     }
1564
1565   ctx->current_typed = NULL;
1566   return TRUE;
1567 }
1568
1569 static gboolean
1570 start_return_value (GMarkupParseContext *context,
1571                     const gchar         *element_name,
1572                     const gchar        **attribute_names,
1573                     const gchar        **attribute_values,
1574                     ParseContext       *ctx,
1575                     GError             **error)
1576 {
1577   if (strcmp (element_name, "return-value") == 0 &&
1578       ctx->state == STATE_FUNCTION)
1579     {
1580       GIrNodeParam *param;
1581
1582       param = (GIrNodeParam *)g_ir_node_new (G_IR_NODE_PARAM);
1583       param->in = FALSE;
1584       param->out = FALSE;
1585       param->retval = TRUE;
1586
1587       ctx->current_typed = (GIrNode*) param;
1588
1589       state_switch (ctx, STATE_FUNCTION_RETURN);
1590
1591       switch (ctx->current_node->type)
1592         {
1593         case G_IR_NODE_FUNCTION:
1594         case G_IR_NODE_CALLBACK:
1595           {
1596             GIrNodeFunction *func = (GIrNodeFunction *)ctx->current_node;
1597             func->result = param;
1598           }
1599           break;
1600         case G_IR_NODE_SIGNAL:
1601           {
1602             GIrNodeSignal *signal = (GIrNodeSignal *)ctx->current_node;
1603             signal->result = param;
1604           }
1605           break;
1606         case G_IR_NODE_VFUNC:
1607           {
1608             GIrNodeVFunc *vfunc = (GIrNodeVFunc *)ctx->current_node;
1609             vfunc->result = param;
1610           }
1611           break;
1612         default:
1613           g_assert_not_reached ();
1614         }
1615       
1616       return TRUE;
1617     }
1618
1619   return FALSE;
1620 }
1621
1622 static gboolean
1623 start_implements (GMarkupParseContext *context,
1624                   const gchar         *element_name,
1625                   const gchar        **attribute_names,
1626                   const gchar        **attribute_values,
1627                   ParseContext       *ctx,
1628                   GError             **error)
1629 {
1630   GIrNodeInterface *iface;
1631   const char *name;
1632
1633   if (strcmp (element_name, "implements") != 0 ||
1634       !(ctx->state == STATE_CLASS))
1635     return FALSE;
1636
1637   state_switch (ctx, STATE_IMPLEMENTS);
1638   
1639   name = find_attribute ("name", attribute_names, attribute_values);
1640   if (name == NULL)
1641     {
1642       MISSING_ATTRIBUTE (context, error, element_name, "name");
1643       return FALSE;
1644     }
1645       
1646   iface = (GIrNodeInterface *)ctx->current_node;
1647   iface->interfaces = g_list_append (iface->interfaces, g_strdup (name));
1648
1649   return TRUE;
1650 }
1651
1652 static gboolean
1653 start_glib_signal (GMarkupParseContext *context,
1654                    const gchar         *element_name,
1655                    const gchar        **attribute_names,
1656                    const gchar        **attribute_values,
1657                    ParseContext       *ctx,
1658                    GError             **error)
1659 {
1660   if (strcmp (element_name, "glib:signal") == 0 && 
1661       (ctx->state == STATE_CLASS ||
1662        ctx->state == STATE_INTERFACE))
1663     {
1664       const gchar *name;
1665       const gchar *when;
1666       const gchar *no_recurse;
1667       const gchar *detailed;
1668       const gchar *action;
1669       const gchar *no_hooks;
1670       const gchar *has_class_closure;
1671       
1672       name = find_attribute ("name", attribute_names, attribute_values);
1673       when = find_attribute ("when", attribute_names, attribute_values);
1674       no_recurse = find_attribute ("no-recurse", attribute_names, attribute_values);
1675       detailed = find_attribute ("detailed", attribute_names, attribute_values);
1676       action = find_attribute ("action", attribute_names, attribute_values);
1677       no_hooks = find_attribute ("no-hooks", attribute_names, attribute_values);
1678       has_class_closure = find_attribute ("has-class-closure", attribute_names, attribute_values);
1679       
1680       if (name == NULL)
1681         MISSING_ATTRIBUTE (context, error, element_name, "name");
1682       else
1683         {
1684           GIrNodeInterface *iface;
1685           GIrNodeSignal *signal;
1686
1687           signal = (GIrNodeSignal *)g_ir_node_new (G_IR_NODE_SIGNAL);
1688           
1689           ((GIrNode *)signal)->name = g_strdup (name);
1690           
1691           signal->run_first = FALSE;
1692           signal->run_last = FALSE;
1693           signal->run_cleanup = FALSE;
1694           if (when == NULL || strcmp (when, "LAST") == 0)
1695             signal->run_last = TRUE;
1696           else if (strcmp (when, "FIRST") == 0)
1697             signal->run_first = TRUE;
1698           else 
1699             signal->run_cleanup = TRUE;
1700           
1701           if (no_recurse && strcmp (no_recurse, "1") == 0)
1702             signal->no_recurse = TRUE;
1703           else
1704             signal->no_recurse = FALSE;
1705           if (detailed && strcmp (detailed, "1") == 0)
1706             signal->detailed = TRUE;
1707           else
1708             signal->detailed = FALSE;
1709           if (action && strcmp (action, "1") == 0)
1710             signal->action = TRUE;
1711           else
1712             signal->action = FALSE;
1713           if (no_hooks && strcmp (no_hooks, "1") == 0)
1714             signal->no_hooks = TRUE;
1715           else
1716             signal->no_hooks = FALSE;
1717           if (has_class_closure && strcmp (has_class_closure, "1") == 0)
1718             signal->has_class_closure = TRUE;
1719           else
1720             signal->has_class_closure = FALSE;
1721
1722           iface = (GIrNodeInterface *)ctx->current_node;
1723           iface->members = g_list_append (iface->members, signal);
1724
1725           ctx->current_node = (GIrNode *)signal;
1726           state_switch (ctx, STATE_FUNCTION);
1727         }
1728       
1729       return TRUE;
1730     }
1731   return FALSE;
1732 }
1733
1734 static gboolean
1735 start_vfunc (GMarkupParseContext *context,
1736              const gchar         *element_name,
1737              const gchar        **attribute_names,
1738              const gchar        **attribute_values,
1739              ParseContext       *ctx,
1740              GError             **error)
1741 {
1742   if (strcmp (element_name, "vfunc") == 0 && 
1743       (ctx->state == STATE_CLASS ||
1744        ctx->state == STATE_INTERFACE))
1745     {
1746       const gchar *name;
1747       const gchar *must_chain_up;
1748       const gchar *override;
1749       const gchar *is_class_closure;
1750       const gchar *offset;
1751       
1752       name = find_attribute ("name", attribute_names, attribute_values);
1753       must_chain_up = find_attribute ("must-chain-up", attribute_names, attribute_values);        
1754       override = find_attribute ("override", attribute_names, attribute_values);
1755       is_class_closure = find_attribute ("is-class-closure", attribute_names, attribute_values);
1756       offset = find_attribute ("offset", attribute_names, attribute_values);
1757       
1758       if (name == NULL)
1759         MISSING_ATTRIBUTE (context, error, element_name, "name");
1760       else
1761         {
1762           GIrNodeInterface *iface;
1763           GIrNodeVFunc *vfunc;
1764
1765           vfunc = (GIrNodeVFunc *)g_ir_node_new (G_IR_NODE_VFUNC);
1766           
1767           ((GIrNode *)vfunc)->name = g_strdup (name);
1768
1769           if (must_chain_up && strcmp (must_chain_up, "1") == 0)
1770             vfunc->must_chain_up = TRUE;
1771           else
1772             vfunc->must_chain_up = FALSE;
1773
1774           if (override && strcmp (override, "always") == 0)
1775             {
1776               vfunc->must_be_implemented = TRUE;
1777               vfunc->must_not_be_implemented = FALSE;
1778             }
1779           else if (override && strcmp (override, "never") == 0)
1780             {
1781               vfunc->must_be_implemented = FALSE;
1782               vfunc->must_not_be_implemented = TRUE;
1783             }
1784           else
1785             {
1786               vfunc->must_be_implemented = FALSE;
1787               vfunc->must_not_be_implemented = FALSE;
1788             }
1789           
1790           if (is_class_closure && strcmp (is_class_closure, "1") == 0)
1791             vfunc->is_class_closure = TRUE;
1792           else
1793             vfunc->is_class_closure = FALSE;
1794           
1795           if (offset)
1796             vfunc->offset = atoi (offset);
1797           else
1798             vfunc->offset = 0;
1799
1800           iface = (GIrNodeInterface *)ctx->current_node;
1801           iface->members = g_list_append (iface->members, vfunc);
1802
1803           ctx->current_node = (GIrNode *)vfunc;
1804           state_switch (ctx, STATE_FUNCTION);
1805         }
1806       
1807       return TRUE;
1808     }
1809   return FALSE;
1810 }
1811
1812
1813 static gboolean
1814 start_struct (GMarkupParseContext *context,
1815               const gchar         *element_name,
1816               const gchar        **attribute_names,
1817               const gchar        **attribute_values,
1818               ParseContext       *ctx,
1819               GError             **error)
1820 {
1821   if (strcmp (element_name, "record") == 0 && 
1822       ctx->state == STATE_NAMESPACE)
1823     {
1824       const gchar *name;
1825       const gchar *deprecated;
1826       
1827       name = find_attribute ("name", attribute_names, attribute_values);
1828       deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
1829       
1830       if (name == NULL)
1831         MISSING_ATTRIBUTE (context, error, element_name, "name");
1832       else
1833         {
1834           GIrNodeStruct *struct_;
1835
1836           struct_ = (GIrNodeStruct *) g_ir_node_new (G_IR_NODE_STRUCT);
1837           
1838           ((GIrNode *)struct_)->name = g_strdup (name);
1839           if (deprecated && strcmp (deprecated, "1") == 0)
1840             struct_->deprecated = TRUE;
1841           else
1842             struct_->deprecated = FALSE;
1843
1844           ctx->current_node = (GIrNode *)struct_;
1845           ctx->current_module->entries = 
1846             g_list_append (ctx->current_module->entries, struct_);
1847           
1848           state_switch (ctx, STATE_STRUCT);
1849         }
1850       return TRUE;
1851     }
1852   return FALSE;
1853 }
1854   
1855
1856 static gboolean
1857 start_union (GMarkupParseContext *context,
1858              const gchar         *element_name,
1859              const gchar        **attribute_names,
1860              const gchar        **attribute_values,
1861              ParseContext       *ctx,
1862              GError             **error)
1863 {
1864   if (strcmp (element_name, "union") == 0 && 
1865       ctx->state == STATE_NAMESPACE)
1866     {
1867       const gchar *name;
1868       const gchar *deprecated;
1869       const gchar *typename;
1870       const gchar *typeinit;
1871       
1872       name = find_attribute ("name", attribute_names, attribute_values);
1873       deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
1874       typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
1875       typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
1876       
1877       if (name == NULL)
1878         MISSING_ATTRIBUTE (context, error, element_name, "name");
1879       else
1880         {
1881           GIrNodeUnion *union_;
1882
1883           union_ = (GIrNodeUnion *) g_ir_node_new (G_IR_NODE_UNION);
1884           
1885           ((GIrNode *)union_)->name = g_strdup (name);
1886           union_->gtype_name = g_strdup (typename);
1887           union_->gtype_init = g_strdup (typeinit);
1888           if (deprecated && strcmp (deprecated, "1") == 0)
1889             union_->deprecated = TRUE;
1890           else
1891             union_->deprecated = FALSE;
1892
1893           ctx->current_node = (GIrNode *)union_;
1894           ctx->current_module->entries = 
1895             g_list_append (ctx->current_module->entries, union_);
1896           
1897           state_switch (ctx, STATE_UNION);
1898         }
1899       return TRUE;
1900     }
1901   return FALSE;
1902 }
1903
1904 static gboolean
1905 start_discriminator (GMarkupParseContext *context,
1906                      const gchar         *element_name,
1907                      const gchar        **attribute_names,
1908                      const gchar        **attribute_values,
1909                      ParseContext       *ctx,
1910                      GError             **error)
1911 {
1912   if (strcmp (element_name, "discriminator") == 0 &&
1913       ctx->state == STATE_UNION)
1914     {
1915       const gchar *type;
1916       const gchar *offset;
1917       
1918       type = find_attribute ("type", attribute_names, attribute_values);
1919       offset = find_attribute ("offset", attribute_names, attribute_values);
1920       if (type == NULL)
1921         MISSING_ATTRIBUTE (context, error, element_name, "type");
1922       else if (offset == NULL)
1923         MISSING_ATTRIBUTE (context, error, element_name, "offset");
1924         {
1925           ((GIrNodeUnion *)ctx->current_node)->discriminator_type 
1926             = parse_type (ctx, type);
1927           ((GIrNodeUnion *)ctx->current_node)->discriminator_offset 
1928             = atoi (offset);
1929         }
1930       
1931       return TRUE;
1932     }
1933
1934   return FALSE;
1935 }
1936
1937 static gboolean
1938 parse_include (GMarkupParseContext *context,
1939                ParseContext        *ctx,
1940                const char          *name,
1941                GError             **error)
1942 {
1943   ParseContext sub_ctx = { 0 };
1944   GMarkupParseContext *sub_context;
1945   gchar *buffer;
1946   gsize length;
1947   char *girpath;
1948   
1949   girpath = locate_gir (name, ctx->includes);
1950
1951   if (girpath == NULL)
1952     {
1953       g_set_error (error,
1954                    G_MARKUP_ERROR,
1955                    G_MARKUP_ERROR_INVALID_CONTENT,
1956                    "Could not find GIR file '%s'; check XDG_DATA_DIRS or use --includedir",
1957                    name);
1958       return FALSE;
1959     }
1960
1961   g_debug ("Parsing include %s", girpath);
1962
1963   if (!g_file_get_contents (girpath, &buffer, &length, error))
1964     {
1965       g_free (girpath);
1966       return FALSE;
1967     }
1968   g_free (girpath);
1969
1970   sub_ctx.state = STATE_START;
1971   sub_ctx.prefix_aliases = TRUE;
1972   sub_ctx.namespace = name;
1973   sub_ctx.aliases = ctx->aliases;
1974   sub_ctx.type_depth = 0;
1975
1976   context = g_markup_parse_context_new (&firstpass_parser, 0, &sub_ctx, NULL);
1977           
1978   if (!g_markup_parse_context_parse (context, buffer, length, error))
1979     {
1980       g_free (buffer);
1981       return FALSE;
1982     }
1983           
1984   if (!g_markup_parse_context_end_parse (context, error))
1985     {
1986       g_free (buffer);
1987       return FALSE;
1988     }
1989           
1990   g_markup_parse_context_free (context);
1991   return TRUE;
1992 }
1993   
1994 extern GLogLevelFlags logged_levels;
1995
1996 static void
1997 start_element_handler (GMarkupParseContext *context,
1998                        const gchar         *element_name,
1999                        const gchar        **attribute_names,
2000                        const gchar        **attribute_values,
2001                        gpointer             user_data,
2002                        GError             **error)
2003 {
2004   ParseContext *ctx = user_data;
2005   gint line_number, char_number;
2006
2007   if (logged_levels & G_LOG_LEVEL_DEBUG)
2008     {
2009       GString *tags = g_string_new ("");
2010       int i;
2011       for (i = 0; attribute_names[i]; i++)
2012         g_string_append_printf (tags, "%s=\"%s\" ",
2013                                 attribute_names[i],
2014                                 attribute_values[i]);
2015
2016       if (i)
2017         {
2018           g_string_insert_c (tags, 0, ' ');
2019           g_string_truncate (tags, tags->len - 1);
2020         }
2021       g_debug ("<%s%s>", element_name, tags->str);
2022       g_string_free (tags, TRUE);
2023     }
2024
2025   switch (element_name[0]) 
2026     {
2027     case 'a':
2028       if (ctx->state == STATE_NAMESPACE && strcmp (element_name, "alias") == 0) 
2029         {
2030           state_switch (ctx, STATE_ALIAS);
2031           goto out;
2032         }
2033       break;
2034     case 'b':
2035       if (start_enum (context, element_name, 
2036                       attribute_names, attribute_values,
2037                       ctx, error))
2038         goto out;
2039       break;
2040     case 'c':
2041       if (start_function (context, element_name, 
2042                           attribute_names, attribute_values,
2043                           ctx, error))
2044         goto out;
2045       else if (start_constant (context, element_name,
2046                                attribute_names, attribute_values,
2047                                ctx, error))
2048         goto out;
2049       else if (start_class (context, element_name, 
2050                             attribute_names, attribute_values,
2051                             ctx, error))
2052         goto out;
2053       else if (strcmp (element_name, "class") == 0 &&
2054                ctx->state == STATE_REQUIRES)
2055         {
2056           const gchar *name;
2057
2058           name = find_attribute ("name", attribute_names, attribute_values);
2059
2060           if (name == NULL)
2061             MISSING_ATTRIBUTE (context, error, element_name, "name");
2062           else
2063             {  
2064               GIrNodeInterface *iface;
2065
2066               iface = (GIrNodeInterface *)ctx->current_node;
2067               iface ->prerequisites = g_list_append (iface->prerequisites, g_strdup (name));
2068             }
2069
2070           goto out;
2071         }
2072       break;
2073
2074     case 'd':
2075       if (start_discriminator (context, element_name, 
2076                                attribute_names, attribute_values,
2077                                ctx, error))
2078         goto out;
2079       break;
2080
2081     case 'e':
2082       if (start_enum (context, element_name, 
2083                       attribute_names, attribute_values,
2084                       ctx, error))
2085         goto out;
2086       else if (start_errordomain (context, element_name, 
2087                       attribute_names, attribute_values,
2088                       ctx, error))
2089         goto out;
2090       break;
2091
2092     case 'f':
2093       if (start_function (context, element_name, 
2094                           attribute_names, attribute_values,
2095                           ctx, error))
2096         goto out;
2097       else if (start_field (context, element_name, 
2098                             attribute_names, attribute_values,
2099                             ctx, error))
2100         goto out;
2101       break;
2102
2103     case 'g':
2104       if (start_glib_boxed (context, element_name,
2105                             attribute_names, attribute_values,
2106                             ctx, error))
2107         goto out;
2108       else if (start_glib_signal (context, element_name,
2109                              attribute_names, attribute_values,
2110                              ctx, error))
2111         goto out;
2112       break;
2113
2114     case 'i':
2115       if (strcmp (element_name, "include") == 0 &&
2116           ctx->state == STATE_REPOSITORY)
2117         {
2118           const gchar *name;
2119           
2120           name = find_attribute ("name", attribute_names, attribute_values);
2121
2122           if (name == NULL)
2123             {
2124               MISSING_ATTRIBUTE (context, error, element_name, "name");
2125               break;
2126             }
2127
2128           if (!parse_include (context, ctx, name, error))
2129             break;
2130
2131           state_switch (ctx, STATE_INCLUDE);
2132           goto out;
2133         }
2134       if (start_interface (context, element_name, 
2135                            attribute_names, attribute_values,
2136                            ctx, error))
2137         goto out;
2138       else if (start_implements (context, element_name,
2139                                  attribute_names, attribute_values,
2140                                  ctx, error))
2141         goto out;
2142       break;
2143
2144     case 'm':
2145       if (start_function (context, element_name, 
2146                           attribute_names, attribute_values,
2147                           ctx, error))
2148         goto out;
2149       else if (start_member (context, element_name, 
2150                           attribute_names, attribute_values,
2151                           ctx, error))
2152         goto out;
2153       break;
2154
2155     case 'n':
2156       if (strcmp (element_name, "namespace") == 0 && ctx->state == STATE_REPOSITORY)
2157         {
2158           const gchar *name, *shared_library;
2159           
2160           name = find_attribute ("name", attribute_names, attribute_values);
2161           shared_library = find_attribute ("shared-library", attribute_names, attribute_values);
2162
2163           if (name == NULL)
2164             MISSING_ATTRIBUTE (context, error, element_name, "name");
2165           else
2166             {
2167               ctx->current_module = g_ir_module_new (name, shared_library);
2168               ctx->modules = g_list_append (ctx->modules, ctx->current_module);
2169
2170               state_switch (ctx, STATE_NAMESPACE);
2171             }
2172
2173           goto out;
2174         }
2175       break;
2176
2177     case 'p':
2178       if (start_property (context, element_name,
2179                           attribute_names, attribute_values,
2180                           ctx, error))
2181         goto out;
2182       else if (strcmp (element_name, "parameters") == 0 &&
2183                ctx->state == STATE_FUNCTION)
2184         {
2185           state_switch (ctx, STATE_FUNCTION_PARAMETERS);
2186
2187           goto out;
2188         }
2189       else if (start_parameter (context, element_name,
2190                                 attribute_names, attribute_values,
2191                                 ctx, error))
2192         goto out;
2193
2194       break;
2195
2196     case 'r':
2197       if (strcmp (element_name, "repository") == 0 && ctx->state == STATE_START)
2198         {
2199           const gchar *version;
2200
2201           version = find_attribute ("version", attribute_names, attribute_values);
2202           
2203           if (version == NULL)
2204             MISSING_ATTRIBUTE (context, error, element_name, "version");
2205           else if (strcmp (version, "1.0") != 0)
2206             g_set_error (error,
2207                          G_MARKUP_ERROR,
2208                          G_MARKUP_ERROR_INVALID_CONTENT,
2209                          "Unsupported version '%s'",
2210                          version);
2211           else
2212             state_switch (ctx, STATE_REPOSITORY);
2213           
2214           goto out;
2215         }
2216       else if (start_return_value (context, element_name,
2217                                    attribute_names, attribute_values,
2218                                    ctx, error))
2219         goto out;      
2220       else if (strcmp (element_name, "requires") == 0 &&
2221                ctx->state == STATE_INTERFACE)
2222         {
2223           state_switch (ctx, STATE_REQUIRES);
2224           
2225           goto out;
2226         }
2227       else if (start_struct (context, element_name,
2228                              attribute_names, attribute_values,
2229                              ctx, error))
2230         goto out;      
2231       break;
2232
2233     case 'u':
2234       if (start_union (context, element_name,
2235                        attribute_names, attribute_values,
2236                        ctx, error))
2237         goto out;
2238       break;
2239
2240     case 't':
2241       if (start_type (context, element_name,
2242                       attribute_names, attribute_values,
2243                       ctx, error))
2244         goto out;
2245       break;
2246
2247     case 'v':
2248       if (start_vfunc (context, element_name,
2249                        attribute_names, attribute_values,
2250                        ctx, error))
2251         goto out;      
2252       break;
2253     }
2254
2255   g_markup_parse_context_get_position (context, &line_number, &char_number);
2256
2257   if (error && *error == NULL)
2258     g_set_error (error,
2259                  G_MARKUP_ERROR,
2260                  G_MARKUP_ERROR_UNKNOWN_ELEMENT,
2261                  "Unexpected start tag '%s' on line %d char %d; current state=%d",
2262                  element_name,
2263                  line_number, char_number, ctx->state);
2264   
2265  out: ;
2266   if (*error) 
2267     {
2268       g_markup_parse_context_get_position (context, &line_number, &char_number);
2269
2270       fprintf (stderr, "Error at line %d, character %d: %s\n", line_number, char_number, (*error)->message);
2271       backtrace_stderr ();
2272     }
2273 }
2274
2275 static gboolean
2276 require_one_of_end_elements (GMarkupParseContext *context,
2277                              ParseContext        *ctx,
2278                              const char          *actual_name,
2279                              GError             **error, 
2280                              ...)
2281 {
2282   va_list args;
2283   int line_number, char_number;
2284   const char *expected;
2285   gboolean matched = FALSE;
2286
2287   va_start (args, error);
2288
2289   while ((expected = va_arg (args, const char*)) != NULL) 
2290     {
2291       if (strcmp (expected, actual_name) == 0)
2292         {
2293           matched = TRUE;
2294           break;
2295         }
2296     }
2297
2298   va_end (args);
2299
2300   if (matched)
2301     return TRUE;
2302
2303   g_markup_parse_context_get_position (context, &line_number, &char_number);
2304   g_set_error (error,
2305                G_MARKUP_ERROR,
2306                G_MARKUP_ERROR_INVALID_CONTENT,
2307                "Unexpected end tag '%s' on line %d char %d; current state=%d",
2308                actual_name, 
2309                line_number, char_number, ctx->state);
2310   backtrace_stderr();
2311   return FALSE;
2312 }
2313
2314 static gboolean
2315 require_end_element (GMarkupParseContext *context,
2316                      ParseContext        *ctx,
2317                      const char          *expected_name,
2318                      const char          *actual_name,
2319                      GError             **error)
2320 {
2321   return require_one_of_end_elements (context, ctx, actual_name, error, expected_name, NULL);
2322 }
2323
2324 static void
2325 end_element_handler (GMarkupParseContext *context,
2326                      const gchar         *element_name,
2327                      gpointer             user_data,
2328                      GError             **error)
2329 {
2330   ParseContext *ctx = user_data;
2331
2332   g_debug ("</%s>", element_name);
2333
2334   switch (ctx->state)
2335     {
2336     case STATE_START:
2337     case STATE_END:
2338       /* no need to GError here, GMarkup already catches this */
2339       break;
2340
2341     case STATE_REPOSITORY:
2342       state_switch (ctx, STATE_END);
2343       break;
2344
2345     case STATE_INCLUDE:
2346       if (require_end_element (context, ctx, "include", element_name, error))
2347         {
2348           state_switch (ctx, STATE_REPOSITORY);
2349         }
2350       break;
2351
2352     case STATE_NAMESPACE:
2353       if (require_end_element (context, ctx, "namespace", element_name, error))
2354         {
2355           ctx->current_module = NULL;
2356           state_switch (ctx, STATE_REPOSITORY);
2357         }
2358       break;
2359
2360     case STATE_ALIAS:
2361       if (require_end_element (context, ctx, "alias", element_name, error))
2362         {
2363           state_switch (ctx, STATE_NAMESPACE);
2364         }
2365       break;
2366
2367     case STATE_FUNCTION_RETURN:
2368       if (strcmp ("type", element_name) == 0)
2369         break;
2370       if (require_end_element (context, ctx, "return-value", element_name, error))
2371         {
2372           state_switch (ctx, STATE_FUNCTION);
2373         }
2374       break;
2375
2376     case STATE_FUNCTION_PARAMETERS:
2377       if (require_end_element (context, ctx, "parameters", element_name, error))
2378         {
2379           state_switch (ctx, STATE_FUNCTION);
2380         }
2381       break;
2382
2383     case STATE_FUNCTION_PARAMETER:
2384       if (strcmp ("type", element_name) == 0)
2385         break;
2386       if (require_end_element (context, ctx, "parameter", element_name, error))
2387         {
2388           state_switch (ctx, STATE_FUNCTION_PARAMETERS);
2389         }
2390       break;
2391
2392     case STATE_FUNCTION:
2393        if (ctx->current_node == g_list_last (ctx->current_module->entries)->data)
2394         {
2395           ctx->current_node = NULL;
2396           state_switch (ctx, STATE_NAMESPACE);
2397         }
2398       else 
2399         { 
2400           ctx->current_node = g_list_last (ctx->current_module->entries)->data;
2401           if (ctx->current_node->type == G_IR_NODE_INTERFACE)
2402             state_switch (ctx, STATE_INTERFACE);
2403           else if (ctx->current_node->type == G_IR_NODE_OBJECT)
2404             state_switch (ctx, STATE_CLASS);
2405           else if (ctx->current_node->type == G_IR_NODE_BOXED)
2406             state_switch (ctx, STATE_BOXED);
2407           else if (ctx->current_node->type == G_IR_NODE_STRUCT)
2408             state_switch (ctx, STATE_STRUCT);
2409           else if (ctx->current_node->type == G_IR_NODE_UNION)
2410             state_switch (ctx, STATE_UNION);
2411           else
2412             {
2413               int line_number, char_number;
2414               g_markup_parse_context_get_position (context, &line_number, &char_number);
2415               g_set_error (error,
2416                            G_MARKUP_ERROR,
2417                            G_MARKUP_ERROR_INVALID_CONTENT,
2418                            "Unexpected end tag '%s' on line %d char %d",
2419                            element_name,
2420                            line_number, char_number);
2421             }
2422         }
2423       break;
2424
2425     case STATE_CLASS_FIELD:
2426       if (strcmp ("type", element_name) == 0)
2427         break;
2428       if (require_end_element (context, ctx, "field", element_name, error))
2429         {
2430           state_switch (ctx, STATE_CLASS);
2431         }
2432       break;
2433
2434     case STATE_CLASS_PROPERTY:
2435       if (strcmp ("type", element_name) == 0)
2436         break;
2437       if (require_end_element (context, ctx, "property", element_name, error))
2438         {
2439           state_switch (ctx, STATE_CLASS);
2440         }
2441       break;
2442
2443     case STATE_CLASS:
2444       if (require_end_element (context, ctx, "class", element_name, error))
2445         {
2446           ctx->current_node = NULL;
2447           state_switch (ctx, STATE_NAMESPACE);
2448         }
2449       break;
2450
2451     case STATE_ERRORDOMAIN:
2452       if (require_end_element (context, ctx, "errordomain", element_name, error))
2453         {
2454           ctx->current_node = NULL;
2455           state_switch (ctx, STATE_NAMESPACE);
2456         }
2457       break;
2458
2459     case STATE_INTERFACE_PROPERTY:
2460       if (strcmp ("type", element_name) == 0)
2461         break;
2462       if (require_end_element (context, ctx, "property", element_name, error))
2463         {
2464           state_switch (ctx, STATE_INTERFACE);
2465         }
2466       break;
2467
2468     case STATE_INTERFACE_FIELD:
2469       if (strcmp ("type", element_name) == 0)
2470         break;
2471       if (require_end_element (context, ctx, "field", element_name, error))
2472         {
2473           state_switch (ctx, STATE_INTERFACE);
2474         }
2475       break;
2476
2477     case STATE_INTERFACE:
2478       if (require_end_element (context, ctx, "interface", element_name, error))
2479         {
2480           ctx->current_node = NULL;
2481           state_switch (ctx, STATE_NAMESPACE);
2482         }
2483       break;
2484
2485     case STATE_ENUM:
2486       if (strcmp ("member", element_name) == 0)
2487         break;
2488       else if (require_one_of_end_elements (context, ctx, 
2489                                             element_name, error, "enumeration", 
2490                                             "bitfield", NULL))
2491         {
2492           ctx->current_node = NULL;
2493           state_switch (ctx, STATE_NAMESPACE);
2494         }
2495       break;
2496
2497     case STATE_BOXED:
2498       if (require_end_element (context, ctx, "glib:boxed", element_name, error))
2499         {
2500           ctx->current_node = NULL;
2501           state_switch (ctx, STATE_NAMESPACE);
2502         }
2503       break;
2504
2505     case STATE_BOXED_FIELD:
2506       if (strcmp ("type", element_name) == 0)
2507         break;
2508       if (require_end_element (context, ctx, "field", element_name, error))
2509         {
2510           state_switch (ctx, STATE_BOXED);
2511         }
2512       break;
2513
2514     case STATE_STRUCT_FIELD:
2515       if (strcmp ("type", element_name) == 0)
2516         break;
2517       if (require_end_element (context, ctx, "field", element_name, error))
2518         {
2519           state_switch (ctx, STATE_STRUCT);
2520         }
2521       break;
2522
2523     case STATE_STRUCT:
2524       if (require_end_element (context, ctx, "record", element_name, error))
2525         {
2526           ctx->current_node = NULL;
2527           state_switch (ctx, STATE_NAMESPACE);
2528         }
2529       break;
2530
2531     case STATE_UNION_FIELD:
2532       if (strcmp ("type", element_name) == 0)
2533         break;
2534       if (require_end_element (context, ctx, "field", element_name, error))
2535         {
2536           state_switch (ctx, STATE_UNION);
2537         }
2538       break;
2539
2540     case STATE_UNION:
2541       if (require_end_element (context, ctx, "union", element_name, error))
2542         {
2543           ctx->current_node = NULL;
2544           state_switch (ctx, STATE_NAMESPACE);
2545         }
2546       break;
2547     case STATE_IMPLEMENTS:
2548       if (strcmp ("interface", element_name) == 0)
2549         break;
2550       if (require_end_element (context, ctx, "implements", element_name, error))
2551         state_switch (ctx, STATE_CLASS);
2552       break;
2553     case STATE_REQUIRES:
2554       if (require_end_element (context, ctx, "requires", element_name, error))
2555         state_switch (ctx, STATE_INTERFACE);
2556       break;
2557     case STATE_NAMESPACE_CONSTANT:
2558     case STATE_CLASS_CONSTANT:
2559     case STATE_INTERFACE_CONSTANT:
2560       if (strcmp ("type", element_name) == 0)
2561         break;
2562       if (require_end_element (context, ctx, "constant", element_name, error))
2563         {
2564           ctx->current_node = NULL;
2565           switch (ctx->state)
2566             {
2567             case STATE_NAMESPACE_CONSTANT:
2568               state_switch (ctx, STATE_NAMESPACE);
2569               break;
2570             case STATE_CLASS_CONSTANT:
2571               state_switch (ctx, STATE_CLASS);
2572               break;
2573             case STATE_INTERFACE_CONSTANT:
2574               state_switch (ctx, STATE_INTERFACE);
2575               break;
2576             default:
2577               g_assert_not_reached ();
2578               break;
2579             }
2580         }
2581       break;
2582     case STATE_TYPE:
2583       if (strcmp ("type", element_name) == 0)
2584         {
2585           if (ctx->type_depth == 1)
2586             state_switch (ctx, ctx->prev_state);
2587           else
2588             ctx->type_depth -= 1;
2589           break;
2590         }
2591     default:
2592       g_error ("Unhandled state %d in end_element_handler\n", ctx->state);
2593     }
2594 }
2595
2596 static void 
2597 text_handler (GMarkupParseContext *context,
2598               const gchar         *text,
2599               gsize                text_len,  
2600               gpointer             user_data,
2601               GError             **error)
2602 {
2603   /* FIXME warn about non-whitespace text */
2604 }
2605
2606 static void
2607 cleanup (GMarkupParseContext *context,
2608          GError              *error,
2609          gpointer             user_data)
2610 {
2611   ParseContext *ctx = user_data;
2612   GList *m;
2613   int line_number, char_number;
2614
2615   for (m = ctx->modules; m; m = m->next)
2616     g_ir_module_free (m->data);
2617   g_list_free (ctx->modules);
2618   ctx->modules = NULL;
2619   
2620   ctx->current_module = NULL;
2621 }
2622
2623 static GMarkupParser parser = 
2624 {
2625   start_element_handler,
2626   end_element_handler,
2627   text_handler,
2628   NULL,
2629   cleanup
2630 };
2631
2632 GList * 
2633 g_ir_parse_string (const char   *namespace,
2634                    const gchar  *buffer, 
2635                    gssize        length,
2636                    GError      **error)
2637 {
2638   ParseContext ctx = { 0 };
2639   GMarkupParseContext *context;
2640
2641   ctx.state = STATE_START;
2642   ctx.prefix_aliases = FALSE;
2643   ctx.namespace = namespace;
2644   ctx.aliases = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
2645   ctx.type_depth = 0;
2646
2647   context = g_markup_parse_context_new (&firstpass_parser, 0, &ctx, NULL);
2648
2649   if (!g_markup_parse_context_parse (context, buffer, length, error))
2650     goto out;
2651
2652   if (!g_markup_parse_context_end_parse (context, error))
2653     goto out;
2654
2655   g_markup_parse_context_free (context);
2656   
2657   context = g_markup_parse_context_new (&parser, 0, &ctx, NULL);
2658   if (!g_markup_parse_context_parse (context, buffer, length, error))
2659     goto out;
2660
2661   if (!g_markup_parse_context_end_parse (context, error))
2662     goto out;
2663
2664  out:
2665
2666   g_hash_table_destroy (ctx.aliases);
2667   
2668   g_markup_parse_context_free (context);
2669   
2670   return ctx.modules;
2671 }
2672
2673 GList *
2674 g_ir_parse_file (const gchar  *filename,
2675                  GError      **error)
2676 {
2677   gchar *buffer;
2678   gsize length;
2679   GList *modules;
2680   const char *slash;
2681   char *namespace;
2682
2683   if (!g_str_has_suffix (filename, ".gir"))
2684     {
2685       g_set_error (error,
2686                    G_MARKUP_ERROR,
2687                    G_MARKUP_ERROR_INVALID_CONTENT,
2688                    "Expected filename to end with '.gir'");
2689       return NULL;
2690     }
2691
2692   g_debug ("[parsing] filename %s", filename);
2693
2694   slash = g_strrstr (filename, "/");
2695   if (!slash)
2696     namespace = g_strdup (filename);
2697   else
2698     namespace = g_strdup (slash+1);
2699   namespace[strlen(namespace)-4] = '\0';
2700
2701   if (!g_file_get_contents (filename, &buffer, &length, error))
2702     return NULL;
2703   
2704   modules = g_ir_parse_string (namespace, buffer, length, error);
2705
2706   g_free (namespace);
2707
2708   g_free (buffer);
2709
2710   return modules;
2711 }
2712
2713