5a9459fd24f659d4bb40c1e7431053788cc749d6
[gnome.gobject-introspection] / girepository / girwriter.c
1 /* GObject introspection: gen-introspect
2  *
3  * Copyright (C) 2007  Jürg Billeter
4  * Copyright (C) 2007  Johan Dahlin
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.1 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  * Author:
22  *      Jürg Billeter <j@bitron.ch>
23  */
24
25 #include <stdio.h>
26 #include <glib.h>
27 #include "scanner.h"
28 #include "gidlnode.h"
29
30 typedef struct {
31   int indent;
32   FILE *output;
33 } GIdlWriter;
34
35 static void node_generate (GIdlWriter * writer, GIdlNode * node);
36
37 static void
38 g_writer_write_inline (GIdlWriter * writer, const char *s)
39 {
40   fprintf (writer->output, "%s", s);
41 }
42
43 static void
44 g_writer_write (GIdlWriter * writer, const char *s)
45 {
46   int i;
47   for (i = 0; i < writer->indent; i++)
48     {
49       fprintf (writer->output, "\t");
50     }
51
52   g_writer_write_inline (writer, s);
53 }
54
55 static void
56 g_writer_write_indent (GIdlWriter * writer, const char *s)
57 {
58   g_writer_write (writer, s);
59   writer->indent++;
60 }
61
62 static void
63 g_writer_write_unindent (GIdlWriter * writer, const char *s)
64 {
65   writer->indent--;
66   g_writer_write (writer, s);
67 }
68
69 static void
70 field_generate (GIdlWriter * writer, GIdlNodeField * node)
71 {
72   char *markup =
73     g_markup_printf_escaped ("<field name=\"%s\" type=\"%s\"/>\n",
74                              node->node.name, node->type->unparsed);
75   g_writer_write (writer, markup);
76   g_free (markup);
77 }
78
79 static void
80 value_generate (GIdlWriter * writer, GIdlNodeValue * node)
81 {
82   char *markup =
83     g_markup_printf_escaped ("<member name=\"%s\" value=\"%d\"/>\n",
84                              node->node.name, node->value);
85   g_writer_write (writer, markup);
86   g_free (markup);
87 }
88
89 static void
90 constant_generate (GIdlWriter * writer, GIdlNodeConstant * node)
91 {
92   char *markup =
93     g_markup_printf_escaped
94     ("<constant name=\"%s\" type=\"%s\" value=\"%s\"/>\n", node->node.name,
95      node->type->unparsed, node->value);
96   g_writer_write (writer, markup);
97   g_free (markup);
98 }
99
100 static void
101 property_generate (GIdlWriter * writer, GIdlNodeProperty * node)
102 {
103   char *markup =
104     g_markup_printf_escaped ("<property name=\"%s\" "
105                              "type=\"%s\" "
106                              "readable=\"%s\" "
107                              "writable=\"%s\" "
108                              "construct=\"%s\" "
109                              "construct-only=\"%s\"/>\n",
110                              node->node.name,
111                              node->type->unparsed,
112                              node->readable ? "1" : "0",
113                              node->writable ? "1" : "0",
114                              node->construct ? "1" : "0",
115                              node->construct_only ? "1" : "0");
116   g_writer_write (writer, markup);
117   g_free (markup);
118 }
119
120 static void
121 function_generate (GIdlWriter * writer, GIdlNodeFunction * node)
122 {
123   const char *tag_name;
124   GString *markup_s;
125   gchar *markup;
126
127   if (node->node.type == G_IR_NODE_CALLBACK)
128     tag_name = "callback";
129   else if (node->is_constructor)
130     tag_name = "constructor";
131   else if (node->is_method)
132     tag_name = "method";
133   else
134     tag_name = "function";
135
136   markup_s = g_string_new ("<");
137   g_string_append_printf (markup_s,
138                           "%s name=\"%s\"",
139                           tag_name, node->node.name);
140
141   if (node->node.type != G_IR_NODE_CALLBACK)
142     g_string_append_printf (markup_s,
143                             g_markup_printf_escaped (" symbol=\"%s\"", node->symbol));
144
145   if (node->deprecated)
146     g_string_append_printf (markup_s, " deprecated=\"1\"");
147
148   g_string_append (markup_s, ">\n");
149
150   g_writer_write_indent (writer, markup_s->str);
151   g_string_free (markup_s, TRUE);
152
153   markup_s =
154     g_string_new (g_markup_printf_escaped ("<return-type type=\"%s\"",
155                              node->result->type->unparsed));
156
157   if (node->result->transfer)
158     g_string_append (markup_s, g_markup_printf_escaped (" transfer=\"full\"/>\n"));
159   else
160     g_string_append (markup_s, "/>\n");
161
162   g_writer_write (writer, markup_s->str);
163   g_string_free (markup_s, TRUE);
164
165   if (node->parameters != NULL)
166     {
167       GList *l;
168       g_writer_write_indent (writer, "<parameters>\n");
169       for (l = node->parameters; l != NULL; l = l->next)
170         {
171           GIdlNodeParam *param = l->data;
172           const gchar *direction = g_idl_node_param_direction_string (param);
173           
174           markup_s = g_string_new ("<parameter");
175
176           g_string_append_printf (markup_s, " name=\"%s\"", param->node.name);
177
178           g_string_append (markup_s,
179                            g_markup_printf_escaped (" type=\"%s\"",
180                                                     param->type->unparsed));
181
182           if (param->transfer)
183             g_string_append (markup_s,
184                            g_markup_printf_escaped (" transfer=\"full\""));
185
186           if (param->allow_none)
187             g_string_append (markup_s,
188                              g_markup_printf_escaped (" allow-none=\"1\""));
189           
190           if (strcmp (direction, "in") != 0)
191             g_string_append (markup_s,
192                              g_markup_printf_escaped (" direction=\"%s\"",
193                                                       direction));
194
195           g_string_append (markup_s, "/>\n");
196
197           g_writer_write (writer, markup_s->str);
198           g_string_free (markup_s, TRUE);
199         }
200       g_writer_write_unindent (writer, "</parameters>\n");
201     }
202   markup = g_strdup_printf ("</%s>\n", tag_name);
203   g_writer_write_unindent (writer, markup);
204   g_free (markup);
205 }
206
207 static void
208 vfunc_generate (GIdlWriter * writer, GIdlNodeVFunc * node)
209 {
210   char *markup =
211     g_markup_printf_escaped ("<vfunc name=\"%s\">\n", node->node.name);
212   g_writer_write_indent (writer, markup);
213   g_free (markup);
214   markup =
215     g_markup_printf_escaped ("<return-type type=\"%s\"/>\n",
216                              node->result->type->unparsed);
217   g_writer_write (writer, markup);
218   g_free (markup);
219   if (node->parameters != NULL)
220     {
221       GList *l;
222       g_writer_write_indent (writer, "<parameters>\n");
223       for (l = node->parameters; l != NULL; l = l->next)
224         {
225           GIdlNodeParam *param = l->data;
226           markup =
227             g_markup_printf_escaped ("<parameter name=\"%s\" type=\"%s\"/>\n",
228                                      param->node.name, param->type->unparsed);
229           g_writer_write (writer, markup);
230           g_free (markup);
231         }
232       g_writer_write_unindent (writer, "</parameters>\n");
233     }
234   g_writer_write_unindent (writer, "</vfunc>\n");
235 }
236
237 static void
238 signal_generate (GIdlWriter * writer, GIdlNodeSignal * node)
239 {
240   char *markup;
241   const char *when = "LAST";
242   if (node->run_first)
243     {
244       when = "FIRST";
245     }
246   else if (node->run_cleanup)
247     {
248       when = "CLEANUP";
249     }
250   markup =
251     g_markup_printf_escaped ("<signal name=\"%s\" when=\"%s\">\n",
252                              node->node.name, when);
253   g_writer_write_indent (writer, markup);
254   g_free (markup);
255   markup =
256     g_markup_printf_escaped ("<return-type type=\"%s\"/>\n",
257                              node->result->type->unparsed);
258   g_writer_write (writer, markup);
259   g_free (markup);
260   if (node->parameters != NULL)
261     {
262       GList *l;
263       g_writer_write_indent (writer, "<parameters>\n");
264       for (l = node->parameters; l != NULL; l = l->next)
265         {
266           GIdlNodeParam *param = l->data;
267           markup =
268             g_markup_printf_escaped ("<parameter name=\"%s\" type=\"%s\"/>\n",
269                                      param->node.name, param->type->unparsed);
270           g_writer_write (writer, markup);
271           g_free (markup);
272         }
273       g_writer_write_unindent (writer, "</parameters>\n");
274     }
275   g_writer_write_unindent (writer, "</signal>\n");
276 }
277
278 static void
279 interface_generate (GIdlWriter * writer, GIdlNodeInterface * node)
280 {
281   GList *l;
282   char *markup;
283   if (node->node.type == G_IR_NODE_OBJECT)
284     {
285       markup =
286         g_markup_printf_escaped ("<object name=\"%s\" "
287                                  "parent=\"%s\" "
288                                  "type-name=\"%s\" "
289                                  "get-type=\"%s\">\n",
290                                  node->node.name,
291                                  node->parent,
292                                  node->gtype_name,
293                                  node->gtype_init);
294     }
295   else if (node->node.type == G_IR_NODE_INTERFACE)
296     {
297       markup =
298         g_markup_printf_escaped
299         ("<interface name=\"%s\" type-name=\"%s\" get-type=\"%s\">\n",
300          node->node.name, node->gtype_name, node->gtype_init);
301     }
302
303   g_writer_write_indent (writer, markup);
304   g_free (markup);
305   if (node->node.type == G_IR_NODE_OBJECT && node->interfaces != NULL)
306     {
307       GList *l;
308       g_writer_write_indent (writer, "<implements>\n");
309       for (l = node->interfaces; l != NULL; l = l->next)
310         {
311           markup =
312             g_markup_printf_escaped ("<interface name=\"%s\"/>\n",
313                                      (char *) l->data);
314           g_writer_write (writer, markup);
315           g_free (markup);
316         }
317       g_writer_write_unindent (writer, "</implements>\n");
318     }
319   else if (node->node.type == G_IR_NODE_INTERFACE
320            && node->prerequisites != NULL)
321     {
322       GList *l;
323       g_writer_write_indent (writer, "<requires>\n");
324       for (l = node->prerequisites; l != NULL; l = l->next)
325         {
326           markup =
327             g_markup_printf_escaped ("<interface name=\"%s\"/>\n",
328                                      (char *) l->data);
329           g_writer_write (writer, markup);
330           g_free (markup);
331         }
332       g_writer_write_unindent (writer, "</requires>\n");
333     }
334
335   for (l = node->members; l != NULL; l = l->next)
336     {
337       node_generate (writer, l->data);
338     }
339
340   if (node->node.type == G_IR_NODE_OBJECT)
341     {
342       g_writer_write_unindent (writer, "</object>\n");
343     }
344   else if (node->node.type == G_IR_NODE_INTERFACE)
345     {
346       g_writer_write_unindent (writer, "</interface>\n");
347     }
348 }
349
350 static void
351 struct_generate (GIdlWriter * writer, GIdlNodeStruct * node)
352 {
353   GList *l;
354   char *markup =
355     g_markup_printf_escaped ("<struct name=\"%s\">\n", node->node.name);
356   g_writer_write_indent (writer, markup);
357   g_free (markup);
358   for (l = node->members; l != NULL; l = l->next)
359     {
360       node_generate (writer, l->data);
361     }
362   g_writer_write_unindent (writer, "</struct>\n");
363 }
364
365 static void
366 union_generate (GIdlWriter * writer, GIdlNodeUnion * node)
367 {
368   GList *l;
369   char *markup =
370     g_markup_printf_escaped ("<union name=\"%s\">\n", node->node.name);
371   g_writer_write_indent (writer, markup);
372   g_free (markup);
373   for (l = node->members; l != NULL; l = l->next)
374     {
375       node_generate (writer, l->data);
376     }
377   g_writer_write_unindent (writer, "</union>\n");
378 }
379
380 static void
381 boxed_generate (GIdlWriter * writer, GIdlNodeBoxed * node)
382 {
383   GList *l;
384   char *markup =
385     g_markup_printf_escaped
386     ("<boxed name=\"%s\" type-name=\"%s\" get-type=\"%s\">\n",
387      node->node.name, node->gtype_name, node->gtype_init);
388   g_writer_write_indent (writer, markup);
389   g_free (markup);
390   for (l = node->members; l != NULL; l = l->next)
391     {
392       node_generate (writer, l->data);
393     }
394   g_writer_write_unindent (writer, "</boxed>\n");
395 }
396
397 static void
398 enum_generate (GIdlWriter * writer, GIdlNodeEnum * node)
399 {
400   GList *l;
401   GString *markup_s;
402   char *markup;
403   const char *tag_name = NULL;
404
405   if (node->node.type == G_IR_NODE_ENUM)
406     {
407       tag_name = "enum";
408     }
409   else if (node->node.type == G_IR_NODE_FLAGS)
410     {
411       tag_name = "flags";
412     }
413
414   markup_s = g_string_new ("<");
415   g_string_append_printf (markup_s,
416                           "%s name=\"%s\"",
417                           tag_name, node->node.name);
418
419   if (node->gtype_name != NULL)
420     g_string_append_printf (markup_s,
421                             g_markup_printf_escaped (" type-name=\"%s\"", node->gtype_name));
422
423   if (node->gtype_init != NULL)
424     g_string_append_printf (markup_s,
425                             g_markup_printf_escaped (" get-type=\"%s\"", node->gtype_init));
426
427   if (node->deprecated)
428     g_string_append_printf (markup_s, " deprecated=\"1\"");
429
430   g_string_append (markup_s, ">\n");
431
432   g_writer_write_indent (writer, markup_s->str);
433   g_string_free (markup_s, TRUE);
434
435   for (l = node->values; l != NULL; l = l->next)
436     {
437       node_generate (writer, l->data);
438     }
439
440   markup = g_strdup_printf ("</%s>\n", tag_name);
441   g_writer_write_unindent (writer, markup);
442   g_free (markup);
443 }
444
445 static void
446 node_generate (GIdlWriter * writer, GIdlNode * node)
447 {
448   switch (node->type)
449     {
450     case G_IR_NODE_FUNCTION:
451     case G_IR_NODE_CALLBACK:
452       function_generate (writer, (GIdlNodeFunction *) node);
453       break;
454     case G_IR_NODE_VFUNC:
455       vfunc_generate (writer, (GIdlNodeVFunc *) node);
456       break;
457     case G_IR_NODE_OBJECT:
458     case G_IR_NODE_INTERFACE:
459       interface_generate (writer, (GIdlNodeInterface *) node);
460       break;
461     case G_IR_NODE_STRUCT:
462       struct_generate (writer, (GIdlNodeStruct *) node);
463       break;
464     case G_IR_NODE_UNION:
465       union_generate (writer, (GIdlNodeUnion *) node);
466       break;
467     case G_IR_NODE_BOXED:
468       boxed_generate (writer, (GIdlNodeBoxed *) node);
469       break;
470     case G_IR_NODE_ENUM:
471     case G_IR_NODE_FLAGS:
472       enum_generate (writer, (GIdlNodeEnum *) node);
473       break;
474     case G_IR_NODE_PROPERTY:
475       property_generate (writer, (GIdlNodeProperty *) node);
476       break;
477     case G_IR_NODE_FIELD:
478       field_generate (writer, (GIdlNodeField *) node);
479       break;
480     case G_IR_NODE_SIGNAL:
481       signal_generate (writer, (GIdlNodeSignal *) node);
482       break;
483     case G_IR_NODE_VALUE:
484       value_generate (writer, (GIdlNodeValue *) node);
485       break;
486     case G_IR_NODE_CONSTANT:
487       constant_generate (writer, (GIdlNodeConstant *) node);
488       break;
489     default:
490       g_assert_not_reached ();
491     }
492 }
493
494 static void
495 g_writer_write_module (GIdlWriter * writer, GIdlModule * module)
496 {
497   GList *l;
498   char *markup =
499     g_markup_printf_escaped ("<namespace name=\"%s\">\n", module->name);
500   g_writer_write_indent (writer, markup);
501   g_free (markup);
502   for (l = module->entries; l != NULL; l = l->next)
503     {
504       node_generate (writer, l->data);
505     }
506   g_writer_write_unindent (writer, "</namespace>\n");
507 }
508
509 void
510 g_idl_writer_save_file (GIdlModule *module,
511                         const gchar *filename)
512 {
513   GIdlWriter *writer;
514
515   writer = g_new0 (GIdlWriter, 1);
516
517   if (!filename)
518     writer->output = stdout;
519   else
520     writer->output = fopen (filename, "w");
521
522   g_writer_write (writer, "<?xml version=\"1.0\"?>\n");
523   g_writer_write_indent (writer, "<repository version=\"1.0\""
524                          "xmlns=\"http://www.gtk.org/introspection/core/1.0\""
525                          "xmlns:c=\"http://www.gtk.org/introspection/c/1.0\""
526                          "xmlns:glib=\"http://www.gtk.org/introspection/glib/1.0\">");
527   g_writer_write_module (writer, module);
528   g_writer_write_unindent (writer, "</repository>\n");
529
530   if (filename)
531     fclose (writer->output);
532 }