1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2  * GObject introspection: A parser for the XML GIR format
3  *
4  * Copyright (C) 2005 Matthias Clasen
5  * Copyright (C) 2008 Philip Van Hoof
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 
23 #include "config.h"
24 
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28 
29 #include <glib.h>
30 #include "girparser.h"
31 #include "girmodule.h"
32 #include "girnode.h"
33 #include "gitypelib-internal.h"
34 
35 /* This is a "major" version in the sense that it's only bumped
36  * for incompatible changes.
37  */
38 #define SUPPORTED_GIR_VERSION "1.2"
39 
40 #ifdef G_OS_WIN32
41 
42 #include <windows.h>
43 
44 #ifdef GIR_DIR
45 #undef GIR_DIR
46 #endif
47 
48 /* GIR_DIR is used only in code called just once,
49  * so no problem leaking this
50  */
51 #define GIR_DIR \
52   g_build_filename (g_win32_get_package_installation_directory_of_module(NULL), \
53     "share", \
54     GIR_SUFFIX, \
55     NULL)
56 #endif
57 
58 struct _GIrParser
59 {
60   gchar **includes;
61   GList *parsed_modules; /* All previously parsed modules */
62 };
63 
64 typedef enum
65 {
66   STATE_NONE = 0,
67   STATE_START,
68   STATE_END,
69   STATE_REPOSITORY,
70   STATE_INCLUDE,
71   STATE_C_INCLUDE,     /* 5 */
72   STATE_PACKAGE,
73   STATE_NAMESPACE,
74   STATE_ENUM,
75   STATE_BITFIELD,
76   STATE_FUNCTION,      /* 10 */
77   STATE_FUNCTION_RETURN,
78   STATE_FUNCTION_PARAMETERS,
79   STATE_FUNCTION_PARAMETER,
80   STATE_CLASS,
81   STATE_CLASS_FIELD,   /* 15 */
82   STATE_CLASS_PROPERTY,
83   STATE_INTERFACE,
84   STATE_INTERFACE_PROPERTY,
85   STATE_INTERFACE_FIELD,
86   STATE_IMPLEMENTS,    /* 20 */
87   STATE_PREREQUISITE,
88   STATE_BOXED,
89   STATE_BOXED_FIELD,
90   STATE_STRUCT,
91   STATE_STRUCT_FIELD,  /* 25 */
92   STATE_UNION,
93   STATE_UNION_FIELD,
94   STATE_NAMESPACE_CONSTANT,
95   STATE_CLASS_CONSTANT,
96   STATE_INTERFACE_CONSTANT,  /* 30 */
97   STATE_ALIAS,
98   STATE_TYPE,
99   STATE_ATTRIBUTE,
100   STATE_PASSTHROUGH
101 } ParseState;
102 
103 typedef struct _ParseContext ParseContext;
104 struct _ParseContext
105 {
106   GIrParser *parser;
107 
108   ParseState state;
109   int unknown_depth;
110   ParseState prev_state;
111 
112   GList *modules;
113   GList *include_modules;
114   GList *dependencies;
115   GHashTable *aliases;
116   GHashTable *disguised_structures;
117 
118   const char *file_path;
119   const char *namespace;
120   const char *c_prefix;
121   GIrModule *current_module;
122   GSList *node_stack;
123   char *current_alias;
124   GIrNode *current_typed;
125   GList *type_stack;
126   GList *type_parameters;
127   int type_depth;
128   ParseState in_embedded_state;
129 };
130 #define CURRENT_NODE(ctx) ((GIrNode *)((ctx)->node_stack->data))
131 
132 static void start_element_handler (GMarkupParseContext *context,
133 				   const gchar         *element_name,
134 				   const gchar        **attribute_names,
135 				   const gchar        **attribute_values,
136 				   gpointer             user_data,
137 				   GError             **error);
138 static void end_element_handler   (GMarkupParseContext *context,
139 				   const gchar         *element_name,
140 				   gpointer             user_data,
141 				   GError             **error);
142 static void text_handler          (GMarkupParseContext *context,
143 				   const gchar         *text,
144 				   gsize                text_len,
145 				   gpointer             user_data,
146 				   GError             **error);
147 static void cleanup               (GMarkupParseContext *context,
148 				   GError              *error,
149 				   gpointer             user_data);
150 static void state_switch (ParseContext *ctx, ParseState newstate);
151 
152 
153 static GMarkupParser markup_parser =
154 {
155   start_element_handler,
156   end_element_handler,
157   text_handler,
158   NULL,
159   cleanup
160 };
161 
162 static gboolean
163 start_alias (GMarkupParseContext *context,
164 	     const gchar         *element_name,
165 	     const gchar        **attribute_names,
166 	     const gchar        **attribute_values,
167 	     ParseContext        *ctx,
168 	     GError             **error);
169 static gboolean
170 start_type (GMarkupParseContext *context,
171 	    const gchar         *element_name,
172 	    const gchar        **attribute_names,
173 	    const gchar        **attribute_values,
174 	    ParseContext        *ctx,
175 	    GError             **error);
176 
177 static const gchar *find_attribute (const gchar  *name,
178 				    const gchar **attribute_names,
179 				    const gchar **attribute_values);
180 
181 
182 GIrParser *
_g_ir_parser_new(void)183 _g_ir_parser_new (void)
184 {
185   GIrParser *parser = g_slice_new0 (GIrParser);
186 
187   return parser;
188 }
189 
190 void
_g_ir_parser_free(GIrParser * parser)191 _g_ir_parser_free (GIrParser *parser)
192 {
193   GList *l;
194 
195   if (parser->includes)
196     g_strfreev (parser->includes);
197 
198   for (l = parser->parsed_modules; l; l = l->next)
199     _g_ir_module_free (l->data);
200 
201   g_slice_free (GIrParser, parser);
202 }
203 
204 void
_g_ir_parser_set_includes(GIrParser * parser,const gchar * const * includes)205 _g_ir_parser_set_includes (GIrParser          *parser,
206 			   const gchar *const *includes)
207 {
208   if (parser->includes)
209     g_strfreev (parser->includes);
210 
211   parser->includes = g_strdupv ((char **)includes);
212 }
213 
214 static void
firstpass_start_element_handler(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,gpointer user_data,GError ** error)215 firstpass_start_element_handler (GMarkupParseContext *context,
216 				 const gchar         *element_name,
217 				 const gchar        **attribute_names,
218 				 const gchar        **attribute_values,
219 				 gpointer             user_data,
220 				 GError             **error)
221 {
222   ParseContext *ctx = user_data;
223 
224   if (strcmp (element_name, "alias") == 0)
225     {
226       start_alias (context, element_name, attribute_names, attribute_values,
227 		   ctx, error);
228     }
229   else if (ctx->state == STATE_ALIAS && strcmp (element_name, "type") == 0)
230     {
231       start_type (context, element_name, attribute_names, attribute_values,
232 		  ctx, error);
233     }
234   else if (strcmp (element_name, "record") == 0)
235     {
236       const gchar *name;
237       const gchar *disguised;
238 
239       name = find_attribute ("name", attribute_names, attribute_values);
240       disguised = find_attribute ("disguised", attribute_names, attribute_values);
241 
242       if (disguised && strcmp (disguised, "1") == 0)
243 	{
244 	  char *key;
245 
246 	  key = g_strdup_printf ("%s.%s", ctx->namespace, name);
247 	  g_hash_table_replace (ctx->disguised_structures, key, GINT_TO_POINTER (1));
248 	}
249     }
250 }
251 
252 static void
firstpass_end_element_handler(GMarkupParseContext * context,const gchar * element_name,gpointer user_data,GError ** error)253 firstpass_end_element_handler (GMarkupParseContext *context,
254 			       const gchar         *element_name,
255 			       gpointer             user_data,
256 			       GError             **error)
257 {
258   ParseContext *ctx = user_data;
259   if (strcmp (element_name, "alias") == 0)
260     {
261       state_switch (ctx, STATE_NAMESPACE);
262       g_free (ctx->current_alias);
263       ctx->current_alias = NULL;
264     }
265   else if (strcmp (element_name, "type") == 0 && ctx->state == STATE_TYPE)
266     state_switch (ctx, ctx->prev_state);
267 }
268 
269 static GMarkupParser firstpass_parser =
270 {
271   firstpass_start_element_handler,
272   firstpass_end_element_handler,
273   NULL,
274   NULL,
275   NULL,
276 };
277 
278 static char *
locate_gir(GIrParser * parser,const char * girname)279 locate_gir (GIrParser  *parser,
280 	    const char *girname)
281 {
282   const gchar *const *datadirs;
283   const gchar *const *dir;
284   char *path = NULL;
285 
286   datadirs = g_get_system_data_dirs ();
287 
288   if (parser->includes != NULL)
289     {
290       for (dir = (const gchar *const *)parser->includes; *dir; dir++)
291 	{
292 	  path = g_build_filename (*dir, girname, NULL);
293 	  if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
294 	    return path;
295 	  g_free (path);
296 	  path = NULL;
297 	}
298     }
299   for (dir = datadirs; *dir; dir++)
300     {
301       path = g_build_filename (*dir, GIR_SUFFIX, girname, NULL);
302       if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
303 	return path;
304       g_free (path);
305       path = NULL;
306     }
307 
308   path = g_build_filename (GIR_DIR, girname, NULL);
309   if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
310     return path;
311   g_free (path);
312   return NULL;
313 }
314 
315 #define MISSING_ATTRIBUTE(context,error,element,attribute)			        \
316   do {                                                                          \
317     int line_number, char_number;                                                \
318     g_markup_parse_context_get_position (context, &line_number, &char_number);  \
319     g_set_error (error,                                                         \
320    	         G_MARKUP_ERROR,                                                \
321 	         G_MARKUP_ERROR_INVALID_CONTENT,                                \
322 	         "Line %d, character %d: The attribute '%s' on the element '%s' must be specified",    \
323 	         line_number, char_number, attribute, element);		\
324   } while (0)
325 
326 static const gchar *
find_attribute(const gchar * name,const gchar ** attribute_names,const gchar ** attribute_values)327 find_attribute (const gchar  *name,
328 		const gchar **attribute_names,
329 		const gchar **attribute_values)
330 {
331   gint i;
332 
333   for (i = 0; attribute_names[i] != NULL; i++)
334     if (strcmp (attribute_names[i], name) == 0)
335       return attribute_values[i];
336 
337   return 0;
338 }
339 
340 static void
state_switch(ParseContext * ctx,ParseState newstate)341 state_switch (ParseContext *ctx, ParseState newstate)
342 {
343   g_assert (ctx->state != newstate);
344   ctx->prev_state = ctx->state;
345   ctx->state = newstate;
346 
347   if (ctx->state == STATE_PASSTHROUGH)
348     ctx->unknown_depth = 1;
349 }
350 
351 static GIrNode *
pop_node(ParseContext * ctx)352 pop_node (ParseContext *ctx)
353 {
354   GSList *top;
355   GIrNode *node;
356   g_assert (ctx->node_stack != 0);
357 
358   top = ctx->node_stack;
359   node = top->data;
360 
361   g_debug ("popping node %d %s", node->type, node->name);
362   ctx->node_stack = top->next;
363   g_slist_free_1 (top);
364   return node;
365 }
366 
367 static void
push_node(ParseContext * ctx,GIrNode * node)368 push_node (ParseContext *ctx, GIrNode *node)
369 {
370   g_assert (node != NULL);
371   g_debug ("pushing node %d %s", node->type, node->name);
372   ctx->node_stack = g_slist_prepend (ctx->node_stack, node);
373 }
374 
375 static GIrNodeType * parse_type_internal (GIrModule *module,
376 					  const gchar *str, gchar **next, gboolean in_glib,
377 					  gboolean in_gobject);
378 
379 typedef struct {
380   const gchar *str;
381   guint size;
382   guint is_signed : 1;
383 } IntegerAliasInfo;
384 
385 static IntegerAliasInfo integer_aliases[] = {
386   { "gchar",    SIZEOF_CHAR,      1 },
387   { "guchar",   SIZEOF_CHAR,      0 },
388   { "gshort",   SIZEOF_SHORT,     1 },
389   { "gushort",  SIZEOF_SHORT,     0 },
390   { "gint",     SIZEOF_INT,       1 },
391   { "guint",    SIZEOF_INT,       0 },
392   { "glong",    SIZEOF_LONG,      1 },
393   { "gulong",   SIZEOF_LONG,      0 },
394   { "gssize",   GLIB_SIZEOF_SIZE_T,    1 },
395   { "gsize",    GLIB_SIZEOF_SIZE_T,    0 },
396   { "gintptr",  GLIB_SIZEOF_SIZE_T,    1 },
397   { "guintptr", GLIB_SIZEOF_SIZE_T,    0 },
398 };
399 
400 typedef struct {
401   const gchar *str;
402   gint tag;
403   gboolean pointer;
404 } BasicTypeInfo;
405 
406 #define BASIC_TYPE_FIXED_OFFSET 3
407 
408 static BasicTypeInfo basic_types[] = {
409     { "none",      GI_TYPE_TAG_VOID,    0 },
410     { "gpointer",  GI_TYPE_TAG_VOID,    1 },
411 
412     { "gboolean",  GI_TYPE_TAG_BOOLEAN, 0 },
413     { "gint8",     GI_TYPE_TAG_INT8,    0 }, /* Start of BASIC_TYPE_FIXED_OFFSET */
414     { "guint8",    GI_TYPE_TAG_UINT8,   0 },
415     { "gint16",    GI_TYPE_TAG_INT16,   0 },
416     { "guint16",   GI_TYPE_TAG_UINT16,  0 },
417     { "gint32",    GI_TYPE_TAG_INT32,   0 },
418     { "guint32",   GI_TYPE_TAG_UINT32,  0 },
419     { "gint64",    GI_TYPE_TAG_INT64,   0 },
420     { "guint64",   GI_TYPE_TAG_UINT64,  0 },
421     { "gfloat",    GI_TYPE_TAG_FLOAT,   0 },
422     { "gdouble",   GI_TYPE_TAG_DOUBLE,  0 },
423     { "GType",     GI_TYPE_TAG_GTYPE,   0 },
424     { "utf8",      GI_TYPE_TAG_UTF8,    1 },
425     { "filename",  GI_TYPE_TAG_FILENAME,1 },
426     { "gunichar",  GI_TYPE_TAG_UNICHAR, 0 },
427 };
428 
429 static const BasicTypeInfo *
parse_basic(const char * str)430 parse_basic (const char *str)
431 {
432   guint i;
433   guint n_basic = G_N_ELEMENTS (basic_types);
434 
435   for (i = 0; i < n_basic; i++)
436     {
437       if (strcmp (str, basic_types[i].str) == 0)
438 	return &(basic_types[i]);
439     }
440   for (i = 0; i < G_N_ELEMENTS (integer_aliases); i++)
441     {
442       if (strcmp (str, integer_aliases[i].str) == 0)
443 	{
444 	  switch (integer_aliases[i].size)
445 	    {
446 	    case sizeof(guint8):
447 	      if (integer_aliases[i].is_signed)
448 		return &basic_types[BASIC_TYPE_FIXED_OFFSET];
449 	      else
450 		return &basic_types[BASIC_TYPE_FIXED_OFFSET+1];
451 	      break;
452 	    case sizeof(guint16):
453 	      if (integer_aliases[i].is_signed)
454 		return &basic_types[BASIC_TYPE_FIXED_OFFSET+2];
455 	      else
456 		return &basic_types[BASIC_TYPE_FIXED_OFFSET+3];
457 	      break;
458 	    case sizeof(guint32):
459 	      if (integer_aliases[i].is_signed)
460 		return &basic_types[BASIC_TYPE_FIXED_OFFSET+4];
461 	      else
462 		return &basic_types[BASIC_TYPE_FIXED_OFFSET+5];
463 	      break;
464 	    case sizeof(guint64):
465 	      if (integer_aliases[i].is_signed)
466 		return &basic_types[BASIC_TYPE_FIXED_OFFSET+6];
467 	      else
468 		return &basic_types[BASIC_TYPE_FIXED_OFFSET+7];
469 	      break;
470 	    default:
471 	      g_assert_not_reached ();
472 	    }
473 	}
474     }
475   return NULL;
476 }
477 
478 static GIrNodeType *
parse_type_internal(GIrModule * module,const gchar * str,char ** next,gboolean in_glib,gboolean in_gobject)479 parse_type_internal (GIrModule *module,
480 		     const gchar *str, char **next, gboolean in_glib,
481 		     gboolean in_gobject)
482 {
483   const BasicTypeInfo *basic;
484   GIrNodeType *type;
485   char *temporary_type = NULL;
486 
487   type = (GIrNodeType *)_g_ir_node_new (G_IR_NODE_TYPE, module);
488 
489   type->unparsed = g_strdup (str);
490 
491   /* See comment below on GLib.List handling */
492   if (in_gobject && strcmp (str, "Type") == 0)
493     {
494       temporary_type = g_strdup ("GLib.Type");
495       str = temporary_type;
496     }
497 
498   basic = parse_basic (str);
499   if (basic != NULL)
500     {
501       type->is_basic = TRUE;
502       type->tag = basic->tag;
503       type->is_pointer = basic->pointer;
504 
505       str += strlen(basic->str);
506     }
507   else if (in_glib)
508     {
509       /* If we're inside GLib, handle "List" etc. by prefixing with
510        * "GLib." so the parsing code below doesn't have to get more
511        * special.
512        */
513       if (g_str_has_prefix (str, "List<") ||
514 	  strcmp (str, "List") == 0)
515 	{
516 	  temporary_type = g_strdup_printf ("GLib.List%s", str + 4);
517 	  str = temporary_type;
518 	}
519       else if (g_str_has_prefix (str, "SList<") ||
520 	  strcmp (str, "SList") == 0)
521 	{
522 	  temporary_type = g_strdup_printf ("GLib.SList%s", str + 5);
523 	  str = temporary_type;
524 	}
525       else if (g_str_has_prefix (str, "HashTable<") ||
526 	  strcmp (str, "HashTable") == 0)
527 	{
528 	  temporary_type = g_strdup_printf ("GLib.HashTable%s", str + 9);
529 	  str = temporary_type;
530 	}
531       else if (g_str_has_prefix (str, "Error<") ||
532 	  strcmp (str, "Error") == 0)
533 	{
534 	  temporary_type = g_strdup_printf ("GLib.Error%s", str + 5);
535 	  str = temporary_type;
536 	}
537     }
538 
539   if (basic != NULL)
540     /* found a basic type */;
541   else if (g_str_has_prefix (str, "GLib.List") ||
542 	   g_str_has_prefix (str, "GLib.SList"))
543     {
544       str += strlen ("GLib.");
545       if (g_str_has_prefix (str, "List"))
546 	{
547 	  type->tag = GI_TYPE_TAG_GLIST;
548 	  type->is_glist = TRUE;
549 	  type->is_pointer = TRUE;
550 	  str += strlen ("List");
551 	}
552       else
553 	{
554 	  type->tag = GI_TYPE_TAG_GSLIST;
555 	  type->is_gslist = TRUE;
556 	  type->is_pointer = TRUE;
557 	  str += strlen ("SList");
558 	}
559     }
560   else if (g_str_has_prefix (str, "GLib.HashTable"))
561     {
562       str += strlen ("GLib.");
563 
564       type->tag = GI_TYPE_TAG_GHASH;
565       type->is_ghashtable = TRUE;
566       type->is_pointer = TRUE;
567       str += strlen ("HashTable");
568     }
569   else if (g_str_has_prefix (str, "GLib.Error"))
570     {
571       str += strlen ("GLib.");
572 
573       type->tag = GI_TYPE_TAG_ERROR;
574       type->is_error = TRUE;
575       type->is_pointer = TRUE;
576       str += strlen ("Error");
577 
578       if (*str == '<')
579 	{
580 	  char *tmp, *end;
581 	  (str)++;
582 
583 	  end = strchr (str, '>');
584 	  tmp = g_strndup (str, end - str);
585 	  type->errors = g_strsplit (tmp, ",", 0);
586 	  g_free (tmp);
587 
588 	  str = end;
589 	}
590     }
591   else
592     {
593       const char *start;
594       type->tag = GI_TYPE_TAG_INTERFACE;
595       type->is_interface = TRUE;
596       start = str;
597 
598       /* must be an interface type */
599       while (g_ascii_isalnum (*str) ||
600 	     *str == '.' ||
601 	     *str == '-' ||
602 	     *str == '_' ||
603 	     *str == ':')
604 	(str)++;
605 
606       type->giinterface = g_strndup (start, str - start);
607     }
608 
609   if (next)
610     *next = (char*)str;
611   g_assert (type->tag >= 0 && type->tag < GI_TYPE_TAG_N_TYPES);
612   g_free (temporary_type);
613   return type;
614 
615 /* error: */
616   _g_ir_node_free ((GIrNode *)type);
617   g_free (temporary_type);
618   return NULL;
619 }
620 
621 static const char *
resolve_aliases(ParseContext * ctx,const gchar * type)622 resolve_aliases (ParseContext *ctx, const gchar *type)
623 {
624   gpointer orig;
625   gpointer value;
626   GSList *seen_values = NULL;
627   const gchar *lookup;
628   gchar *prefixed;
629 
630   if (strchr (type, '.') == NULL)
631     {
632       prefixed = g_strdup_printf ("%s.%s", ctx->namespace, type);
633       lookup = prefixed;
634     }
635   else
636     {
637       lookup = type;
638       prefixed = NULL;
639     }
640 
641   seen_values = g_slist_prepend (seen_values, (char*)lookup);
642   while (g_hash_table_lookup_extended (ctx->current_module->aliases, lookup, &orig, &value))
643     {
644       g_debug ("Resolved: %s => %s\n", lookup, (char*)value);
645       lookup = value;
646       if (g_slist_find_custom (seen_values, lookup,
647 			       (GCompareFunc)strcmp) != NULL)
648 	break;
649       seen_values = g_slist_prepend (seen_values, (gchar*)lookup);
650     }
651   g_slist_free (seen_values);
652 
653   if (lookup == prefixed)
654     lookup = type;
655 
656   g_free (prefixed);
657 
658   return lookup;
659 }
660 
661 static gboolean
is_disguised_structure(ParseContext * ctx,const gchar * type)662 is_disguised_structure (ParseContext *ctx, const gchar *type)
663 {
664   const gchar *lookup;
665   gchar *prefixed;
666   gboolean result;
667 
668   if (strchr (type, '.') == NULL)
669     {
670       prefixed = g_strdup_printf ("%s.%s", ctx->namespace, type);
671       lookup = prefixed;
672     }
673   else
674     {
675       lookup = type;
676       prefixed = NULL;
677     }
678 
679   result = g_hash_table_lookup (ctx->current_module->disguised_structures,
680 				lookup) != NULL;
681 
682   g_free (prefixed);
683 
684   return result;
685 }
686 
687 static GIrNodeType *
parse_type(ParseContext * ctx,const gchar * type)688 parse_type (ParseContext *ctx, const gchar *type)
689 {
690   GIrNodeType *node;
691   const BasicTypeInfo *basic;
692   gboolean in_glib, in_gobject;
693 
694   in_glib = strcmp (ctx->namespace, "GLib") == 0;
695   in_gobject = strcmp (ctx->namespace, "GObject") == 0;
696 
697   /* Do not search aliases for basic types */
698   basic = parse_basic (type);
699   if (basic == NULL)
700     type = resolve_aliases (ctx, type);
701 
702   node = parse_type_internal (ctx->current_module, type, NULL, in_glib, in_gobject);
703   if (node)
704     g_debug ("Parsed type: %s => %d", type, node->tag);
705   else
706     g_critical ("Failed to parse type: '%s'", type);
707 
708   return node;
709 }
710 
711 static gboolean
introspectable_prelude(GMarkupParseContext * context,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,ParseState new_state)712 introspectable_prelude (GMarkupParseContext *context,
713 		    const gchar        **attribute_names,
714 		    const gchar        **attribute_values,
715 		    ParseContext        *ctx,
716 		    ParseState           new_state)
717 {
718   const gchar *introspectable_arg;
719   const gchar *shadowed_by;
720   gboolean introspectable;
721 
722   g_assert (ctx->state != STATE_PASSTHROUGH);
723 
724   introspectable_arg = find_attribute ("introspectable", attribute_names, attribute_values);
725   shadowed_by = find_attribute ("shadowed-by", attribute_names, attribute_values);
726 
727   introspectable = !(introspectable_arg && atoi (introspectable_arg) == 0) && shadowed_by == NULL;
728 
729   if (introspectable)
730     state_switch (ctx, new_state);
731   else
732     state_switch (ctx, STATE_PASSTHROUGH);
733 
734   return introspectable;
735 }
736 
737 static gboolean
start_glib_boxed(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)738 start_glib_boxed (GMarkupParseContext *context,
739 		  const gchar         *element_name,
740 		  const gchar        **attribute_names,
741 		  const gchar        **attribute_values,
742 		  ParseContext        *ctx,
743 		  GError             **error)
744 {
745   const gchar *name;
746   const gchar *typename;
747   const gchar *typeinit;
748   const gchar *deprecated;
749   GIrNodeBoxed *boxed;
750 
751   if (!(strcmp (element_name, "glib:boxed") == 0 &&
752 	ctx->state == STATE_NAMESPACE))
753     return FALSE;
754 
755   if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_BOXED))
756     return TRUE;
757 
758   name = find_attribute ("glib:name", attribute_names, attribute_values);
759   typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
760   typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
761   deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
762 
763   if (name == NULL)
764     {
765       MISSING_ATTRIBUTE (context, error, element_name, "glib:name");
766       return FALSE;
767     }
768   else if (typename == NULL)
769     {
770       MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name");
771       return FALSE;
772     }
773   else if (typeinit == NULL)
774     {
775       MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
776       return FALSE;
777     }
778 
779   boxed = (GIrNodeBoxed *) _g_ir_node_new (G_IR_NODE_BOXED,
780 					  ctx->current_module);
781 
782   ((GIrNode *)boxed)->name = g_strdup (name);
783   boxed->gtype_name = g_strdup (typename);
784   boxed->gtype_init = g_strdup (typeinit);
785   if (deprecated)
786     boxed->deprecated = TRUE;
787   else
788     boxed->deprecated = FALSE;
789 
790   push_node (ctx, (GIrNode *)boxed);
791   ctx->current_module->entries =
792     g_list_append (ctx->current_module->entries, boxed);
793 
794   return TRUE;
795 }
796 
797 static gboolean
start_function(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)798 start_function (GMarkupParseContext *context,
799 		const gchar         *element_name,
800 		const gchar        **attribute_names,
801 		const gchar        **attribute_values,
802 		ParseContext        *ctx,
803 		GError             **error)
804 {
805   const gchar *name;
806   const gchar *shadows;
807   const gchar *symbol;
808   const gchar *deprecated;
809   const gchar *throws;
810   const gchar *set_property;
811   const gchar *get_property;
812   GIrNodeFunction *function;
813   gboolean found = FALSE;
814   ParseState in_embedded_state = STATE_NONE;
815 
816   switch (ctx->state)
817     {
818     case STATE_NAMESPACE:
819       found = (strcmp (element_name, "function") == 0 ||
820 	       strcmp (element_name, "callback") == 0);
821       break;
822     case STATE_CLASS:
823     case STATE_BOXED:
824     case STATE_STRUCT:
825     case STATE_UNION:
826       found = strcmp (element_name, "constructor") == 0;
827       /* fallthrough */
828     case STATE_INTERFACE:
829       found = (found ||
830 	       strcmp (element_name, "function") == 0 ||
831 	       strcmp (element_name, "method") == 0 ||
832 	       strcmp (element_name, "callback") == 0);
833       break;
834     case STATE_ENUM:
835       found = strcmp (element_name, "function") == 0;
836       break;
837     case STATE_CLASS_FIELD:
838     case STATE_STRUCT_FIELD:
839       found = (found || strcmp (element_name, "callback") == 0);
840       in_embedded_state = ctx->state;
841       break;
842     default:
843       break;
844     }
845 
846   if (!found)
847     return FALSE;
848 
849   if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_FUNCTION))
850     return TRUE;
851 
852   ctx->in_embedded_state = in_embedded_state;
853 
854   name = find_attribute ("name", attribute_names, attribute_values);
855   shadows = find_attribute ("shadows", attribute_names, attribute_values);
856   symbol = find_attribute ("c:identifier", attribute_names, attribute_values);
857   deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
858   throws = find_attribute ("throws", attribute_names, attribute_values);
859   set_property = find_attribute ("glib:set-property", attribute_names, attribute_values);
860   get_property = find_attribute ("glib:get-property", attribute_names, attribute_values);
861 
862   if (name == NULL)
863     {
864       MISSING_ATTRIBUTE (context, error, element_name, "name");
865       return FALSE;
866     }
867   else if (strcmp (element_name, "callback") != 0 && symbol == NULL)
868     {
869       MISSING_ATTRIBUTE (context, error, element_name, "c:identifier");
870       return FALSE;
871     }
872 
873   if (shadows)
874     name = shadows;
875 
876   function = (GIrNodeFunction *) _g_ir_node_new (G_IR_NODE_FUNCTION,
877 						ctx->current_module);
878 
879   ((GIrNode *)function)->name = g_strdup (name);
880   function->symbol = g_strdup (symbol);
881   function->parameters = NULL;
882   if (deprecated)
883     function->deprecated = TRUE;
884   else
885     function->deprecated = FALSE;
886 
887   if (strcmp (element_name, "method") == 0 ||
888       strcmp (element_name, "constructor") == 0)
889     {
890       function->is_method = TRUE;
891 
892       if (strcmp (element_name, "constructor") == 0)
893 	function->is_constructor = TRUE;
894       else
895 	function->is_constructor = FALSE;
896 
897       if (set_property != NULL)
898         {
899           function->is_setter = TRUE;
900           function->is_getter = FALSE;
901           function->property = g_strdup (set_property);
902         }
903       else if (get_property != NULL)
904         {
905           function->is_setter = FALSE;
906           function->is_getter = TRUE;
907           function->property = g_strdup (get_property);
908         }
909       else
910         {
911           function->is_setter = FALSE;
912           function->is_getter = FALSE;
913           function->property = NULL;
914         }
915     }
916   else
917     {
918       function->is_method = FALSE;
919       function->is_setter = FALSE;
920       function->is_getter = FALSE;
921       function->is_constructor = FALSE;
922       if (strcmp (element_name, "callback") == 0)
923 	((GIrNode *)function)->type = G_IR_NODE_CALLBACK;
924     }
925 
926   if (throws && strcmp (throws, "1") == 0)
927     function->throws = TRUE;
928   else
929     function->throws = FALSE;
930 
931   if (ctx->node_stack == NULL)
932     {
933       ctx->current_module->entries =
934 	g_list_append (ctx->current_module->entries, function);
935     }
936   else if (ctx->current_typed)
937     {
938       GIrNodeField *field;
939 
940       field = (GIrNodeField *)ctx->current_typed;
941       field->callback = function;
942     }
943   else
944     switch (CURRENT_NODE (ctx)->type)
945       {
946       case G_IR_NODE_INTERFACE:
947       case G_IR_NODE_OBJECT:
948 	{
949 	  GIrNodeInterface *iface;
950 
951 	  iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
952 	  iface->members = g_list_append (iface->members, function);
953 	}
954 	break;
955       case G_IR_NODE_BOXED:
956 	{
957 	  GIrNodeBoxed *boxed;
958 
959 	  boxed = (GIrNodeBoxed *)CURRENT_NODE (ctx);
960 	  boxed->members = g_list_append (boxed->members, function);
961 	}
962 	break;
963       case G_IR_NODE_STRUCT:
964 	{
965 	  GIrNodeStruct *struct_;
966 
967 	  struct_ = (GIrNodeStruct *)CURRENT_NODE (ctx);
968 	  struct_->members = g_list_append (struct_->members, function);		}
969 	break;
970       case G_IR_NODE_UNION:
971 	{
972 	  GIrNodeUnion *union_;
973 
974 	  union_ = (GIrNodeUnion *)CURRENT_NODE (ctx);
975 	  union_->members = g_list_append (union_->members, function);
976 	}
977 	break;
978       case G_IR_NODE_ENUM:
979       case G_IR_NODE_FLAGS:
980 	{
981 	  GIrNodeEnum *enum_;
982 
983 	  enum_ = (GIrNodeEnum *)CURRENT_NODE (ctx);
984 	  enum_->methods = g_list_append (enum_->methods, function);
985 	}
986 	break;
987       default:
988 	g_assert_not_reached ();
989       }
990 
991   push_node(ctx, (GIrNode *)function);
992 
993   return TRUE;
994 }
995 
996 static void
parse_property_transfer(GIrNodeProperty * property,const gchar * transfer,ParseContext * ctx)997 parse_property_transfer (GIrNodeProperty *property,
998                          const gchar     *transfer,
999                          ParseContext    *ctx)
1000 {
1001   if (transfer == NULL)
1002   {
1003 #if 0
1004     GIrNodeInterface *iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
1005 
1006     g_debug ("required attribute 'transfer-ownership' is missing from "
1007              "property '%s' in type '%s.%s'. Assuming 'none'\n",
1008              property->node.name, ctx->namespace, iface->node.name);
1009 #endif
1010     transfer = "none";
1011   }
1012   if (strcmp (transfer, "none") == 0)
1013     {
1014       property->transfer = FALSE;
1015       property->shallow_transfer = FALSE;
1016     }
1017   else if (strcmp (transfer, "container") == 0)
1018     {
1019       property->transfer = FALSE;
1020       property->shallow_transfer = TRUE;
1021     }
1022   else if (strcmp (transfer, "full") == 0)
1023     {
1024       property->transfer = TRUE;
1025       property->shallow_transfer = FALSE;
1026     }
1027   else
1028     {
1029       GIrNodeInterface *iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
1030 
1031       g_warning ("Unknown transfer-ownership value: '%s' for property '%s' in "
1032                  "type '%s.%s'", transfer, property->node.name, ctx->namespace,
1033                  iface->node.name);
1034     }
1035 }
1036 
1037 static gboolean
parse_param_transfer(GIrNodeParam * param,const gchar * transfer,const gchar * name,GError ** error)1038 parse_param_transfer (GIrNodeParam *param, const gchar *transfer, const gchar *name,
1039 		      GError **error)
1040 {
1041   if (transfer == NULL)
1042   {
1043     g_set_error (error, G_MARKUP_ERROR,
1044 		 G_MARKUP_ERROR_INVALID_CONTENT,
1045 		 "required attribute 'transfer-ownership' missing");
1046     return FALSE;
1047   }
1048   else if (strcmp (transfer, "none") == 0)
1049     {
1050       param->transfer = FALSE;
1051       param->shallow_transfer = FALSE;
1052     }
1053   else if (strcmp (transfer, "container") == 0)
1054     {
1055       param->transfer = FALSE;
1056       param->shallow_transfer = TRUE;
1057     }
1058   else if (strcmp (transfer, "full") == 0)
1059     {
1060       param->transfer = TRUE;
1061       param->shallow_transfer = FALSE;
1062     }
1063   else
1064     {
1065       g_set_error (error, G_MARKUP_ERROR,
1066 		   G_MARKUP_ERROR_INVALID_CONTENT,
1067 		   "invalid value for 'transfer-ownership': %s", transfer);
1068       return FALSE;
1069     }
1070   return TRUE;
1071 }
1072 
1073 static gboolean
start_instance_parameter(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)1074 start_instance_parameter (GMarkupParseContext *context,
1075                           const gchar         *element_name,
1076                           const gchar        **attribute_names,
1077                           const gchar        **attribute_values,
1078                           ParseContext        *ctx,
1079                           GError             **error)
1080 {
1081   const gchar *transfer;
1082   gboolean transfer_full;
1083 
1084   if (!(strcmp (element_name, "instance-parameter") == 0 &&
1085 	ctx->state == STATE_FUNCTION_PARAMETERS))
1086     return FALSE;
1087 
1088   transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values);
1089 
1090   state_switch (ctx, STATE_PASSTHROUGH);
1091 
1092   if (g_strcmp0 (transfer, "full") == 0)
1093     transfer_full = TRUE;
1094   else if (g_strcmp0 (transfer, "none") == 0)
1095     transfer_full = FALSE;
1096   else
1097     {
1098       g_set_error (error, G_MARKUP_ERROR,
1099 		   G_MARKUP_ERROR_INVALID_CONTENT,
1100 		   "invalid value for 'transfer-ownership' for instance parameter: %s", transfer);
1101       return FALSE;
1102     }
1103 
1104   switch (CURRENT_NODE (ctx)->type)
1105     {
1106     case G_IR_NODE_FUNCTION:
1107     case G_IR_NODE_CALLBACK:
1108       {
1109 	GIrNodeFunction *func;
1110 
1111 	func = (GIrNodeFunction *)CURRENT_NODE (ctx);
1112         func->instance_transfer_full = transfer_full;
1113       }
1114       break;
1115     case G_IR_NODE_SIGNAL:
1116       {
1117 	GIrNodeSignal *signal;
1118 
1119 	signal = (GIrNodeSignal *)CURRENT_NODE (ctx);
1120         signal->instance_transfer_full = transfer_full;
1121       }
1122       break;
1123     case G_IR_NODE_VFUNC:
1124       {
1125 	GIrNodeVFunc *vfunc;
1126 
1127 	vfunc = (GIrNodeVFunc *)CURRENT_NODE (ctx);
1128         vfunc->instance_transfer_full = transfer_full;
1129       }
1130       break;
1131     default:
1132       g_assert_not_reached ();
1133     }
1134 
1135   return TRUE;
1136 }
1137 
1138 static gboolean
start_parameter(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)1139 start_parameter (GMarkupParseContext *context,
1140 		 const gchar         *element_name,
1141 		 const gchar        **attribute_names,
1142 		 const gchar        **attribute_values,
1143 		 ParseContext        *ctx,
1144 		 GError             **error)
1145 {
1146   const gchar *name;
1147   const gchar *direction;
1148   const gchar *retval;
1149   const gchar *optional;
1150   const gchar *caller_allocates;
1151   const gchar *allow_none;
1152   const gchar *transfer;
1153   const gchar *scope;
1154   const gchar *closure;
1155   const gchar *destroy;
1156   const gchar *skip;
1157   const gchar *nullable;
1158   GIrNodeParam *param;
1159 
1160   if (!(strcmp (element_name, "parameter") == 0 &&
1161 	ctx->state == STATE_FUNCTION_PARAMETERS))
1162     return FALSE;
1163 
1164   name = find_attribute ("name", attribute_names, attribute_values);
1165   direction = find_attribute ("direction", attribute_names, attribute_values);
1166   retval = find_attribute ("retval", attribute_names, attribute_values);
1167   optional = find_attribute ("optional", attribute_names, attribute_values);
1168   allow_none = find_attribute ("allow-none", attribute_names, attribute_values);
1169   caller_allocates = find_attribute ("caller-allocates", attribute_names, attribute_values);
1170   transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values);
1171   scope = find_attribute ("scope", attribute_names, attribute_values);
1172   closure = find_attribute ("closure", attribute_names, attribute_values);
1173   destroy = find_attribute ("destroy", attribute_names, attribute_values);
1174   skip = find_attribute ("skip", attribute_names, attribute_values);
1175   nullable = find_attribute ("nullable", attribute_names, attribute_values);
1176 
1177   if (name == NULL)
1178     name = "unknown";
1179 
1180   param = (GIrNodeParam *)_g_ir_node_new (G_IR_NODE_PARAM,
1181 					  ctx->current_module);
1182 
1183   ctx->current_typed = (GIrNode*) param;
1184   ctx->current_typed->name = g_strdup (name);
1185 
1186   state_switch (ctx, STATE_FUNCTION_PARAMETER);
1187 
1188   if (direction && strcmp (direction, "out") == 0)
1189     {
1190       param->in = FALSE;
1191       param->out = TRUE;
1192       if (caller_allocates == NULL)
1193 	param->caller_allocates = FALSE;
1194       else
1195 	param->caller_allocates = strcmp (caller_allocates, "1") == 0;
1196     }
1197   else if (direction && strcmp (direction, "inout") == 0)
1198     {
1199       param->in = TRUE;
1200       param->out = TRUE;
1201       param->caller_allocates = FALSE;
1202     }
1203   else
1204     {
1205       param->in = TRUE;
1206       param->out = FALSE;
1207       param->caller_allocates = FALSE;
1208     }
1209 
1210   if (retval && strcmp (retval, "1") == 0)
1211     param->retval = TRUE;
1212   else
1213     param->retval = FALSE;
1214 
1215   if (optional && strcmp (optional, "1") == 0)
1216     param->optional = TRUE;
1217   else
1218     param->optional = FALSE;
1219 
1220   if (nullable && strcmp (nullable, "1") == 0)
1221     param->nullable = TRUE;
1222   else
1223     param->nullable = FALSE;
1224 
1225   if (allow_none && strcmp (allow_none, "1") == 0)
1226     {
1227       if (param->out)
1228         param->optional = TRUE;
1229       else
1230         param->nullable = TRUE;
1231     }
1232 
1233   if (skip && strcmp (skip, "1") == 0)
1234     param->skip = TRUE;
1235   else
1236     param->skip = FALSE;
1237 
1238   if (!parse_param_transfer (param, transfer, name, error))
1239     return FALSE;
1240 
1241   if (scope && strcmp (scope, "call") == 0)
1242     param->scope = GI_SCOPE_TYPE_CALL;
1243   else if (scope && strcmp (scope, "async") == 0)
1244     param->scope = GI_SCOPE_TYPE_ASYNC;
1245   else if (scope && strcmp (scope, "notified") == 0)
1246     param->scope = GI_SCOPE_TYPE_NOTIFIED;
1247   else
1248     param->scope = GI_SCOPE_TYPE_INVALID;
1249 
1250   param->closure = closure ? atoi (closure) : -1;
1251   param->destroy = destroy ? atoi (destroy) : -1;
1252 
1253   ((GIrNode *)param)->name = g_strdup (name);
1254 
1255   switch (CURRENT_NODE (ctx)->type)
1256     {
1257     case G_IR_NODE_FUNCTION:
1258     case G_IR_NODE_CALLBACK:
1259       {
1260 	GIrNodeFunction *func;
1261 
1262 	func = (GIrNodeFunction *)CURRENT_NODE (ctx);
1263 	func->parameters = g_list_append (func->parameters, param);
1264       }
1265       break;
1266     case G_IR_NODE_SIGNAL:
1267       {
1268 	GIrNodeSignal *signal;
1269 
1270 	signal = (GIrNodeSignal *)CURRENT_NODE (ctx);
1271 	signal->parameters = g_list_append (signal->parameters, param);
1272       }
1273       break;
1274     case G_IR_NODE_VFUNC:
1275       {
1276 	GIrNodeVFunc *vfunc;
1277 
1278 	vfunc = (GIrNodeVFunc *)CURRENT_NODE (ctx);
1279 	vfunc->parameters = g_list_append (vfunc->parameters, param);
1280       }
1281       break;
1282     default:
1283       g_assert_not_reached ();
1284     }
1285 
1286   return TRUE;
1287 }
1288 
1289 static gboolean
start_field(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)1290 start_field (GMarkupParseContext *context,
1291 	     const gchar         *element_name,
1292 	     const gchar        **attribute_names,
1293 	     const gchar        **attribute_values,
1294 	     ParseContext        *ctx,
1295 	     GError             **error)
1296 {
1297   const gchar *name;
1298   const gchar *readable;
1299   const gchar *writable;
1300   const gchar *bits;
1301   const gchar *branch;
1302   GIrNodeField *field;
1303   ParseState target_state;
1304   gboolean introspectable;
1305 
1306   switch (ctx->state)
1307     {
1308     case STATE_CLASS:
1309       target_state = STATE_CLASS_FIELD;
1310       break;
1311     case STATE_BOXED:
1312       target_state = STATE_BOXED_FIELD;
1313       break;
1314     case STATE_STRUCT:
1315       target_state = STATE_STRUCT_FIELD;
1316       break;
1317     case STATE_UNION:
1318       target_state = STATE_UNION_FIELD;
1319       break;
1320     case STATE_INTERFACE:
1321       target_state = STATE_INTERFACE_FIELD;
1322       break;
1323     default:
1324       return FALSE;
1325     }
1326 
1327   if (strcmp (element_name, "field") != 0)
1328     return FALSE;
1329 
1330   g_assert (ctx->state != STATE_PASSTHROUGH);
1331 
1332   /* We handle introspectability specially here; we replace with just gpointer
1333    * for the type.
1334    */
1335   introspectable = introspectable_prelude (context, attribute_names, attribute_values, ctx, target_state);
1336 
1337   name = find_attribute ("name", attribute_names, attribute_values);
1338   readable = find_attribute ("readable", attribute_names, attribute_values);
1339   writable = find_attribute ("writable", attribute_names, attribute_values);
1340   bits = find_attribute ("bits", attribute_names, attribute_values);
1341   branch = find_attribute ("branch", attribute_names, attribute_values);
1342 
1343   if (name == NULL)
1344     {
1345       MISSING_ATTRIBUTE (context, error, element_name, "name");
1346       return FALSE;
1347     }
1348 
1349   field = (GIrNodeField *)_g_ir_node_new (G_IR_NODE_FIELD,
1350 					  ctx->current_module);
1351   if (introspectable)
1352     {
1353       ctx->current_typed = (GIrNode*) field;
1354     }
1355   else
1356     {
1357       field->type = parse_type (ctx, "gpointer");
1358     }
1359 
1360   ((GIrNode *)field)->name = g_strdup (name);
1361   /* Fields are assumed to be read-only.
1362    * (see also girwriter.py and generate.c)
1363    */
1364   field->readable = readable == NULL || strcmp (readable, "0") == 0;
1365   field->writable = writable != NULL && strcmp (writable, "1") == 0;
1366 
1367   if (bits)
1368     field->bits = atoi (bits);
1369   else
1370     field->bits = 0;
1371 
1372   switch (CURRENT_NODE (ctx)->type)
1373     {
1374     case G_IR_NODE_OBJECT:
1375       {
1376 	GIrNodeInterface *iface;
1377 
1378 	iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
1379 	iface->members = g_list_append (iface->members, field);
1380       }
1381       break;
1382     case G_IR_NODE_INTERFACE:
1383       {
1384 	GIrNodeInterface *iface;
1385 
1386 	iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
1387 	iface->members = g_list_append (iface->members, field);
1388       }
1389       break;
1390     case G_IR_NODE_BOXED:
1391       {
1392 	GIrNodeBoxed *boxed;
1393 
1394 	boxed = (GIrNodeBoxed *)CURRENT_NODE (ctx);
1395 		boxed->members = g_list_append (boxed->members, field);
1396       }
1397       break;
1398     case G_IR_NODE_STRUCT:
1399       {
1400 	GIrNodeStruct *struct_;
1401 
1402 	struct_ = (GIrNodeStruct *)CURRENT_NODE (ctx);
1403 	struct_->members = g_list_append (struct_->members, field);
1404       }
1405       break;
1406     case G_IR_NODE_UNION:
1407       {
1408 	GIrNodeUnion *union_;
1409 
1410 	union_ = (GIrNodeUnion *)CURRENT_NODE (ctx);
1411 	union_->members = g_list_append (union_->members, field);
1412 	if (branch)
1413 	  {
1414 	    GIrNodeConstant *constant;
1415 
1416 	    constant = (GIrNodeConstant *) _g_ir_node_new (G_IR_NODE_CONSTANT,
1417 							  ctx->current_module);
1418 	    ((GIrNode *)constant)->name = g_strdup (name);
1419 	    constant->value = g_strdup (branch);
1420 	    constant->type = union_->discriminator_type;
1421 	    constant->deprecated = FALSE;
1422 
1423 	    union_->discriminators = g_list_append (union_->discriminators, constant);
1424 	  }
1425       }
1426       break;
1427     default:
1428       g_assert_not_reached ();
1429     }
1430 
1431   return TRUE;
1432 }
1433 
1434 static gboolean
start_alias(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)1435 start_alias (GMarkupParseContext *context,
1436 	     const gchar         *element_name,
1437 	     const gchar        **attribute_names,
1438 	     const gchar        **attribute_values,
1439 	     ParseContext        *ctx,
1440 	     GError             **error)
1441 {
1442   const gchar *name;
1443 
1444   name = find_attribute ("name", attribute_names, attribute_values);
1445   if (name == NULL)
1446     {
1447       MISSING_ATTRIBUTE (context, error, element_name, "name");
1448       return FALSE;
1449     }
1450 
1451   ctx->current_alias = g_strdup (name);
1452   state_switch (ctx, STATE_ALIAS);
1453 
1454   return TRUE;
1455 }
1456 
1457 static gboolean
start_enum(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)1458 start_enum (GMarkupParseContext *context,
1459 	     const gchar         *element_name,
1460 	     const gchar        **attribute_names,
1461 	     const gchar        **attribute_values,
1462 	     ParseContext        *ctx,
1463 	     GError             **error)
1464 {
1465   const gchar *name;
1466   const gchar *typename;
1467   const gchar *typeinit;
1468   const gchar *deprecated;
1469   const gchar *error_domain;
1470   GIrNodeEnum *enum_;
1471 
1472   if (!((strcmp (element_name, "enumeration") == 0 && ctx->state == STATE_NAMESPACE) ||
1473 	(strcmp (element_name, "bitfield") == 0 && ctx->state == STATE_NAMESPACE)))
1474     return FALSE;
1475 
1476   if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_ENUM))
1477     return TRUE;
1478 
1479   name = find_attribute ("name", attribute_names, attribute_values);
1480   typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
1481   typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
1482   error_domain = find_attribute ("glib:error-domain", attribute_names, attribute_values);
1483   deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
1484 
1485   if (name == NULL)
1486     {
1487       MISSING_ATTRIBUTE (context, error, element_name, "name");
1488       return FALSE;
1489     }
1490 
1491   if (strcmp (element_name, "enumeration") == 0)
1492     enum_ = (GIrNodeEnum *) _g_ir_node_new (G_IR_NODE_ENUM,
1493 					   ctx->current_module);
1494   else
1495     enum_ = (GIrNodeEnum *) _g_ir_node_new (G_IR_NODE_FLAGS,
1496 					   ctx->current_module);
1497   ((GIrNode *)enum_)->name = g_strdup (name);
1498   enum_->gtype_name = g_strdup (typename);
1499   enum_->gtype_init = g_strdup (typeinit);
1500   enum_->error_domain = g_strdup (error_domain);
1501 
1502   if (deprecated)
1503     enum_->deprecated = TRUE;
1504   else
1505     enum_->deprecated = FALSE;
1506 
1507   push_node (ctx, (GIrNode *) enum_);
1508   ctx->current_module->entries =
1509     g_list_append (ctx->current_module->entries, enum_);
1510 
1511   return TRUE;
1512 }
1513 
1514 static gboolean
start_property(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)1515 start_property (GMarkupParseContext *context,
1516 		const gchar         *element_name,
1517 		const gchar        **attribute_names,
1518 		const gchar        **attribute_values,
1519 		ParseContext        *ctx,
1520 		GError             **error)
1521 {
1522   ParseState target_state;
1523   const gchar *name;
1524   const gchar *readable;
1525   const gchar *writable;
1526   const gchar *construct;
1527   const gchar *construct_only;
1528   const gchar *transfer;
1529   const gchar *setter;
1530   const gchar *getter;
1531   GIrNodeProperty *property;
1532   GIrNodeInterface *iface;
1533 
1534   if (!(strcmp (element_name, "property") == 0 &&
1535 	(ctx->state == STATE_CLASS ||
1536 	 ctx->state == STATE_INTERFACE)))
1537     return FALSE;
1538 
1539   if (ctx->state == STATE_CLASS)
1540     target_state = STATE_CLASS_PROPERTY;
1541   else if (ctx->state == STATE_INTERFACE)
1542     target_state = STATE_INTERFACE_PROPERTY;
1543   else
1544     g_assert_not_reached ();
1545 
1546   if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, target_state))
1547     return TRUE;
1548 
1549 
1550   name = find_attribute ("name", attribute_names, attribute_values);
1551   readable = find_attribute ("readable", attribute_names, attribute_values);
1552   writable = find_attribute ("writable", attribute_names, attribute_values);
1553   construct = find_attribute ("construct", attribute_names, attribute_values);
1554   construct_only = find_attribute ("construct-only", attribute_names, attribute_values);
1555   transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values);
1556   setter = find_attribute ("setter", attribute_names, attribute_values);
1557   getter = find_attribute ("getter", attribute_names, attribute_values);
1558 
1559   if (name == NULL)
1560     {
1561       MISSING_ATTRIBUTE (context, error, element_name, "name");
1562       return FALSE;
1563     }
1564 
1565   property = (GIrNodeProperty *) _g_ir_node_new (G_IR_NODE_PROPERTY,
1566 						ctx->current_module);
1567   ctx->current_typed = (GIrNode*) property;
1568 
1569   ((GIrNode *)property)->name = g_strdup (name);
1570 
1571   /* Assume properties are readable */
1572   if (readable == NULL || strcmp (readable, "1") == 0)
1573     property->readable = TRUE;
1574   else
1575     property->readable = FALSE;
1576   if (writable && strcmp (writable, "1") == 0)
1577     property->writable = TRUE;
1578   else
1579     property->writable = FALSE;
1580   if (construct && strcmp (construct, "1") == 0)
1581     property->construct = TRUE;
1582   else
1583     property->construct = FALSE;
1584   if (construct_only && strcmp (construct_only, "1") == 0)
1585     property->construct_only = TRUE;
1586   else
1587     property->construct_only = FALSE;
1588 
1589   property->setter = g_strdup (setter);
1590   property->getter = g_strdup (getter);
1591 
1592   parse_property_transfer (property, transfer, ctx);
1593 
1594   iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
1595   iface->members = g_list_append (iface->members, property);
1596 
1597   return TRUE;
1598 }
1599 
1600 static gint64
parse_value(const gchar * str)1601 parse_value (const gchar *str)
1602 {
1603   gchar *shift_op;
1604 
1605   /* FIXME just a quick hack */
1606   shift_op = strstr (str, "<<");
1607 
1608   if (shift_op)
1609     {
1610       gint64 base, shift;
1611 
1612       base = g_ascii_strtoll (str, NULL, 10);
1613       shift = g_ascii_strtoll (shift_op + 3, NULL, 10);
1614 
1615       return base << shift;
1616     }
1617   else
1618     return g_ascii_strtoll (str, NULL, 10);
1619 
1620   return 0;
1621 }
1622 
1623 static gboolean
start_member(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)1624 start_member (GMarkupParseContext *context,
1625 	      const gchar         *element_name,
1626 	      const gchar        **attribute_names,
1627 	      const gchar        **attribute_values,
1628 	      ParseContext        *ctx,
1629 	      GError             **error)
1630 {
1631   const gchar *name;
1632   const gchar *value;
1633   const gchar *deprecated;
1634   const gchar *c_identifier;
1635   GIrNodeEnum *enum_;
1636   GIrNodeValue *value_;
1637 
1638   if (!(strcmp (element_name, "member") == 0 &&
1639 	ctx->state == STATE_ENUM))
1640     return FALSE;
1641 
1642   name = find_attribute ("name", attribute_names, attribute_values);
1643   value = find_attribute ("value", attribute_names, attribute_values);
1644   deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
1645   c_identifier = find_attribute ("c:identifier", attribute_names, attribute_values);
1646 
1647   if (name == NULL)
1648     {
1649       MISSING_ATTRIBUTE (context, error, element_name, "name");
1650       return FALSE;
1651     }
1652 
1653   value_ = (GIrNodeValue *) _g_ir_node_new (G_IR_NODE_VALUE,
1654 					   ctx->current_module);
1655 
1656   ((GIrNode *)value_)->name = g_strdup (name);
1657 
1658   value_->value = parse_value (value);
1659 
1660   if (deprecated)
1661     value_->deprecated = TRUE;
1662   else
1663     value_->deprecated = FALSE;
1664 
1665   g_hash_table_insert (((GIrNode *)value_)->attributes,
1666                        g_strdup ("c:identifier"),
1667                        g_strdup (c_identifier));
1668 
1669   enum_ = (GIrNodeEnum *)CURRENT_NODE (ctx);
1670   enum_->values = g_list_append (enum_->values, value_);
1671 
1672   return TRUE;
1673 }
1674 
1675 static gboolean
start_constant(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)1676 start_constant (GMarkupParseContext *context,
1677 		const gchar         *element_name,
1678 		const gchar        **attribute_names,
1679 		const gchar        **attribute_values,
1680 		ParseContext        *ctx,
1681 		GError             **error)
1682 {
1683   ParseState prev_state;
1684   ParseState target_state;
1685   const gchar *name;
1686   const gchar *value;
1687   const gchar *deprecated;
1688   GIrNodeConstant *constant;
1689 
1690   if (!(strcmp (element_name, "constant") == 0 &&
1691 	(ctx->state == STATE_NAMESPACE ||
1692 	 ctx->state == STATE_CLASS ||
1693 	 ctx->state == STATE_INTERFACE)))
1694     return FALSE;
1695 
1696   switch (ctx->state)
1697     {
1698     case STATE_NAMESPACE:
1699       target_state = STATE_NAMESPACE_CONSTANT;
1700       break;
1701     case STATE_CLASS:
1702       target_state = STATE_CLASS_CONSTANT;
1703       break;
1704     case STATE_INTERFACE:
1705       target_state = STATE_INTERFACE_CONSTANT;
1706       break;
1707     default:
1708       g_assert_not_reached ();
1709     }
1710 
1711   prev_state = ctx->state;
1712 
1713   if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, target_state))
1714     return TRUE;
1715 
1716   name = find_attribute ("name", attribute_names, attribute_values);
1717   value = find_attribute ("value", attribute_names, attribute_values);
1718   deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
1719 
1720   if (name == NULL)
1721     {
1722       MISSING_ATTRIBUTE (context, error, element_name, "name");
1723       return FALSE;
1724     }
1725   else if (value == NULL)
1726     {
1727       MISSING_ATTRIBUTE (context, error, element_name, "value");
1728       return FALSE;
1729     }
1730 
1731   constant = (GIrNodeConstant *) _g_ir_node_new (G_IR_NODE_CONSTANT,
1732 						ctx->current_module);
1733 
1734   ((GIrNode *)constant)->name = g_strdup (name);
1735   constant->value = g_strdup (value);
1736 
1737   ctx->current_typed = (GIrNode*) constant;
1738 
1739   if (deprecated)
1740     constant->deprecated = TRUE;
1741   else
1742     constant->deprecated = FALSE;
1743 
1744   if (prev_state == STATE_NAMESPACE)
1745     {
1746       push_node (ctx, (GIrNode *) constant);
1747       ctx->current_module->entries =
1748 	g_list_append (ctx->current_module->entries, constant);
1749     }
1750   else
1751     {
1752       GIrNodeInterface *iface;
1753 
1754       iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
1755       iface->members = g_list_append (iface->members, constant);
1756     }
1757 
1758   return TRUE;
1759 }
1760 
1761 static gboolean
start_interface(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)1762 start_interface (GMarkupParseContext *context,
1763 		 const gchar         *element_name,
1764 		 const gchar        **attribute_names,
1765 		 const gchar        **attribute_values,
1766 		 ParseContext        *ctx,
1767 		 GError             **error)
1768 {
1769   const gchar *name;
1770   const gchar *typename;
1771   const gchar *typeinit;
1772   const gchar *deprecated;
1773   const gchar *glib_type_struct;
1774   GIrNodeInterface *iface;
1775 
1776   if (!(strcmp (element_name, "interface") == 0 &&
1777 	ctx->state == STATE_NAMESPACE))
1778     return FALSE;
1779 
1780   if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_INTERFACE))
1781     return TRUE;
1782 
1783   name = find_attribute ("name", attribute_names, attribute_values);
1784   typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
1785   typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
1786   glib_type_struct = find_attribute ("glib:type-struct", attribute_names, attribute_values);
1787   deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
1788 
1789   if (name == NULL)
1790     {
1791       MISSING_ATTRIBUTE (context, error, element_name, "name");
1792       return FALSE;
1793     }
1794   else if (typename == NULL)
1795     {
1796       MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name");
1797       return FALSE;
1798     }
1799   else if (typeinit == NULL)
1800     {
1801       MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
1802       return FALSE;
1803     }
1804 
1805   iface = (GIrNodeInterface *) _g_ir_node_new (G_IR_NODE_INTERFACE,
1806 					      ctx->current_module);
1807   ((GIrNode *)iface)->name = g_strdup (name);
1808   iface->gtype_name = g_strdup (typename);
1809   iface->gtype_init = g_strdup (typeinit);
1810   iface->glib_type_struct = g_strdup (glib_type_struct);
1811   if (deprecated)
1812     iface->deprecated = TRUE;
1813   else
1814     iface->deprecated = FALSE;
1815 
1816   push_node (ctx, (GIrNode *) iface);
1817   ctx->current_module->entries =
1818     g_list_append (ctx->current_module->entries, iface);
1819 
1820   return TRUE;
1821 }
1822 
1823 static gboolean
start_class(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)1824 start_class (GMarkupParseContext *context,
1825 	      const gchar         *element_name,
1826 	      const gchar        **attribute_names,
1827 	      const gchar        **attribute_values,
1828 	      ParseContext        *ctx,
1829 	      GError             **error)
1830 {
1831   const gchar *name;
1832   const gchar *parent;
1833   const gchar *glib_type_struct;
1834   const gchar *typename;
1835   const gchar *typeinit;
1836   const gchar *deprecated;
1837   const gchar *abstract;
1838   const gchar *fundamental;
1839   const gchar *final;
1840   const gchar *ref_func;
1841   const gchar *unref_func;
1842   const gchar *set_value_func;
1843   const gchar *get_value_func;
1844   GIrNodeInterface *iface;
1845 
1846   if (!(strcmp (element_name, "class") == 0 &&
1847 	ctx->state == STATE_NAMESPACE))
1848     return FALSE;
1849 
1850   if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_CLASS))
1851     return TRUE;
1852 
1853   name = find_attribute ("name", attribute_names, attribute_values);
1854   parent = find_attribute ("parent", attribute_names, attribute_values);
1855   glib_type_struct = find_attribute ("glib:type-struct", attribute_names, attribute_values);
1856   typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
1857   typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
1858   deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
1859   abstract = find_attribute ("abstract", attribute_names, attribute_values);
1860   final = find_attribute ("final", attribute_names, attribute_values);
1861   fundamental = find_attribute ("glib:fundamental", attribute_names, attribute_values);
1862   ref_func = find_attribute ("glib:ref-func", attribute_names, attribute_values);
1863   unref_func = find_attribute ("glib:unref-func", attribute_names, attribute_values);
1864   set_value_func = find_attribute ("glib:set-value-func", attribute_names, attribute_values);
1865   get_value_func = find_attribute ("glib:get-value-func", attribute_names, attribute_values);
1866 
1867   if (name == NULL)
1868     {
1869       MISSING_ATTRIBUTE (context, error, element_name, "name");
1870       return FALSE;
1871     }
1872   else if (typename == NULL)
1873     {
1874       MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name");
1875       return FALSE;
1876     }
1877   else if (typeinit == NULL && strcmp (typename, "GObject"))
1878     {
1879       MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
1880       return FALSE;
1881     }
1882 
1883   iface = (GIrNodeInterface *) _g_ir_node_new (G_IR_NODE_OBJECT,
1884 					      ctx->current_module);
1885   ((GIrNode *)iface)->name = g_strdup (name);
1886   iface->gtype_name = g_strdup (typename);
1887   iface->gtype_init = g_strdup (typeinit);
1888   iface->parent = g_strdup (parent);
1889   iface->glib_type_struct = g_strdup (glib_type_struct);
1890   if (deprecated)
1891     iface->deprecated = TRUE;
1892   else
1893     iface->deprecated = FALSE;
1894 
1895   iface->abstract = abstract && strcmp (abstract, "1") == 0;
1896   iface->final_ = final && strcmp (final, "1") == 0;
1897 
1898   if (fundamental)
1899     iface->fundamental = TRUE;
1900   if (ref_func)
1901     iface->ref_func = g_strdup (ref_func);
1902   if (unref_func)
1903     iface->unref_func = g_strdup (unref_func);
1904   if (set_value_func)
1905     iface->set_value_func = g_strdup (set_value_func);
1906   if (get_value_func)
1907     iface->get_value_func = g_strdup (get_value_func);
1908 
1909   push_node (ctx, (GIrNode *) iface);
1910   ctx->current_module->entries =
1911     g_list_append (ctx->current_module->entries, iface);
1912 
1913   return TRUE;
1914 }
1915 
1916 static gboolean
start_type(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)1917 start_type (GMarkupParseContext *context,
1918 	    const gchar         *element_name,
1919 	    const gchar        **attribute_names,
1920 	    const gchar        **attribute_values,
1921 	    ParseContext       *ctx,
1922 	    GError             **error)
1923 {
1924   const gchar *name;
1925   const gchar *ctype;
1926   gboolean in_alias = FALSE;
1927   gboolean is_array;
1928   gboolean is_varargs;
1929   GIrNodeType *typenode;
1930 
1931   is_array = strcmp (element_name, "array") == 0;
1932   is_varargs = strcmp (element_name, "varargs") == 0;
1933 
1934   if (!(is_array || is_varargs || (strcmp (element_name, "type") == 0)))
1935     return FALSE;
1936 
1937   if (ctx->state == STATE_TYPE)
1938     {
1939       ctx->type_depth++;
1940       ctx->type_stack = g_list_prepend (ctx->type_stack, ctx->type_parameters);
1941       ctx->type_parameters = NULL;
1942     }
1943   else if (ctx->state == STATE_FUNCTION_PARAMETER ||
1944 	   ctx->state == STATE_FUNCTION_RETURN ||
1945 	   ctx->state == STATE_STRUCT_FIELD ||
1946 	   ctx->state == STATE_UNION_FIELD ||
1947 	   ctx->state == STATE_CLASS_PROPERTY ||
1948 	   ctx->state == STATE_CLASS_FIELD ||
1949 	   ctx->state == STATE_INTERFACE_FIELD ||
1950 	   ctx->state == STATE_INTERFACE_PROPERTY ||
1951 	   ctx->state == STATE_BOXED_FIELD ||
1952 	   ctx->state == STATE_NAMESPACE_CONSTANT ||
1953 	   ctx->state == STATE_CLASS_CONSTANT ||
1954 	   ctx->state == STATE_INTERFACE_CONSTANT ||
1955 	   ctx->state == STATE_ALIAS
1956 	   )
1957     {
1958       if (ctx->state == STATE_ALIAS)
1959 	in_alias = TRUE;
1960       state_switch (ctx, STATE_TYPE);
1961       ctx->type_depth = 1;
1962       ctx->type_stack = NULL;
1963       ctx->type_parameters = NULL;
1964     }
1965 
1966   name = find_attribute ("name", attribute_names, attribute_values);
1967 
1968   if (in_alias && ctx->current_alias)
1969     {
1970       char *key;
1971       char *value;
1972 
1973       if (name == NULL)
1974 	{
1975 	  MISSING_ATTRIBUTE (context, error, element_name, "name");
1976 	  return FALSE;
1977 	}
1978 
1979       key = g_strdup_printf ("%s.%s", ctx->namespace, ctx->current_alias);
1980       if (!strchr (name, '.'))
1981 	{
1982 	  const BasicTypeInfo *basic = parse_basic (name);
1983 	  if (!basic)
1984 	    {
1985 	      /* For non-basic types, re-qualify the interface */
1986 	      value = g_strdup_printf ("%s.%s", ctx->namespace, name);
1987 	    }
1988 	  else
1989 	    {
1990 	      value = g_strdup (name);
1991 	    }
1992 	}
1993       else
1994 	value = g_strdup (name);
1995 
1996       g_hash_table_replace (ctx->aliases, key, value);
1997 
1998       return TRUE;
1999     }
2000   else if (!ctx->current_module || in_alias)
2001     return TRUE;
2002 
2003   if (!ctx->current_typed)
2004     {
2005       g_set_error (error,
2006 		   G_MARKUP_ERROR,
2007 		   G_MARKUP_ERROR_INVALID_CONTENT,
2008 		   "The element <type> is invalid here");
2009       return FALSE;
2010     }
2011 
2012   if (is_varargs)
2013     return TRUE;
2014 
2015   if (is_array)
2016     {
2017       const char *zero;
2018       const char *len;
2019       const char *size;
2020 
2021       typenode = (GIrNodeType *)_g_ir_node_new (G_IR_NODE_TYPE,
2022 						ctx->current_module);
2023 
2024       typenode->tag = GI_TYPE_TAG_ARRAY;
2025       typenode->is_pointer = TRUE;
2026       typenode->is_array = TRUE;
2027 
2028       if (name && strcmp (name, "GLib.Array") == 0) {
2029         typenode->array_type = GI_ARRAY_TYPE_ARRAY;
2030       } else if (name && strcmp (name, "GLib.ByteArray") == 0) {
2031         typenode->array_type = GI_ARRAY_TYPE_BYTE_ARRAY;
2032       } else if (name && strcmp (name, "GLib.PtrArray") == 0) {
2033         typenode->array_type = GI_ARRAY_TYPE_PTR_ARRAY;
2034       } else {
2035         typenode->array_type = GI_ARRAY_TYPE_C;
2036       }
2037 
2038       if (typenode->array_type == GI_ARRAY_TYPE_C) {
2039           zero = find_attribute ("zero-terminated", attribute_names, attribute_values);
2040           len = find_attribute ("length", attribute_names, attribute_values);
2041           size = find_attribute ("fixed-size", attribute_names, attribute_values);
2042 
2043           typenode->has_length = len != NULL;
2044           typenode->length = typenode->has_length ? atoi (len) : -1;
2045 
2046           typenode->has_size = size != NULL;
2047           typenode->size = typenode->has_size ? atoi (size) : -1;
2048 
2049           if (zero)
2050             typenode->zero_terminated = strcmp(zero, "1") == 0;
2051           else
2052             /* If neither zero-terminated nor length nor fixed-size is given, assume zero-terminated. */
2053             typenode->zero_terminated = !(typenode->has_length || typenode->has_size);
2054 
2055           if (typenode->has_size && ctx->current_typed->type == G_IR_NODE_FIELD)
2056             typenode->is_pointer = FALSE;
2057         } else {
2058           typenode->zero_terminated = FALSE;
2059           typenode->has_length = FALSE;
2060           typenode->length = -1;
2061           typenode->has_size = FALSE;
2062           typenode->size = -1;
2063         }
2064     }
2065   else
2066     {
2067       int pointer_depth;
2068 
2069       if (name == NULL)
2070 	{
2071 	  MISSING_ATTRIBUTE (context, error, element_name, "name");
2072 	  return FALSE;
2073 	}
2074 
2075       pointer_depth = 0;
2076       ctype = find_attribute ("c:type", attribute_names, attribute_values);
2077       if (ctype != NULL)
2078         {
2079           const char *cp = ctype + strlen(ctype) - 1;
2080           while (cp > ctype && *cp-- == '*')
2081             pointer_depth++;
2082 
2083 	  if (g_str_has_prefix (ctype, "gpointer")
2084 	      || g_str_has_prefix (ctype, "gconstpointer"))
2085 	    pointer_depth++;
2086         }
2087 
2088       if (ctx->current_typed->type == G_IR_NODE_PARAM &&
2089           ((GIrNodeParam *)ctx->current_typed)->out &&
2090           pointer_depth > 0)
2091         pointer_depth--;
2092 
2093       typenode = parse_type (ctx, name);
2094 
2095       /* A 'disguised' structure is one where the c:type is a typedef that
2096        * doesn't look like a pointer, but is internally.
2097        */
2098       if (typenode->tag == GI_TYPE_TAG_INTERFACE &&
2099 	  is_disguised_structure (ctx, typenode->giinterface))
2100 	pointer_depth++;
2101 
2102       if (pointer_depth > 0)
2103 	typenode->is_pointer = TRUE;
2104     }
2105 
2106   ctx->type_parameters = g_list_append (ctx->type_parameters, typenode);
2107 
2108   return TRUE;
2109 }
2110 
2111 static void
end_type_top(ParseContext * ctx)2112 end_type_top (ParseContext *ctx)
2113 {
2114   GIrNodeType *typenode;
2115 
2116   if (!ctx->type_parameters)
2117     goto out;
2118 
2119   typenode = (GIrNodeType*)ctx->type_parameters->data;
2120 
2121   /* Default to pointer for unspecified containers */
2122   if (typenode->tag == GI_TYPE_TAG_ARRAY ||
2123       typenode->tag == GI_TYPE_TAG_GLIST ||
2124       typenode->tag == GI_TYPE_TAG_GSLIST)
2125     {
2126       if (typenode->parameter_type1 == NULL)
2127 	typenode->parameter_type1 = parse_type (ctx, "gpointer");
2128     }
2129   else if (typenode->tag == GI_TYPE_TAG_GHASH)
2130     {
2131       if (typenode->parameter_type1 == NULL)
2132 	{
2133 	  typenode->parameter_type1 = parse_type (ctx, "gpointer");
2134 	  typenode->parameter_type2 = parse_type (ctx, "gpointer");
2135 	}
2136     }
2137 
2138   switch (ctx->current_typed->type)
2139     {
2140     case G_IR_NODE_PARAM:
2141       {
2142 	GIrNodeParam *param = (GIrNodeParam *)ctx->current_typed;
2143 	param->type = typenode;
2144       }
2145       break;
2146     case G_IR_NODE_FIELD:
2147       {
2148 	GIrNodeField *field = (GIrNodeField *)ctx->current_typed;
2149 	field->type = typenode;
2150       }
2151       break;
2152     case G_IR_NODE_PROPERTY:
2153       {
2154 	GIrNodeProperty *property = (GIrNodeProperty *) ctx->current_typed;
2155 	property->type = typenode;
2156       }
2157       break;
2158     case G_IR_NODE_CONSTANT:
2159       {
2160 	GIrNodeConstant *constant = (GIrNodeConstant *)ctx->current_typed;
2161 	constant->type = typenode;
2162       }
2163       break;
2164     default:
2165       g_printerr("current node is %d\n", CURRENT_NODE (ctx)->type);
2166       g_assert_not_reached ();
2167     }
2168   g_list_free (ctx->type_parameters);
2169 
2170  out:
2171   ctx->type_depth = 0;
2172   ctx->type_parameters = NULL;
2173   ctx->current_typed = NULL;
2174 }
2175 
2176 static void
end_type_recurse(ParseContext * ctx)2177 end_type_recurse (ParseContext *ctx)
2178 {
2179   GIrNodeType *parent;
2180   GIrNodeType *param = NULL;
2181 
2182   parent = (GIrNodeType *) ((GList*)ctx->type_stack->data)->data;
2183   if (ctx->type_parameters)
2184     param = (GIrNodeType *) ctx->type_parameters->data;
2185 
2186   if (parent->tag == GI_TYPE_TAG_ARRAY ||
2187       parent->tag == GI_TYPE_TAG_GLIST ||
2188       parent->tag == GI_TYPE_TAG_GSLIST)
2189     {
2190       g_assert (param != NULL);
2191 
2192       if (parent->parameter_type1 == NULL)
2193         parent->parameter_type1 = param;
2194       else
2195         g_assert_not_reached ();
2196     }
2197   else if (parent->tag == GI_TYPE_TAG_GHASH)
2198     {
2199       g_assert (param != NULL);
2200 
2201       if (parent->parameter_type1 == NULL)
2202         parent->parameter_type1 = param;
2203       else if (parent->parameter_type2 == NULL)
2204         parent->parameter_type2 = param;
2205       else
2206         g_assert_not_reached ();
2207     }
2208   g_list_free (ctx->type_parameters);
2209   ctx->type_parameters = (GList *)ctx->type_stack->data;
2210   ctx->type_stack = g_list_delete_link (ctx->type_stack, ctx->type_stack);
2211 }
2212 
2213 static void
end_type(ParseContext * ctx)2214 end_type (ParseContext *ctx)
2215 {
2216   if (ctx->type_depth == 1)
2217     {
2218       end_type_top (ctx);
2219       state_switch (ctx, ctx->prev_state);
2220     }
2221   else
2222     {
2223       end_type_recurse (ctx);
2224       ctx->type_depth--;
2225     }
2226 }
2227 
2228 static gboolean
start_attribute(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)2229 start_attribute (GMarkupParseContext *context,
2230                  const gchar         *element_name,
2231                  const gchar        **attribute_names,
2232                  const gchar        **attribute_values,
2233                  ParseContext       *ctx,
2234                  GError             **error)
2235 {
2236   const gchar *name;
2237   const gchar *value;
2238   GIrNode *curnode;
2239 
2240   if (strcmp (element_name, "attribute") != 0 || ctx->node_stack == NULL)
2241     return FALSE;
2242 
2243   name = find_attribute ("name", attribute_names, attribute_values);
2244   value = find_attribute ("value", attribute_names, attribute_values);
2245 
2246   if (name == NULL)
2247     {
2248       MISSING_ATTRIBUTE (context, error, element_name, "name");
2249       return FALSE;
2250     }
2251   if (value == NULL)
2252     {
2253       MISSING_ATTRIBUTE (context, error, element_name, "value");
2254       return FALSE;
2255     }
2256 
2257   state_switch (ctx, STATE_ATTRIBUTE);
2258 
2259   curnode = CURRENT_NODE (ctx);
2260 
2261   if (ctx->current_typed && ctx->current_typed->type == G_IR_NODE_PARAM)
2262     {
2263       g_hash_table_insert (ctx->current_typed->attributes, g_strdup (name), g_strdup (value));
2264     }
2265   else
2266     {
2267       g_hash_table_insert (curnode->attributes, g_strdup (name), g_strdup (value));
2268     }
2269 
2270   return TRUE;
2271 }
2272 
2273 static gboolean
start_return_value(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)2274 start_return_value (GMarkupParseContext *context,
2275 		    const gchar         *element_name,
2276 		    const gchar        **attribute_names,
2277 		    const gchar        **attribute_values,
2278 		    ParseContext       *ctx,
2279 		    GError             **error)
2280 {
2281   GIrNodeParam *param;
2282   const gchar  *transfer;
2283   const gchar  *skip;
2284   const gchar  *nullable;
2285 
2286   if (!(strcmp (element_name, "return-value") == 0 &&
2287 	ctx->state == STATE_FUNCTION))
2288     return FALSE;
2289 
2290   param = (GIrNodeParam *)_g_ir_node_new (G_IR_NODE_PARAM,
2291 					  ctx->current_module);
2292   param->in = FALSE;
2293   param->out = FALSE;
2294   param->retval = TRUE;
2295 
2296   ctx->current_typed = (GIrNode*) param;
2297 
2298   state_switch (ctx, STATE_FUNCTION_RETURN);
2299 
2300   skip = find_attribute ("skip", attribute_names, attribute_values);
2301   if (skip && strcmp (skip, "1") == 0)
2302     param->skip = TRUE;
2303   else
2304     param->skip = FALSE;
2305 
2306   transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values);
2307   if (!parse_param_transfer (param, transfer, NULL, error))
2308     return FALSE;
2309 
2310   nullable = find_attribute ("nullable", attribute_names, attribute_values);
2311   if (nullable && g_str_equal (nullable, "1"))
2312     param->nullable = TRUE;
2313 
2314   switch (CURRENT_NODE (ctx)->type)
2315     {
2316     case G_IR_NODE_FUNCTION:
2317     case G_IR_NODE_CALLBACK:
2318       {
2319 	GIrNodeFunction *func = (GIrNodeFunction *)CURRENT_NODE (ctx);
2320 	func->result = param;
2321       }
2322       break;
2323     case G_IR_NODE_SIGNAL:
2324       {
2325 	GIrNodeSignal *signal = (GIrNodeSignal *)CURRENT_NODE (ctx);
2326 	signal->result = param;
2327       }
2328       break;
2329     case G_IR_NODE_VFUNC:
2330       {
2331 	GIrNodeVFunc *vfunc = (GIrNodeVFunc *)CURRENT_NODE (ctx);
2332 	vfunc->result = param;
2333       }
2334       break;
2335     default:
2336       g_assert_not_reached ();
2337     }
2338 
2339   return TRUE;
2340 }
2341 
2342 static gboolean
start_implements(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)2343 start_implements (GMarkupParseContext *context,
2344 		  const gchar         *element_name,
2345 		  const gchar        **attribute_names,
2346 		  const gchar        **attribute_values,
2347 		  ParseContext       *ctx,
2348 		  GError             **error)
2349 {
2350   GIrNodeInterface *iface;
2351   const char *name;
2352 
2353   if (strcmp (element_name, "implements") != 0 ||
2354       !(ctx->state == STATE_CLASS))
2355     return FALSE;
2356 
2357   state_switch (ctx, STATE_IMPLEMENTS);
2358 
2359   name = find_attribute ("name", attribute_names, attribute_values);
2360   if (name == NULL)
2361     {
2362       MISSING_ATTRIBUTE (context, error, element_name, "name");
2363       return FALSE;
2364     }
2365 
2366   iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
2367   iface->interfaces = g_list_append (iface->interfaces, g_strdup (name));
2368 
2369   return TRUE;
2370 }
2371 
2372 static gboolean
start_glib_signal(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)2373 start_glib_signal (GMarkupParseContext *context,
2374 		   const gchar         *element_name,
2375 		   const gchar        **attribute_names,
2376 		   const gchar        **attribute_values,
2377 		   ParseContext       *ctx,
2378 		   GError             **error)
2379 {
2380   const gchar *name;
2381   const gchar *when;
2382   const gchar *no_recurse;
2383   const gchar *detailed;
2384   const gchar *action;
2385   const gchar *no_hooks;
2386   const gchar *has_class_closure;
2387   GIrNodeInterface *iface;
2388   GIrNodeSignal *signal;
2389 
2390   if (!(strcmp (element_name, "glib:signal") == 0 &&
2391 	(ctx->state == STATE_CLASS ||
2392 	 ctx->state == STATE_INTERFACE)))
2393     return FALSE;
2394 
2395   if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_FUNCTION))
2396     return TRUE;
2397 
2398   name = find_attribute ("name", attribute_names, attribute_values);
2399   when = find_attribute ("when", attribute_names, attribute_values);
2400   no_recurse = find_attribute ("no-recurse", attribute_names, attribute_values);
2401   detailed = find_attribute ("detailed", attribute_names, attribute_values);
2402   action = find_attribute ("action", attribute_names, attribute_values);
2403   no_hooks = find_attribute ("no-hooks", attribute_names, attribute_values);
2404   has_class_closure = find_attribute ("has-class-closure", attribute_names, attribute_values);
2405 
2406   if (name == NULL)
2407     {
2408       MISSING_ATTRIBUTE (context, error, element_name, "name");
2409       return FALSE;
2410     }
2411   signal = (GIrNodeSignal *)_g_ir_node_new (G_IR_NODE_SIGNAL,
2412 					    ctx->current_module);
2413 
2414   ((GIrNode *)signal)->name = g_strdup (name);
2415 
2416   signal->run_first = FALSE;
2417   signal->run_last = FALSE;
2418   signal->run_cleanup = FALSE;
2419   if (when == NULL || g_ascii_strcasecmp (when, "LAST") == 0)
2420     signal->run_last = TRUE;
2421   else if (g_ascii_strcasecmp (when, "FIRST") == 0)
2422     signal->run_first = TRUE;
2423   else
2424     signal->run_cleanup = TRUE;
2425 
2426   if (no_recurse && strcmp (no_recurse, "1") == 0)
2427     signal->no_recurse = TRUE;
2428   else
2429     signal->no_recurse = FALSE;
2430   if (detailed && strcmp (detailed, "1") == 0)
2431     signal->detailed = TRUE;
2432   else
2433     signal->detailed = FALSE;
2434   if (action && strcmp (action, "1") == 0)
2435     signal->action = TRUE;
2436   else
2437     signal->action = FALSE;
2438   if (no_hooks && strcmp (no_hooks, "1") == 0)
2439     signal->no_hooks = TRUE;
2440   else
2441     signal->no_hooks = FALSE;
2442   if (has_class_closure && strcmp (has_class_closure, "1") == 0)
2443     signal->has_class_closure = TRUE;
2444   else
2445     signal->has_class_closure = FALSE;
2446 
2447   iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
2448   iface->members = g_list_append (iface->members, signal);
2449 
2450   push_node (ctx, (GIrNode *)signal);
2451 
2452   return TRUE;
2453 }
2454 
2455 static gboolean
start_vfunc(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)2456 start_vfunc (GMarkupParseContext *context,
2457 	     const gchar         *element_name,
2458 	     const gchar        **attribute_names,
2459 	     const gchar        **attribute_values,
2460 	     ParseContext       *ctx,
2461 	     GError             **error)
2462 {
2463   const gchar *name;
2464   const gchar *must_chain_up;
2465   const gchar *override;
2466   const gchar *is_class_closure;
2467   const gchar *offset;
2468   const gchar *invoker;
2469   const gchar *throws;
2470   GIrNodeInterface *iface;
2471   GIrNodeVFunc *vfunc;
2472 
2473   if (!(strcmp (element_name, "virtual-method") == 0 &&
2474 	(ctx->state == STATE_CLASS ||
2475 	 ctx->state == STATE_INTERFACE)))
2476     return FALSE;
2477 
2478   if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_FUNCTION))
2479     return TRUE;
2480 
2481   name = find_attribute ("name", attribute_names, attribute_values);
2482   must_chain_up = find_attribute ("must-chain-up", attribute_names, attribute_values);
2483   override = find_attribute ("override", attribute_names, attribute_values);
2484   is_class_closure = find_attribute ("is-class-closure", attribute_names, attribute_values);
2485   offset = find_attribute ("offset", attribute_names, attribute_values);
2486   invoker = find_attribute ("invoker", attribute_names, attribute_values);
2487   throws = find_attribute ("throws", attribute_names, attribute_values);
2488 
2489   if (name == NULL)
2490     {
2491       MISSING_ATTRIBUTE (context, error, element_name, "name");
2492       return FALSE;
2493     }
2494 
2495   vfunc = (GIrNodeVFunc *)_g_ir_node_new (G_IR_NODE_VFUNC,
2496 					  ctx->current_module);
2497 
2498   ((GIrNode *)vfunc)->name = g_strdup (name);
2499 
2500   if (must_chain_up && strcmp (must_chain_up, "1") == 0)
2501     vfunc->must_chain_up = TRUE;
2502   else
2503     vfunc->must_chain_up = FALSE;
2504 
2505   if (override && strcmp (override, "always") == 0)
2506     {
2507       vfunc->must_be_implemented = TRUE;
2508       vfunc->must_not_be_implemented = FALSE;
2509     }
2510   else if (override && strcmp (override, "never") == 0)
2511     {
2512       vfunc->must_be_implemented = FALSE;
2513       vfunc->must_not_be_implemented = TRUE;
2514     }
2515   else
2516     {
2517       vfunc->must_be_implemented = FALSE;
2518       vfunc->must_not_be_implemented = FALSE;
2519     }
2520 
2521   if (is_class_closure && strcmp (is_class_closure, "1") == 0)
2522     vfunc->is_class_closure = TRUE;
2523   else
2524     vfunc->is_class_closure = FALSE;
2525 
2526   if (throws && strcmp (throws, "1") == 0)
2527     vfunc->throws = TRUE;
2528   else
2529     vfunc->throws = FALSE;
2530 
2531   if (offset)
2532     vfunc->offset = atoi (offset);
2533   else
2534     vfunc->offset = 0xFFFF;
2535 
2536   vfunc->invoker = g_strdup (invoker);
2537 
2538   iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
2539   iface->members = g_list_append (iface->members, vfunc);
2540 
2541   push_node (ctx, (GIrNode *)vfunc);
2542 
2543   return TRUE;
2544 }
2545 
2546 static gboolean
start_struct(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)2547 start_struct (GMarkupParseContext *context,
2548 	      const gchar         *element_name,
2549 	      const gchar        **attribute_names,
2550 	      const gchar        **attribute_values,
2551 	      ParseContext       *ctx,
2552 	      GError             **error)
2553 {
2554   const gchar *name;
2555   const gchar *deprecated;
2556   const gchar *disguised;
2557   const gchar *gtype_name;
2558   const gchar *gtype_init;
2559   const gchar *gtype_struct;
2560   const gchar *foreign;
2561   GIrNodeStruct *struct_;
2562 
2563   if (!(strcmp (element_name, "record") == 0 &&
2564 	(ctx->state == STATE_NAMESPACE ||
2565 	 ctx->state == STATE_UNION ||
2566 	 ctx->state == STATE_STRUCT ||
2567 	 ctx->state == STATE_CLASS)))
2568     return FALSE;
2569 
2570   if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_STRUCT))
2571     return TRUE;
2572 
2573   name = find_attribute ("name", attribute_names, attribute_values);
2574   deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
2575   disguised = find_attribute ("disguised", attribute_names, attribute_values);
2576   gtype_name = find_attribute ("glib:type-name", attribute_names, attribute_values);
2577   gtype_init = find_attribute ("glib:get-type", attribute_names, attribute_values);
2578   gtype_struct = find_attribute ("glib:is-gtype-struct-for", attribute_names, attribute_values);
2579   foreign = find_attribute ("foreign", attribute_names, attribute_values);
2580 
2581   if (name == NULL && ctx->node_stack == NULL)
2582     {
2583       MISSING_ATTRIBUTE (context, error, element_name, "name");
2584       return FALSE;
2585     }
2586   if ((gtype_name == NULL && gtype_init != NULL))
2587     {
2588       MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name");
2589       return FALSE;
2590     }
2591   if ((gtype_name != NULL && gtype_init == NULL))
2592     {
2593       MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type");
2594       return FALSE;
2595     }
2596 
2597   struct_ = (GIrNodeStruct *) _g_ir_node_new (G_IR_NODE_STRUCT,
2598 					     ctx->current_module);
2599 
2600   ((GIrNode *)struct_)->name = g_strdup (name ? name : "");
2601   if (deprecated)
2602     struct_->deprecated = TRUE;
2603   else
2604     struct_->deprecated = FALSE;
2605 
2606   if (disguised && strcmp (disguised, "1") == 0)
2607     struct_->disguised = TRUE;
2608 
2609   struct_->is_gtype_struct = gtype_struct != NULL;
2610 
2611   struct_->gtype_name = g_strdup (gtype_name);
2612   struct_->gtype_init = g_strdup (gtype_init);
2613 
2614   struct_->foreign = (g_strcmp0 (foreign, "1") == 0);
2615 
2616   if (ctx->node_stack == NULL)
2617     ctx->current_module->entries =
2618       g_list_append (ctx->current_module->entries, struct_);
2619   push_node (ctx, (GIrNode *)struct_);
2620   return TRUE;
2621 }
2622 
2623 static gboolean
start_union(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)2624 start_union (GMarkupParseContext *context,
2625 	     const gchar         *element_name,
2626 	     const gchar        **attribute_names,
2627 	     const gchar        **attribute_values,
2628 	     ParseContext       *ctx,
2629 	     GError             **error)
2630 {
2631   const gchar *name;
2632   const gchar *deprecated;
2633   const gchar *typename;
2634   const gchar *typeinit;
2635   GIrNodeUnion *union_;
2636 
2637   if (!(strcmp (element_name, "union") == 0 &&
2638 	(ctx->state == STATE_NAMESPACE ||
2639 	 ctx->state == STATE_UNION ||
2640 	 ctx->state == STATE_STRUCT ||
2641 	 ctx->state == STATE_CLASS)))
2642     return FALSE;
2643 
2644   if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_UNION))
2645     return TRUE;
2646 
2647   name = find_attribute ("name", attribute_names, attribute_values);
2648   deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
2649   typename = find_attribute ("glib:type-name", attribute_names, attribute_values);
2650   typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values);
2651 
2652   if (name == NULL && ctx->node_stack == NULL)
2653     {
2654       MISSING_ATTRIBUTE (context, error, element_name, "name");
2655       return FALSE;
2656     }
2657 
2658   union_ = (GIrNodeUnion *) _g_ir_node_new (G_IR_NODE_UNION,
2659 					   ctx->current_module);
2660 
2661   ((GIrNode *)union_)->name = g_strdup (name ? name : "");
2662   union_->gtype_name = g_strdup (typename);
2663   union_->gtype_init = g_strdup (typeinit);
2664   if (deprecated)
2665     union_->deprecated = TRUE;
2666   else
2667     union_->deprecated = FALSE;
2668 
2669   if (ctx->node_stack == NULL)
2670     ctx->current_module->entries =
2671       g_list_append (ctx->current_module->entries, union_);
2672   push_node (ctx, (GIrNode *)union_);
2673   return TRUE;
2674 }
2675 
2676 static gboolean
start_discriminator(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,ParseContext * ctx,GError ** error)2677 start_discriminator (GMarkupParseContext *context,
2678 		     const gchar         *element_name,
2679 		     const gchar        **attribute_names,
2680 		     const gchar        **attribute_values,
2681 		     ParseContext       *ctx,
2682 		     GError             **error)
2683 {
2684   const gchar *type;
2685   const gchar *offset;
2686   if (!(strcmp (element_name, "discriminator") == 0 &&
2687 	ctx->state == STATE_UNION))
2688     return FALSE;
2689 
2690   type = find_attribute ("type", attribute_names, attribute_values);
2691   offset = find_attribute ("offset", attribute_names, attribute_values);
2692   if (type == NULL)
2693     {
2694       MISSING_ATTRIBUTE (context, error, element_name, "type");
2695       return FALSE;
2696     }
2697   else if (offset == NULL)
2698     {
2699       MISSING_ATTRIBUTE (context, error, element_name, "offset");
2700       return FALSE;
2701     }
2702 
2703   ((GIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_type
2704     = parse_type (ctx, type);
2705   ((GIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_offset
2706     = atoi (offset);
2707 
2708   return TRUE;
2709 }
2710 
2711 static gboolean
parse_include(GMarkupParseContext * context,ParseContext * ctx,const char * name,const char * version)2712 parse_include (GMarkupParseContext *context,
2713 	       ParseContext        *ctx,
2714 	       const char          *name,
2715 	       const char          *version)
2716 {
2717   GError *error = NULL;
2718   gchar *buffer;
2719   gsize length;
2720   gchar *girpath, *girname;
2721   GIrModule *module;
2722   GList *l;
2723 
2724   for (l = ctx->parser->parsed_modules; l; l = l->next)
2725     {
2726       GIrModule *m = l->data;
2727 
2728       if (strcmp (m->name, name) == 0)
2729 	{
2730 	  if (strcmp (m->version, version) == 0)
2731 	    {
2732 	      ctx->include_modules = g_list_prepend (ctx->include_modules, m);
2733 
2734 	      return TRUE;
2735 	    }
2736 	  else
2737 	    {
2738 	      g_printerr ("Module '%s' imported with conflicting versions '%s' and '%s'\n",
2739 			  name, m->version, version);
2740 	      return FALSE;
2741 	    }
2742 	}
2743     }
2744 
2745   girname = g_strdup_printf ("%s-%s.gir", name, version);
2746   girpath = locate_gir (ctx->parser, girname);
2747 
2748   if (girpath == NULL)
2749     {
2750       g_printerr ("Could not find GIR file '%s'; check XDG_DATA_DIRS or use --includedir\n",
2751 		   girname);
2752       g_free (girname);
2753       return FALSE;
2754     }
2755   g_free (girname);
2756 
2757   g_debug ("Parsing include %s\n", girpath);
2758 
2759   if (!g_file_get_contents (girpath, &buffer, &length, &error))
2760     {
2761       g_printerr ("%s: %s\n", girpath, error->message);
2762       g_clear_error (&error);
2763       g_free (girpath);
2764       return FALSE;
2765     }
2766 
2767   module = _g_ir_parser_parse_string (ctx->parser, name, girpath, buffer, length, &error);
2768   g_free (buffer);
2769   if (error != NULL)
2770     {
2771       int line_number, char_number;
2772       g_markup_parse_context_get_position (context, &line_number, &char_number);
2773       g_printerr ("%s:%d:%d: error: %s\n", girpath, line_number, char_number, error->message);
2774       g_clear_error (&error);
2775       g_free (girpath);
2776       return FALSE;
2777     }
2778   g_free (girpath);
2779 
2780   ctx->include_modules = g_list_append (ctx->include_modules,
2781 					module);
2782 
2783   return TRUE;
2784 }
2785 
2786 extern GLogLevelFlags logged_levels;
2787 
2788 static void
start_element_handler(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,gpointer user_data,GError ** error)2789 start_element_handler (GMarkupParseContext *context,
2790 		       const gchar         *element_name,
2791 		       const gchar        **attribute_names,
2792 		       const gchar        **attribute_values,
2793 		       gpointer             user_data,
2794 		       GError             **error)
2795 {
2796   ParseContext *ctx = user_data;
2797 
2798   if (logged_levels & G_LOG_LEVEL_DEBUG)
2799     {
2800       GString *tags = g_string_new ("");
2801       int i;
2802       for (i = 0; attribute_names[i]; i++)
2803         g_string_append_printf (tags, "%s=\"%s\" ",
2804 				attribute_names[i],
2805 				attribute_values[i]);
2806 
2807       if (i)
2808         {
2809           g_string_insert_c (tags, 0, ' ');
2810           g_string_truncate (tags, tags->len - 1);
2811         }
2812       g_debug ("<%s%s>", element_name, tags->str);
2813       g_string_free (tags, TRUE);
2814     }
2815 
2816   if (ctx->state == STATE_PASSTHROUGH)
2817     {
2818       ctx->unknown_depth += 1;
2819       return;
2820     }
2821 
2822   switch (element_name[0])
2823     {
2824     case 'a':
2825       if (ctx->state == STATE_NAMESPACE && strcmp (element_name, "alias") == 0)
2826 	{
2827 	  state_switch (ctx, STATE_ALIAS);
2828 	  goto out;
2829 	}
2830       if (start_type (context, element_name,
2831 		      attribute_names, attribute_values,
2832 		      ctx, error))
2833 	goto out;
2834       else if (start_attribute (context, element_name,
2835                                 attribute_names, attribute_values,
2836                                 ctx, error))
2837         goto out;
2838       break;
2839     case 'b':
2840       if (start_enum (context, element_name,
2841 		      attribute_names, attribute_values,
2842 		      ctx, error))
2843 	goto out;
2844       break;
2845     case 'c':
2846       if (start_function (context, element_name,
2847 			  attribute_names, attribute_values,
2848 			  ctx, error))
2849 	goto out;
2850       else if (start_constant (context, element_name,
2851 			       attribute_names, attribute_values,
2852 			       ctx, error))
2853 	goto out;
2854       else if (start_class (context, element_name,
2855 			    attribute_names, attribute_values,
2856 			    ctx, error))
2857 	goto out;
2858       break;
2859 
2860     case 'd':
2861       if (start_discriminator (context, element_name,
2862 			       attribute_names, attribute_values,
2863 			       ctx, error))
2864     goto out;
2865       if (strcmp ("doc", element_name) == 0 || strcmp ("doc-deprecated", element_name) == 0 ||
2866           strcmp ("doc-stability", element_name) == 0 || strcmp ("doc-version", element_name) == 0 ||
2867           strcmp ("docsection", element_name) == 0)
2868         {
2869           state_switch (ctx, STATE_PASSTHROUGH);
2870           goto out;
2871         }
2872       break;
2873 
2874     case 'e':
2875       if (start_enum (context, element_name,
2876 		      attribute_names, attribute_values,
2877 		      ctx, error))
2878 	goto out;
2879       break;
2880 
2881     case 'f':
2882       if (strcmp ("function-macro", element_name) == 0)
2883         {
2884           state_switch (ctx, STATE_PASSTHROUGH);
2885           goto out;
2886         }
2887       else if (start_function (context, element_name,
2888 			  attribute_names, attribute_values,
2889 			  ctx, error))
2890 	goto out;
2891       else if (start_field (context, element_name,
2892 			    attribute_names, attribute_values,
2893 			    ctx, error))
2894 	goto out;
2895       break;
2896 
2897     case 'g':
2898       if (start_glib_boxed (context, element_name,
2899 			    attribute_names, attribute_values,
2900 			    ctx, error))
2901 	goto out;
2902       else if (start_glib_signal (context, element_name,
2903 			     attribute_names, attribute_values,
2904 			     ctx, error))
2905 	goto out;
2906       break;
2907 
2908     case 'i':
2909       if (strcmp (element_name, "include") == 0 &&
2910 	  ctx->state == STATE_REPOSITORY)
2911 	{
2912 	  const gchar *name;
2913 	  const gchar *version;
2914 
2915 	  name = find_attribute ("name", attribute_names, attribute_values);
2916 	  version = find_attribute ("version", attribute_names, attribute_values);
2917 
2918 	  if (name == NULL)
2919 	    {
2920 	      MISSING_ATTRIBUTE (context, error, element_name, "name");
2921 	      break;
2922 	    }
2923 	  if (version == NULL)
2924 	    {
2925 	      MISSING_ATTRIBUTE (context, error, element_name, "version");
2926 	      break;
2927 	    }
2928 
2929 	  if (!parse_include (context, ctx, name, version))
2930 	    {
2931 	      g_set_error (error,
2932 			   G_MARKUP_ERROR,
2933 			   G_MARKUP_ERROR_INVALID_CONTENT,
2934 			   "Failed to parse included gir %s-%s",
2935 			   name,
2936 			   version);
2937 	      return;
2938 	    }
2939 
2940 	  ctx->dependencies = g_list_prepend (ctx->dependencies,
2941 					      g_strdup_printf ("%s-%s", name, version));
2942 
2943 
2944 	  state_switch (ctx, STATE_INCLUDE);
2945 	  goto out;
2946 	}
2947       if (start_interface (context, element_name,
2948 			   attribute_names, attribute_values,
2949 			   ctx, error))
2950 	goto out;
2951       else if (start_implements (context, element_name,
2952 				 attribute_names, attribute_values,
2953 				 ctx, error))
2954 	goto out;
2955       else if (start_instance_parameter (context, element_name,
2956 				attribute_names, attribute_values,
2957 				ctx, error))
2958 	goto out;
2959       else if (strcmp (element_name, "c:include") == 0)
2960 	{
2961 	  state_switch (ctx, STATE_C_INCLUDE);
2962 	  goto out;
2963 	}
2964       break;
2965 
2966     case 'm':
2967       if (start_function (context, element_name,
2968 			  attribute_names, attribute_values,
2969 			  ctx, error))
2970 	goto out;
2971       else if (start_member (context, element_name,
2972 			  attribute_names, attribute_values,
2973 			  ctx, error))
2974 	goto out;
2975       break;
2976 
2977     case 'n':
2978       if (strcmp (element_name, "namespace") == 0 && ctx->state == STATE_REPOSITORY)
2979 	{
2980 	  const gchar *name, *version, *shared_library, *cprefix;
2981 
2982 	  if (ctx->current_module != NULL)
2983 	    {
2984 	      g_set_error (error,
2985 			   G_MARKUP_ERROR,
2986 			   G_MARKUP_ERROR_INVALID_CONTENT,
2987 			   "Only one <namespace/> element is currently allowed per <repository/>");
2988 	      goto out;
2989 	    }
2990 
2991 	  name = find_attribute ("name", attribute_names, attribute_values);
2992 	  version = find_attribute ("version", attribute_names, attribute_values);
2993 	  shared_library = find_attribute ("shared-library", attribute_names, attribute_values);
2994 	  cprefix = find_attribute ("c:identifier-prefixes", attribute_names, attribute_values);
2995           /* Backwards compatibility; vala currently still generates this */
2996           if (cprefix == NULL)
2997             cprefix = find_attribute ("c:prefix", attribute_names, attribute_values);
2998 
2999 	  if (name == NULL)
3000 	    MISSING_ATTRIBUTE (context, error, element_name, "name");
3001 	  else if (version == NULL)
3002 	    MISSING_ATTRIBUTE (context, error, element_name, "version");
3003 	  else
3004 	    {
3005 	      GList *l;
3006 
3007 	      if (strcmp (name, ctx->namespace) != 0)
3008 		g_set_error (error,
3009 			     G_MARKUP_ERROR,
3010 			     G_MARKUP_ERROR_INVALID_CONTENT,
3011 			     "<namespace/> name element '%s' doesn't match file name '%s'",
3012 			     name, ctx->namespace);
3013 
3014 	      ctx->current_module = _g_ir_module_new (name, version, shared_library, cprefix);
3015 
3016 	      ctx->current_module->aliases = ctx->aliases;
3017 	      ctx->aliases = NULL;
3018 	      ctx->current_module->disguised_structures = ctx->disguised_structures;
3019 	      ctx->disguised_structures = NULL;
3020 
3021 	      for (l = ctx->include_modules; l; l = l->next)
3022 		_g_ir_module_add_include_module (ctx->current_module, l->data);
3023 
3024 	      g_list_free (ctx->include_modules);
3025 	      ctx->include_modules = NULL;
3026 
3027 	      ctx->modules = g_list_append (ctx->modules, ctx->current_module);
3028 	      ctx->current_module->dependencies = ctx->dependencies;
3029 
3030 	      state_switch (ctx, STATE_NAMESPACE);
3031 	      goto out;
3032 	    }
3033 	}
3034       break;
3035 
3036     case 'p':
3037       if (start_property (context, element_name,
3038 			  attribute_names, attribute_values,
3039 			  ctx, error))
3040 	goto out;
3041       else if (strcmp (element_name, "parameters") == 0 &&
3042 	       ctx->state == STATE_FUNCTION)
3043 	{
3044 	  state_switch (ctx, STATE_FUNCTION_PARAMETERS);
3045 
3046 	  goto out;
3047 	}
3048       else if (start_parameter (context, element_name,
3049 				attribute_names, attribute_values,
3050 				ctx, error))
3051 	goto out;
3052       else if (strcmp (element_name, "prerequisite") == 0 &&
3053 	       ctx->state == STATE_INTERFACE)
3054 	{
3055 	  const gchar *name;
3056 
3057 	  name = find_attribute ("name", attribute_names, attribute_values);
3058 
3059 	  state_switch (ctx, STATE_PREREQUISITE);
3060 
3061 	  if (name == NULL)
3062 	    MISSING_ATTRIBUTE (context, error, element_name, "name");
3063 	  else
3064 	    {
3065 	      GIrNodeInterface *iface;
3066 
3067 	      iface = (GIrNodeInterface *)CURRENT_NODE(ctx);
3068 	      iface->prerequisites = g_list_append (iface->prerequisites, g_strdup (name));
3069 	    }
3070 	  goto out;
3071 	}
3072       else if (strcmp (element_name, "package") == 0 &&
3073           ctx->state == STATE_REPOSITORY)
3074         {
3075           state_switch (ctx, STATE_PACKAGE);
3076           goto out;
3077         }
3078       break;
3079 
3080     case 'r':
3081       if (strcmp (element_name, "repository") == 0 && ctx->state == STATE_START)
3082 	{
3083 	  const gchar *version;
3084 
3085 	  version = find_attribute ("version", attribute_names, attribute_values);
3086 
3087 	  if (version == NULL)
3088 	    MISSING_ATTRIBUTE (context, error, element_name, "version");
3089 	  else if (strcmp (version, SUPPORTED_GIR_VERSION) != 0)
3090 	    g_set_error (error,
3091 			 G_MARKUP_ERROR,
3092 			 G_MARKUP_ERROR_INVALID_CONTENT,
3093 			 "Unsupported version '%s'",
3094 			 version);
3095 	  else
3096 	    state_switch (ctx, STATE_REPOSITORY);
3097 
3098 	  goto out;
3099 	}
3100       else if (start_return_value (context, element_name,
3101 				   attribute_names, attribute_values,
3102 				   ctx, error))
3103 	goto out;
3104       else if (start_struct (context, element_name,
3105 			     attribute_names, attribute_values,
3106 			     ctx, error))
3107 	goto out;
3108       break;
3109 
3110     case 's':
3111       if (strcmp ("source-position", element_name) == 0)
3112       {
3113           state_switch (ctx, STATE_PASSTHROUGH);
3114           goto out;
3115       }
3116       break;
3117     case 'u':
3118       if (start_union (context, element_name,
3119 		       attribute_names, attribute_values,
3120 		       ctx, error))
3121 	goto out;
3122       break;
3123 
3124     case 't':
3125       if (start_type (context, element_name,
3126 		      attribute_names, attribute_values,
3127 		      ctx, error))
3128 	goto out;
3129       break;
3130 
3131     case 'v':
3132       if (start_vfunc (context, element_name,
3133 		       attribute_names, attribute_values,
3134 		       ctx, error))
3135 	goto out;
3136       if (start_type (context, element_name,
3137 		      attribute_names, attribute_values,
3138 		      ctx, error))
3139 	goto out;
3140       break;
3141     default:
3142       break;
3143     }
3144 
3145   if (*error == NULL && ctx->state != STATE_PASSTHROUGH)
3146     {
3147       gint line_number, char_number;
3148       g_markup_parse_context_get_position (context, &line_number, &char_number);
3149       if (!g_str_has_prefix (element_name, "c:"))
3150 	g_printerr ("%s:%d:%d: warning: element %s from state %d is unknown, ignoring\n",
3151 		    ctx->file_path, line_number, char_number, element_name,
3152 		    ctx->state);
3153       state_switch (ctx, STATE_PASSTHROUGH);
3154     }
3155 
3156  out:
3157   if (*error)
3158     {
3159       gint line_number, char_number;
3160       g_markup_parse_context_get_position (context, &line_number, &char_number);
3161 
3162       g_printerr ("%s:%d:%d: error: %s\n", ctx->file_path, line_number, char_number, (*error)->message);
3163     }
3164 }
3165 
3166 static gboolean
require_one_of_end_elements(GMarkupParseContext * context,ParseContext * ctx,const char * actual_name,GError ** error,...)3167 require_one_of_end_elements (GMarkupParseContext *context,
3168 			     ParseContext        *ctx,
3169 			     const char          *actual_name,
3170 			     GError             **error,
3171 			     ...)
3172 {
3173   va_list args;
3174   int line_number, char_number;
3175   const char *expected;
3176   gboolean matched = FALSE;
3177 
3178   va_start (args, error);
3179 
3180   while ((expected = va_arg (args, const char*)) != NULL)
3181     {
3182       if (strcmp (expected, actual_name) == 0)
3183 	{
3184 	  matched = TRUE;
3185 	  break;
3186 	}
3187     }
3188 
3189   va_end (args);
3190 
3191   if (matched)
3192     return TRUE;
3193 
3194   g_markup_parse_context_get_position (context, &line_number, &char_number);
3195   g_set_error (error,
3196 	       G_MARKUP_ERROR,
3197 	       G_MARKUP_ERROR_INVALID_CONTENT,
3198 	       "Unexpected end tag '%s' on line %d char %d; current state=%d (prev=%d)",
3199 	       actual_name,
3200 	       line_number, char_number, ctx->state, ctx->prev_state);
3201   return FALSE;
3202 }
3203 
3204 static gboolean
state_switch_end_struct_or_union(GMarkupParseContext * context,ParseContext * ctx,const gchar * element_name,GError ** error)3205 state_switch_end_struct_or_union (GMarkupParseContext *context,
3206                                   ParseContext *ctx,
3207                                   const gchar *element_name,
3208                                   GError **error)
3209 {
3210   pop_node (ctx);
3211   if (ctx->node_stack == NULL)
3212     {
3213       state_switch (ctx, STATE_NAMESPACE);
3214     }
3215   else
3216     {
3217       if (CURRENT_NODE (ctx)->type == G_IR_NODE_STRUCT)
3218         state_switch (ctx, STATE_STRUCT);
3219       else if (CURRENT_NODE (ctx)->type == G_IR_NODE_UNION)
3220         state_switch (ctx, STATE_UNION);
3221       else if (CURRENT_NODE (ctx)->type == G_IR_NODE_OBJECT)
3222         state_switch (ctx, STATE_CLASS);
3223       else
3224         {
3225           int line_number, char_number;
3226           g_markup_parse_context_get_position (context, &line_number, &char_number);
3227           g_set_error (error,
3228                        G_MARKUP_ERROR,
3229                        G_MARKUP_ERROR_INVALID_CONTENT,
3230                        "Unexpected end tag '%s' on line %d char %d",
3231                        element_name,
3232                        line_number, char_number);
3233           return FALSE;
3234         }
3235     }
3236   return TRUE;
3237 }
3238 
3239 static gboolean
require_end_element(GMarkupParseContext * context,ParseContext * ctx,const char * expected_name,const char * actual_name,GError ** error)3240 require_end_element (GMarkupParseContext *context,
3241 		     ParseContext        *ctx,
3242 		     const char          *expected_name,
3243 		     const char          *actual_name,
3244 		     GError             **error)
3245 {
3246   return require_one_of_end_elements (context, ctx, actual_name, error, expected_name, NULL);
3247 }
3248 
3249 static void
end_element_handler(GMarkupParseContext * context,const gchar * element_name,gpointer user_data,GError ** error)3250 end_element_handler (GMarkupParseContext *context,
3251 		     const gchar         *element_name,
3252 		     gpointer             user_data,
3253 		     GError             **error)
3254 {
3255   ParseContext *ctx = user_data;
3256 
3257   g_debug ("</%s>", element_name);
3258 
3259   switch (ctx->state)
3260     {
3261     case STATE_START:
3262     case STATE_END:
3263       /* no need to GError here, GMarkup already catches this */
3264       break;
3265 
3266     case STATE_REPOSITORY:
3267       state_switch (ctx, STATE_END);
3268       break;
3269 
3270     case STATE_INCLUDE:
3271       if (require_end_element (context, ctx, "include", element_name, error))
3272 	{
3273           state_switch (ctx, STATE_REPOSITORY);
3274         }
3275       break;
3276 
3277     case STATE_C_INCLUDE:
3278       if (require_end_element (context, ctx, "c:include", element_name, error))
3279 	{
3280           state_switch (ctx, STATE_REPOSITORY);
3281         }
3282       break;
3283 
3284     case STATE_PACKAGE:
3285       if (require_end_element (context, ctx, "package", element_name, error))
3286         {
3287           state_switch (ctx, STATE_REPOSITORY);
3288         }
3289       break;
3290 
3291     case STATE_NAMESPACE:
3292       if (require_end_element (context, ctx, "namespace", element_name, error))
3293 	{
3294           ctx->current_module = NULL;
3295           state_switch (ctx, STATE_REPOSITORY);
3296         }
3297       break;
3298 
3299     case STATE_ALIAS:
3300       if (require_end_element (context, ctx, "alias", element_name, error))
3301 	{
3302 	  g_free (ctx->current_alias);
3303 	  ctx->current_alias = NULL;
3304 	  state_switch (ctx, STATE_NAMESPACE);
3305 	}
3306       break;
3307 
3308     case STATE_FUNCTION_RETURN:
3309       if (strcmp ("type", element_name) == 0)
3310 	break;
3311       if (require_end_element (context, ctx, "return-value", element_name, error))
3312 	{
3313 	  state_switch (ctx, STATE_FUNCTION);
3314 	}
3315       break;
3316 
3317     case STATE_FUNCTION_PARAMETERS:
3318       if (require_end_element (context, ctx, "parameters", element_name, error))
3319 	{
3320 	  state_switch (ctx, STATE_FUNCTION);
3321 	}
3322       break;
3323 
3324     case STATE_FUNCTION_PARAMETER:
3325       if (strcmp ("type", element_name) == 0)
3326 	break;
3327       if (require_end_element (context, ctx, "parameter", element_name, error))
3328 	{
3329 	  state_switch (ctx, STATE_FUNCTION_PARAMETERS);
3330 	}
3331       break;
3332 
3333     case STATE_FUNCTION:
3334       {
3335         pop_node (ctx);
3336 	if (ctx->node_stack == NULL)
3337 	  {
3338 	    state_switch (ctx, STATE_NAMESPACE);
3339 	  }
3340 	else
3341 	  {
3342             g_debug("case STATE_FUNCTION %d", CURRENT_NODE (ctx)->type);
3343             if (ctx->in_embedded_state != STATE_NONE)
3344               {
3345                 state_switch (ctx, ctx->in_embedded_state);
3346                 ctx->in_embedded_state = STATE_NONE;
3347               }
3348 	    else if (CURRENT_NODE (ctx)->type == G_IR_NODE_INTERFACE)
3349 	      state_switch (ctx, STATE_INTERFACE);
3350 	    else if (CURRENT_NODE (ctx)->type == G_IR_NODE_OBJECT)
3351 	      state_switch (ctx, STATE_CLASS);
3352 	    else if (CURRENT_NODE (ctx)->type == G_IR_NODE_BOXED)
3353 	      state_switch (ctx, STATE_BOXED);
3354 	    else if (CURRENT_NODE (ctx)->type == G_IR_NODE_STRUCT)
3355 	      state_switch (ctx, STATE_STRUCT);
3356 	    else if (CURRENT_NODE (ctx)->type == G_IR_NODE_UNION)
3357 	      state_switch (ctx, STATE_UNION);
3358 	    else if (CURRENT_NODE (ctx)->type == G_IR_NODE_ENUM ||
3359 		     CURRENT_NODE (ctx)->type == G_IR_NODE_FLAGS)
3360 	      state_switch (ctx, STATE_ENUM);
3361 	    else
3362 	      {
3363 		int line_number, char_number;
3364 		g_markup_parse_context_get_position (context, &line_number, &char_number);
3365 		g_set_error (error,
3366 			     G_MARKUP_ERROR,
3367 			     G_MARKUP_ERROR_INVALID_CONTENT,
3368 			     "Unexpected end tag '%s' on line %d char %d",
3369 			     element_name,
3370 			     line_number, char_number);
3371 	      }
3372 	  }
3373       }
3374       break;
3375 
3376     case STATE_CLASS_FIELD:
3377       if (strcmp ("type", element_name) == 0)
3378 	break;
3379       if (require_end_element (context, ctx, "field", element_name, error))
3380 	{
3381 	  state_switch (ctx, STATE_CLASS);
3382 	}
3383       break;
3384 
3385     case STATE_CLASS_PROPERTY:
3386       if (strcmp ("type", element_name) == 0)
3387 	break;
3388       if (require_end_element (context, ctx, "property", element_name, error))
3389 	{
3390 	  state_switch (ctx, STATE_CLASS);
3391 	}
3392       break;
3393 
3394     case STATE_CLASS:
3395       if (require_end_element (context, ctx, "class", element_name, error))
3396 	{
3397 	  pop_node (ctx);
3398 	  state_switch (ctx, STATE_NAMESPACE);
3399 	}
3400       break;
3401 
3402     case STATE_INTERFACE_PROPERTY:
3403       if (strcmp ("type", element_name) == 0)
3404 	break;
3405       if (require_end_element (context, ctx, "property", element_name, error))
3406 	{
3407 	  state_switch (ctx, STATE_INTERFACE);
3408 	}
3409       break;
3410 
3411     case STATE_INTERFACE_FIELD:
3412       if (strcmp ("type", element_name) == 0)
3413 	break;
3414       if (require_end_element (context, ctx, "field", element_name, error))
3415 	{
3416 	  state_switch (ctx, STATE_INTERFACE);
3417 	}
3418       break;
3419 
3420     case STATE_INTERFACE:
3421       if (require_end_element (context, ctx, "interface", element_name, error))
3422 	{
3423 	  pop_node (ctx);
3424 	  state_switch (ctx, STATE_NAMESPACE);
3425 	}
3426       break;
3427 
3428     case STATE_ENUM:
3429       if (strcmp ("member", element_name) == 0)
3430 	break;
3431       else if (strcmp ("function", element_name) == 0)
3432 	break;
3433       else if (require_one_of_end_elements (context, ctx,
3434 					    element_name, error, "enumeration",
3435 					    "bitfield", NULL))
3436 	{
3437 	  pop_node (ctx);
3438 	  state_switch (ctx, STATE_NAMESPACE);
3439 	}
3440       break;
3441 
3442     case STATE_BOXED:
3443       if (require_end_element (context, ctx, "glib:boxed", element_name, error))
3444 	{
3445 	  pop_node (ctx);
3446 	  state_switch (ctx, STATE_NAMESPACE);
3447 	}
3448       break;
3449 
3450     case STATE_BOXED_FIELD:
3451       if (strcmp ("type", element_name) == 0)
3452 	break;
3453       if (require_end_element (context, ctx, "field", element_name, error))
3454 	{
3455 	  state_switch (ctx, STATE_BOXED);
3456 	}
3457       break;
3458 
3459     case STATE_STRUCT_FIELD:
3460       if (strcmp ("type", element_name) == 0)
3461 	break;
3462       if (require_end_element (context, ctx, "field", element_name, error))
3463 	{
3464 	  state_switch (ctx, STATE_STRUCT);
3465 	}
3466       break;
3467 
3468     case STATE_STRUCT:
3469       if (require_end_element (context, ctx, "record", element_name, error))
3470 	{
3471 	  state_switch_end_struct_or_union (context, ctx, element_name, error);
3472 	}
3473       break;
3474 
3475     case STATE_UNION_FIELD:
3476       if (strcmp ("type", element_name) == 0)
3477 	break;
3478       if (require_end_element (context, ctx, "field", element_name, error))
3479 	{
3480 	  state_switch (ctx, STATE_UNION);
3481 	}
3482       break;
3483 
3484     case STATE_UNION:
3485       if (require_end_element (context, ctx, "union", element_name, error))
3486 	{
3487 	  state_switch_end_struct_or_union (context, ctx, element_name, error);
3488 	}
3489       break;
3490     case STATE_IMPLEMENTS:
3491       if (strcmp ("interface", element_name) == 0)
3492 	break;
3493       if (require_end_element (context, ctx, "implements", element_name, error))
3494         state_switch (ctx, STATE_CLASS);
3495       break;
3496     case STATE_PREREQUISITE:
3497       if (require_end_element (context, ctx, "prerequisite", element_name, error))
3498         state_switch (ctx, STATE_INTERFACE);
3499       break;
3500     case STATE_NAMESPACE_CONSTANT:
3501     case STATE_CLASS_CONSTANT:
3502     case STATE_INTERFACE_CONSTANT:
3503       if (strcmp ("type", element_name) == 0)
3504 	break;
3505       if (require_end_element (context, ctx, "constant", element_name, error))
3506 	{
3507 	  switch (ctx->state)
3508 	    {
3509 	    case STATE_NAMESPACE_CONSTANT:
3510 	  	  pop_node (ctx);
3511 	      state_switch (ctx, STATE_NAMESPACE);
3512 	      break;
3513 	    case STATE_CLASS_CONSTANT:
3514 	      state_switch (ctx, STATE_CLASS);
3515 	      break;
3516 	    case STATE_INTERFACE_CONSTANT:
3517 	      state_switch (ctx, STATE_INTERFACE);
3518 	      break;
3519 	    default:
3520 	      g_assert_not_reached ();
3521 	      break;
3522 	    }
3523 	}
3524       break;
3525     case STATE_TYPE:
3526       if ((strcmp ("type", element_name) == 0) || (strcmp ("array", element_name) == 0) ||
3527 	  (strcmp ("varargs", element_name) == 0))
3528 	{
3529 	  end_type (ctx);
3530 	}
3531       break;
3532     case STATE_ATTRIBUTE:
3533       if (strcmp ("attribute", element_name) == 0)
3534         {
3535           state_switch (ctx, ctx->prev_state);
3536         }
3537       break;
3538 
3539     case STATE_PASSTHROUGH:
3540       ctx->unknown_depth -= 1;
3541       g_assert (ctx->unknown_depth >= 0);
3542       if (ctx->unknown_depth == 0)
3543         state_switch (ctx, ctx->prev_state);
3544       break;
3545     default:
3546       g_error ("Unhandled state %d in end_element_handler\n", ctx->state);
3547     }
3548 }
3549 
3550 static void
text_handler(GMarkupParseContext * context,const gchar * text,gsize text_len,gpointer user_data,GError ** error)3551 text_handler (GMarkupParseContext *context,
3552 	      const gchar         *text,
3553 	      gsize                text_len,
3554 	      gpointer             user_data,
3555 	      GError             **error)
3556 {
3557   /* FIXME warn about non-whitespace text */
3558 }
3559 
3560 static void
cleanup(GMarkupParseContext * context,GError * error,gpointer user_data)3561 cleanup (GMarkupParseContext *context,
3562 	 GError              *error,
3563 	 gpointer             user_data)
3564 {
3565   ParseContext *ctx = user_data;
3566   GList *m;
3567 
3568   for (m = ctx->modules; m; m = m->next)
3569     _g_ir_module_free (m->data);
3570   g_list_free (ctx->modules);
3571   ctx->modules = NULL;
3572 
3573   ctx->current_module = NULL;
3574 }
3575 
3576 /**
3577  * _g_ir_parser_parse_string:
3578  * @parser: a #GIrParser
3579  * @namespace: the namespace of the string
3580  * @filename: (allow-none): Path to parsed file, or %NULL
3581  * @buffer: the data containing the XML
3582  * @length: length of the data
3583  * @error: return location for a #GError, or %NULL
3584  *
3585  * Parse a string that holds a complete GIR XML file, and return a list of a
3586  * a #GirModule for each &lt;namespace/&gt; element within the file.
3587  *
3588  * Returns: (transfer none): a new #GirModule
3589  */
3590 GIrModule *
_g_ir_parser_parse_string(GIrParser * parser,const gchar * namespace,const gchar * filename,const gchar * buffer,gssize length,GError ** error)3591 _g_ir_parser_parse_string (GIrParser           *parser,
3592 			   const gchar         *namespace,
3593 			   const gchar         *filename,
3594 			   const gchar         *buffer,
3595 			   gssize               length,
3596 			   GError             **error)
3597 {
3598   ParseContext ctx = { 0 };
3599   GMarkupParseContext *context;
3600 
3601   ctx.parser = parser;
3602   ctx.state = STATE_START;
3603   ctx.file_path = filename;
3604   ctx.namespace = namespace;
3605   ctx.include_modules = NULL;
3606   ctx.aliases = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
3607   ctx.disguised_structures = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
3608   ctx.type_depth = 0;
3609   ctx.dependencies = NULL;
3610   ctx.current_module = NULL;
3611 
3612   context = g_markup_parse_context_new (&firstpass_parser, 0, &ctx, NULL);
3613 
3614   if (!g_markup_parse_context_parse (context, buffer, length, error))
3615     goto out;
3616 
3617   if (!g_markup_parse_context_end_parse (context, error))
3618     goto out;
3619 
3620   g_markup_parse_context_free (context);
3621 
3622   ctx.state = STATE_START;
3623   context = g_markup_parse_context_new (&markup_parser, 0, &ctx, NULL);
3624   if (!g_markup_parse_context_parse (context, buffer, length, error))
3625     goto out;
3626 
3627   if (!g_markup_parse_context_end_parse (context, error))
3628     goto out;
3629 
3630   parser->parsed_modules = g_list_concat (g_list_copy (ctx.modules),
3631 					  parser->parsed_modules);
3632 
3633  out:
3634 
3635   if (ctx.modules == NULL)
3636     {
3637       /* An error occurred before we created a module, so we haven't
3638        * transferred ownership of these hash tables to the module.
3639        */
3640       if (ctx.aliases != NULL)
3641 	g_hash_table_destroy (ctx.aliases);
3642       if (ctx.disguised_structures != NULL)
3643 	g_hash_table_destroy (ctx.disguised_structures);
3644       g_list_free (ctx.include_modules);
3645     }
3646 
3647   g_markup_parse_context_free (context);
3648 
3649   if (ctx.modules)
3650     return ctx.modules->data;
3651 
3652   if (error && *error == NULL)
3653     g_set_error (error,
3654                  G_MARKUP_ERROR,
3655                  G_MARKUP_ERROR_INVALID_CONTENT,
3656                  "Expected namespace element in the gir file");
3657   return NULL;
3658 }
3659 
3660 /**
3661  * _g_ir_parser_parse_file:
3662  * @parser: a #GIrParser
3663  * @filename: filename to parse
3664  * @error: return location for a #GError, or %NULL
3665  *
3666  * Parse GIR XML file, and return a list of a a #GirModule for each
3667  * &lt;namespace/&gt; element within the file.
3668  *
3669  * Returns: (transfer container): a newly allocated list of #GIrModule. The modules themselves
3670  *  are owned by the #GIrParser and will be freed along with the parser.
3671  */
3672 GIrModule *
_g_ir_parser_parse_file(GIrParser * parser,const gchar * filename,GError ** error)3673 _g_ir_parser_parse_file (GIrParser   *parser,
3674 			 const gchar *filename,
3675 			 GError     **error)
3676 {
3677   gchar *buffer;
3678   gsize length;
3679   GIrModule *module;
3680   const char *slash;
3681   char *dash;
3682   char *namespace;
3683 
3684   if (!g_str_has_suffix (filename, ".gir"))
3685     {
3686       g_set_error (error,
3687 		   G_MARKUP_ERROR,
3688 		   G_MARKUP_ERROR_INVALID_CONTENT,
3689 		   "Expected filename to end with '.gir'");
3690       return NULL;
3691     }
3692 
3693   g_debug ("[parsing] filename %s", filename);
3694 
3695   slash = g_strrstr (filename, "/");
3696   if (!slash)
3697     namespace = g_strdup (filename);
3698   else
3699     namespace = g_strdup (slash+1);
3700   namespace[strlen(namespace)-4] = '\0';
3701 
3702   /* Remove version */
3703   dash = strstr (namespace, "-");
3704   if (dash != NULL)
3705     *dash = '\0';
3706 
3707   if (!g_file_get_contents (filename, &buffer, &length, error))
3708     {
3709       g_free (namespace);
3710 
3711       return NULL;
3712     }
3713 
3714   module = _g_ir_parser_parse_string (parser, namespace, filename, buffer, length, error);
3715 
3716   g_free (namespace);
3717 
3718   g_free (buffer);
3719 
3720   return module;
3721 }
3722 
3723 
3724