Keep track of generated XML tree and handle indentation and closing tags
[gnome.gobject-introspection] / tools / generate.c
1 /* -*- Mode: C; c-file-style: "gnu"; -*- */
2 /* GObject introspection: IDL generator
3  *
4  * Copyright (C) 2005 Matthias Clasen
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include <errno.h>
23 #include <string.h>
24
25 #include <glib.h>
26 #include <glib-object.h>
27 #include <glib/gstdio.h>
28
29 #include "girepository.h"
30 #include "gtypelib.h"
31
32 /* FIXME: Avoid global */
33 static gchar *output = NULL;
34 gchar **includedirs = NULL;
35
36 typedef struct {
37   FILE *file;
38   GSList *stack;
39 } Xml;
40
41 typedef struct {
42   char *name;
43   guint has_children : 1;
44 } XmlElement;
45
46 static XmlElement *
47 xml_element_new (const char *name)
48 {
49   XmlElement *elem;
50
51   elem = g_new (XmlElement, 1);
52   elem->name = g_strdup (name);
53   elem->has_children = FALSE;
54   return elem;
55 }
56
57 static void
58 xml_element_free (XmlElement *elem)
59 {
60   g_free (elem->name);
61   g_free (elem);
62 }
63
64 static void
65 xml_printf (Xml *xml, const char *fmt, ...)
66 {
67   va_list ap;
68
69   va_start (ap, fmt);
70   vfprintf (xml->file, fmt, ap);
71   va_end (ap);
72 }
73
74 static void
75 xml_start_element (Xml *xml, const char *element_name)
76 {
77   XmlElement *parent = NULL;
78
79   if (xml->stack)
80     {
81       parent = xml->stack->data;
82
83       if (!parent->has_children)
84         xml_printf (xml, ">\n");
85
86       parent->has_children = TRUE;
87     }
88
89   xml_printf (xml, "%*s<%s", g_slist_length(xml->stack)*2, "", element_name);
90
91   xml->stack = g_slist_prepend (xml->stack, xml_element_new (element_name));
92 }
93
94 static void
95 xml_end_element (Xml *xml, const char *name)
96 {
97   XmlElement *elem;
98
99   g_assert (xml->stack != NULL);
100
101   elem = xml->stack->data;
102   xml->stack = g_slist_delete_link (xml->stack, xml->stack);
103
104   if (name != NULL)
105     g_assert_cmpstr (name, ==, elem->name);
106
107   if (elem->has_children)
108     xml_printf (xml, "%*s</%s>\n", g_slist_length (xml->stack)*2, "", elem->name);
109   else
110     xml_printf (xml, "/>\n");
111
112   xml_element_free (elem);
113 }
114
115 static void
116 xml_end_element_unchecked (Xml *xml)
117 {
118   xml_end_element (xml, NULL);
119 }
120
121 static Xml *
122 xml_open (FILE *file)
123 {
124   Xml *xml;
125
126   xml = g_new (Xml, 1);
127   xml->file = file;
128   xml->stack = NULL;
129
130   return xml;
131 }
132
133 static void
134 xml_close (Xml *xml)
135 {
136   g_assert (xml->stack == NULL);
137   if (xml->file != NULL)
138     {
139       fflush (xml->file);
140       if (xml->file != stdout)
141         fclose (xml->file);
142       xml->file = NULL;
143     }
144 }
145
146 static void
147 xml_free (Xml *xml)
148 {
149   xml_close (xml);
150   g_free (xml);
151 }
152
153
154 static void 
155 check_unresolved (GIBaseInfo *info)
156 {
157   if (g_base_info_get_type (info) != GI_INFO_TYPE_UNRESOLVED)
158     return;
159
160   g_critical ("Found unresolved type '%s' '%s'\n", 
161               g_base_info_get_name (info), g_base_info_get_namespace (info));
162 }
163
164 static void 
165 write_type_name (const gchar *namespace,
166                  GIBaseInfo  *info,
167                  Xml         *file)
168 {
169   if (strcmp (namespace, g_base_info_get_namespace (info)) != 0)
170     xml_printf (file, "%s.", g_base_info_get_namespace (info));
171
172   xml_printf (file, "%s", g_base_info_get_name (info));
173 }
174
175 static void
176 write_type_info (const gchar *namespace,
177                  GITypeInfo  *info, 
178                  Xml         *file)
179 {
180   gint tag;
181   gint i;
182   GITypeInfo *type;
183   gboolean is_pointer;
184   
185   check_unresolved ((GIBaseInfo*)info);
186
187   tag = g_type_info_get_tag (info);
188   is_pointer = g_type_info_is_pointer (info);
189
190   if (tag == GI_TYPE_TAG_VOID) 
191     {
192       if (is_pointer)
193         xml_printf (file, "%s", "any");
194       else
195         xml_printf (file, "%s", "none");
196     } 
197   else if (G_TYPE_TAG_IS_BASIC (tag))
198     xml_printf (file, "%s", g_type_tag_to_string (tag));
199   else if (tag == GI_TYPE_TAG_ARRAY)
200     {
201       gint length;
202
203       type = g_type_info_get_param_type (info, 0);
204       write_type_info (namespace, type, file);
205       xml_printf (file, "[");
206
207       length = g_type_info_get_array_length (info);
208       
209       if (length >= 0)
210         xml_printf (file, "length=%d", length);
211       
212       if (g_type_info_is_zero_terminated (info))
213         xml_printf (file, "%szero-terminated=1", length >= 0 ? "," : "");
214       
215      xml_printf (file, "]");
216       g_base_info_unref ((GIBaseInfo *)type);
217     }
218   else if (tag == GI_TYPE_TAG_INTERFACE)
219     {
220       GIBaseInfo *iface = g_type_info_get_interface (info);
221       write_type_name (namespace, iface, file);
222       g_base_info_unref (iface);
223     }
224   else if (tag == GI_TYPE_TAG_GLIST)
225     {
226       type = g_type_info_get_param_type (info, 0);
227       xml_printf (file, "GLib.List");
228       if (type)
229         {
230           xml_printf (file, "<");
231           write_type_info (namespace, type, file);
232           xml_printf (file, ">");
233           g_base_info_unref ((GIBaseInfo *)type);
234         }
235     }
236   else if (tag == GI_TYPE_TAG_GSLIST)
237     {
238       type = g_type_info_get_param_type (info, 0);
239       xml_printf (file, "GLib.SList");
240       if (type)
241         {
242           xml_printf (file, "<");
243           write_type_info (namespace, type, file);
244           xml_printf (file, ">");
245           g_base_info_unref ((GIBaseInfo *)type);
246         }
247     }
248   else if (tag == GI_TYPE_TAG_GHASH)
249     {
250       type = g_type_info_get_param_type (info, 0);
251       xml_printf (file, "GLib.HashTable");
252       if (type)
253         {
254           xml_printf (file, "<");
255           write_type_info (namespace, type, file);
256           g_base_info_unref ((GIBaseInfo *)type);
257           type = g_type_info_get_param_type (info, 1);
258           xml_printf (file, ",");
259           write_type_info (namespace, type, file);
260           xml_printf (file, ">");
261           g_base_info_unref ((GIBaseInfo *)type);
262         }
263     }
264   else if (tag == GI_TYPE_TAG_ERROR) 
265     {
266       gint n;
267
268       xml_printf (file, "GLib.Error");
269       n = g_type_info_get_n_error_domains (info);
270       if (n > 0)
271         {
272           xml_printf (file, "<");
273           for (i = 0; i < n; i++)
274             {
275               GIErrorDomainInfo *ed = g_type_info_get_error_domain (info, i);
276               if (i > 0)
277                 xml_printf (file, ",");
278               write_type_name (namespace, (GIBaseInfo *)ed, file);
279               g_base_info_unref ((GIBaseInfo *)ed);
280             }
281           xml_printf (file, ">");
282         }
283     }
284   else
285     {
286       g_printerr ("Unhandled type tag %d\n", tag);
287       g_assert_not_reached ();
288     }
289 }
290
291 static void
292 write_constant_value (const gchar *namespace, 
293                       GITypeInfo *info,
294                       GArgument *argument,
295                       Xml *file);
296
297 static void
298 write_field_info (const gchar *namespace,
299                   GIFieldInfo *info,
300                   GIConstantInfo *branch,
301                   Xml         *file)
302 {
303   const gchar *name;
304   GIFieldInfoFlags flags;
305   gint size;
306   gint offset;
307   GITypeInfo *type;
308   GArgument value; 
309
310   name = g_base_info_get_name ((GIBaseInfo *)info);
311   flags = g_field_info_get_flags (info);
312   size = g_field_info_get_size (info);
313   offset = g_field_info_get_offset (info);
314
315   xml_start_element (file, "field");
316   xml_printf (file, " name=\"%s\" readable=\"%s\" writable=\"%s\"",
317              name, 
318              flags & GI_FIELD_IS_READABLE ? "1" : "0", 
319              flags & GI_FIELD_IS_WRITABLE ? "1" : "0");
320   if (size)
321     xml_printf (file, " bits=\"%d\"", size);
322
323   xml_printf (file, " offset=\"%d\"", offset);
324
325   type = g_field_info_get_type (info);
326
327   if (branch)
328     {
329       xml_printf (file, " branch=\"");
330       type = g_constant_info_get_type (branch);
331       g_constant_info_get_value (branch, &value);
332       write_constant_value (namespace, type, &value, file);
333       xml_printf (file, "\"");
334     }
335
336   xml_start_element (file, "type");
337
338   xml_printf (file, " name=\"");
339
340   write_type_info (namespace, type, file);
341   g_base_info_unref ((GIBaseInfo *)type);
342
343   xml_printf (file, "\"");
344
345   xml_end_element (file, "type");
346
347   xml_end_element (file, "field");
348 }
349
350 static void 
351 write_callable_info (const gchar    *namespace,
352                      GICallableInfo *info,
353                      Xml            *file,
354                      gint            indent)
355 {
356   GITypeInfo *type;
357   gint i;
358
359   type = g_callable_info_get_return_type (info);
360
361   xml_start_element (file, "return-value");
362
363   if (g_type_info_is_pointer (type))
364     {
365       switch (g_callable_info_get_caller_owns (info))
366         {
367         case GI_TRANSFER_NOTHING:
368           break;
369         case GI_TRANSFER_CONTAINER:
370           xml_printf (file, " transfer-ownership=\"container\"");
371           break;
372         case GI_TRANSFER_EVERYTHING:
373           xml_printf (file, " transfer-ownership=\"full\"");
374           break;
375         default:
376           g_assert_not_reached ();
377         }
378     }
379   
380   if (g_callable_info_may_return_null (info))
381     xml_printf (file, " null-ok=\"1\"");
382
383   xml_start_element (file, "type");
384
385   xml_printf (file, " name=\"");
386
387   write_type_info (namespace, type, file);
388
389   xml_printf (file, "\"");
390
391   xml_end_element (file, "type");
392
393   xml_end_element (file, "return-value");
394         
395   if (g_callable_info_get_n_args (info) <= 0)
396     return;
397
398   xml_start_element (file, "parameters");
399   for (i = 0; i < g_callable_info_get_n_args (info); i++)
400     {
401       GIArgInfo *arg = g_callable_info_get_arg (info, i);
402       
403       xml_start_element (file, "parameter");
404       xml_printf (file, " name=\"%s\"",
405                   g_base_info_get_name ((GIBaseInfo *) arg));
406       
407       switch (g_arg_info_get_ownership_transfer (arg))
408         {
409         case GI_TRANSFER_NOTHING:
410           break;
411         case GI_TRANSFER_CONTAINER:
412           xml_printf (file, " transfer=\"container\"");
413           break;
414         case GI_TRANSFER_EVERYTHING:
415           xml_printf (file, " transfer=\"full\"");
416           break;
417         default:
418           g_assert_not_reached ();
419         }
420       
421       xml_printf (file, " direction=\"");
422       switch (g_arg_info_get_direction (arg))
423         {
424         case GI_DIRECTION_IN:
425           xml_printf (file, "in");
426           break;
427         case GI_DIRECTION_OUT:
428           xml_printf (file, "out");
429           break;
430         case GI_DIRECTION_INOUT:
431           xml_printf (file, "inout");
432           break;
433         }
434       xml_printf (file, "\"");
435       
436       if (g_arg_info_may_be_null (arg))
437         xml_printf (file, " null-ok=\"1\"");
438       
439       if (g_arg_info_is_dipper (arg))
440         xml_printf (file, " dipper=\"1\"");
441       
442       if (g_arg_info_is_return_value (arg))
443         xml_printf (file, " retval=\"1\"");
444       
445       if (g_arg_info_is_optional (arg))
446         xml_printf (file, " optional=\"1\"");
447       
448       xml_start_element (file, "type");
449       
450       xml_printf (file, " name=\"");
451
452       type = g_arg_info_get_type (arg);
453       write_type_info (namespace, type, file);
454
455       xml_printf (file, "\"");
456
457       xml_end_element (file, "type");
458
459       xml_end_element (file, "parameter");
460
461       g_base_info_unref ((GIBaseInfo *)arg);
462     }
463   
464   xml_end_element (file, "parameters");
465   g_base_info_unref ((GIBaseInfo *)type);
466 }
467
468 static void
469 write_function_info (const gchar    *namespace,
470                      GIFunctionInfo *info,
471                      Xml            *file,
472                      gint            indent)
473 {
474   GIFunctionInfoFlags flags;
475   const gchar *tag;
476   const gchar *name;
477   const gchar *symbol;
478   gboolean deprecated;
479
480   flags = g_function_info_get_flags (info);
481   name = g_base_info_get_name ((GIBaseInfo *)info);
482   symbol = g_function_info_get_symbol (info);
483   deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
484
485   if (flags & GI_FUNCTION_IS_CONSTRUCTOR)
486     tag = "constructor";
487   else if (flags & GI_FUNCTION_IS_METHOD)
488     tag = "method";
489   else
490     tag = "function";
491         
492   xml_start_element (file, tag);
493   xml_printf (file, " name=\"%s\" c:identifier=\"%s\"",
494               name, symbol);
495         
496   if (flags & GI_FUNCTION_IS_SETTER)
497     xml_printf (file, " type=\"setter\"");
498   else if (flags & GI_FUNCTION_IS_GETTER)
499     xml_printf (file, " type=\"getter\"");
500           
501   if (deprecated)
502     xml_printf (file, " deprecated=\"1\"");
503
504   write_callable_info (namespace, (GICallableInfo*)info, file, indent);
505   xml_end_element (file, tag);
506 }
507
508 static void
509 write_callback_info (const gchar    *namespace,
510                      GICallbackInfo *info,
511                      Xml            *file,
512                      gint            indent)
513 {
514   const gchar *name;
515   gboolean deprecated;
516
517   name = g_base_info_get_name ((GIBaseInfo *)info);
518   deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
519
520   xml_start_element (file, "callback");
521   xml_printf (file, " name=\"%s\"", name);
522         
523   if (deprecated)
524     xml_printf (file, " deprecated=\"1\"");
525         
526   write_callable_info (namespace, (GICallableInfo*)info, file, indent);
527   xml_end_element (file, "callback");
528 }
529
530 static void
531 write_struct_info (const gchar  *namespace,
532                    GIStructInfo *info,
533                    Xml          *file)
534 {
535   const gchar *name;
536   const gchar *type_name;
537   const gchar *type_init;
538   gboolean deprecated;
539   gint i;
540   int n_elts;
541
542   name = g_base_info_get_name ((GIBaseInfo *)info);
543   deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
544
545   type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
546   type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info);
547   
548   if (g_base_info_get_type ((GIBaseInfo *)info) == GI_INFO_TYPE_BOXED)
549     {
550       xml_start_element (file, "glib:boxed");
551       xml_printf (file, " glib:name=\"%s\"", name);
552     }
553   else
554     {
555       xml_start_element (file, "record");
556       xml_printf (file, " name=\"%s\"", name);
557     }
558   
559   if (type_name != NULL)
560     xml_printf (file, " glib:type-name=\"%s\" glib:get-type=\"%s\"", type_name, type_init);
561           
562   if (deprecated)
563     xml_printf (file, " deprecated=\"1\"");
564         
565   n_elts = g_struct_info_get_n_fields (info) + g_struct_info_get_n_methods (info);
566   if (n_elts > 0)
567     {
568       for (i = 0; i < g_struct_info_get_n_fields (info); i++)
569         {
570           GIFieldInfo *field = g_struct_info_get_field (info, i);
571           write_field_info (namespace, field, NULL, file);
572           g_base_info_unref ((GIBaseInfo *)field);
573         }
574       
575       for (i = 0; i < g_struct_info_get_n_methods (info); i++)
576         {
577           GIFunctionInfo *function = g_struct_info_get_method (info, i);
578           write_function_info (namespace, function, file, 6);
579           g_base_info_unref ((GIBaseInfo *)function);
580         }
581       
582     } 
583
584   xml_end_element_unchecked (file);
585 }
586
587 static void
588 write_value_info (const gchar *namespace,
589                   GIValueInfo *info,
590                   Xml         *file)
591 {
592   const gchar *name;
593   glong value;
594   gboolean deprecated;
595
596   name = g_base_info_get_name ((GIBaseInfo *)info);
597   value = g_value_info_get_value (info);
598   deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
599
600   xml_start_element (file, "member");
601   xml_printf (file, " name=\"%s\" value=\"%ld\"", name, value);
602
603   if (deprecated)
604     xml_printf (file, " deprecated=\"1\"");
605   
606   xml_end_element (file, "member");
607 }
608
609 static void
610 write_constant_value (const gchar *namespace, 
611                       GITypeInfo *type,
612                       GArgument  *value,
613                       Xml        *file)
614 {
615   switch (g_type_info_get_tag (type))
616     {
617     case GI_TYPE_TAG_BOOLEAN:
618       xml_printf (file, "%d", value->v_boolean);
619       break;
620     case GI_TYPE_TAG_INT8:
621       xml_printf (file, "%d", value->v_int8);
622       break;
623     case GI_TYPE_TAG_UINT8:
624       xml_printf (file, "%d", value->v_uint8);
625       break;
626     case GI_TYPE_TAG_INT16:
627       xml_printf (file, "%" G_GINT16_FORMAT, value->v_int16);
628       break;
629     case GI_TYPE_TAG_UINT16:
630       xml_printf (file, "%" G_GUINT16_FORMAT, value->v_uint16);
631       break;
632     case GI_TYPE_TAG_INT32:
633       xml_printf (file, "%" G_GINT32_FORMAT, value->v_int32);
634       break;
635     case GI_TYPE_TAG_UINT32:
636       xml_printf (file, "%" G_GUINT32_FORMAT, value->v_uint32);
637       break;
638     case GI_TYPE_TAG_INT64:
639       xml_printf (file, "%" G_GINT64_FORMAT, value->v_int64);
640       break;
641     case GI_TYPE_TAG_UINT64:
642       xml_printf (file, "%" G_GUINT64_FORMAT, value->v_uint64);
643       break;
644     case GI_TYPE_TAG_INT:
645       xml_printf (file, "%d", value->v_int);
646       break;
647     case GI_TYPE_TAG_UINT:
648       xml_printf (file, "%d", value->v_uint);
649       break;
650     case GI_TYPE_TAG_LONG:
651       xml_printf (file, "%ld", value->v_long);
652       break;
653     case GI_TYPE_TAG_ULONG:
654       xml_printf (file, "%ld", value->v_ulong);
655       break;
656     case GI_TYPE_TAG_SSIZE:
657       xml_printf (file, "%zd", value->v_ssize);
658       break;
659     case GI_TYPE_TAG_SIZE:
660       xml_printf (file, "%zd", value->v_size);
661       break;
662     case GI_TYPE_TAG_FLOAT:
663       xml_printf (file, "%f", value->v_float);
664       break;
665     case GI_TYPE_TAG_DOUBLE:
666       xml_printf (file, "%f", value->v_double);
667       break;
668     case GI_TYPE_TAG_UTF8:
669     case GI_TYPE_TAG_FILENAME:
670       xml_printf (file, "%s", value->v_string);
671       break;
672     default:
673       g_assert_not_reached ();
674     }
675 }
676
677 static void
678 write_constant_info (const gchar    *namespace,
679                      GIConstantInfo *info,
680                      Xml            *file,
681                      gint            indent)
682 {
683   GITypeInfo *type;
684   const gchar *name;
685   gboolean deprecated;
686   GArgument value;
687
688   name = g_base_info_get_name ((GIBaseInfo *)info);
689   deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
690
691   xml_start_element (file, "constant");
692   xml_printf (file, " name=\"%s\"", name);
693
694   type = g_constant_info_get_type (info);
695   xml_printf (file, " value=\"");
696
697   g_constant_info_get_value (info, &value);
698   write_constant_value (namespace, type, &value, file);
699   xml_printf (file, "\"");
700
701   xml_start_element (file, "type");
702   xml_printf (file, " name=\"");
703
704   write_type_info (namespace, type, file);
705   xml_printf (file, "\"");
706
707   xml_end_element (file, "type");
708
709   xml_end_element (file, "constant");
710   
711   g_base_info_unref ((GIBaseInfo *)type);
712 }
713
714
715 static void
716 write_enum_info (const gchar *namespace,
717                  GIEnumInfo *info,
718                  Xml         *file)
719 {
720   const gchar *name;
721   const gchar *type_name;
722   const gchar *type_init;
723   gboolean deprecated;
724   gint i;
725
726   name = g_base_info_get_name ((GIBaseInfo *)info);
727   deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
728
729   type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
730   type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info);
731
732   if (g_base_info_get_type ((GIBaseInfo *)info) == GI_INFO_TYPE_ENUM)
733     xml_start_element (file, "enumeration");
734   else
735     xml_start_element (file, "bitfield");
736   xml_printf (file, " name=\"%s\"", name);
737
738   if (type_init)
739     xml_printf (file, " glib:type-name=\"%s\" glib:get-type=\"%s\"", type_name, type_init);
740   
741   if (deprecated)
742     xml_printf (file, " deprecated=\"1\"");
743         
744
745   for (i = 0; i < g_enum_info_get_n_values (info); i++)
746     {
747       GIValueInfo *value = g_enum_info_get_value (info, i);
748       write_value_info (namespace, value, file);
749       g_base_info_unref ((GIBaseInfo *)value);
750     }
751
752   xml_end_element_unchecked (file);
753 }
754
755 static void
756 write_signal_info (const gchar  *namespace,
757                    GISignalInfo *info,
758                    Xml          *file)
759 {
760   GSignalFlags flags;
761   const gchar *name;
762   gboolean deprecated;
763
764   name = g_base_info_get_name ((GIBaseInfo *)info);
765   flags = g_signal_info_get_flags (info);
766   deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
767
768   xml_start_element (file, "glib:signal");
769   xml_printf (file, " name=\"%s\"", name);
770
771   if (deprecated)
772     xml_printf (file, " deprecated=\"1\"");
773         
774   if (flags & G_SIGNAL_RUN_FIRST)
775     xml_printf (file, " when=\"FIRST\"");
776   else if (flags & G_SIGNAL_RUN_LAST)
777     xml_printf (file, " when=\"LAST\"");
778   else if (flags & G_SIGNAL_RUN_CLEANUP)
779     xml_printf (file, " when=\"CLEANUP\"");
780
781   if (flags & G_SIGNAL_NO_RECURSE)
782     xml_printf (file, " no-recurse=\"1\"");
783
784   if (flags & G_SIGNAL_DETAILED)
785     xml_printf (file, " detailed=\"1\"");
786
787   if (flags & G_SIGNAL_ACTION)
788     xml_printf (file, " action=\"1\"");
789
790   if (flags & G_SIGNAL_NO_HOOKS)
791     xml_printf (file, " no-hooks=\"1\"");
792
793   write_callable_info (namespace, (GICallableInfo*)info, file, 6);
794
795   xml_end_element (file, "glib:signal");
796 }
797
798 static void
799 write_vfunc_info (const gchar *namespace, 
800                   GIVFuncInfo *info,
801                   Xml         *file)
802 {
803   GIVFuncInfoFlags flags;
804   const gchar *name;
805   gboolean deprecated;
806   gint offset;
807
808   name = g_base_info_get_name ((GIBaseInfo *)info);
809   flags = g_vfunc_info_get_flags (info);
810   deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
811   offset = g_vfunc_info_get_offset (info);
812
813   xml_start_element (file, "vfunc");
814   xml_printf (file, " name=\"%s\"", name);
815
816   if (deprecated)
817     xml_printf (file, " deprecated=\"1\"");
818         
819   if (flags & GI_VFUNC_MUST_CHAIN_UP)
820     xml_printf (file, " must-chain-up=\"1\"");
821
822   if (flags & GI_VFUNC_MUST_OVERRIDE)
823     xml_printf (file, " override=\"always\"");
824   else if (flags & GI_VFUNC_MUST_NOT_OVERRIDE)
825     xml_printf (file, " override=\"never\"");
826     
827   xml_printf (file, " offset=\"%d\"", offset);
828
829   write_callable_info (namespace, (GICallableInfo*)info, file, 6);
830
831   xml_end_element (file, "vfunc");
832 }
833
834 static void
835 write_property_info (const gchar    *namespace,
836                      GIPropertyInfo *info,
837                      Xml            *file)
838 {
839   GParamFlags flags;
840   const gchar *name;
841   gboolean deprecated;
842   GITypeInfo *type;
843
844   name = g_base_info_get_name ((GIBaseInfo *)info);
845   flags = g_property_info_get_flags (info);
846   deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
847
848   xml_start_element (file, "property");
849   xml_printf (file, " name=\"%s\"", name);
850
851   if (deprecated)
852     xml_printf (file, " deprecated=\"1\"");
853         
854   if (flags & G_PARAM_READABLE)
855     xml_printf (file, " readable=\"1\"");
856   else
857     xml_printf (file, " readable=\"0\"");
858
859   if (flags & G_PARAM_WRITABLE)
860     xml_printf (file, " writable=\"1\"");
861   else
862     xml_printf (file, " writable=\"0\"");
863
864   if (flags & G_PARAM_CONSTRUCT)
865     xml_printf (file, " construct=\"1\"");
866
867   if (flags & G_PARAM_CONSTRUCT_ONLY)
868     xml_printf (file, " construct-only=\"1\"");
869     
870   type = g_property_info_get_type (info);
871
872   xml_start_element (file, "type");
873
874   xml_printf (file, " name=\"");
875
876   write_type_info (namespace, type, file);
877
878   xml_printf (file, "\"");
879   
880   xml_end_element (file, "type");
881
882   xml_end_element (file, "property");
883 }
884
885 static void
886 write_object_info (const gchar  *namespace, 
887                    GIObjectInfo *info,
888                    Xml          *file)
889 {
890   const gchar *name;
891   const gchar *type_name;
892   const gchar *type_init;
893   gboolean deprecated;
894   GIObjectInfo *pnode;
895   gint i;
896
897   name = g_base_info_get_name ((GIBaseInfo *)info);
898   deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
899   
900   type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
901   type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info);
902   xml_start_element (file, "class");
903   xml_printf (file, " name=\"%s\"", name);
904
905   pnode = g_object_info_get_parent (info);
906   if (pnode)
907     {
908       xml_printf (file, " parent=\"");
909       write_type_name (namespace, (GIBaseInfo *)pnode, file);
910       xml_printf (file, "\""  );
911       g_base_info_unref ((GIBaseInfo *)pnode);
912     }
913
914   xml_printf (file, " glib:type-name=\"%s\" glib:get-type=\"%s\"", type_name, type_init);
915
916   if (deprecated)
917     xml_printf (file, " deprecated=\"1\"");
918         
919
920   if (g_object_info_get_n_interfaces (info) > 0)
921     {
922       for (i = 0; i < g_object_info_get_n_interfaces (info); i++)
923         {
924           GIInterfaceInfo *imp = g_object_info_get_interface (info, i);
925           xml_start_element (file, "implements");
926           xml_printf (file, " name=\"");
927           write_type_name (namespace, (GIBaseInfo*)imp, file);
928           xml_printf (file,"\"");
929           xml_end_element (file, "implements");
930           g_base_info_unref ((GIBaseInfo*)imp);
931         }
932     }
933
934   for (i = 0; i < g_object_info_get_n_fields (info); i++)
935     {
936       GIFieldInfo *field = g_object_info_get_field (info, i);
937       write_field_info (namespace, field, NULL, file);
938       g_base_info_unref ((GIBaseInfo *)field);
939     }
940
941   for (i = 0; i < g_object_info_get_n_methods (info); i++)
942     {
943       GIFunctionInfo *function = g_object_info_get_method (info, i);
944       write_function_info (namespace, function, file, 6);
945       g_base_info_unref ((GIBaseInfo *)function);
946     }
947
948   for (i = 0; i < g_object_info_get_n_properties (info); i++)
949     {
950       GIPropertyInfo *prop = g_object_info_get_property (info, i);
951       write_property_info (namespace, prop, file);
952       g_base_info_unref ((GIBaseInfo *)prop);
953     }
954
955   for (i = 0; i < g_object_info_get_n_signals (info); i++)
956     {
957       GISignalInfo *signal = g_object_info_get_signal (info, i);
958       write_signal_info (namespace, signal, file);
959       g_base_info_unref ((GIBaseInfo *)signal);
960     }
961   
962   for (i = 0; i < g_object_info_get_n_vfuncs (info); i++)
963     {
964       GIVFuncInfo *vfunc = g_object_info_get_vfunc (info, i);
965       write_vfunc_info (namespace, vfunc, file);
966       g_base_info_unref ((GIBaseInfo *)vfunc);
967     }
968
969   for (i = 0; i < g_object_info_get_n_constants (info); i++)
970     {
971       GIConstantInfo *constant = g_object_info_get_constant (info, i);
972       write_constant_info (namespace, constant, file, 6);
973       g_base_info_unref ((GIBaseInfo *)constant);
974     }
975   
976   xml_end_element (file, "class");
977 }
978
979 static void
980 write_interface_info (const gchar     *namespace,
981                       GIInterfaceInfo *info,
982                       Xml             *file)
983 {
984   const gchar *name;
985   const gchar *type_name;
986   const gchar *type_init;
987   gboolean deprecated;
988   gint i;
989
990   name = g_base_info_get_name ((GIBaseInfo *)info);
991   deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
992
993   type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
994   type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info);
995   xml_start_element (file, "interface");
996   xml_printf (file, " name=\"%s\" glib:type-name=\"%s\" glib:get-type=\"%s\"",
997              name, type_name, type_init);
998
999   if (deprecated)
1000     xml_printf (file, " deprecated=\"1\"");
1001         
1002
1003   if (g_interface_info_get_n_prerequisites (info) > 0)
1004     {
1005       xml_start_element (file, "requires");
1006       for (i = 0; i < g_interface_info_get_n_prerequisites (info); i++)
1007         {
1008           GIBaseInfo *req = g_interface_info_get_prerequisite (info, i);
1009           
1010           if (g_base_info_get_type (req) == GI_INFO_TYPE_INTERFACE)
1011             xml_start_element (file, "interface");
1012           else
1013             xml_start_element (file, "object");
1014           xml_printf (file, " name=\"");
1015           write_type_name (namespace, req, file);
1016           xml_end_element_unchecked (file);
1017           g_base_info_unref (req);
1018         }
1019       xml_end_element (file, "requires");
1020     }
1021
1022   for (i = 0; i < g_interface_info_get_n_methods (info); i++)
1023     {
1024       GIFunctionInfo *function = g_interface_info_get_method (info, i);
1025       write_function_info (namespace, function, file, 6);
1026       g_base_info_unref ((GIBaseInfo *)function);
1027     }
1028
1029   for (i = 0; i < g_interface_info_get_n_properties (info); i++)
1030     {
1031       GIPropertyInfo *prop = g_interface_info_get_property (info, i);
1032       write_property_info (namespace, prop, file);
1033       g_base_info_unref ((GIBaseInfo *)prop);
1034     }
1035
1036   for (i = 0; i < g_interface_info_get_n_signals (info); i++)
1037     {
1038       GISignalInfo *signal = g_interface_info_get_signal (info, i);
1039       write_signal_info (namespace, signal, file);
1040       g_base_info_unref ((GIBaseInfo *)signal);
1041     }
1042   
1043   for (i = 0; i < g_interface_info_get_n_vfuncs (info); i++)
1044     {
1045       GIVFuncInfo *vfunc = g_interface_info_get_vfunc (info, i);
1046       write_vfunc_info (namespace, vfunc, file);
1047       g_base_info_unref ((GIBaseInfo *)vfunc);
1048     }
1049
1050   for (i = 0; i < g_interface_info_get_n_constants (info); i++)
1051     {
1052       GIConstantInfo *constant = g_interface_info_get_constant (info, i);
1053       write_constant_info (namespace, constant, file, 6);
1054       g_base_info_unref ((GIBaseInfo *)constant);
1055     }
1056   
1057   xml_end_element (file, "interface");
1058 }
1059
1060 static void
1061 write_error_domain_info (const gchar       *namespace,
1062                          GIErrorDomainInfo *info,
1063                          Xml               *file)
1064 {
1065   GIBaseInfo *enum_;
1066   const gchar *name, *quark;
1067   
1068   name = g_base_info_get_name ((GIBaseInfo *)info);
1069   quark = g_error_domain_info_get_quark (info);
1070   enum_ = (GIBaseInfo *)g_error_domain_info_get_codes (info);
1071   xml_start_element (file, "errordomain");
1072   xml_printf (file, " name=\"%s\" get-quark=\"%s\" codes=\"",
1073               name, quark);
1074   write_type_name (namespace, enum_, file);
1075   xml_end_element (file, "errordomain");
1076   g_base_info_unref (enum_);
1077 }
1078
1079 static void
1080 write_union_info (const gchar *namespace, 
1081                   GIUnionInfo *info, 
1082                   Xml         *file)
1083 {
1084   const gchar *name;
1085   const gchar *type_name;
1086   const gchar *type_init;
1087   gboolean deprecated;
1088   gint i;
1089
1090   name = g_base_info_get_name ((GIBaseInfo *)info);
1091   deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
1092
1093   type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
1094   type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info);
1095   
1096   xml_start_element (file, "union");
1097   xml_printf (file, " name=\"%s\"", name);
1098   
1099   if (type_name)
1100     xml_printf (file, " type-name=\"%s\" get-type=\"%s\"", type_name, type_init);
1101           
1102   if (deprecated)
1103     xml_printf (file, " deprecated=\"1\"");
1104         
1105
1106   if (g_union_info_is_discriminated (info))
1107     {
1108       gint offset;
1109       GITypeInfo *type;
1110
1111       offset = g_union_info_get_discriminator_offset (info);
1112       type = g_union_info_get_discriminator_type (info);
1113       
1114       xml_start_element (file, "discriminator");
1115       xml_printf (file, " offset=\"%d\" type=\"", offset);
1116       write_type_info (namespace, type, file);
1117       xml_end_element (file, "discriminator");
1118       g_base_info_unref ((GIBaseInfo *)type);
1119     }
1120
1121   for (i = 0; i < g_union_info_get_n_fields (info); i++)
1122     {
1123       GIFieldInfo *field = g_union_info_get_field (info, i);
1124       GIConstantInfo *constant = g_union_info_get_discriminator (info, i);
1125       write_field_info (namespace, field, constant, file);
1126       g_base_info_unref ((GIBaseInfo *)field);
1127       if (constant)
1128         g_base_info_unref ((GIBaseInfo *)constant);
1129     }
1130
1131   for (i = 0; i < g_union_info_get_n_methods (info); i++)
1132     {
1133       GIFunctionInfo *function = g_union_info_get_method (info, i);
1134       write_function_info (namespace, function, file, 6);
1135       g_base_info_unref ((GIBaseInfo *)function);
1136     }
1137
1138   xml_end_element (file, "union");
1139 }
1140
1141 static void
1142 write_repository (const char   *namespace,
1143                   gboolean      needs_prefix)
1144 {
1145   FILE *ofile;
1146   gchar *ns;
1147   gint i, j;
1148   char **dependencies;
1149   GIRepository *repository;
1150   Xml *xml;
1151
1152   repository = g_irepository_get_default ();
1153
1154   if (output == NULL)
1155     ofile = stdout;
1156   else
1157     {
1158       gchar *filename;
1159       
1160       if (needs_prefix)
1161         filename = g_strdup_printf ("%s-%s", namespace, output);  
1162       else
1163         filename = g_strdup (output);
1164       ofile = g_fopen (filename, "w");
1165       
1166       if (ofile == NULL)
1167         {
1168           g_fprintf (stderr, "failed to open '%s': %s\n",
1169                      filename, g_strerror (errno));
1170           g_free (filename);
1171           
1172           return;
1173         }
1174       
1175       g_free (filename);
1176     }
1177
1178   xml = xml_open (ofile);
1179   
1180   xml_printf (xml, "<?xml version=\"1.0\"?>\n");
1181   xml_start_element (xml, "repository");
1182   xml_printf (xml, " version=\"1.0\"\n"
1183               "            xmlns=\"http://www.gtk.org/introspection/core/1.0\"\n"
1184               "            xmlns:c=\"http://www.gtk.org/introspection/c/1.0\"\n"
1185               "            xmlns:glib=\"http://www.gtk.org/introspection/glib/1.0\"");
1186
1187   dependencies = g_irepository_get_dependencies (repository,
1188                                                  namespace);
1189   if (dependencies != NULL)
1190     {
1191       for (i = 0; dependencies[i]; i++)
1192         {
1193           xml_start_element (xml, "include");
1194           xml_printf (xml, " name=\"%s\"", dependencies[i]);
1195           xml_end_element (xml, "include");
1196         }
1197     }
1198
1199   if (TRUE)
1200     {
1201       const gchar *shared_library;
1202       const char *ns = namespace;
1203       const char *version;
1204
1205       version = g_irepository_get_version (repository, ns);
1206
1207       shared_library = g_irepository_get_shared_library (repository, ns);
1208       xml_start_element (xml, "namespace");
1209       xml_printf (xml, " name=\"%s\" version=\"%s\"", ns, version);
1210       if (shared_library)
1211         xml_printf (xml, " shared-library=\"%s\"", shared_library);
1212       
1213       for (j = 0; j < g_irepository_get_n_infos (repository, ns); j++)
1214         {
1215           GIBaseInfo *info = g_irepository_get_info (repository, ns, j);
1216           switch (g_base_info_get_type (info))
1217             {
1218             case GI_INFO_TYPE_FUNCTION:
1219               write_function_info (ns, (GIFunctionInfo *)info, xml, 4);
1220               break;
1221               
1222             case GI_INFO_TYPE_CALLBACK:
1223               write_callback_info (ns, (GICallbackInfo *)info, xml, 4);
1224               break;
1225
1226             case GI_INFO_TYPE_STRUCT:
1227             case GI_INFO_TYPE_BOXED:
1228               write_struct_info (ns, (GIStructInfo *)info, xml);
1229               break;
1230
1231             case GI_INFO_TYPE_UNION:
1232               write_union_info (ns, (GIUnionInfo *)info, xml);
1233               break;
1234
1235             case GI_INFO_TYPE_ENUM:
1236             case GI_INFO_TYPE_FLAGS:
1237               write_enum_info (ns, (GIEnumInfo *)info, xml);
1238               break;
1239               
1240             case GI_INFO_TYPE_CONSTANT:
1241               write_constant_info (ns, (GIConstantInfo *)info, xml, 4);
1242               break;
1243
1244             case GI_INFO_TYPE_OBJECT:
1245               write_object_info (ns, (GIObjectInfo *)info, xml);
1246               break;
1247
1248             case GI_INFO_TYPE_INTERFACE:
1249               write_interface_info (ns, (GIInterfaceInfo *)info, xml);
1250               break;
1251
1252             case GI_INFO_TYPE_ERROR_DOMAIN:
1253               write_error_domain_info (ns, (GIErrorDomainInfo *)info, xml);
1254               break;
1255
1256             default:
1257               g_error ("unknown info type %d\n", g_base_info_get_type (info));
1258             }
1259
1260           g_base_info_unref (info);
1261         }
1262
1263       xml_end_element (xml, "namespace");
1264     }
1265
1266   xml_end_element (xml, "repository");
1267       
1268   xml_free (xml);
1269 }
1270
1271 static const guchar *
1272 load_typelib (const gchar  *filename,
1273                GModule     **dlhandle,
1274                gsize        *len)
1275 {
1276   guchar *typelib;
1277   gsize *typelib_size;
1278   GModule *handle; 
1279
1280   handle = g_module_open (filename, G_MODULE_BIND_LOCAL|G_MODULE_BIND_LAZY);
1281   if (handle == NULL)
1282     {
1283       g_printerr ("Could not load typelib from '%s': %s\n", 
1284                   filename, g_module_error ());
1285       return NULL;
1286     }
1287
1288   if (!g_module_symbol (handle, "_G_TYPELIB", (gpointer *) &typelib))
1289     {
1290       g_printerr ("Could not load typelib from '%s': %s\n", 
1291                   filename, g_module_error ());
1292       return NULL;
1293     }
1294   
1295   if (!g_module_symbol (handle, "_G_TYPELIB_SIZE", (gpointer *) &typelib_size))
1296     {
1297       g_printerr ("Could not load typelib from '%s': %s\n", 
1298                   filename, g_module_error ());
1299       return NULL;
1300     }
1301
1302   *len = *typelib_size;
1303   
1304   if (dlhandle)
1305     *dlhandle = handle;
1306
1307   return typelib;
1308 }
1309
1310 int 
1311 main (int argc, char *argv[])
1312 {  
1313   gboolean shlib = FALSE;
1314   gchar **input = NULL;
1315   GOptionContext *context;
1316   GError *error = NULL;
1317   gboolean needs_prefix;
1318   gint i;
1319   GTypelib *data;
1320   GOptionEntry options[] = 
1321     {
1322       { "shlib", 0, 0, G_OPTION_ARG_NONE, &shlib, "handle typelib embedded in shlib", NULL },
1323       { "output", 'o', 0, G_OPTION_ARG_FILENAME, &output, "output file", "FILE" }, 
1324       { "includedir", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &includedirs, "include directories in GIR search path", NULL }, 
1325       { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &input, NULL, NULL },
1326       { NULL, }
1327     };
1328
1329   g_log_set_always_fatal (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL);
1330
1331   g_type_init ();
1332
1333   g_typelib_check_sanity ();
1334
1335   context = g_option_context_new ("");
1336   g_option_context_add_main_entries (context, options, NULL);
1337   g_option_context_parse (context, &argc, &argv, &error);
1338
1339   if (!input) 
1340     { 
1341       g_fprintf (stderr, "no input files\n"); 
1342       
1343       return 1;
1344     }
1345
1346   if (includedirs != NULL)
1347     for (i = 0; includedirs[i]; i++)
1348       g_irepository_prepend_search_path (includedirs[i]);
1349
1350   for (i = 0; input[i]; i++)
1351     {
1352       GModule *dlhandle = NULL;
1353       const guchar *typelib;
1354       gsize len;
1355       const char *namespace;
1356
1357       if (!shlib)
1358         {
1359           if (!g_file_get_contents (input[i], (gchar **)&typelib, &len, &error))
1360             {
1361               g_fprintf (stderr, "failed to read '%s': %s\n", 
1362                          input[i], error->message);
1363               g_clear_error (&error);
1364               continue;
1365             }
1366         }
1367       else
1368         {
1369           typelib = load_typelib (input[i], &dlhandle, &len);
1370           if (!typelib)
1371             {
1372               g_fprintf (stderr, "failed to load typelib from '%s'\n", 
1373                          input[i]);
1374               continue;
1375             }
1376         }
1377
1378       if (input[i + 1] && output)
1379         needs_prefix = TRUE;
1380       else
1381         needs_prefix = FALSE;
1382
1383       data = g_typelib_new_from_const_memory (typelib, len);
1384       {
1385         GError *error = NULL;
1386         if (!g_typelib_validate (data, &error)) {
1387           g_printerr ("typelib not valid: %s\n", error->message);
1388           g_clear_error (&error);
1389           return 1;
1390         }
1391       }
1392       namespace = g_irepository_load_typelib (g_irepository_get_default (), data, 0,
1393                                               &error);
1394       if (namespace == NULL)
1395         {
1396           g_printerr ("failed to load typelib: %s\n", error->message);
1397           return 1;
1398         }
1399         
1400       write_repository (namespace, needs_prefix);
1401
1402       if (dlhandle)
1403         {
1404           g_module_close (dlhandle);
1405           dlhandle = NULL;
1406         }
1407
1408       /* when writing to stdout, stop after the first module */
1409       if (input[i + 1] && !output)
1410         {
1411           g_fprintf (stderr, "warning, %d modules omitted\n",
1412                      g_strv_length (input) - 1);
1413
1414           break;
1415         }
1416     }
1417       
1418   return 0;
1419 }