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