Fix generated introspection information when using DBus.BusName sender
[vala-lang.git] / gobject-introspection / scanner.c
blob95e4e81bda52466def3e193ff5bd80559790aa9f
1 /* GObject introspection: scanner
3 * Copyright (C) 2007-2008 Jürg Billeter
4 * Copyright (C) 2007 Johan Dahlin
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.
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.
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.
21 * Author:
22 * Jürg Billeter <j@bitron.ch>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #include <glib.h>
30 #include <glib/gstdio.h>
31 #include <glib-object.h>
32 #include <signal.h>
33 #include <sys/wait.h> /* waitpid */
34 #include <gmodule.h>
35 #include "scanner.h"
36 #include "gidlparser.h"
37 #include "gidlmodule.h"
38 #include "gidlnode.h"
39 #include "gidlwriter.h"
40 #include "grealpath.h"
43 typedef GType (*TypeFunction) (void);
45 static void g_igenerator_parse_macros (GIGenerator * igenerator);
47 static GIGenerator *
48 g_igenerator_new (const gchar *namespace,
49 const gchar *shared_library)
51 GIGenerator *igenerator = g_new0 (GIGenerator, 1);
52 igenerator->namespace = g_strdup (namespace);
53 igenerator->shared_library = g_strdup (shared_library);
54 igenerator->lower_case_namespace =
55 g_ascii_strdown (igenerator->namespace, -1);
56 igenerator->module = g_idl_module_new (namespace, shared_library);
58 igenerator->typedef_table = g_hash_table_new (g_str_hash, g_str_equal);
59 igenerator->struct_or_union_or_enum_table =
60 g_hash_table_new (g_str_hash, g_str_equal);
62 igenerator->type_map = g_hash_table_new (g_str_hash, g_str_equal);
63 igenerator->type_by_lower_case_prefix =
64 g_hash_table_new (g_str_hash, g_str_equal);
65 igenerator->symbols = g_hash_table_new (g_str_hash, g_str_equal);
67 return igenerator;
70 static void
71 g_igenerator_free (GIGenerator *generator)
73 g_free (generator->namespace);
74 g_free (generator->shared_library);
75 g_free (generator->lower_case_namespace);
76 #if 0
77 g_idl_module_free (generator->module);
78 #endif
79 g_hash_table_destroy (generator->typedef_table);
80 g_hash_table_destroy (generator->struct_or_union_or_enum_table);
81 g_hash_table_destroy (generator->type_map);
82 g_hash_table_destroy (generator->type_by_lower_case_prefix);
83 g_hash_table_destroy (generator->symbols);
84 g_list_foreach (generator->filenames, (GFunc)g_free, NULL);
85 g_list_free (generator->filenames);
86 #if 0
87 g_list_foreach (generator->symbol_list, (GFunc)csymbol_free, NULL);
88 g_list_free (generator->symbol_list);
89 #endif
90 g_free (generator);
93 static GIdlNodeType *
94 create_node_from_gtype (GType type_id)
96 GIdlNodeType *node;
97 GType fundamental;
99 node = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
101 fundamental = g_type_fundamental (type_id);
102 switch (fundamental)
104 case G_TYPE_STRING:
105 node->unparsed = g_strdup ("char*");
106 break;
107 case G_TYPE_INTERFACE:
108 case G_TYPE_BOXED:
109 case G_TYPE_OBJECT:
110 node->unparsed = g_strdup_printf ("%s*", g_type_name (type_id));
111 break;
112 case G_TYPE_PARAM:
113 node->unparsed = g_strdup ("GParamSpec*");
114 break;
115 default:
116 if (fundamental == G_TYPE_STRV)
117 node->unparsed = g_strdup ("char*[]");
118 else
119 node->unparsed = g_strdup (g_type_name (type_id));
120 break;
123 return node;
126 static GIdlNodeType *
127 create_node_from_ctype (CType * ctype)
129 GIdlNodeType *node;
131 node = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
133 switch (ctype->type)
135 case CTYPE_VOID:
136 node->unparsed = g_strdup ("void");
137 break;
138 case CTYPE_BASIC_TYPE:
139 node->unparsed = g_strdup (ctype->name);
140 break;
141 case CTYPE_TYPEDEF:
142 node->unparsed = g_strdup (ctype->name);
143 break;
144 case CTYPE_STRUCT:
145 if (ctype->name == NULL)
146 /* anonymous struct */
147 node->unparsed = g_strdup ("gpointer");
148 else
149 node->unparsed = g_strdup_printf ("struct %s", ctype->name);
150 break;
151 case CTYPE_UNION:
152 if (ctype->name == NULL)
153 /* anonymous union */
154 node->unparsed = g_strdup ("gpointer");
155 else
156 node->unparsed = g_strdup_printf ("union %s", ctype->name);
157 break;
158 case CTYPE_ENUM:
159 if (ctype->name == NULL)
160 /* anonymous enum */
161 node->unparsed = g_strdup ("gint");
162 else
163 node->unparsed = g_strdup_printf ("enum %s", ctype->name);
164 break;
165 case CTYPE_POINTER:
166 if (ctype->base_type->type == CTYPE_FUNCTION)
167 /* anonymous function pointer */
168 node->unparsed = g_strdup ("GCallback");
169 else
171 GIdlNodeType *gibasetype = create_node_from_ctype (ctype->base_type);
172 node->unparsed = g_strdup_printf ("%s*", gibasetype->unparsed);
174 break;
175 case CTYPE_ARRAY:
177 GIdlNodeType *gibasetype = create_node_from_ctype (ctype->base_type);
178 node->unparsed = g_strdup_printf ("%s[]", gibasetype->unparsed);
179 break;
181 default:
182 node->unparsed = g_strdup ("unknown");
183 break;
186 return node;
189 static char *
190 str_replace (const char *str, const char *needle, const char *replacement)
192 char **strings = g_strsplit (str, needle, 0);
193 char *result = g_strjoinv (replacement, strings);
194 g_strfreev (strings);
195 return result;
198 static void
199 g_igenerator_process_properties (GIGenerator * igenerator,
200 GIdlNodeInterface * node, GType type_id)
202 int i;
203 guint n_properties;
204 GParamSpec **properties;
206 if (node->node.type == G_IDL_NODE_OBJECT)
208 GObjectClass *type_class = g_type_class_ref (type_id);
209 properties = g_object_class_list_properties (type_class, &n_properties);
211 else if (node->node.type == G_IDL_NODE_INTERFACE)
213 GTypeInterface *iface = g_type_default_interface_ref (type_id);
214 properties = g_object_interface_list_properties (iface, &n_properties);
216 else
218 g_assert_not_reached ();
221 for (i = 0; i < n_properties; i++)
223 GIdlNodeProperty *giprop;
225 /* ignore inherited properties */
226 if (properties[i]->owner_type != type_id)
228 continue;
230 giprop = (GIdlNodeProperty *) g_idl_node_new (G_IDL_NODE_PROPERTY);
231 giprop->node.name = properties[i]->name;
232 node->members =
233 g_list_insert_sorted (node->members, giprop,
234 (GCompareFunc) g_idl_node_cmp);
235 giprop->type = create_node_from_gtype (properties[i]->value_type);
236 giprop->readable = (properties[i]->flags & G_PARAM_READABLE) != 0;
237 giprop->writable = (properties[i]->flags & G_PARAM_WRITABLE) != 0;
238 giprop->construct = (properties[i]->flags & G_PARAM_CONSTRUCT) != 0;
239 giprop->construct_only =
240 (properties[i]->flags & G_PARAM_CONSTRUCT_ONLY) != 0;
244 static void
245 g_igenerator_process_signals (GIGenerator * igenerator,
246 GIdlNodeInterface * node, GType type_id)
248 int i, j;
249 guint n_signal_ids;
250 guint *signal_ids = g_signal_list_ids (type_id, &n_signal_ids);
252 for (i = 0; i < n_signal_ids; i++)
254 GSignalQuery signal_query;
255 GIdlNodeSignal *gisig;
256 GIdlNodeParam *giparam;
258 g_signal_query (signal_ids[i], &signal_query);
259 gisig = (GIdlNodeSignal *) g_idl_node_new (G_IDL_NODE_SIGNAL);
260 gisig->node.name = g_strdup (signal_query.signal_name);
261 node->members =
262 g_list_insert_sorted (node->members, gisig,
263 (GCompareFunc) g_idl_node_cmp);
265 gisig->run_first =
266 (signal_query.signal_flags & G_SIGNAL_RUN_FIRST) != 0;
267 gisig->run_last = (signal_query.signal_flags & G_SIGNAL_RUN_LAST) != 0;
268 gisig->run_cleanup =
269 (signal_query.signal_flags & G_SIGNAL_RUN_CLEANUP) != 0;
271 /* add sender parameter */
272 giparam = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
273 gisig->parameters = g_list_append (gisig->parameters, giparam);
274 giparam->node.name = g_strdup ("object");
275 giparam->type = create_node_from_gtype (type_id);
277 for (j = 0; j < signal_query.n_params; j++)
279 giparam = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
280 gisig->parameters = g_list_append (gisig->parameters, giparam);
281 giparam->node.name = g_strdup_printf ("p%d", j);
282 giparam->type = create_node_from_gtype (signal_query.param_types[j]);
284 gisig->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
285 gisig->result->type = create_node_from_gtype (signal_query.return_type);
289 static const gchar *
290 lookup_symbol (GIGenerator *igenerator, const gchar *typename)
292 const gchar *name =
293 g_hash_table_lookup (igenerator->symbols, typename);
295 if (!name)
297 g_printerr ("Unknown symbol: %s\n", typename);
298 return typename;
301 return name;
304 static void
305 g_igenerator_create_object (GIGenerator *igenerator,
306 const char *symbol_name,
307 GType type_id,
308 char *lower_case_prefix)
311 char *alt_lower_case_prefix;
312 GIdlNodeInterface *node;
313 guint n_type_interfaces;
314 GType *type_interfaces;
315 int i;
317 node = (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_OBJECT);
318 node->node.name = g_strdup (g_type_name (type_id));
319 igenerator->module->entries =
320 g_list_insert_sorted (igenerator->module->entries, node,
321 (GCompareFunc) g_idl_node_cmp);
322 g_hash_table_insert (igenerator->type_map, node->node.name,
323 node);
324 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
325 lower_case_prefix, node);
326 alt_lower_case_prefix = g_ascii_strdown (node->node.name, -1);
328 if (strcmp (alt_lower_case_prefix, lower_case_prefix) != 0)
330 /* alternative prefix sometimes necessary, for example
331 * for GdkWindow
333 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
334 alt_lower_case_prefix, node);
336 else
338 g_free (alt_lower_case_prefix);
341 node->gtype_name = node->node.name;
342 node->gtype_init = g_strdup (symbol_name);
343 node->parent = g_strdup (lookup_symbol (igenerator,
344 g_type_name (g_type_parent (type_id))));
346 type_interfaces = g_type_interfaces (type_id, &n_type_interfaces);
347 for (i = 0; i < n_type_interfaces; i++)
349 char *iface_name =
350 g_strdup (g_type_name (type_interfaces[i]));
351 /* workaround for AtkImplementorIface */
352 if (g_str_has_suffix (iface_name, "Iface"))
354 iface_name[strlen (iface_name) - strlen ("Iface")] =
355 '\0';
357 node->interfaces =
358 g_list_append (node->interfaces, iface_name);
361 g_hash_table_insert (igenerator->symbols,
362 g_strdup (node->gtype_name),
363 /* FIXME: Strip igenerator->namespace */
364 g_strdup (node->node.name));
366 g_igenerator_process_properties (igenerator, node, type_id);
367 g_igenerator_process_signals (igenerator, node, type_id);
370 static void
371 g_igenerator_create_interface (GIGenerator *igenerator,
372 const char *symbol_name,
373 GType type_id,
374 char *lower_case_prefix)
377 GIdlNodeInterface *node;
378 gboolean is_gobject = FALSE;
379 guint n_iface_prereqs;
380 GType *iface_prereqs;
381 int i;
383 node = (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_INTERFACE);
384 node->node.name = g_strdup (g_type_name (type_id));
386 /* workaround for AtkImplementorIface */
387 if (g_str_has_suffix (node->node.name, "Iface"))
389 node->node.name[strlen (node->node.name) -
390 strlen ("Iface")] = '\0';
392 igenerator->module->entries =
393 g_list_insert_sorted (igenerator->module->entries, node,
394 (GCompareFunc) g_idl_node_cmp);
395 g_hash_table_insert (igenerator->type_map, node->node.name,
396 node);
397 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
398 lower_case_prefix, node);
399 node->gtype_name = node->node.name;
400 node->gtype_init = g_strdup (symbol_name);
402 iface_prereqs =
403 g_type_interface_prerequisites (type_id, &n_iface_prereqs);
405 for (i = 0; i < n_iface_prereqs; i++)
407 if (g_type_fundamental (iface_prereqs[i]) == G_TYPE_OBJECT)
409 is_gobject = TRUE;
411 node->prerequisites =
412 g_list_append (node->prerequisites,
413 g_strdup (g_type_name (iface_prereqs[i])));
416 if (is_gobject)
417 g_igenerator_process_properties (igenerator, node, type_id);
418 else
419 g_type_default_interface_ref (type_id);
421 g_igenerator_process_signals (igenerator, node, type_id);
424 static void
425 g_igenerator_create_boxed (GIGenerator *igenerator,
426 const char *symbol_name,
427 GType type_id,
428 char *lower_case_prefix)
430 GIdlNodeBoxed *node =
431 (GIdlNodeBoxed *) g_idl_node_new (G_IDL_NODE_BOXED);
432 node->node.name = g_strdup (g_type_name (type_id));
433 igenerator->module->entries =
434 g_list_insert_sorted (igenerator->module->entries, node,
435 (GCompareFunc) g_idl_node_cmp);
436 g_hash_table_insert (igenerator->type_map, node->node.name,
437 node);
438 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
439 lower_case_prefix, node);
440 node->gtype_name = node->node.name;
441 node->gtype_init = g_strdup (symbol_name);
444 static void
445 g_igenerator_create_enum (GIGenerator *igenerator,
446 const char *symbol_name,
447 GType type_id,
448 char *lower_case_prefix)
450 GIdlNodeEnum *node;
451 int i;
452 GEnumClass *type_class;
454 node = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_ENUM);
455 node->node.name = g_strdup (g_type_name (type_id));
456 igenerator->module->entries =
457 g_list_insert_sorted (igenerator->module->entries, node,
458 (GCompareFunc) g_idl_node_cmp);
459 g_hash_table_insert (igenerator->type_map, node->node.name,
460 node);
461 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
462 lower_case_prefix, node);
463 node->gtype_name = node->node.name;
464 node->gtype_init = g_strdup (symbol_name);
466 type_class = g_type_class_ref (type_id);
468 for (i = 0; i < type_class->n_values; i++)
470 GIdlNodeValue *gival =
471 (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
472 node->values = g_list_append (node->values, gival);
473 gival->node.name =
474 g_strdup (type_class->values[i].value_name);
475 gival->value = type_class->values[i].value;
479 static void
480 g_igenerator_create_flags (GIGenerator *igenerator,
481 const char *symbol_name,
482 GType type_id,
483 char *lower_case_prefix)
485 GIdlNodeEnum *node;
486 GFlagsClass *type_class;
487 int i;
489 node = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_FLAGS);
490 node->node.name = g_strdup (g_type_name (type_id));
491 igenerator->module->entries =
492 g_list_insert_sorted (igenerator->module->entries, node,
493 (GCompareFunc) g_idl_node_cmp);
494 g_hash_table_insert (igenerator->type_map, node->node.name,
495 node);
496 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
497 lower_case_prefix, node);
498 node->gtype_name = node->node.name;
499 node->gtype_init = g_strdup (symbol_name);
501 type_class = g_type_class_ref (type_id);
503 for (i = 0; i < type_class->n_values; i++)
505 GIdlNodeValue *gival =
506 (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
507 node->values = g_list_append (node->values, gival);
508 gival->node.name =
509 g_strdup (type_class->values[i].value_name);
510 gival->value = type_class->values[i].value;
514 static gboolean
515 g_igenerator_process_module_symbol (GIGenerator *igenerator,
516 GModule *module,
517 const gchar *symbol_name)
519 TypeFunction type_fun;
520 GType type_id;
521 GType type_fundamental;
522 char *lower_case_prefix;
524 /* ignore already processed functions */
525 if (symbol_name == NULL)
526 return FALSE;
528 if (!g_module_symbol (module,
529 symbol_name,
530 (gpointer *) & type_fun))
531 return FALSE;
533 type_id = type_fun ();
534 type_fundamental = g_type_fundamental (type_id);
535 lower_case_prefix =
536 str_replace (g_strndup
537 (symbol_name,
538 strlen (symbol_name) - strlen ("_get_type")),
539 "_", "");
541 switch (type_fundamental)
543 case G_TYPE_OBJECT:
544 g_igenerator_create_object (igenerator, symbol_name, type_id,
545 lower_case_prefix);
546 break;
547 case G_TYPE_INTERFACE:
548 g_igenerator_create_interface (igenerator, symbol_name, type_id,
549 lower_case_prefix);
550 break;
551 case G_TYPE_BOXED:
552 g_igenerator_create_boxed (igenerator, symbol_name, type_id,
553 lower_case_prefix);
554 break;
555 case G_TYPE_ENUM:
556 g_igenerator_create_enum (igenerator, symbol_name, type_id,
557 lower_case_prefix);
558 break;
559 case G_TYPE_FLAGS:
560 g_igenerator_create_flags (igenerator, symbol_name, type_id,
561 lower_case_prefix);
562 break;
563 default:
564 break;
566 return TRUE;
569 static void
570 g_igenerator_process_module (GIGenerator * igenerator,
571 const gchar *filename)
573 GModule *module;
574 GList *l;
576 module = g_module_open (filename,
577 G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
579 if (module == NULL)
581 g_critical ("Couldn't open module: %s", filename);
582 return;
585 for (l = igenerator->get_type_symbols; l != NULL; l = l->next)
587 if (g_igenerator_process_module_symbol (igenerator,
588 module, (const char *)l->data))
589 /* symbol found, ignore in future iterations */
590 l->data = NULL;
594 static void
595 g_igenerator_process_function_symbol (GIGenerator * igenerator, CSymbol * sym)
597 GIdlNodeFunction *func;
598 char *last_underscore;
599 GList *param_l;
600 int i;
601 GSList *l;
603 func = (GIdlNodeFunction *) g_idl_node_new (G_IDL_NODE_FUNCTION);
605 /* check whether this is a type method */
606 last_underscore = strrchr (sym->ident, '_');
608 while (last_underscore != NULL)
610 char *prefix;
611 GIdlNode *node;
613 prefix = g_strndup (sym->ident, last_underscore - sym->ident);
614 prefix = str_replace (prefix, "_", "");
616 node = g_hash_table_lookup (igenerator->type_by_lower_case_prefix,
617 prefix);
618 if (node != NULL )
620 func->node.name = g_strdup (last_underscore + 1);
622 /* ignore get_type functions in registered types */
623 if (strcmp (func->node.name, "get_type") == 0)
624 return;
626 if ((node->type == G_IDL_NODE_OBJECT ||
627 node->type == G_IDL_NODE_BOXED) &&
628 g_str_has_prefix (func->node.name, "new"))
629 func->is_constructor = TRUE;
630 else
631 func->is_method = TRUE;
632 if (g_idl_node_can_have_member (node))
634 g_idl_node_add_member (node, func);
635 break;
637 else
639 /* reset function attributes */
640 g_free (func->node.name);
641 func->node.name = NULL;
642 func->is_constructor = FALSE;
643 func->is_method = FALSE;
646 else if (strcmp (igenerator->lower_case_namespace, prefix) == 0)
648 func->node.name = g_strdup (last_underscore + 1);
649 igenerator->module->entries =
650 g_list_insert_sorted (igenerator->module->entries, func,
651 (GCompareFunc) g_idl_node_cmp);
652 break;
654 last_underscore =
655 g_utf8_strrchr (sym->ident, last_underscore - sym->ident, '_');
658 /* create a namespace function if no prefix matches */
659 if (func->node.name == NULL)
661 func->node.name = sym->ident;
662 func->is_constructor = FALSE;
663 func->is_method = FALSE;
664 igenerator->module->entries =
665 g_list_insert_sorted (igenerator->module->entries, func,
666 (GCompareFunc) g_idl_node_cmp);
669 func->symbol = sym->ident;
670 func->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
671 func->result->type = create_node_from_ctype (sym->base_type->base_type);
673 for (param_l = sym->base_type->child_list, i = 1; param_l != NULL;
674 param_l = param_l->next, i++)
676 CSymbol *param_sym = param_l->data;
677 GIdlNodeParam *param;
679 param = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
680 param->type = create_node_from_ctype (param_sym->base_type);
682 if (param_sym->ident == NULL)
683 param->node.name = g_strdup_printf ("p%d", i);
684 else
685 param->node.name = param_sym->ident;
687 func->parameters = g_list_append (func->parameters, param);
690 for (l = sym->directives; l; l = l->next)
692 CDirective *directive = (CDirective*)l->data;
694 if (!strcmp (directive->name, "deprecated"))
695 func->deprecated = TRUE;
696 else
697 g_printerr ("Unknown function directive: %s\n",
698 directive->name);
702 static void
703 g_igenerator_process_unregistered_struct_typedef (GIGenerator * igenerator,
704 CSymbol * sym,
705 CType * struct_type)
707 GIdlNodeStruct *node =
708 (GIdlNodeStruct *) g_idl_node_new (G_IDL_NODE_STRUCT);
709 GList *member_l;
710 char *lower_case_prefix;
712 node->node.name = sym->ident;
713 igenerator->module->entries =
714 g_list_insert_sorted (igenerator->module->entries, node,
715 (GCompareFunc) g_idl_node_cmp);
716 lower_case_prefix = g_ascii_strdown (sym->ident, -1);
717 g_hash_table_insert (igenerator->type_map, sym->ident, node);
718 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
719 lower_case_prefix, node);
721 for (member_l = struct_type->child_list; member_l != NULL;
722 member_l = member_l->next)
724 CSymbol *member = member_l->data;
725 GIdlNodeField *gifield =
726 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
728 node->members = g_list_append (node->members, gifield);
729 gifield->node.name = member->ident;
730 gifield->type = create_node_from_ctype (member->base_type);
734 static void
735 g_igenerator_process_struct_typedef (GIGenerator * igenerator, CSymbol * sym)
737 CType *struct_type = sym->base_type;
738 gboolean opaque_type = FALSE;
739 GIdlNode *type;
741 if (struct_type->child_list == NULL)
743 CSymbol *struct_symbol;
744 g_assert (struct_type->name != NULL);
745 struct_symbol =
746 g_hash_table_lookup (igenerator->struct_or_union_or_enum_table,
747 struct_type->name);
748 if (struct_symbol != NULL)
750 struct_type = struct_symbol->base_type;
754 if (struct_type->child_list == NULL)
756 opaque_type = TRUE;
759 type = g_hash_table_lookup (igenerator->type_map, sym->ident);
760 if (type != NULL)
762 /* struct of a GTypeInstance */
763 if (!opaque_type
764 && (type->type == G_IDL_NODE_OBJECT
765 || type->type == G_IDL_NODE_INTERFACE))
767 GIdlNodeInterface *node = (GIdlNodeInterface *) type;
768 GList *member_l;
769 /* ignore first field => parent */
770 for (member_l = struct_type->child_list->next; member_l != NULL;
771 member_l = member_l->next)
773 CSymbol *member = member_l->data;
774 /* ignore private / reserved members */
775 if (member->ident[0] == '_'
776 || g_str_has_prefix (member->ident, "priv"))
778 continue;
780 GIdlNodeField *gifield =
781 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
782 node->members = g_list_append (node->members, gifield);
783 gifield->node.name = member->ident;
784 gifield->type = create_node_from_ctype (member->base_type);
787 else if (type->type == G_IDL_NODE_BOXED)
789 GIdlNodeBoxed *node = (GIdlNodeBoxed *) type;
790 GList *member_l;
791 for (member_l = struct_type->child_list; member_l != NULL;
792 member_l = member_l->next)
794 CSymbol *member = member_l->data;
795 GIdlNodeField *gifield =
796 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
797 node->members = g_list_append (node->members, gifield);
798 gifield->node.name = member->ident;
799 gifield->type = create_node_from_ctype (member->base_type);
803 else if (!opaque_type
804 && (g_str_has_suffix (sym->ident, "Class")
805 || g_str_has_suffix (sym->ident, "Iface")
806 || g_str_has_suffix (sym->ident, "Interface")))
808 char *base_name;
809 GList *member_l;
810 GIdlNodeInterface *node;
812 if (g_str_has_suffix (sym->ident, "Interface"))
814 base_name =
815 g_strndup (sym->ident,
816 strlen (sym->ident) - strlen ("Interface"));
818 else
820 base_name =
821 g_strndup (sym->ident, strlen (sym->ident) - strlen ("Class"));
823 type = g_hash_table_lookup (igenerator->type_map, base_name);
824 if (type == NULL
825 || (type->type != G_IDL_NODE_OBJECT
826 && type->type != G_IDL_NODE_INTERFACE))
828 g_igenerator_process_unregistered_struct_typedef (igenerator, sym,
829 struct_type);
830 return;
832 node = (GIdlNodeInterface *) type;
834 /* ignore first field => parent */
835 for (member_l = struct_type->child_list->next; member_l != NULL;
836 member_l = member_l->next)
838 CSymbol *member = member_l->data;
839 /* ignore private / reserved members */
840 if (member->ident[0] == '_')
842 continue;
844 if (member->base_type->type == CTYPE_POINTER
845 && member->base_type->base_type->type == CTYPE_FUNCTION)
847 /* ignore default handlers of signals */
848 gboolean found_signal = FALSE;
849 GList *type_member_l;
850 GList *param_l;
851 int i;
852 GIdlNodeVFunc *givfunc;
854 for (type_member_l = node->members; type_member_l != NULL;
855 type_member_l = type_member_l->next)
857 GIdlNode *type_member = type_member_l->data;
858 char *normalized_name =
859 str_replace (type_member->name, "-", "_");
860 if (type_member->type == G_IDL_NODE_SIGNAL
861 && strcmp (normalized_name, member->ident) == 0)
863 GList *vfunc_param_l;
864 GList *sig_param_l;
865 GIdlNodeSignal *sig = (GIdlNodeSignal *) type_member;
866 found_signal = TRUE;
867 /* set signal parameter names */
868 for (vfunc_param_l =
869 member->base_type->base_type->child_list,
870 sig_param_l = sig->parameters;
871 vfunc_param_l != NULL && sig_param_l != NULL;
872 vfunc_param_l = vfunc_param_l->next, sig_param_l =
873 sig_param_l->next)
875 CSymbol *vfunc_param = vfunc_param_l->data;
876 GIdlNodeParam *sig_param = sig_param_l->data;
877 if (vfunc_param->ident != NULL)
879 g_free (sig_param->node.name);
880 sig_param->node.name =
881 g_strdup (vfunc_param->ident);
884 break;
887 if (found_signal)
889 continue;
892 givfunc = (GIdlNodeVFunc *) g_idl_node_new (G_IDL_NODE_VFUNC);
893 givfunc->node.name = member->ident;
894 node->members =
895 g_list_insert_sorted (node->members, givfunc,
896 (GCompareFunc) g_idl_node_cmp);
897 givfunc->result =
898 (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
899 givfunc->result->type =
900 create_node_from_ctype (member->base_type->base_type->base_type);
901 for (param_l = member->base_type->base_type->child_list, i = 1;
902 param_l != NULL; param_l = param_l->next, i++)
904 CSymbol *param_sym = param_l->data;
905 GIdlNodeParam *param =
906 (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
907 if (param_sym->ident == NULL)
909 param->node.name = g_strdup_printf ("p%d", i);
911 else
913 param->node.name = param_sym->ident;
915 param->type = create_node_from_ctype (param_sym->base_type);
916 givfunc->parameters =
917 g_list_append (givfunc->parameters, param);
922 else if (g_str_has_suffix (sym->ident, "Private"))
924 /* ignore private structs */
926 else
928 g_igenerator_process_unregistered_struct_typedef (igenerator, sym,
929 struct_type);
933 static void
934 g_igenerator_process_union_typedef (GIGenerator * igenerator, CSymbol * sym)
936 CType *union_type = sym->base_type;
937 gboolean opaque_type = FALSE;
938 GIdlNode *type;
940 if (union_type->child_list == NULL)
942 g_assert (union_type->name != NULL);
943 CSymbol *union_symbol =
944 g_hash_table_lookup (igenerator->struct_or_union_or_enum_table,
945 union_type->name);
946 if (union_symbol != NULL)
948 union_type = union_symbol->base_type;
951 if (union_type->child_list == NULL)
953 opaque_type = TRUE;
956 type = g_hash_table_lookup (igenerator->type_map, sym->ident);
957 if (type != NULL)
959 g_assert (type->type == G_IDL_NODE_BOXED);
960 GIdlNodeBoxed *node = (GIdlNodeBoxed *) type;
961 GList *member_l;
962 for (member_l = union_type->child_list; member_l != NULL;
963 member_l = member_l->next)
965 CSymbol *member = member_l->data;
966 GIdlNodeField *gifield =
967 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
968 node->members = g_list_append (node->members, gifield);
969 gifield->node.name = member->ident;
970 gifield->type = create_node_from_ctype (member->base_type);
973 else
975 GIdlNodeUnion *node =
976 (GIdlNodeUnion *) g_idl_node_new (G_IDL_NODE_UNION);
977 char *lower_case_prefix;
978 GList *member_l;
980 node->node.name = sym->ident;
981 igenerator->module->entries =
982 g_list_insert_sorted (igenerator->module->entries, node,
983 (GCompareFunc) g_idl_node_cmp);
984 lower_case_prefix = g_ascii_strdown (sym->ident, -1);
985 g_hash_table_insert (igenerator->type_map, sym->ident, node);
986 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
987 lower_case_prefix, node);
989 node->node.name = sym->ident;
990 for (member_l = union_type->child_list; member_l != NULL;
991 member_l = member_l->next)
993 CSymbol *member = member_l->data;
994 GIdlNodeField *gifield =
995 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
996 node->members = g_list_append (node->members, gifield);
997 gifield->node.name = member->ident;
998 gifield->type = create_node_from_ctype (member->base_type);
1003 static void
1004 g_igenerator_process_enum_typedef (GIGenerator * igenerator, CSymbol * sym)
1006 CType *enum_type;
1007 GList *member_l;
1008 GIdlNodeEnum *node;
1009 CSymbol *enum_symbol;
1011 enum_type = sym->base_type;
1012 if (enum_type->child_list == NULL)
1014 g_assert (enum_type->name != NULL);
1015 enum_symbol =
1016 g_hash_table_lookup (igenerator->struct_or_union_or_enum_table,
1017 enum_type->name);
1018 if (enum_symbol != NULL)
1020 enum_type = enum_symbol->base_type;
1023 if (enum_type->child_list == NULL)
1025 /* opaque type */
1026 return;
1029 node = g_hash_table_lookup (igenerator->type_map, sym->ident);
1030 if (node != NULL)
1032 return;
1035 node = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_ENUM);
1036 node->node.name = sym->ident;
1037 igenerator->module->entries =
1038 g_list_insert_sorted (igenerator->module->entries, node,
1039 (GCompareFunc) g_idl_node_cmp);
1041 for (member_l = enum_type->child_list; member_l != NULL;
1042 member_l = member_l->next)
1044 CSymbol *member = member_l->data;
1045 GIdlNodeValue *gival =
1046 (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
1047 node->values = g_list_append (node->values, gival);
1048 gival->node.name = member->ident;
1049 gival->value = member->const_int;
1053 static void
1054 g_igenerator_process_function_typedef (GIGenerator * igenerator,
1055 CSymbol * sym)
1057 GList *param_l;
1058 int i;
1060 /* handle callback types */
1061 GIdlNodeFunction *gifunc =
1062 (GIdlNodeFunction *) g_idl_node_new (G_IDL_NODE_CALLBACK);
1064 gifunc->node.name = sym->ident;
1065 igenerator->module->entries =
1066 g_list_insert_sorted (igenerator->module->entries, gifunc,
1067 (GCompareFunc) g_idl_node_cmp);
1069 gifunc->symbol = sym->ident;
1070 gifunc->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
1071 gifunc->result->type =
1072 create_node_from_ctype (sym->base_type->base_type->base_type);
1074 for (param_l = sym->base_type->base_type->child_list, i = 1;
1075 param_l != NULL; param_l = param_l->next, i++)
1077 CSymbol *param_sym = param_l->data;
1078 GIdlNodeParam *param =
1079 (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
1080 if (param_sym->ident == NULL)
1082 param->node.name = g_strdup_printf ("p%d", i);
1084 else
1086 param->node.name = param_sym->ident;
1088 param->type = create_node_from_ctype (param_sym->base_type);
1089 gifunc->parameters = g_list_append (gifunc->parameters, param);
1093 static void
1094 g_igenerator_process_constant (GIGenerator * igenerator, CSymbol * sym)
1096 GIdlNodeConstant *giconst =
1097 (GIdlNodeConstant *) g_idl_node_new (G_IDL_NODE_CONSTANT);
1098 giconst->node.name = sym->ident;
1099 igenerator->module->entries =
1100 g_list_insert_sorted (igenerator->module->entries, giconst,
1101 (GCompareFunc) g_idl_node_cmp);
1103 giconst->type = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
1104 if (sym->const_int_set)
1106 giconst->type->unparsed = g_strdup ("int");
1107 giconst->value = g_strdup_printf ("%d", sym->const_int);
1109 else if (sym->const_string != NULL)
1111 giconst->type->unparsed = g_strdup ("char*");
1112 giconst->value = sym->const_string;
1116 static void
1117 g_igenerator_process_symbols (GIGenerator * igenerator)
1119 GList *l;
1120 /* process type symbols first to ensure complete type hashtables */
1121 /* type symbols */
1122 for (l = igenerator->symbol_list; l != NULL; l = l->next)
1124 CSymbol *sym = l->data;
1125 if (sym->ident[0] == '_')
1127 /* ignore private / reserved symbols */
1128 continue;
1130 if (sym->type == CSYMBOL_TYPE_TYPEDEF)
1132 if (sym->base_type->type == CTYPE_STRUCT)
1134 g_igenerator_process_struct_typedef (igenerator, sym);
1136 else if (sym->base_type->type == CTYPE_UNION)
1138 g_igenerator_process_union_typedef (igenerator, sym);
1140 else if (sym->base_type->type == CTYPE_ENUM)
1142 g_igenerator_process_enum_typedef (igenerator, sym);
1144 else if (sym->base_type->type == CTYPE_POINTER
1145 && sym->base_type->base_type->type == CTYPE_FUNCTION)
1147 g_igenerator_process_function_typedef (igenerator, sym);
1149 else
1151 GIdlNodeStruct *node =
1152 (GIdlNodeStruct *) g_idl_node_new (G_IDL_NODE_STRUCT);
1153 char *lower_case_prefix;
1155 node->node.name = sym->ident;
1156 igenerator->module->entries =
1157 g_list_insert_sorted (igenerator->module->entries, node,
1158 (GCompareFunc) g_idl_node_cmp);
1159 lower_case_prefix = g_ascii_strdown (sym->ident, -1);
1160 g_hash_table_insert (igenerator->type_map, sym->ident, node);
1161 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
1162 lower_case_prefix, node);
1166 /* other symbols */
1167 for (l = igenerator->symbol_list; l != NULL; l = l->next)
1169 CSymbol *sym = l->data;
1170 if (sym->ident[0] == '_')
1172 /* ignore private / reserved symbols */
1173 continue;
1175 if (sym->type == CSYMBOL_TYPE_FUNCTION)
1177 g_igenerator_process_function_symbol (igenerator, sym);
1179 else if (sym->type == CSYMBOL_TYPE_CONST)
1181 g_igenerator_process_constant (igenerator, sym);
1186 void
1187 g_igenerator_add_symbol (GIGenerator * igenerator, CSymbol * symbol)
1189 GList *l;
1191 /* only add symbols of main file */
1192 gboolean found_filename = FALSE;
1194 if (igenerator->current_filename)
1196 for (l = igenerator->filenames; l != NULL; l = l->next)
1198 if (strcmp (l->data, igenerator->current_filename) == 0)
1200 found_filename = TRUE;
1201 break;
1206 symbol->directives = g_slist_reverse (igenerator->directives);
1207 igenerator->directives = NULL;
1209 /* that's not very optimized ! */
1210 for (l = igenerator->symbol_list; l != NULL; l = l->next)
1212 CSymbol *other_symbol = (CSymbol *)l->data;
1213 if (g_str_equal (other_symbol->ident, symbol->ident)
1214 && other_symbol->type == symbol->type)
1216 g_printerr ("Dropping %s duplicate\n", symbol->ident);
1217 return;
1221 if (found_filename || igenerator->macro_scan)
1223 igenerator->symbol_list =
1224 g_list_prepend (igenerator->symbol_list, symbol);
1227 if (symbol->type == CSYMBOL_TYPE_TYPEDEF)
1230 g_hash_table_insert (igenerator->typedef_table, symbol->ident, symbol);
1232 else if (symbol->type == CSYMBOL_TYPE_STRUCT
1233 || symbol->type == CSYMBOL_TYPE_UNION
1234 || symbol->type == CSYMBOL_TYPE_ENUM)
1236 g_hash_table_insert (igenerator->struct_or_union_or_enum_table,
1237 symbol->ident, symbol);
1241 gboolean
1242 g_igenerator_is_typedef (GIGenerator * igenerator, const char *name)
1244 gboolean b = g_hash_table_lookup (igenerator->typedef_table, name) != NULL;
1245 return b;
1248 void
1249 g_igenerator_generate (GIGenerator * igenerator,
1250 const gchar * filename,
1251 GList *libraries)
1253 GList *l;
1255 for (l = igenerator->symbol_list; l != NULL; l = l->next)
1257 CSymbol *sym = l->data;
1258 if (sym->type == CSYMBOL_TYPE_FUNCTION
1259 && g_str_has_suffix (sym->ident, "_get_type"))
1261 if (sym->base_type->child_list == NULL)
1263 // ignore get_type functions with parameters
1264 igenerator->get_type_symbols =
1265 g_list_prepend (igenerator->get_type_symbols, sym->ident);
1270 /* ensure to initialize GObject */
1271 g_type_class_ref (G_TYPE_OBJECT);
1273 for (l = libraries; l; l = l->next)
1274 g_igenerator_process_module (igenerator, (const gchar*)l->data);
1276 g_igenerator_process_symbols (igenerator);
1278 g_idl_writer_save_file (igenerator->module, filename);
1281 static int
1282 eat_hspace (FILE * f)
1284 int c;
1287 c = fgetc (f);
1289 while (c == ' ' || c == '\t');
1290 return c;
1293 static int
1294 eat_line (FILE * f, int c)
1296 while (c != EOF && c != '\n')
1298 c = fgetc (f);
1300 if (c == '\n')
1302 c = fgetc (f);
1303 if (c == ' ' || c == '\t')
1305 c = eat_hspace (f);
1308 return c;
1311 static int
1312 read_identifier (FILE * f, int c, char **identifier)
1314 GString *id = g_string_new ("");
1315 while (isalnum (c) || c == '_')
1317 g_string_append_c (id, c);
1318 c = fgetc (f);
1320 *identifier = g_string_free (id, FALSE);
1321 return c;
1324 static void
1325 g_igenerator_parse_macros (GIGenerator * igenerator)
1327 GError *error = NULL;
1328 char *tmp_name = NULL;
1329 FILE *fmacros =
1330 fdopen (g_file_open_tmp ("gen-introspect-XXXXXX.h", &tmp_name, &error),
1331 "w+");
1332 g_unlink (tmp_name);
1334 GList *l;
1335 for (l = igenerator->filenames; l != NULL; l = l->next)
1337 FILE *f = fopen (l->data, "r");
1338 int line = 1;
1340 GString *define_line;
1341 char *str;
1342 gboolean error_line = FALSE;
1343 int c = eat_hspace (f);
1344 while (c != EOF)
1346 if (c != '#')
1348 /* ignore line */
1349 c = eat_line (f, c);
1350 line++;
1351 continue;
1354 /* print current location */
1355 str = g_strescape (l->data, "");
1356 fprintf (fmacros, "# %d \"%s\"\n", line, str);
1357 g_free (str);
1359 c = eat_hspace (f);
1360 c = read_identifier (f, c, &str);
1361 if (strcmp (str, "define") != 0 || (c != ' ' && c != '\t'))
1363 g_free (str);
1364 /* ignore line */
1365 c = eat_line (f, c);
1366 line++;
1367 continue;
1369 g_free (str);
1370 c = eat_hspace (f);
1371 c = read_identifier (f, c, &str);
1372 if (strlen (str) == 0 || (c != ' ' && c != '\t' && c != '('))
1374 g_free (str);
1375 /* ignore line */
1376 c = eat_line (f, c);
1377 line++;
1378 continue;
1380 define_line = g_string_new ("#define ");
1381 g_string_append (define_line, str);
1382 g_free (str);
1383 if (c == '(')
1385 while (c != ')')
1387 g_string_append_c (define_line, c);
1388 c = fgetc (f);
1389 if (c == EOF || c == '\n')
1391 error_line = TRUE;
1392 break;
1395 if (error_line)
1397 g_string_free (define_line, TRUE);
1398 /* ignore line */
1399 c = eat_line (f, c);
1400 line++;
1401 continue;
1404 g_assert (c == ')');
1405 g_string_append_c (define_line, c);
1406 c = fgetc (f);
1408 /* found function-like macro */
1409 fprintf (fmacros, "%s\n", define_line->str);
1411 g_string_free (define_line, TRUE);
1412 /* ignore rest of line */
1413 c = eat_line (f, c);
1414 line++;
1415 continue;
1417 if (c != ' ' && c != '\t')
1419 g_string_free (define_line, TRUE);
1420 /* ignore line */
1421 c = eat_line (f, c);
1422 line++;
1423 continue;
1425 while (c != EOF && c != '\n')
1427 g_string_append_c (define_line, c);
1428 c = fgetc (f);
1429 if (c == '\\')
1431 c = fgetc (f);
1432 if (c == '\n')
1434 /* fold lines when seeing backslash new-line sequence */
1435 c = fgetc (f);
1437 else
1439 g_string_append_c (define_line, '\\');
1444 /* found object-like macro */
1445 fprintf (fmacros, "%s\n", define_line->str);
1447 c = eat_line (f, c);
1448 line++;
1451 fclose (f);
1454 igenerator->macro_scan = TRUE;
1455 rewind (fmacros);
1457 g_igenerator_parse_file (igenerator, fmacros);
1458 fclose (fmacros);
1460 igenerator->macro_scan = FALSE;
1463 static void
1464 g_igenerator_add_module (GIGenerator *igenerator,
1465 GIdlModule *module)
1467 GList *l;
1469 for (l = module->entries; l; l = l->next)
1471 GIdlNode *node = (GIdlNode*)l->data;
1473 if (node->type == G_IDL_NODE_OBJECT)
1475 GIdlNodeInterface *object = (GIdlNodeInterface*)node;
1476 gchar *name;
1477 if (strcmp(module->name, igenerator->namespace) == 0)
1478 name = g_strdup (node->name);
1479 else
1480 name = g_strdup_printf ("%s.%s", module->name, node->name);
1481 g_hash_table_insert (igenerator->symbols,
1482 g_strdup (object->gtype_name),
1483 name);
1488 static void
1489 g_igenerator_add_include_idl (GIGenerator *igenerator,
1490 const gchar *filename)
1492 GList *l;
1493 GList *modules;
1495 GError *error = NULL;
1497 modules = g_idl_parse_file (filename, &error);
1498 if (error)
1500 g_printerr ("An error occured while parsing %s: %s\n",
1501 filename, error->message);
1502 return;
1505 for (l = modules; l; l = l->next)
1507 GIdlModule *module = (GIdlModule*)l->data;
1508 g_igenerator_add_module (igenerator, module);
1512 static FILE *
1513 g_igenerator_start_preprocessor (GIGenerator *igenerator,
1514 GList *cpp_options)
1516 int cpp_out = -1, cpp_in = -1;
1517 int cpp_argc = 0;
1518 char **cpp_argv;
1519 GList *l;
1520 GError *error = NULL;
1521 FILE *f, *out;
1522 GPid pid;
1523 int status = 0;
1524 int read_bytes;
1525 int i;
1526 char **buffer;
1527 int tmp;
1528 char *tmpname;
1530 cpp_argv = g_new0 (char *, g_list_length (cpp_options) + 4);
1531 cpp_argv[cpp_argc++] = "cpp";
1532 cpp_argv[cpp_argc++] = "-C";
1534 /* Disable GCC extensions as we cannot parse them yet */
1535 cpp_argv[cpp_argc++] = "-U__GNUC__";
1537 for (l = cpp_options; l; l = l->next)
1538 cpp_argv[cpp_argc++] = (char*)l->data;
1540 cpp_argv[cpp_argc++] = NULL;
1542 if (igenerator->verbose)
1544 GString *args = g_string_new ("");
1546 for (i = 0; i < cpp_argc - 1; i++)
1548 g_string_append (args, cpp_argv[i]);
1549 if (i < cpp_argc - 2)
1550 g_string_append_c (args, ' ');
1553 g_printf ("Executing '%s'\n", args->str);
1554 g_string_free (args, FALSE);
1556 g_spawn_async_with_pipes (NULL, cpp_argv, NULL,
1557 G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
1558 NULL, NULL, &pid, &cpp_in, &cpp_out, NULL, &error);
1560 g_free (cpp_argv);
1561 if (error != NULL)
1563 g_error ("%s", error->message);
1564 return NULL;
1567 f = fdopen (cpp_in, "w");
1569 for (l = igenerator->filenames; l != NULL; l = l->next)
1571 if (igenerator->verbose)
1572 g_printf ("Pre-processing %s\n", (char*)l->data);
1574 fprintf (f, "#include <%s>\n", (char *) l->data);
1578 fclose (f);
1579 close (cpp_in);
1581 tmp = g_file_open_tmp (NULL, &tmpname, &error);
1582 if (error != NULL)
1584 g_error (error->message);
1585 return NULL;
1588 buffer = g_malloc0 (4096 * sizeof (char));
1590 while (1)
1592 read_bytes = read (cpp_out, buffer, 4096);
1593 if (read_bytes == 0)
1594 break;
1595 write (tmp, buffer, read_bytes);
1598 g_free (buffer);
1600 close (cpp_out);
1602 if (waitpid (pid, &status, 0) > 0)
1604 if (status != 0)
1606 g_spawn_close_pid (pid);
1607 kill (pid, SIGKILL);
1609 g_error ("cpp returned error code: %d\n", status);
1610 unlink (tmpname);
1611 g_free (tmpname);
1612 return NULL;
1616 f = fdopen (tmp, "r");
1617 if (!f)
1619 g_error (strerror (errno));
1620 unlink (tmpname);
1621 g_free (tmpname);
1622 return NULL;
1624 rewind (f);
1625 unlink (tmpname);
1626 g_free (tmpname);
1628 return f;
1632 void
1633 g_igenerator_set_verbose (GIGenerator *igenerator,
1634 gboolean verbose)
1636 igenerator->verbose = verbose;
1640 main (int argc, char **argv)
1642 GOptionContext *ctx;
1643 gchar *namespace = NULL;
1644 gchar *shared_library = NULL;
1645 gchar **include_idls = NULL;
1646 gchar *output = NULL;
1647 gboolean verbose = FALSE;
1649 GIGenerator *igenerator;
1650 int gopt_argc, i;
1651 char **gopt_argv;
1652 GList *filenames = NULL;
1653 GError *error = NULL;
1654 GList *l, *libraries = NULL;
1655 GList *cpp_options = NULL;
1656 char *buffer;
1657 size_t size;
1658 FILE *tmp;
1659 GOptionEntry entries[] =
1661 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
1662 "Be verbose" },
1663 { "output", 'o', 0, G_OPTION_ARG_STRING, &output,
1664 "write output here instead of stdout", "FILE" },
1665 { "namespace", 'n', 0, G_OPTION_ARG_STRING, &namespace,
1666 "Namespace of the module, like 'Gtk'", "NAMESPACE" },
1667 { "shared-library", 0, 0, G_OPTION_ARG_FILENAME, &shared_library,
1668 "Shared library which contains the symbols", "FILE" },
1669 { "include-idl", 0, 0, G_OPTION_ARG_STRING_ARRAY, &include_idls,
1670 "Other gidls to include", "IDL" },
1671 { NULL }
1674 gopt_argc = 1;
1675 gopt_argv = (char**)g_malloc (argc * sizeof (char*));
1676 gopt_argv[0] = argv[0];
1678 for (i = 1; i < argc; i++)
1680 if (argv[i][0] == '-')
1682 switch (argv[i][1])
1684 case 'I':
1685 case 'D':
1686 case 'U':
1687 cpp_options = g_list_prepend (cpp_options, g_strdup (argv[i]));
1688 break;
1689 case 'p':
1690 /*ignore -pthread*/
1691 if (0==strcmp("-pthread", argv[i]))
1692 break;
1693 default:
1694 gopt_argv[gopt_argc++] = argv[i];
1695 break;
1698 else if (g_str_has_suffix (argv[i], ".h"))
1700 gchar* filename;
1702 if (!g_path_is_absolute (argv[i]))
1704 gchar *dir = g_get_current_dir ();
1705 filename = g_strdup_printf ("%s/%s", dir,
1706 argv[i]);
1707 g_free (dir);
1709 else
1710 filename = g_strdup (argv[i]);
1712 filenames = g_list_append (filenames, g_realpath(filename));
1713 g_free(filename);
1715 else if (g_str_has_suffix (argv[i], ".la") ||
1716 g_str_has_suffix (argv[i], ".so") ||
1717 g_str_has_suffix (argv[i], ".dll"))
1719 libraries = g_list_prepend (libraries, g_strdup (argv[i]));
1721 else
1723 gopt_argv[gopt_argc++] = argv[i];
1727 ctx = g_option_context_new ("");
1728 g_option_context_add_main_entries (ctx, entries, NULL);
1730 if (!g_option_context_parse (ctx, &gopt_argc, &gopt_argv, &error))
1732 g_printerr ("Parsing error: %s\n", error->message);
1733 g_option_context_free (ctx);
1734 return 1;
1737 g_free (gopt_argv);
1738 g_option_context_free (ctx);
1740 if (!namespace)
1742 g_printerr ("ERROR: namespace must be specified\n");
1743 return 1;
1746 igenerator = g_igenerator_new (namespace, shared_library);
1748 if (verbose)
1749 g_igenerator_set_verbose (igenerator, TRUE);
1751 if (!filenames)
1753 g_printerr ("ERROR: Need at least one header file.\n");
1754 g_igenerator_free (igenerator);
1755 return 0;
1757 igenerator->filenames = filenames;
1758 cpp_options = g_list_reverse (cpp_options);
1759 libraries = g_list_reverse (libraries);
1761 g_type_init ();
1763 /* initialize threading as this may be required by libraries that we'll use
1764 * libsoup-2.2 is an example of that.
1766 g_thread_init (NULL);
1768 if (include_idls)
1770 for (i = 0; i < g_strv_length (include_idls); i++)
1771 g_igenerator_add_include_idl (igenerator, include_idls[i]);
1774 tmp = g_igenerator_start_preprocessor (igenerator, cpp_options);
1775 if (!tmp)
1777 g_error ("ERROR in pre-processor.\n");
1778 g_igenerator_free (igenerator);
1779 return 1;
1782 if (!g_igenerator_parse_file (igenerator, tmp))
1784 fclose (tmp);
1785 g_igenerator_free (igenerator);
1786 return 1;
1789 g_igenerator_parse_macros (igenerator);
1791 g_igenerator_generate (igenerator, output, libraries);
1793 fclose (tmp);
1794 g_igenerator_free (igenerator);
1796 return 0;