Release 0.7.8
[vala-lang.git] / gobject-introspection / scanner.c
blob43a8303e8707a3ac0040c37f13c8e55caa4d685d
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 <unistd.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <glib.h>
31 #include <glib/gstdio.h>
32 #include <glib-object.h>
33 #include <signal.h>
34 #include <sys/wait.h> /* waitpid */
35 #include <gmodule.h>
36 #include "scanner.h"
37 #include "gidlparser.h"
38 #include "gidlmodule.h"
39 #include "gidlnode.h"
40 #include "gidlwriter.h"
41 #include "grealpath.h"
44 typedef GType (*TypeFunction) (void);
46 static void g_igenerator_parse_macros (GIGenerator * igenerator);
48 static GIGenerator *
49 g_igenerator_new (const gchar *namespace,
50 const gchar *shared_library)
52 GIGenerator *igenerator = g_new0 (GIGenerator, 1);
53 igenerator->namespace = g_strdup (namespace);
54 igenerator->shared_library = g_strdup (shared_library);
55 igenerator->lower_case_namespace =
56 g_ascii_strdown (igenerator->namespace, -1);
57 igenerator->module = g_idl_module_new (namespace, shared_library);
59 igenerator->typedef_table = g_hash_table_new (g_str_hash, g_str_equal);
60 igenerator->struct_or_union_or_enum_table =
61 g_hash_table_new (g_str_hash, g_str_equal);
63 igenerator->type_map = g_hash_table_new (g_str_hash, g_str_equal);
64 igenerator->type_by_lower_case_prefix =
65 g_hash_table_new (g_str_hash, g_str_equal);
66 igenerator->symbols = g_hash_table_new (g_str_hash, g_str_equal);
68 return igenerator;
71 static void
72 g_igenerator_free (GIGenerator *generator)
74 g_free (generator->namespace);
75 g_free (generator->shared_library);
76 g_free (generator->lower_case_namespace);
77 #if 0
78 g_idl_module_free (generator->module);
79 #endif
80 g_hash_table_destroy (generator->typedef_table);
81 g_hash_table_destroy (generator->struct_or_union_or_enum_table);
82 g_hash_table_destroy (generator->type_map);
83 g_hash_table_destroy (generator->type_by_lower_case_prefix);
84 g_hash_table_destroy (generator->symbols);
85 g_list_foreach (generator->filenames, (GFunc)g_free, NULL);
86 g_list_free (generator->filenames);
87 #if 0
88 g_list_foreach (generator->symbol_list, (GFunc)csymbol_free, NULL);
89 g_list_free (generator->symbol_list);
90 #endif
91 g_free (generator);
94 static GIdlNodeType *
95 create_node_from_gtype (GType type_id)
97 GIdlNodeType *node;
98 GType fundamental;
100 node = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
102 fundamental = g_type_fundamental (type_id);
103 switch (fundamental)
105 case G_TYPE_STRING:
106 node->unparsed = g_strdup ("char*");
107 break;
108 case G_TYPE_INTERFACE:
109 case G_TYPE_BOXED:
110 case G_TYPE_OBJECT:
111 node->unparsed = g_strdup_printf ("%s*", g_type_name (type_id));
112 break;
113 case G_TYPE_PARAM:
114 node->unparsed = g_strdup ("GParamSpec*");
115 break;
116 default:
117 if (fundamental == G_TYPE_STRV)
118 node->unparsed = g_strdup ("char*[]");
119 else
120 node->unparsed = g_strdup (g_type_name (type_id));
121 break;
124 return node;
127 static GIdlNodeType *
128 create_node_from_ctype (CType * ctype)
130 GIdlNodeType *node;
132 node = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
134 switch (ctype->type)
136 case CTYPE_VOID:
137 node->unparsed = g_strdup ("void");
138 break;
139 case CTYPE_BASIC_TYPE:
140 node->unparsed = g_strdup (ctype->name);
141 break;
142 case CTYPE_TYPEDEF:
143 node->unparsed = g_strdup (ctype->name);
144 break;
145 case CTYPE_STRUCT:
146 if (ctype->name == NULL)
147 /* anonymous struct */
148 node->unparsed = g_strdup ("gpointer");
149 else
150 node->unparsed = g_strdup_printf ("struct %s", ctype->name);
151 break;
152 case CTYPE_UNION:
153 if (ctype->name == NULL)
154 /* anonymous union */
155 node->unparsed = g_strdup ("gpointer");
156 else
157 node->unparsed = g_strdup_printf ("union %s", ctype->name);
158 break;
159 case CTYPE_ENUM:
160 if (ctype->name == NULL)
161 /* anonymous enum */
162 node->unparsed = g_strdup ("gint");
163 else
164 node->unparsed = g_strdup_printf ("enum %s", ctype->name);
165 break;
166 case CTYPE_POINTER:
167 if (ctype->base_type->type == CTYPE_FUNCTION)
168 /* anonymous function pointer */
169 node->unparsed = g_strdup ("GCallback");
170 else
172 GIdlNodeType *gibasetype = create_node_from_ctype (ctype->base_type);
173 node->unparsed = g_strdup_printf ("%s*", gibasetype->unparsed);
175 break;
176 case CTYPE_ARRAY:
178 GIdlNodeType *gibasetype = create_node_from_ctype (ctype->base_type);
179 node->unparsed = g_strdup_printf ("%s[]", gibasetype->unparsed);
180 break;
182 default:
183 node->unparsed = g_strdup ("unknown");
184 break;
187 return node;
190 static char *
191 str_replace (const char *str, const char *needle, const char *replacement)
193 char **strings = g_strsplit (str, needle, 0);
194 char *result = g_strjoinv (replacement, strings);
195 g_strfreev (strings);
196 return result;
199 static void
200 g_igenerator_process_properties (GIGenerator * igenerator,
201 GIdlNodeInterface * node, GType type_id)
203 int i;
204 guint n_properties;
205 GParamSpec **properties;
207 if (node->node.type == G_IDL_NODE_OBJECT)
209 GObjectClass *type_class = g_type_class_ref (type_id);
210 properties = g_object_class_list_properties (type_class, &n_properties);
212 else if (node->node.type == G_IDL_NODE_INTERFACE)
214 GTypeInterface *iface = g_type_default_interface_ref (type_id);
215 properties = g_object_interface_list_properties (iface, &n_properties);
217 else
219 g_assert_not_reached ();
222 for (i = 0; i < n_properties; i++)
224 GIdlNodeProperty *giprop;
226 /* ignore inherited properties */
227 if (properties[i]->owner_type != type_id)
229 continue;
231 giprop = (GIdlNodeProperty *) g_idl_node_new (G_IDL_NODE_PROPERTY);
232 giprop->node.name = properties[i]->name;
233 node->members =
234 g_list_insert_sorted (node->members, giprop,
235 (GCompareFunc) g_idl_node_cmp);
236 giprop->type = create_node_from_gtype (properties[i]->value_type);
237 giprop->readable = (properties[i]->flags & G_PARAM_READABLE) != 0;
238 giprop->writable = (properties[i]->flags & G_PARAM_WRITABLE) != 0;
239 giprop->construct = (properties[i]->flags & G_PARAM_CONSTRUCT) != 0;
240 giprop->construct_only =
241 (properties[i]->flags & G_PARAM_CONSTRUCT_ONLY) != 0;
245 static void
246 g_igenerator_process_signals (GIGenerator * igenerator,
247 GIdlNodeInterface * node, GType type_id)
249 int i, j;
250 guint n_signal_ids;
251 guint *signal_ids = g_signal_list_ids (type_id, &n_signal_ids);
253 for (i = 0; i < n_signal_ids; i++)
255 GSignalQuery signal_query;
256 GIdlNodeSignal *gisig;
257 GIdlNodeParam *giparam;
259 g_signal_query (signal_ids[i], &signal_query);
260 gisig = (GIdlNodeSignal *) g_idl_node_new (G_IDL_NODE_SIGNAL);
261 gisig->node.name = g_strdup (signal_query.signal_name);
262 node->members =
263 g_list_insert_sorted (node->members, gisig,
264 (GCompareFunc) g_idl_node_cmp);
266 gisig->run_first =
267 (signal_query.signal_flags & G_SIGNAL_RUN_FIRST) != 0;
268 gisig->run_last = (signal_query.signal_flags & G_SIGNAL_RUN_LAST) != 0;
269 gisig->run_cleanup =
270 (signal_query.signal_flags & G_SIGNAL_RUN_CLEANUP) != 0;
272 /* add sender parameter */
273 giparam = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
274 gisig->parameters = g_list_append (gisig->parameters, giparam);
275 giparam->node.name = g_strdup ("object");
276 giparam->type = create_node_from_gtype (type_id);
278 for (j = 0; j < signal_query.n_params; j++)
280 giparam = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
281 gisig->parameters = g_list_append (gisig->parameters, giparam);
282 giparam->node.name = g_strdup_printf ("p%d", j);
283 giparam->type = create_node_from_gtype (signal_query.param_types[j]);
285 gisig->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
286 gisig->result->type = create_node_from_gtype (signal_query.return_type);
290 static const gchar *
291 lookup_symbol (GIGenerator *igenerator, const gchar *typename)
293 const gchar *name =
294 g_hash_table_lookup (igenerator->symbols, typename);
296 if (!name)
298 g_printerr ("Unknown symbol: %s\n", typename);
299 return typename;
302 return name;
305 static void
306 g_igenerator_create_object (GIGenerator *igenerator,
307 const char *symbol_name,
308 GType type_id,
309 char *lower_case_prefix)
312 char *alt_lower_case_prefix;
313 GIdlNodeInterface *node;
314 guint n_type_interfaces;
315 GType *type_interfaces;
316 int i;
318 node = (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_OBJECT);
319 node->node.name = g_strdup (g_type_name (type_id));
320 igenerator->module->entries =
321 g_list_insert_sorted (igenerator->module->entries, node,
322 (GCompareFunc) g_idl_node_cmp);
323 g_hash_table_insert (igenerator->type_map, node->node.name,
324 node);
325 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
326 lower_case_prefix, node);
327 alt_lower_case_prefix = g_ascii_strdown (node->node.name, -1);
329 if (strcmp (alt_lower_case_prefix, lower_case_prefix) != 0)
331 /* alternative prefix sometimes necessary, for example
332 * for GdkWindow
334 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
335 alt_lower_case_prefix, node);
337 else
339 g_free (alt_lower_case_prefix);
342 node->gtype_name = node->node.name;
343 node->gtype_init = g_strdup (symbol_name);
344 node->parent = g_strdup (lookup_symbol (igenerator,
345 g_type_name (g_type_parent (type_id))));
347 type_interfaces = g_type_interfaces (type_id, &n_type_interfaces);
348 for (i = 0; i < n_type_interfaces; i++)
350 char *iface_name =
351 g_strdup (g_type_name (type_interfaces[i]));
352 /* workaround for AtkImplementorIface */
353 if (g_str_has_suffix (iface_name, "Iface"))
355 iface_name[strlen (iface_name) - strlen ("Iface")] =
356 '\0';
358 node->interfaces =
359 g_list_append (node->interfaces, iface_name);
362 g_hash_table_insert (igenerator->symbols,
363 g_strdup (node->gtype_name),
364 /* FIXME: Strip igenerator->namespace */
365 g_strdup (node->node.name));
367 g_igenerator_process_properties (igenerator, node, type_id);
368 g_igenerator_process_signals (igenerator, node, type_id);
371 static void
372 g_igenerator_create_interface (GIGenerator *igenerator,
373 const char *symbol_name,
374 GType type_id,
375 char *lower_case_prefix)
378 GIdlNodeInterface *node;
379 gboolean is_gobject = FALSE;
380 guint n_iface_prereqs;
381 GType *iface_prereqs;
382 int i;
384 node = (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_INTERFACE);
385 node->node.name = g_strdup (g_type_name (type_id));
387 /* workaround for AtkImplementorIface */
388 if (g_str_has_suffix (node->node.name, "Iface"))
390 node->node.name[strlen (node->node.name) -
391 strlen ("Iface")] = '\0';
393 igenerator->module->entries =
394 g_list_insert_sorted (igenerator->module->entries, node,
395 (GCompareFunc) g_idl_node_cmp);
396 g_hash_table_insert (igenerator->type_map, node->node.name,
397 node);
398 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
399 lower_case_prefix, node);
400 node->gtype_name = node->node.name;
401 node->gtype_init = g_strdup (symbol_name);
403 iface_prereqs =
404 g_type_interface_prerequisites (type_id, &n_iface_prereqs);
406 for (i = 0; i < n_iface_prereqs; i++)
408 if (g_type_fundamental (iface_prereqs[i]) == G_TYPE_OBJECT)
410 is_gobject = TRUE;
412 node->prerequisites =
413 g_list_append (node->prerequisites,
414 g_strdup (g_type_name (iface_prereqs[i])));
417 if (is_gobject)
418 g_igenerator_process_properties (igenerator, node, type_id);
419 else
420 g_type_default_interface_ref (type_id);
422 g_igenerator_process_signals (igenerator, node, type_id);
425 static void
426 g_igenerator_create_boxed (GIGenerator *igenerator,
427 const char *symbol_name,
428 GType type_id,
429 char *lower_case_prefix)
431 GIdlNodeBoxed *node =
432 (GIdlNodeBoxed *) g_idl_node_new (G_IDL_NODE_BOXED);
433 node->node.name = g_strdup (g_type_name (type_id));
434 igenerator->module->entries =
435 g_list_insert_sorted (igenerator->module->entries, node,
436 (GCompareFunc) g_idl_node_cmp);
437 g_hash_table_insert (igenerator->type_map, node->node.name,
438 node);
439 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
440 lower_case_prefix, node);
441 node->gtype_name = node->node.name;
442 node->gtype_init = g_strdup (symbol_name);
445 static void
446 g_igenerator_create_enum (GIGenerator *igenerator,
447 const char *symbol_name,
448 GType type_id,
449 char *lower_case_prefix)
451 GIdlNodeEnum *node;
452 int i;
453 GEnumClass *type_class;
455 node = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_ENUM);
456 node->node.name = g_strdup (g_type_name (type_id));
457 igenerator->module->entries =
458 g_list_insert_sorted (igenerator->module->entries, node,
459 (GCompareFunc) g_idl_node_cmp);
460 g_hash_table_insert (igenerator->type_map, node->node.name,
461 node);
462 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
463 lower_case_prefix, node);
464 node->gtype_name = node->node.name;
465 node->gtype_init = g_strdup (symbol_name);
467 type_class = g_type_class_ref (type_id);
469 for (i = 0; i < type_class->n_values; i++)
471 GIdlNodeValue *gival =
472 (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
473 node->values = g_list_append (node->values, gival);
474 gival->node.name =
475 g_strdup (type_class->values[i].value_name);
476 gival->value = type_class->values[i].value;
480 static void
481 g_igenerator_create_flags (GIGenerator *igenerator,
482 const char *symbol_name,
483 GType type_id,
484 char *lower_case_prefix)
486 GIdlNodeEnum *node;
487 GFlagsClass *type_class;
488 int i;
490 node = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_FLAGS);
491 node->node.name = g_strdup (g_type_name (type_id));
492 igenerator->module->entries =
493 g_list_insert_sorted (igenerator->module->entries, node,
494 (GCompareFunc) g_idl_node_cmp);
495 g_hash_table_insert (igenerator->type_map, node->node.name,
496 node);
497 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
498 lower_case_prefix, node);
499 node->gtype_name = node->node.name;
500 node->gtype_init = g_strdup (symbol_name);
502 type_class = g_type_class_ref (type_id);
504 for (i = 0; i < type_class->n_values; i++)
506 GIdlNodeValue *gival =
507 (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
508 node->values = g_list_append (node->values, gival);
509 gival->node.name =
510 g_strdup (type_class->values[i].value_name);
511 gival->value = type_class->values[i].value;
515 static gboolean
516 g_igenerator_process_module_symbol (GIGenerator *igenerator,
517 GModule *module,
518 const gchar *symbol_name)
520 TypeFunction type_fun;
521 GType type_id;
522 GType type_fundamental;
523 char *lower_case_prefix;
525 /* ignore already processed functions */
526 if (symbol_name == NULL)
527 return FALSE;
529 if (!g_module_symbol (module,
530 symbol_name,
531 (gpointer *) & type_fun))
532 return FALSE;
534 type_id = type_fun ();
535 type_fundamental = g_type_fundamental (type_id);
536 lower_case_prefix =
537 str_replace (g_strndup
538 (symbol_name,
539 strlen (symbol_name) - strlen ("_get_type")),
540 "_", "");
542 switch (type_fundamental)
544 case G_TYPE_OBJECT:
545 g_igenerator_create_object (igenerator, symbol_name, type_id,
546 lower_case_prefix);
547 break;
548 case G_TYPE_INTERFACE:
549 g_igenerator_create_interface (igenerator, symbol_name, type_id,
550 lower_case_prefix);
551 break;
552 case G_TYPE_BOXED:
553 g_igenerator_create_boxed (igenerator, symbol_name, type_id,
554 lower_case_prefix);
555 break;
556 case G_TYPE_ENUM:
557 g_igenerator_create_enum (igenerator, symbol_name, type_id,
558 lower_case_prefix);
559 break;
560 case G_TYPE_FLAGS:
561 g_igenerator_create_flags (igenerator, symbol_name, type_id,
562 lower_case_prefix);
563 break;
564 default:
565 break;
567 return TRUE;
570 static void
571 g_igenerator_process_module (GIGenerator * igenerator,
572 const gchar *filename)
574 GModule *module;
575 GList *l;
577 module = g_module_open (filename,
578 G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
580 if (module == NULL)
582 g_critical ("Couldn't open module: %s", filename);
583 return;
586 for (l = igenerator->get_type_symbols; l != NULL; l = l->next)
588 if (g_igenerator_process_module_symbol (igenerator,
589 module, (const char *)l->data))
590 /* symbol found, ignore in future iterations */
591 l->data = NULL;
595 static void
596 g_igenerator_process_function_symbol (GIGenerator * igenerator, CSymbol * sym)
598 GIdlNodeFunction *func;
599 char *last_underscore;
600 GList *param_l;
601 int i;
602 GSList *l;
604 func = (GIdlNodeFunction *) g_idl_node_new (G_IDL_NODE_FUNCTION);
606 /* check whether this is a type method */
607 last_underscore = strrchr (sym->ident, '_');
609 while (last_underscore != NULL)
611 char *prefix;
612 GIdlNode *node;
614 prefix = g_strndup (sym->ident, last_underscore - sym->ident);
615 prefix = str_replace (prefix, "_", "");
617 node = g_hash_table_lookup (igenerator->type_by_lower_case_prefix,
618 prefix);
619 if (node != NULL )
621 func->node.name = g_strdup (last_underscore + 1);
623 /* ignore get_type functions in registered types */
624 if (strcmp (func->node.name, "get_type") == 0)
625 return;
627 if ((node->type == G_IDL_NODE_OBJECT ||
628 node->type == G_IDL_NODE_BOXED) &&
629 g_str_has_prefix (func->node.name, "new"))
630 func->is_constructor = TRUE;
631 else
632 func->is_method = TRUE;
633 if (g_idl_node_can_have_member (node))
635 g_idl_node_add_member (node, func);
636 break;
638 else
640 /* reset function attributes */
641 g_free (func->node.name);
642 func->node.name = NULL;
643 func->is_constructor = FALSE;
644 func->is_method = FALSE;
647 else if (strcmp (igenerator->lower_case_namespace, prefix) == 0)
649 func->node.name = g_strdup (last_underscore + 1);
650 igenerator->module->entries =
651 g_list_insert_sorted (igenerator->module->entries, func,
652 (GCompareFunc) g_idl_node_cmp);
653 break;
655 last_underscore =
656 g_utf8_strrchr (sym->ident, last_underscore - sym->ident, '_');
659 /* create a namespace function if no prefix matches */
660 if (func->node.name == NULL)
662 func->node.name = sym->ident;
663 func->is_constructor = FALSE;
664 func->is_method = FALSE;
665 igenerator->module->entries =
666 g_list_insert_sorted (igenerator->module->entries, func,
667 (GCompareFunc) g_idl_node_cmp);
670 func->symbol = sym->ident;
671 func->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
672 func->result->type = create_node_from_ctype (sym->base_type->base_type);
674 for (param_l = sym->base_type->child_list, i = 1; param_l != NULL;
675 param_l = param_l->next, i++)
677 CSymbol *param_sym = param_l->data;
678 GIdlNodeParam *param;
680 param = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
681 param->type = create_node_from_ctype (param_sym->base_type);
683 if (param_sym->ident == NULL)
684 param->node.name = g_strdup_printf ("p%d", i);
685 else
686 param->node.name = param_sym->ident;
688 func->parameters = g_list_append (func->parameters, param);
691 for (l = sym->directives; l; l = l->next)
693 CDirective *directive = (CDirective*)l->data;
695 if (!strcmp (directive->name, "deprecated"))
696 func->deprecated = TRUE;
697 else
698 g_printerr ("Unknown function directive: %s\n",
699 directive->name);
703 static void
704 g_igenerator_process_unregistered_struct_typedef (GIGenerator * igenerator,
705 CSymbol * sym,
706 CType * struct_type)
708 GIdlNodeStruct *node =
709 (GIdlNodeStruct *) g_idl_node_new (G_IDL_NODE_STRUCT);
710 GList *member_l;
711 char *lower_case_prefix;
713 node->node.name = sym->ident;
714 igenerator->module->entries =
715 g_list_insert_sorted (igenerator->module->entries, node,
716 (GCompareFunc) g_idl_node_cmp);
717 lower_case_prefix = g_ascii_strdown (sym->ident, -1);
718 g_hash_table_insert (igenerator->type_map, sym->ident, node);
719 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
720 lower_case_prefix, node);
722 for (member_l = struct_type->child_list; member_l != NULL;
723 member_l = member_l->next)
725 CSymbol *member = member_l->data;
726 GIdlNodeField *gifield =
727 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
729 node->members = g_list_append (node->members, gifield);
730 gifield->node.name = member->ident;
731 gifield->type = create_node_from_ctype (member->base_type);
735 static void
736 g_igenerator_process_struct_typedef (GIGenerator * igenerator, CSymbol * sym)
738 CType *struct_type = sym->base_type;
739 gboolean opaque_type = FALSE;
740 GIdlNode *type;
742 if (struct_type->child_list == NULL)
744 CSymbol *struct_symbol;
745 g_assert (struct_type->name != NULL);
746 struct_symbol =
747 g_hash_table_lookup (igenerator->struct_or_union_or_enum_table,
748 struct_type->name);
749 if (struct_symbol != NULL)
751 struct_type = struct_symbol->base_type;
755 if (struct_type->child_list == NULL)
757 opaque_type = TRUE;
760 type = g_hash_table_lookup (igenerator->type_map, sym->ident);
761 if (type != NULL)
763 /* struct of a GTypeInstance */
764 if (!opaque_type
765 && (type->type == G_IDL_NODE_OBJECT
766 || type->type == G_IDL_NODE_INTERFACE))
768 GIdlNodeInterface *node = (GIdlNodeInterface *) type;
769 GList *member_l;
770 /* ignore first field => parent */
771 for (member_l = struct_type->child_list->next; member_l != NULL;
772 member_l = member_l->next)
774 CSymbol *member = member_l->data;
775 /* ignore private / reserved members */
776 if (member->ident[0] == '_'
777 || g_str_has_prefix (member->ident, "priv"))
779 continue;
781 GIdlNodeField *gifield =
782 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
783 node->members = g_list_append (node->members, gifield);
784 gifield->node.name = member->ident;
785 gifield->type = create_node_from_ctype (member->base_type);
788 else if (type->type == G_IDL_NODE_BOXED)
790 GIdlNodeBoxed *node = (GIdlNodeBoxed *) type;
791 GList *member_l;
792 for (member_l = struct_type->child_list; member_l != NULL;
793 member_l = member_l->next)
795 CSymbol *member = member_l->data;
796 GIdlNodeField *gifield =
797 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
798 node->members = g_list_append (node->members, gifield);
799 gifield->node.name = member->ident;
800 gifield->type = create_node_from_ctype (member->base_type);
804 else if (!opaque_type
805 && (g_str_has_suffix (sym->ident, "Class")
806 || g_str_has_suffix (sym->ident, "Iface")
807 || g_str_has_suffix (sym->ident, "Interface")))
809 char *base_name;
810 GList *member_l;
811 GIdlNodeInterface *node;
813 if (g_str_has_suffix (sym->ident, "Interface"))
815 base_name =
816 g_strndup (sym->ident,
817 strlen (sym->ident) - strlen ("Interface"));
819 else
821 base_name =
822 g_strndup (sym->ident, strlen (sym->ident) - strlen ("Class"));
824 type = g_hash_table_lookup (igenerator->type_map, base_name);
825 if (type == NULL
826 || (type->type != G_IDL_NODE_OBJECT
827 && type->type != G_IDL_NODE_INTERFACE))
829 g_igenerator_process_unregistered_struct_typedef (igenerator, sym,
830 struct_type);
831 return;
833 node = (GIdlNodeInterface *) type;
835 /* ignore first field => parent */
836 for (member_l = struct_type->child_list->next; member_l != NULL;
837 member_l = member_l->next)
839 CSymbol *member = member_l->data;
840 /* ignore private / reserved members */
841 if (member->ident[0] == '_')
843 continue;
845 if (member->base_type->type == CTYPE_POINTER
846 && member->base_type->base_type->type == CTYPE_FUNCTION)
848 /* ignore default handlers of signals */
849 gboolean found_signal = FALSE;
850 GList *type_member_l;
851 GList *param_l;
852 int i;
853 GIdlNodeVFunc *givfunc;
855 for (type_member_l = node->members; type_member_l != NULL;
856 type_member_l = type_member_l->next)
858 GIdlNode *type_member = type_member_l->data;
859 char *normalized_name =
860 str_replace (type_member->name, "-", "_");
861 if (type_member->type == G_IDL_NODE_SIGNAL
862 && strcmp (normalized_name, member->ident) == 0)
864 GList *vfunc_param_l;
865 GList *sig_param_l;
866 GIdlNodeSignal *sig = (GIdlNodeSignal *) type_member;
867 found_signal = TRUE;
868 /* set signal parameter names */
869 for (vfunc_param_l =
870 member->base_type->base_type->child_list,
871 sig_param_l = sig->parameters;
872 vfunc_param_l != NULL && sig_param_l != NULL;
873 vfunc_param_l = vfunc_param_l->next, sig_param_l =
874 sig_param_l->next)
876 CSymbol *vfunc_param = vfunc_param_l->data;
877 GIdlNodeParam *sig_param = sig_param_l->data;
878 if (vfunc_param->ident != NULL)
880 g_free (sig_param->node.name);
881 sig_param->node.name =
882 g_strdup (vfunc_param->ident);
885 break;
888 if (found_signal)
890 continue;
893 givfunc = (GIdlNodeVFunc *) g_idl_node_new (G_IDL_NODE_VFUNC);
894 givfunc->node.name = member->ident;
895 node->members =
896 g_list_insert_sorted (node->members, givfunc,
897 (GCompareFunc) g_idl_node_cmp);
898 givfunc->result =
899 (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
900 givfunc->result->type =
901 create_node_from_ctype (member->base_type->base_type->base_type);
902 for (param_l = member->base_type->base_type->child_list, i = 1;
903 param_l != NULL; param_l = param_l->next, i++)
905 CSymbol *param_sym = param_l->data;
906 GIdlNodeParam *param =
907 (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
908 if (param_sym->ident == NULL)
910 param->node.name = g_strdup_printf ("p%d", i);
912 else
914 param->node.name = param_sym->ident;
916 param->type = create_node_from_ctype (param_sym->base_type);
917 givfunc->parameters =
918 g_list_append (givfunc->parameters, param);
923 else if (g_str_has_suffix (sym->ident, "Private"))
925 /* ignore private structs */
927 else
929 g_igenerator_process_unregistered_struct_typedef (igenerator, sym,
930 struct_type);
934 static void
935 g_igenerator_process_union_typedef (GIGenerator * igenerator, CSymbol * sym)
937 CType *union_type = sym->base_type;
938 gboolean opaque_type = FALSE;
939 GIdlNode *type;
941 if (union_type->child_list == NULL)
943 g_assert (union_type->name != NULL);
944 CSymbol *union_symbol =
945 g_hash_table_lookup (igenerator->struct_or_union_or_enum_table,
946 union_type->name);
947 if (union_symbol != NULL)
949 union_type = union_symbol->base_type;
952 if (union_type->child_list == NULL)
954 opaque_type = TRUE;
957 type = g_hash_table_lookup (igenerator->type_map, sym->ident);
958 if (type != NULL)
960 g_assert (type->type == G_IDL_NODE_BOXED);
961 GIdlNodeBoxed *node = (GIdlNodeBoxed *) type;
962 GList *member_l;
963 for (member_l = union_type->child_list; member_l != NULL;
964 member_l = member_l->next)
966 CSymbol *member = member_l->data;
967 GIdlNodeField *gifield =
968 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
969 node->members = g_list_append (node->members, gifield);
970 gifield->node.name = member->ident;
971 gifield->type = create_node_from_ctype (member->base_type);
974 else
976 GIdlNodeUnion *node =
977 (GIdlNodeUnion *) g_idl_node_new (G_IDL_NODE_UNION);
978 char *lower_case_prefix;
979 GList *member_l;
981 node->node.name = sym->ident;
982 igenerator->module->entries =
983 g_list_insert_sorted (igenerator->module->entries, node,
984 (GCompareFunc) g_idl_node_cmp);
985 lower_case_prefix = g_ascii_strdown (sym->ident, -1);
986 g_hash_table_insert (igenerator->type_map, sym->ident, node);
987 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
988 lower_case_prefix, node);
990 node->node.name = sym->ident;
991 for (member_l = union_type->child_list; member_l != NULL;
992 member_l = member_l->next)
994 CSymbol *member = member_l->data;
995 GIdlNodeField *gifield =
996 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
997 node->members = g_list_append (node->members, gifield);
998 gifield->node.name = member->ident;
999 gifield->type = create_node_from_ctype (member->base_type);
1004 static void
1005 g_igenerator_process_enum_typedef (GIGenerator * igenerator, CSymbol * sym)
1007 CType *enum_type;
1008 GList *member_l;
1009 GIdlNodeEnum *node;
1010 CSymbol *enum_symbol;
1012 enum_type = sym->base_type;
1013 if (enum_type->child_list == NULL)
1015 g_assert (enum_type->name != NULL);
1016 enum_symbol =
1017 g_hash_table_lookup (igenerator->struct_or_union_or_enum_table,
1018 enum_type->name);
1019 if (enum_symbol != NULL)
1021 enum_type = enum_symbol->base_type;
1024 if (enum_type->child_list == NULL)
1026 /* opaque type */
1027 return;
1030 node = g_hash_table_lookup (igenerator->type_map, sym->ident);
1031 if (node != NULL)
1033 return;
1036 node = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_ENUM);
1037 node->node.name = sym->ident;
1038 igenerator->module->entries =
1039 g_list_insert_sorted (igenerator->module->entries, node,
1040 (GCompareFunc) g_idl_node_cmp);
1042 for (member_l = enum_type->child_list; member_l != NULL;
1043 member_l = member_l->next)
1045 CSymbol *member = member_l->data;
1046 GIdlNodeValue *gival =
1047 (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
1048 node->values = g_list_append (node->values, gival);
1049 gival->node.name = member->ident;
1050 gival->value = member->const_int;
1054 static void
1055 g_igenerator_process_function_typedef (GIGenerator * igenerator,
1056 CSymbol * sym)
1058 GList *param_l;
1059 int i;
1061 /* handle callback types */
1062 GIdlNodeFunction *gifunc =
1063 (GIdlNodeFunction *) g_idl_node_new (G_IDL_NODE_CALLBACK);
1065 gifunc->node.name = sym->ident;
1066 igenerator->module->entries =
1067 g_list_insert_sorted (igenerator->module->entries, gifunc,
1068 (GCompareFunc) g_idl_node_cmp);
1070 gifunc->symbol = sym->ident;
1071 gifunc->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
1072 gifunc->result->type =
1073 create_node_from_ctype (sym->base_type->base_type->base_type);
1075 for (param_l = sym->base_type->base_type->child_list, i = 1;
1076 param_l != NULL; param_l = param_l->next, i++)
1078 CSymbol *param_sym = param_l->data;
1079 GIdlNodeParam *param =
1080 (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
1081 if (param_sym->ident == NULL)
1083 param->node.name = g_strdup_printf ("p%d", i);
1085 else
1087 param->node.name = param_sym->ident;
1089 param->type = create_node_from_ctype (param_sym->base_type);
1090 gifunc->parameters = g_list_append (gifunc->parameters, param);
1094 static void
1095 g_igenerator_process_constant (GIGenerator * igenerator, CSymbol * sym)
1097 GIdlNodeConstant *giconst =
1098 (GIdlNodeConstant *) g_idl_node_new (G_IDL_NODE_CONSTANT);
1099 giconst->node.name = sym->ident;
1100 igenerator->module->entries =
1101 g_list_insert_sorted (igenerator->module->entries, giconst,
1102 (GCompareFunc) g_idl_node_cmp);
1104 giconst->type = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
1105 if (sym->const_int_set)
1107 giconst->type->unparsed = g_strdup ("int");
1108 giconst->value = g_strdup_printf ("%d", sym->const_int);
1110 else if (sym->const_string != NULL)
1112 giconst->type->unparsed = g_strdup ("char*");
1113 giconst->value = sym->const_string;
1117 static void
1118 g_igenerator_process_symbols (GIGenerator * igenerator)
1120 GList *l;
1121 /* process type symbols first to ensure complete type hashtables */
1122 /* type symbols */
1123 for (l = igenerator->symbol_list; l != NULL; l = l->next)
1125 CSymbol *sym = l->data;
1126 if (sym->ident[0] == '_')
1128 /* ignore private / reserved symbols */
1129 continue;
1131 if (sym->type == CSYMBOL_TYPE_TYPEDEF)
1133 if (sym->base_type->type == CTYPE_STRUCT)
1135 g_igenerator_process_struct_typedef (igenerator, sym);
1137 else if (sym->base_type->type == CTYPE_UNION)
1139 g_igenerator_process_union_typedef (igenerator, sym);
1141 else if (sym->base_type->type == CTYPE_ENUM)
1143 g_igenerator_process_enum_typedef (igenerator, sym);
1145 else if (sym->base_type->type == CTYPE_POINTER
1146 && sym->base_type->base_type->type == CTYPE_FUNCTION)
1148 g_igenerator_process_function_typedef (igenerator, sym);
1150 else
1152 GIdlNodeStruct *node =
1153 (GIdlNodeStruct *) g_idl_node_new (G_IDL_NODE_STRUCT);
1154 char *lower_case_prefix;
1156 node->node.name = sym->ident;
1157 igenerator->module->entries =
1158 g_list_insert_sorted (igenerator->module->entries, node,
1159 (GCompareFunc) g_idl_node_cmp);
1160 lower_case_prefix = g_ascii_strdown (sym->ident, -1);
1161 g_hash_table_insert (igenerator->type_map, sym->ident, node);
1162 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
1163 lower_case_prefix, node);
1167 /* other symbols */
1168 for (l = igenerator->symbol_list; l != NULL; l = l->next)
1170 CSymbol *sym = l->data;
1171 if (sym->ident[0] == '_')
1173 /* ignore private / reserved symbols */
1174 continue;
1176 if (sym->type == CSYMBOL_TYPE_FUNCTION)
1178 g_igenerator_process_function_symbol (igenerator, sym);
1180 else if (sym->type == CSYMBOL_TYPE_CONST)
1182 g_igenerator_process_constant (igenerator, sym);
1187 void
1188 g_igenerator_add_symbol (GIGenerator * igenerator, CSymbol * symbol)
1190 GList *l;
1192 /* only add symbols of main file */
1193 gboolean found_filename = FALSE;
1195 if (igenerator->current_filename)
1197 for (l = igenerator->filenames; l != NULL; l = l->next)
1199 if (strcmp (l->data, igenerator->current_filename) == 0)
1201 found_filename = TRUE;
1202 break;
1207 symbol->directives = g_slist_reverse (igenerator->directives);
1208 igenerator->directives = NULL;
1210 /* that's not very optimized ! */
1211 for (l = igenerator->symbol_list; l != NULL; l = l->next)
1213 CSymbol *other_symbol = (CSymbol *)l->data;
1214 if (g_str_equal (other_symbol->ident, symbol->ident)
1215 && other_symbol->type == symbol->type)
1217 g_printerr ("Dropping %s duplicate\n", symbol->ident);
1218 return;
1222 if (found_filename || igenerator->macro_scan)
1224 igenerator->symbol_list =
1225 g_list_prepend (igenerator->symbol_list, symbol);
1228 if (symbol->type == CSYMBOL_TYPE_TYPEDEF)
1231 g_hash_table_insert (igenerator->typedef_table, symbol->ident, symbol);
1233 else if (symbol->type == CSYMBOL_TYPE_STRUCT
1234 || symbol->type == CSYMBOL_TYPE_UNION
1235 || symbol->type == CSYMBOL_TYPE_ENUM)
1237 g_hash_table_insert (igenerator->struct_or_union_or_enum_table,
1238 symbol->ident, symbol);
1242 gboolean
1243 g_igenerator_is_typedef (GIGenerator * igenerator, const char *name)
1245 gboolean b = g_hash_table_lookup (igenerator->typedef_table, name) != NULL;
1246 return b;
1249 void
1250 g_igenerator_generate (GIGenerator * igenerator,
1251 const gchar * filename,
1252 GList *libraries)
1254 GList *l;
1256 for (l = igenerator->symbol_list; l != NULL; l = l->next)
1258 CSymbol *sym = l->data;
1259 if (sym->type == CSYMBOL_TYPE_FUNCTION
1260 && g_str_has_suffix (sym->ident, "_get_type"))
1262 if (sym->base_type->child_list == NULL)
1264 // ignore get_type functions with parameters
1265 igenerator->get_type_symbols =
1266 g_list_prepend (igenerator->get_type_symbols, sym->ident);
1271 /* ensure to initialize GObject */
1272 g_type_class_ref (G_TYPE_OBJECT);
1274 for (l = libraries; l; l = l->next)
1275 g_igenerator_process_module (igenerator, (const gchar*)l->data);
1277 g_igenerator_process_symbols (igenerator);
1279 g_idl_writer_save_file (igenerator->module, filename);
1282 static int
1283 eat_hspace (FILE * f)
1285 int c;
1288 c = fgetc (f);
1290 while (c == ' ' || c == '\t');
1291 return c;
1294 static int
1295 eat_line (FILE * f, int c)
1297 while (c != EOF && c != '\n')
1299 c = fgetc (f);
1301 if (c == '\n')
1303 c = fgetc (f);
1304 if (c == ' ' || c == '\t')
1306 c = eat_hspace (f);
1309 return c;
1312 static int
1313 read_identifier (FILE * f, int c, char **identifier)
1315 GString *id = g_string_new ("");
1316 while (isalnum (c) || c == '_')
1318 g_string_append_c (id, c);
1319 c = fgetc (f);
1321 *identifier = g_string_free (id, FALSE);
1322 return c;
1325 static void
1326 g_igenerator_parse_macros (GIGenerator * igenerator)
1328 GError *error = NULL;
1329 char *tmp_name = NULL;
1330 FILE *fmacros =
1331 fdopen (g_file_open_tmp ("gen-introspect-XXXXXX.h", &tmp_name, &error),
1332 "w+");
1333 g_unlink (tmp_name);
1335 GList *l;
1336 for (l = igenerator->filenames; l != NULL; l = l->next)
1338 FILE *f = fopen (l->data, "r");
1339 int line = 1;
1341 GString *define_line;
1342 char *str;
1343 gboolean error_line = FALSE;
1344 int c = eat_hspace (f);
1345 while (c != EOF)
1347 if (c != '#')
1349 /* ignore line */
1350 c = eat_line (f, c);
1351 line++;
1352 continue;
1355 /* print current location */
1356 str = g_strescape (l->data, "");
1357 fprintf (fmacros, "# %d \"%s\"\n", line, str);
1358 g_free (str);
1360 c = eat_hspace (f);
1361 c = read_identifier (f, c, &str);
1362 if (strcmp (str, "define") != 0 || (c != ' ' && c != '\t'))
1364 g_free (str);
1365 /* ignore line */
1366 c = eat_line (f, c);
1367 line++;
1368 continue;
1370 g_free (str);
1371 c = eat_hspace (f);
1372 c = read_identifier (f, c, &str);
1373 if (strlen (str) == 0 || (c != ' ' && c != '\t' && c != '('))
1375 g_free (str);
1376 /* ignore line */
1377 c = eat_line (f, c);
1378 line++;
1379 continue;
1381 define_line = g_string_new ("#define ");
1382 g_string_append (define_line, str);
1383 g_free (str);
1384 if (c == '(')
1386 while (c != ')')
1388 g_string_append_c (define_line, c);
1389 c = fgetc (f);
1390 if (c == EOF || c == '\n')
1392 error_line = TRUE;
1393 break;
1396 if (error_line)
1398 g_string_free (define_line, TRUE);
1399 /* ignore line */
1400 c = eat_line (f, c);
1401 line++;
1402 continue;
1405 g_assert (c == ')');
1406 g_string_append_c (define_line, c);
1407 c = fgetc (f);
1409 /* found function-like macro */
1410 fprintf (fmacros, "%s\n", define_line->str);
1412 g_string_free (define_line, TRUE);
1413 /* ignore rest of line */
1414 c = eat_line (f, c);
1415 line++;
1416 continue;
1418 if (c != ' ' && c != '\t')
1420 g_string_free (define_line, TRUE);
1421 /* ignore line */
1422 c = eat_line (f, c);
1423 line++;
1424 continue;
1426 while (c != EOF && c != '\n')
1428 g_string_append_c (define_line, c);
1429 c = fgetc (f);
1430 if (c == '\\')
1432 c = fgetc (f);
1433 if (c == '\n')
1435 /* fold lines when seeing backslash new-line sequence */
1436 c = fgetc (f);
1438 else
1440 g_string_append_c (define_line, '\\');
1445 /* found object-like macro */
1446 fprintf (fmacros, "%s\n", define_line->str);
1448 c = eat_line (f, c);
1449 line++;
1452 fclose (f);
1455 igenerator->macro_scan = TRUE;
1456 rewind (fmacros);
1458 g_igenerator_parse_file (igenerator, fmacros);
1459 fclose (fmacros);
1461 igenerator->macro_scan = FALSE;
1464 static void
1465 g_igenerator_add_module (GIGenerator *igenerator,
1466 GIdlModule *module)
1468 GList *l;
1470 for (l = module->entries; l; l = l->next)
1472 GIdlNode *node = (GIdlNode*)l->data;
1474 if (node->type == G_IDL_NODE_OBJECT)
1476 GIdlNodeInterface *object = (GIdlNodeInterface*)node;
1477 gchar *name;
1478 if (strcmp(module->name, igenerator->namespace) == 0)
1479 name = g_strdup (node->name);
1480 else
1481 name = g_strdup_printf ("%s.%s", module->name, node->name);
1482 g_hash_table_insert (igenerator->symbols,
1483 g_strdup (object->gtype_name),
1484 name);
1489 static void
1490 g_igenerator_add_include_idl (GIGenerator *igenerator,
1491 const gchar *filename)
1493 GList *l;
1494 GList *modules;
1496 GError *error = NULL;
1498 modules = g_idl_parse_file (filename, &error);
1499 if (error)
1501 g_printerr ("An error occured while parsing %s: %s\n",
1502 filename, error->message);
1503 return;
1506 for (l = modules; l; l = l->next)
1508 GIdlModule *module = (GIdlModule*)l->data;
1509 g_igenerator_add_module (igenerator, module);
1513 static FILE *
1514 g_igenerator_start_preprocessor (GIGenerator *igenerator,
1515 GList *cpp_options)
1517 int cpp_out = -1, cpp_in = -1;
1518 int cpp_argc = 0;
1519 char **cpp_argv;
1520 GList *l;
1521 GError *error = NULL;
1522 FILE *f, *out;
1523 GPid pid;
1524 int status = 0;
1525 int read_bytes;
1526 int i;
1527 char **buffer;
1528 int tmp;
1529 char *tmpname;
1531 cpp_argv = g_new0 (char *, g_list_length (cpp_options) + 4);
1532 cpp_argv[cpp_argc++] = "cpp";
1533 cpp_argv[cpp_argc++] = "-C";
1535 /* Disable GCC extensions as we cannot parse them yet */
1536 cpp_argv[cpp_argc++] = "-U__GNUC__";
1538 for (l = cpp_options; l; l = l->next)
1539 cpp_argv[cpp_argc++] = (char*)l->data;
1541 cpp_argv[cpp_argc++] = NULL;
1543 if (igenerator->verbose)
1545 GString *args = g_string_new ("");
1547 for (i = 0; i < cpp_argc - 1; i++)
1549 g_string_append (args, cpp_argv[i]);
1550 if (i < cpp_argc - 2)
1551 g_string_append_c (args, ' ');
1554 g_printf ("Executing '%s'\n", args->str);
1555 g_string_free (args, FALSE);
1557 g_spawn_async_with_pipes (NULL, cpp_argv, NULL,
1558 G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
1559 NULL, NULL, &pid, &cpp_in, &cpp_out, NULL, &error);
1561 g_free (cpp_argv);
1562 if (error != NULL)
1564 g_error ("%s", error->message);
1565 return NULL;
1568 f = fdopen (cpp_in, "w");
1570 for (l = igenerator->filenames; l != NULL; l = l->next)
1572 if (igenerator->verbose)
1573 g_printf ("Pre-processing %s\n", (char*)l->data);
1575 fprintf (f, "#include <%s>\n", (char *) l->data);
1579 fclose (f);
1580 close (cpp_in);
1582 tmp = g_file_open_tmp (NULL, &tmpname, &error);
1583 if (error != NULL)
1585 g_error (error->message);
1586 return NULL;
1589 buffer = g_malloc0 (4096 * sizeof (char));
1591 while (1)
1593 read_bytes = read (cpp_out, buffer, 4096);
1594 if (read_bytes == 0)
1595 break;
1596 write (tmp, buffer, read_bytes);
1599 g_free (buffer);
1601 close (cpp_out);
1603 if (waitpid (pid, &status, 0) > 0)
1605 if (status != 0)
1607 g_spawn_close_pid (pid);
1608 kill (pid, SIGKILL);
1610 g_error ("cpp returned error code: %d\n", status);
1611 unlink (tmpname);
1612 g_free (tmpname);
1613 return NULL;
1617 f = fdopen (tmp, "r");
1618 if (!f)
1620 g_error (strerror (errno));
1621 unlink (tmpname);
1622 g_free (tmpname);
1623 return NULL;
1625 rewind (f);
1626 unlink (tmpname);
1627 g_free (tmpname);
1629 return f;
1633 void
1634 g_igenerator_set_verbose (GIGenerator *igenerator,
1635 gboolean verbose)
1637 igenerator->verbose = verbose;
1641 main (int argc, char **argv)
1643 GOptionContext *ctx;
1644 gchar *namespace = NULL;
1645 gchar *shared_library = NULL;
1646 gchar **include_idls = NULL;
1647 gchar *output = NULL;
1648 gboolean verbose = FALSE;
1650 GIGenerator *igenerator;
1651 int gopt_argc, i;
1652 char **gopt_argv;
1653 GList *filenames = NULL;
1654 GError *error = NULL;
1655 GList *l, *libraries = NULL;
1656 GList *cpp_options = NULL;
1657 char *buffer;
1658 size_t size;
1659 FILE *tmp;
1660 GOptionEntry entries[] =
1662 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
1663 "Be verbose" },
1664 { "output", 'o', 0, G_OPTION_ARG_STRING, &output,
1665 "write output here instead of stdout", "FILE" },
1666 { "namespace", 'n', 0, G_OPTION_ARG_STRING, &namespace,
1667 "Namespace of the module, like 'Gtk'", "NAMESPACE" },
1668 { "shared-library", 0, 0, G_OPTION_ARG_FILENAME, &shared_library,
1669 "Shared library which contains the symbols", "FILE" },
1670 { "include-idl", 0, 0, G_OPTION_ARG_STRING_ARRAY, &include_idls,
1671 "Other gidls to include", "IDL" },
1672 { NULL }
1675 gopt_argc = 1;
1676 gopt_argv = (char**)g_malloc (argc * sizeof (char*));
1677 gopt_argv[0] = argv[0];
1679 for (i = 1; i < argc; i++)
1681 if (argv[i][0] == '-')
1683 switch (argv[i][1])
1685 case 'I':
1686 case 'D':
1687 case 'U':
1688 cpp_options = g_list_prepend (cpp_options, g_strdup (argv[i]));
1689 break;
1690 case 'p':
1691 /*ignore -pthread*/
1692 if (0==strcmp("-pthread", argv[i]))
1693 break;
1694 default:
1695 gopt_argv[gopt_argc++] = argv[i];
1696 break;
1699 else if (g_str_has_suffix (argv[i], ".h"))
1701 gchar* filename;
1703 if (!g_path_is_absolute (argv[i]))
1705 gchar *dir = g_get_current_dir ();
1706 filename = g_strdup_printf ("%s/%s", dir,
1707 argv[i]);
1708 g_free (dir);
1710 else
1711 filename = g_strdup (argv[i]);
1713 filenames = g_list_append (filenames, g_realpath(filename));
1714 g_free(filename);
1716 else if (g_str_has_suffix (argv[i], ".la") ||
1717 g_str_has_suffix (argv[i], ".so") ||
1718 g_str_has_suffix (argv[i], ".dll"))
1720 libraries = g_list_prepend (libraries, g_strdup (argv[i]));
1722 else
1724 gopt_argv[gopt_argc++] = argv[i];
1728 ctx = g_option_context_new ("");
1729 g_option_context_add_main_entries (ctx, entries, NULL);
1731 if (!g_option_context_parse (ctx, &gopt_argc, &gopt_argv, &error))
1733 g_printerr ("Parsing error: %s\n", error->message);
1734 g_option_context_free (ctx);
1735 return 1;
1738 g_free (gopt_argv);
1739 g_option_context_free (ctx);
1741 if (!namespace)
1743 g_printerr ("ERROR: namespace must be specified\n");
1744 return 1;
1747 igenerator = g_igenerator_new (namespace, shared_library);
1749 if (verbose)
1750 g_igenerator_set_verbose (igenerator, TRUE);
1752 if (!filenames)
1754 g_printerr ("ERROR: Need at least one header file.\n");
1755 g_igenerator_free (igenerator);
1756 return 0;
1758 igenerator->filenames = filenames;
1759 cpp_options = g_list_reverse (cpp_options);
1760 libraries = g_list_reverse (libraries);
1762 g_type_init ();
1764 /* initialize threading as this may be required by libraries that we'll use
1765 * libsoup-2.2 is an example of that.
1767 g_thread_init (NULL);
1769 if (include_idls)
1771 for (i = 0; i < g_strv_length (include_idls); i++)
1772 g_igenerator_add_include_idl (igenerator, include_idls[i]);
1775 tmp = g_igenerator_start_preprocessor (igenerator, cpp_options);
1776 if (!tmp)
1778 g_error ("ERROR in pre-processor.\n");
1779 g_igenerator_free (igenerator);
1780 return 1;
1783 if (!g_igenerator_parse_file (igenerator, tmp))
1785 fclose (tmp);
1786 g_igenerator_free (igenerator);
1787 return 1;
1790 g_igenerator_parse_macros (igenerator);
1792 g_igenerator_generate (igenerator, output, libraries);
1794 fclose (tmp);
1795 g_igenerator_free (igenerator);
1797 return 0;