Release 0.41.92
[vala-gnome.git] / gobject-introspection / scanner.c
blobb7fa84ff2750ab3ddd36bf511bbf1b77d7ede010
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 <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"
42 #ifndef _WIN32
43 #include <sys/wait.h> /* waitpid */
44 #endif
47 typedef GType (*TypeFunction) (void);
49 static void g_igenerator_parse_macros (GIGenerator * igenerator);
51 static GIGenerator *
52 g_igenerator_new (const gchar *namespace,
53 const gchar *shared_library)
55 GIGenerator *igenerator = g_new0 (GIGenerator, 1);
56 igenerator->namespace = g_strdup (namespace);
57 igenerator->shared_library = g_strdup (shared_library);
58 igenerator->lower_case_namespace =
59 g_ascii_strdown (igenerator->namespace, -1);
60 igenerator->module = g_idl_module_new (namespace, shared_library);
62 igenerator->typedef_table = g_hash_table_new (g_str_hash, g_str_equal);
63 igenerator->struct_or_union_or_enum_table =
64 g_hash_table_new (g_str_hash, g_str_equal);
66 igenerator->type_map = g_hash_table_new (g_str_hash, g_str_equal);
67 igenerator->type_by_lower_case_prefix =
68 g_hash_table_new (g_str_hash, g_str_equal);
69 igenerator->symbols = g_hash_table_new (g_str_hash, g_str_equal);
71 return igenerator;
74 static void
75 g_igenerator_free (GIGenerator *generator)
77 g_free (generator->namespace);
78 g_free (generator->shared_library);
79 g_free (generator->lower_case_namespace);
80 #if 0
81 g_idl_module_free (generator->module);
82 #endif
83 g_hash_table_destroy (generator->typedef_table);
84 g_hash_table_destroy (generator->struct_or_union_or_enum_table);
85 g_hash_table_destroy (generator->type_map);
86 g_hash_table_destroy (generator->type_by_lower_case_prefix);
87 g_hash_table_destroy (generator->symbols);
88 g_list_foreach (generator->filenames, (GFunc)g_free, NULL);
89 g_list_free (generator->filenames);
90 #if 0
91 g_list_foreach (generator->symbol_list, (GFunc)csymbol_free, NULL);
92 g_list_free (generator->symbol_list);
93 #endif
94 g_free (generator);
97 static GIdlNodeType *
98 create_node_from_gtype (GType type_id)
100 GIdlNodeType *node;
101 GType fundamental;
103 node = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
105 fundamental = g_type_fundamental (type_id);
106 switch (fundamental)
108 case G_TYPE_STRING:
109 node->unparsed = g_strdup ("char*");
110 break;
111 case G_TYPE_INTERFACE:
112 case G_TYPE_BOXED:
113 case G_TYPE_OBJECT:
114 node->unparsed = g_strdup_printf ("%s*", g_type_name (type_id));
115 break;
116 case G_TYPE_PARAM:
117 node->unparsed = g_strdup ("GParamSpec*");
118 break;
119 default:
120 if (fundamental == G_TYPE_STRV)
121 node->unparsed = g_strdup ("char*[]");
122 else
123 node->unparsed = g_strdup (g_type_name (type_id));
124 break;
127 return node;
130 static GIdlNodeType *
131 create_node_from_ctype (CType * ctype)
133 GIdlNodeType *node;
135 node = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
137 switch (ctype->type)
139 case CTYPE_VOID:
140 node->unparsed = g_strdup ("void");
141 break;
142 case CTYPE_BASIC_TYPE:
143 node->unparsed = g_strdup (ctype->name);
144 break;
145 case CTYPE_TYPEDEF:
146 node->unparsed = g_strdup (ctype->name);
147 break;
148 case CTYPE_STRUCT:
149 if (ctype->name == NULL)
150 /* anonymous struct */
151 node->unparsed = g_strdup ("gpointer");
152 else
153 node->unparsed = g_strdup_printf ("struct %s", ctype->name);
154 break;
155 case CTYPE_UNION:
156 if (ctype->name == NULL)
157 /* anonymous union */
158 node->unparsed = g_strdup ("gpointer");
159 else
160 node->unparsed = g_strdup_printf ("union %s", ctype->name);
161 break;
162 case CTYPE_ENUM:
163 if (ctype->name == NULL)
164 /* anonymous enum */
165 node->unparsed = g_strdup ("gint");
166 else
167 node->unparsed = g_strdup_printf ("enum %s", ctype->name);
168 break;
169 case CTYPE_POINTER:
170 if (ctype->base_type->type == CTYPE_FUNCTION)
171 /* anonymous function pointer */
172 node->unparsed = g_strdup ("GCallback");
173 else
175 GIdlNodeType *gibasetype = create_node_from_ctype (ctype->base_type);
176 node->unparsed = g_strdup_printf ("%s*", gibasetype->unparsed);
178 break;
179 case CTYPE_ARRAY:
181 GIdlNodeType *gibasetype = create_node_from_ctype (ctype->base_type);
182 node->unparsed = g_strdup_printf ("%s[]", gibasetype->unparsed);
183 break;
185 default:
186 node->unparsed = g_strdup ("unknown");
187 break;
190 return node;
193 static char *
194 str_replace (const char *str, const char *needle, const char *replacement)
196 char **strings = g_strsplit (str, needle, 0);
197 char *result = g_strjoinv (replacement, strings);
198 g_strfreev (strings);
199 return result;
202 static void
203 g_igenerator_process_properties (GIGenerator * igenerator,
204 GIdlNodeInterface * node, GType type_id)
206 int i;
207 guint n_properties;
208 GParamSpec **properties;
210 if (node->node.type == G_IDL_NODE_OBJECT)
212 GObjectClass *type_class = g_type_class_ref (type_id);
213 properties = g_object_class_list_properties (type_class, &n_properties);
215 else if (node->node.type == G_IDL_NODE_INTERFACE)
217 GTypeInterface *iface = g_type_default_interface_ref (type_id);
218 properties = g_object_interface_list_properties (iface, &n_properties);
220 else
222 g_assert_not_reached ();
225 for (i = 0; i < n_properties; i++)
227 GIdlNodeProperty *giprop;
229 /* ignore inherited properties */
230 if (properties[i]->owner_type != type_id)
232 continue;
234 giprop = (GIdlNodeProperty *) g_idl_node_new (G_IDL_NODE_PROPERTY);
235 giprop->node.name = properties[i]->name;
236 node->members =
237 g_list_insert_sorted (node->members, giprop,
238 (GCompareFunc) g_idl_node_cmp);
239 giprop->type = create_node_from_gtype (properties[i]->value_type);
240 giprop->readable = (properties[i]->flags & G_PARAM_READABLE) != 0;
241 giprop->writable = (properties[i]->flags & G_PARAM_WRITABLE) != 0;
242 giprop->construct = (properties[i]->flags & G_PARAM_CONSTRUCT) != 0;
243 giprop->construct_only =
244 (properties[i]->flags & G_PARAM_CONSTRUCT_ONLY) != 0;
248 static void
249 g_igenerator_process_signals (GIGenerator * igenerator,
250 GIdlNodeInterface * node, GType type_id)
252 int i, j;
253 guint n_signal_ids;
254 guint *signal_ids = g_signal_list_ids (type_id, &n_signal_ids);
256 for (i = 0; i < n_signal_ids; i++)
258 GSignalQuery signal_query;
259 GIdlNodeSignal *gisig;
260 GIdlNodeParam *giparam;
262 g_signal_query (signal_ids[i], &signal_query);
263 gisig = (GIdlNodeSignal *) g_idl_node_new (G_IDL_NODE_SIGNAL);
264 gisig->node.name = g_strdup (signal_query.signal_name);
265 node->members =
266 g_list_insert_sorted (node->members, gisig,
267 (GCompareFunc) g_idl_node_cmp);
269 gisig->run_first =
270 (signal_query.signal_flags & G_SIGNAL_RUN_FIRST) != 0;
271 gisig->run_last = (signal_query.signal_flags & G_SIGNAL_RUN_LAST) != 0;
272 gisig->run_cleanup =
273 (signal_query.signal_flags & G_SIGNAL_RUN_CLEANUP) != 0;
275 /* add sender parameter */
276 giparam = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
277 gisig->parameters = g_list_append (gisig->parameters, giparam);
278 giparam->node.name = g_strdup ("object");
279 giparam->type = create_node_from_gtype (type_id);
281 for (j = 0; j < signal_query.n_params; j++)
283 giparam = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
284 gisig->parameters = g_list_append (gisig->parameters, giparam);
285 giparam->node.name = g_strdup_printf ("p%d", j);
286 giparam->type = create_node_from_gtype (signal_query.param_types[j]);
288 gisig->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
289 gisig->result->type = create_node_from_gtype (signal_query.return_type);
293 static const gchar *
294 lookup_symbol (GIGenerator *igenerator, const gchar *typename)
296 const gchar *name =
297 g_hash_table_lookup (igenerator->symbols, typename);
299 if (!name)
301 g_printerr ("Unknown symbol: %s\n", typename);
302 return typename;
305 return name;
308 static void
309 g_igenerator_create_object (GIGenerator *igenerator,
310 const char *symbol_name,
311 GType type_id,
312 char *lower_case_prefix)
315 char *alt_lower_case_prefix;
316 GIdlNodeInterface *node;
317 guint n_type_interfaces;
318 GType *type_interfaces;
319 int i;
321 node = (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_OBJECT);
322 node->node.name = g_strdup (g_type_name (type_id));
323 igenerator->module->entries =
324 g_list_insert_sorted (igenerator->module->entries, node,
325 (GCompareFunc) g_idl_node_cmp);
326 g_hash_table_insert (igenerator->type_map, node->node.name,
327 node);
328 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
329 lower_case_prefix, node);
330 alt_lower_case_prefix = g_ascii_strdown (node->node.name, -1);
332 if (strcmp (alt_lower_case_prefix, lower_case_prefix) != 0)
334 /* alternative prefix sometimes necessary, for example
335 * for GdkWindow
337 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
338 alt_lower_case_prefix, node);
340 else
342 g_free (alt_lower_case_prefix);
345 node->gtype_name = node->node.name;
346 node->gtype_init = g_strdup (symbol_name);
347 node->parent = g_strdup (lookup_symbol (igenerator,
348 g_type_name (g_type_parent (type_id))));
350 type_interfaces = g_type_interfaces (type_id, &n_type_interfaces);
351 for (i = 0; i < n_type_interfaces; i++)
353 char *iface_name =
354 g_strdup (g_type_name (type_interfaces[i]));
355 /* workaround for AtkImplementorIface */
356 if (g_str_has_suffix (iface_name, "Iface"))
358 iface_name[strlen (iface_name) - strlen ("Iface")] =
359 '\0';
361 node->interfaces =
362 g_list_append (node->interfaces, iface_name);
365 g_hash_table_insert (igenerator->symbols,
366 g_strdup (node->gtype_name),
367 /* FIXME: Strip igenerator->namespace */
368 g_strdup (node->node.name));
370 g_igenerator_process_properties (igenerator, node, type_id);
371 g_igenerator_process_signals (igenerator, node, type_id);
374 static void
375 g_igenerator_create_interface (GIGenerator *igenerator,
376 const char *symbol_name,
377 GType type_id,
378 char *lower_case_prefix)
381 GIdlNodeInterface *node;
382 gboolean is_gobject = FALSE;
383 guint n_iface_prereqs;
384 GType *iface_prereqs;
385 int i;
387 node = (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_INTERFACE);
388 node->node.name = g_strdup (g_type_name (type_id));
390 /* workaround for AtkImplementorIface */
391 if (g_str_has_suffix (node->node.name, "Iface"))
393 node->node.name[strlen (node->node.name) -
394 strlen ("Iface")] = '\0';
396 igenerator->module->entries =
397 g_list_insert_sorted (igenerator->module->entries, node,
398 (GCompareFunc) g_idl_node_cmp);
399 g_hash_table_insert (igenerator->type_map, node->node.name,
400 node);
401 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
402 lower_case_prefix, node);
403 node->gtype_name = node->node.name;
404 node->gtype_init = g_strdup (symbol_name);
406 iface_prereqs =
407 g_type_interface_prerequisites (type_id, &n_iface_prereqs);
409 for (i = 0; i < n_iface_prereqs; i++)
411 if (g_type_fundamental (iface_prereqs[i]) == G_TYPE_OBJECT)
413 is_gobject = TRUE;
415 node->prerequisites =
416 g_list_append (node->prerequisites,
417 g_strdup (g_type_name (iface_prereqs[i])));
420 if (is_gobject)
421 g_igenerator_process_properties (igenerator, node, type_id);
422 else
423 g_type_default_interface_ref (type_id);
425 g_igenerator_process_signals (igenerator, node, type_id);
428 static void
429 g_igenerator_create_boxed (GIGenerator *igenerator,
430 const char *symbol_name,
431 GType type_id,
432 char *lower_case_prefix)
434 GIdlNodeBoxed *node =
435 (GIdlNodeBoxed *) g_idl_node_new (G_IDL_NODE_BOXED);
436 node->node.name = g_strdup (g_type_name (type_id));
437 igenerator->module->entries =
438 g_list_insert_sorted (igenerator->module->entries, node,
439 (GCompareFunc) g_idl_node_cmp);
440 g_hash_table_insert (igenerator->type_map, node->node.name,
441 node);
442 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
443 lower_case_prefix, node);
444 node->gtype_name = node->node.name;
445 node->gtype_init = g_strdup (symbol_name);
448 static void
449 g_igenerator_create_enum (GIGenerator *igenerator,
450 const char *symbol_name,
451 GType type_id,
452 char *lower_case_prefix)
454 GIdlNodeEnum *node;
455 int i;
456 GEnumClass *type_class;
458 node = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_ENUM);
459 node->node.name = g_strdup (g_type_name (type_id));
460 igenerator->module->entries =
461 g_list_insert_sorted (igenerator->module->entries, node,
462 (GCompareFunc) g_idl_node_cmp);
463 g_hash_table_insert (igenerator->type_map, node->node.name,
464 node);
465 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
466 lower_case_prefix, node);
467 node->gtype_name = node->node.name;
468 node->gtype_init = g_strdup (symbol_name);
470 type_class = g_type_class_ref (type_id);
472 for (i = 0; i < type_class->n_values; i++)
474 GIdlNodeValue *gival =
475 (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
476 node->values = g_list_append (node->values, gival);
477 gival->node.name =
478 g_strdup (type_class->values[i].value_name);
479 gival->value = type_class->values[i].value;
483 static void
484 g_igenerator_create_flags (GIGenerator *igenerator,
485 const char *symbol_name,
486 GType type_id,
487 char *lower_case_prefix)
489 GIdlNodeEnum *node;
490 GFlagsClass *type_class;
491 int i;
493 node = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_FLAGS);
494 node->node.name = g_strdup (g_type_name (type_id));
495 igenerator->module->entries =
496 g_list_insert_sorted (igenerator->module->entries, node,
497 (GCompareFunc) g_idl_node_cmp);
498 g_hash_table_insert (igenerator->type_map, node->node.name,
499 node);
500 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
501 lower_case_prefix, node);
502 node->gtype_name = node->node.name;
503 node->gtype_init = g_strdup (symbol_name);
505 type_class = g_type_class_ref (type_id);
507 for (i = 0; i < type_class->n_values; i++)
509 GIdlNodeValue *gival =
510 (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
511 node->values = g_list_append (node->values, gival);
512 gival->node.name =
513 g_strdup (type_class->values[i].value_name);
514 gival->value = type_class->values[i].value;
518 static gboolean
519 g_igenerator_process_module_symbol (GIGenerator *igenerator,
520 GModule *module,
521 const gchar *symbol_name)
523 TypeFunction type_fun;
524 GType type_id;
525 GType type_fundamental;
526 char *lower_case_prefix;
528 /* ignore already processed functions */
529 if (symbol_name == NULL)
530 return FALSE;
532 if (!g_module_symbol (module,
533 symbol_name,
534 (gpointer *) & type_fun))
535 return FALSE;
537 type_id = type_fun ();
538 type_fundamental = g_type_fundamental (type_id);
539 lower_case_prefix =
540 str_replace (g_strndup
541 (symbol_name,
542 strlen (symbol_name) - strlen ("_get_type")),
543 "_", "");
545 switch (type_fundamental)
547 case G_TYPE_OBJECT:
548 g_igenerator_create_object (igenerator, symbol_name, type_id,
549 lower_case_prefix);
550 break;
551 case G_TYPE_INTERFACE:
552 g_igenerator_create_interface (igenerator, symbol_name, type_id,
553 lower_case_prefix);
554 break;
555 case G_TYPE_BOXED:
556 g_igenerator_create_boxed (igenerator, symbol_name, type_id,
557 lower_case_prefix);
558 break;
559 case G_TYPE_ENUM:
560 g_igenerator_create_enum (igenerator, symbol_name, type_id,
561 lower_case_prefix);
562 break;
563 case G_TYPE_FLAGS:
564 g_igenerator_create_flags (igenerator, symbol_name, type_id,
565 lower_case_prefix);
566 break;
567 default:
568 break;
570 return TRUE;
573 static void
574 g_igenerator_process_module (GIGenerator * igenerator,
575 const gchar *filename)
577 GModule *module;
578 GList *l;
580 module = g_module_open (filename,
581 G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
583 if (module == NULL)
585 g_critical ("Couldn't open module: %s", filename);
586 return;
589 for (l = igenerator->get_type_symbols; l != NULL; l = l->next)
591 if (g_igenerator_process_module_symbol (igenerator,
592 module, (const char *)l->data))
593 /* symbol found, ignore in future iterations */
594 l->data = NULL;
598 static void
599 g_igenerator_process_function_symbol (GIGenerator * igenerator, CSymbol * sym)
601 GIdlNodeFunction *func;
602 char *last_underscore;
603 GList *param_l;
604 int i;
605 GSList *l;
607 func = (GIdlNodeFunction *) g_idl_node_new (G_IDL_NODE_FUNCTION);
609 /* check whether this is a type method */
610 last_underscore = strrchr (sym->ident, '_');
612 while (last_underscore != NULL)
614 char *prefix;
615 GIdlNode *node;
617 prefix = g_strndup (sym->ident, last_underscore - sym->ident);
618 prefix = str_replace (prefix, "_", "");
620 node = g_hash_table_lookup (igenerator->type_by_lower_case_prefix,
621 prefix);
622 if (node != NULL )
624 func->node.name = g_strdup (last_underscore + 1);
626 /* ignore get_type functions in registered types */
627 if (strcmp (func->node.name, "get_type") == 0)
628 return;
630 if ((node->type == G_IDL_NODE_OBJECT ||
631 node->type == G_IDL_NODE_BOXED) &&
632 g_str_has_prefix (func->node.name, "new"))
633 func->is_constructor = TRUE;
634 else
635 func->is_method = TRUE;
636 if (g_idl_node_can_have_member (node))
638 g_idl_node_add_member (node, func);
639 break;
641 else
643 /* reset function attributes */
644 g_free (func->node.name);
645 func->node.name = NULL;
646 func->is_constructor = FALSE;
647 func->is_method = FALSE;
650 else if (strcmp (igenerator->lower_case_namespace, prefix) == 0)
652 func->node.name = g_strdup (last_underscore + 1);
653 igenerator->module->entries =
654 g_list_insert_sorted (igenerator->module->entries, func,
655 (GCompareFunc) g_idl_node_cmp);
656 break;
658 last_underscore =
659 g_utf8_strrchr (sym->ident, last_underscore - sym->ident, '_');
662 /* create a namespace function if no prefix matches */
663 if (func->node.name == NULL)
665 func->node.name = sym->ident;
666 func->is_constructor = FALSE;
667 func->is_method = FALSE;
668 igenerator->module->entries =
669 g_list_insert_sorted (igenerator->module->entries, func,
670 (GCompareFunc) g_idl_node_cmp);
673 func->symbol = sym->ident;
674 func->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
675 func->result->type = create_node_from_ctype (sym->base_type->base_type);
677 for (param_l = sym->base_type->child_list, i = 1; param_l != NULL;
678 param_l = param_l->next, i++)
680 CSymbol *param_sym = param_l->data;
681 GIdlNodeParam *param;
683 param = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
684 param->type = create_node_from_ctype (param_sym->base_type);
686 if (param_sym->ident == NULL)
687 param->node.name = g_strdup_printf ("p%d", i);
688 else
689 param->node.name = param_sym->ident;
691 func->parameters = g_list_append (func->parameters, param);
694 for (l = sym->directives; l; l = l->next)
696 CDirective *directive = (CDirective*)l->data;
698 if (!strcmp (directive->name, "deprecated"))
699 func->deprecated = TRUE;
700 else
701 g_printerr ("Unknown function directive: %s\n",
702 directive->name);
706 static void
707 g_igenerator_process_unregistered_struct_typedef (GIGenerator * igenerator,
708 CSymbol * sym,
709 CType * struct_type)
711 GIdlNodeStruct *node =
712 (GIdlNodeStruct *) g_idl_node_new (G_IDL_NODE_STRUCT);
713 GList *member_l;
714 char *lower_case_prefix;
716 node->node.name = sym->ident;
717 igenerator->module->entries =
718 g_list_insert_sorted (igenerator->module->entries, node,
719 (GCompareFunc) g_idl_node_cmp);
720 lower_case_prefix = g_ascii_strdown (sym->ident, -1);
721 g_hash_table_insert (igenerator->type_map, sym->ident, node);
722 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
723 lower_case_prefix, node);
725 for (member_l = struct_type->child_list; member_l != NULL;
726 member_l = member_l->next)
728 CSymbol *member = member_l->data;
729 GIdlNodeField *gifield =
730 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
732 node->members = g_list_append (node->members, gifield);
733 gifield->node.name = member->ident;
734 gifield->type = create_node_from_ctype (member->base_type);
738 static void
739 g_igenerator_process_struct_typedef (GIGenerator * igenerator, CSymbol * sym)
741 CType *struct_type = sym->base_type;
742 gboolean opaque_type = FALSE;
743 GIdlNode *type;
745 if (struct_type->child_list == NULL)
747 CSymbol *struct_symbol;
748 g_assert (struct_type->name != NULL);
749 struct_symbol =
750 g_hash_table_lookup (igenerator->struct_or_union_or_enum_table,
751 struct_type->name);
752 if (struct_symbol != NULL)
754 struct_type = struct_symbol->base_type;
758 if (struct_type->child_list == NULL)
760 opaque_type = TRUE;
763 type = g_hash_table_lookup (igenerator->type_map, sym->ident);
764 if (type != NULL)
766 /* struct of a GTypeInstance */
767 if (!opaque_type
768 && (type->type == G_IDL_NODE_OBJECT
769 || type->type == G_IDL_NODE_INTERFACE))
771 GIdlNodeInterface *node = (GIdlNodeInterface *) type;
772 GList *member_l;
773 /* ignore first field => parent */
774 for (member_l = struct_type->child_list->next; member_l != NULL;
775 member_l = member_l->next)
777 CSymbol *member = member_l->data;
778 /* ignore private / reserved members */
779 if (member->ident[0] == '_'
780 || g_str_has_prefix (member->ident, "priv"))
782 continue;
784 GIdlNodeField *gifield =
785 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
786 node->members = g_list_append (node->members, gifield);
787 gifield->node.name = member->ident;
788 gifield->type = create_node_from_ctype (member->base_type);
791 else if (type->type == G_IDL_NODE_BOXED)
793 GIdlNodeBoxed *node = (GIdlNodeBoxed *) type;
794 GList *member_l;
795 for (member_l = struct_type->child_list; member_l != NULL;
796 member_l = member_l->next)
798 CSymbol *member = member_l->data;
799 GIdlNodeField *gifield =
800 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
801 node->members = g_list_append (node->members, gifield);
802 gifield->node.name = member->ident;
803 gifield->type = create_node_from_ctype (member->base_type);
807 else if (!opaque_type
808 && (g_str_has_suffix (sym->ident, "Class")
809 || g_str_has_suffix (sym->ident, "Iface")
810 || g_str_has_suffix (sym->ident, "Interface")))
812 char *base_name;
813 GList *member_l;
814 GIdlNodeInterface *node;
816 if (g_str_has_suffix (sym->ident, "Interface"))
818 base_name =
819 g_strndup (sym->ident,
820 strlen (sym->ident) - strlen ("Interface"));
822 else
824 base_name =
825 g_strndup (sym->ident, strlen (sym->ident) - strlen ("Class"));
827 type = g_hash_table_lookup (igenerator->type_map, base_name);
828 if (type == NULL
829 || (type->type != G_IDL_NODE_OBJECT
830 && type->type != G_IDL_NODE_INTERFACE))
832 g_igenerator_process_unregistered_struct_typedef (igenerator, sym,
833 struct_type);
834 return;
836 node = (GIdlNodeInterface *) type;
838 /* ignore first field => parent */
839 for (member_l = struct_type->child_list->next; member_l != NULL;
840 member_l = member_l->next)
842 CSymbol *member = member_l->data;
843 /* ignore private / reserved members */
844 if (member->ident[0] == '_')
846 continue;
848 if (member->base_type->type == CTYPE_POINTER
849 && member->base_type->base_type->type == CTYPE_FUNCTION)
851 /* ignore default handlers of signals */
852 gboolean found_signal = FALSE;
853 GList *type_member_l;
854 GList *param_l;
855 int i;
856 GIdlNodeVFunc *givfunc;
858 for (type_member_l = node->members; type_member_l != NULL;
859 type_member_l = type_member_l->next)
861 GIdlNode *type_member = type_member_l->data;
862 char *normalized_name =
863 str_replace (type_member->name, "-", "_");
864 if (type_member->type == G_IDL_NODE_SIGNAL
865 && strcmp (normalized_name, member->ident) == 0)
867 GList *vfunc_param_l;
868 GList *sig_param_l;
869 GIdlNodeSignal *sig = (GIdlNodeSignal *) type_member;
870 found_signal = TRUE;
871 /* set signal parameter names */
872 for (vfunc_param_l =
873 member->base_type->base_type->child_list,
874 sig_param_l = sig->parameters;
875 vfunc_param_l != NULL && sig_param_l != NULL;
876 vfunc_param_l = vfunc_param_l->next, sig_param_l =
877 sig_param_l->next)
879 CSymbol *vfunc_param = vfunc_param_l->data;
880 GIdlNodeParam *sig_param = sig_param_l->data;
881 if (vfunc_param->ident != NULL)
883 g_free (sig_param->node.name);
884 sig_param->node.name =
885 g_strdup (vfunc_param->ident);
888 break;
891 if (found_signal)
893 continue;
896 givfunc = (GIdlNodeVFunc *) g_idl_node_new (G_IDL_NODE_VFUNC);
897 givfunc->node.name = member->ident;
898 node->members =
899 g_list_insert_sorted (node->members, givfunc,
900 (GCompareFunc) g_idl_node_cmp);
901 givfunc->result =
902 (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
903 givfunc->result->type =
904 create_node_from_ctype (member->base_type->base_type->base_type);
905 for (param_l = member->base_type->base_type->child_list, i = 1;
906 param_l != NULL; param_l = param_l->next, i++)
908 CSymbol *param_sym = param_l->data;
909 GIdlNodeParam *param =
910 (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
911 if (param_sym->ident == NULL)
913 param->node.name = g_strdup_printf ("p%d", i);
915 else
917 param->node.name = param_sym->ident;
919 param->type = create_node_from_ctype (param_sym->base_type);
920 givfunc->parameters =
921 g_list_append (givfunc->parameters, param);
926 else if (g_str_has_suffix (sym->ident, "Private"))
928 /* ignore private structs */
930 else
932 g_igenerator_process_unregistered_struct_typedef (igenerator, sym,
933 struct_type);
937 static void
938 g_igenerator_process_union_typedef (GIGenerator * igenerator, CSymbol * sym)
940 CType *union_type = sym->base_type;
941 gboolean opaque_type = FALSE;
942 GIdlNode *type;
944 if (union_type->child_list == NULL)
946 g_assert (union_type->name != NULL);
947 CSymbol *union_symbol =
948 g_hash_table_lookup (igenerator->struct_or_union_or_enum_table,
949 union_type->name);
950 if (union_symbol != NULL)
952 union_type = union_symbol->base_type;
955 if (union_type->child_list == NULL)
957 opaque_type = TRUE;
960 type = g_hash_table_lookup (igenerator->type_map, sym->ident);
961 if (type != NULL)
963 g_assert (type->type == G_IDL_NODE_BOXED);
964 GIdlNodeBoxed *node = (GIdlNodeBoxed *) type;
965 GList *member_l;
966 for (member_l = union_type->child_list; member_l != NULL;
967 member_l = member_l->next)
969 CSymbol *member = member_l->data;
970 GIdlNodeField *gifield =
971 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
972 node->members = g_list_append (node->members, gifield);
973 gifield->node.name = member->ident;
974 gifield->type = create_node_from_ctype (member->base_type);
977 else
979 GIdlNodeUnion *node =
980 (GIdlNodeUnion *) g_idl_node_new (G_IDL_NODE_UNION);
981 char *lower_case_prefix;
982 GList *member_l;
984 node->node.name = sym->ident;
985 igenerator->module->entries =
986 g_list_insert_sorted (igenerator->module->entries, node,
987 (GCompareFunc) g_idl_node_cmp);
988 lower_case_prefix = g_ascii_strdown (sym->ident, -1);
989 g_hash_table_insert (igenerator->type_map, sym->ident, node);
990 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
991 lower_case_prefix, node);
993 node->node.name = sym->ident;
994 for (member_l = union_type->child_list; member_l != NULL;
995 member_l = member_l->next)
997 CSymbol *member = member_l->data;
998 GIdlNodeField *gifield =
999 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
1000 node->members = g_list_append (node->members, gifield);
1001 gifield->node.name = member->ident;
1002 gifield->type = create_node_from_ctype (member->base_type);
1007 static void
1008 g_igenerator_process_enum_typedef (GIGenerator * igenerator, CSymbol * sym)
1010 CType *enum_type;
1011 GList *member_l;
1012 GIdlNodeEnum *node;
1013 CSymbol *enum_symbol;
1015 enum_type = sym->base_type;
1016 if (enum_type->child_list == NULL)
1018 g_assert (enum_type->name != NULL);
1019 enum_symbol =
1020 g_hash_table_lookup (igenerator->struct_or_union_or_enum_table,
1021 enum_type->name);
1022 if (enum_symbol != NULL)
1024 enum_type = enum_symbol->base_type;
1027 if (enum_type->child_list == NULL)
1029 /* opaque type */
1030 return;
1033 node = g_hash_table_lookup (igenerator->type_map, sym->ident);
1034 if (node != NULL)
1036 return;
1039 node = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_ENUM);
1040 node->node.name = sym->ident;
1041 igenerator->module->entries =
1042 g_list_insert_sorted (igenerator->module->entries, node,
1043 (GCompareFunc) g_idl_node_cmp);
1045 for (member_l = enum_type->child_list; member_l != NULL;
1046 member_l = member_l->next)
1048 CSymbol *member = member_l->data;
1049 GIdlNodeValue *gival =
1050 (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
1051 node->values = g_list_append (node->values, gival);
1052 gival->node.name = member->ident;
1053 gival->value = member->const_int;
1057 static void
1058 g_igenerator_process_function_typedef (GIGenerator * igenerator,
1059 CSymbol * sym)
1061 GList *param_l;
1062 int i;
1064 /* handle callback types */
1065 GIdlNodeFunction *gifunc =
1066 (GIdlNodeFunction *) g_idl_node_new (G_IDL_NODE_CALLBACK);
1068 gifunc->node.name = sym->ident;
1069 igenerator->module->entries =
1070 g_list_insert_sorted (igenerator->module->entries, gifunc,
1071 (GCompareFunc) g_idl_node_cmp);
1073 gifunc->symbol = sym->ident;
1074 gifunc->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
1075 gifunc->result->type =
1076 create_node_from_ctype (sym->base_type->base_type->base_type);
1078 for (param_l = sym->base_type->base_type->child_list, i = 1;
1079 param_l != NULL; param_l = param_l->next, i++)
1081 CSymbol *param_sym = param_l->data;
1082 GIdlNodeParam *param =
1083 (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
1084 if (param_sym->ident == NULL)
1086 param->node.name = g_strdup_printf ("p%d", i);
1088 else
1090 param->node.name = param_sym->ident;
1092 param->type = create_node_from_ctype (param_sym->base_type);
1093 gifunc->parameters = g_list_append (gifunc->parameters, param);
1097 static void
1098 g_igenerator_process_constant (GIGenerator * igenerator, CSymbol * sym)
1100 GIdlNodeConstant *giconst =
1101 (GIdlNodeConstant *) g_idl_node_new (G_IDL_NODE_CONSTANT);
1102 giconst->node.name = sym->ident;
1103 igenerator->module->entries =
1104 g_list_insert_sorted (igenerator->module->entries, giconst,
1105 (GCompareFunc) g_idl_node_cmp);
1107 giconst->type = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
1108 if (sym->const_int_set)
1110 giconst->type->unparsed = g_strdup ("int");
1111 giconst->value = g_strdup_printf ("%d", sym->const_int);
1113 else if (sym->const_string != NULL)
1115 giconst->type->unparsed = g_strdup ("char*");
1116 giconst->value = sym->const_string;
1120 static void
1121 g_igenerator_process_symbols (GIGenerator * igenerator)
1123 GList *l;
1124 /* process type symbols first to ensure complete type hashtables */
1125 /* type symbols */
1126 for (l = igenerator->symbol_list; l != NULL; l = l->next)
1128 CSymbol *sym = l->data;
1129 if (sym->ident[0] == '_')
1131 /* ignore private / reserved symbols */
1132 continue;
1134 if (sym->type == CSYMBOL_TYPE_TYPEDEF)
1136 if (sym->base_type->type == CTYPE_STRUCT)
1138 g_igenerator_process_struct_typedef (igenerator, sym);
1140 else if (sym->base_type->type == CTYPE_UNION)
1142 g_igenerator_process_union_typedef (igenerator, sym);
1144 else if (sym->base_type->type == CTYPE_ENUM)
1146 g_igenerator_process_enum_typedef (igenerator, sym);
1148 else if (sym->base_type->type == CTYPE_POINTER
1149 && sym->base_type->base_type->type == CTYPE_FUNCTION)
1151 g_igenerator_process_function_typedef (igenerator, sym);
1153 else
1155 GIdlNodeStruct *node =
1156 (GIdlNodeStruct *) g_idl_node_new (G_IDL_NODE_STRUCT);
1157 char *lower_case_prefix;
1159 node->node.name = sym->ident;
1160 igenerator->module->entries =
1161 g_list_insert_sorted (igenerator->module->entries, node,
1162 (GCompareFunc) g_idl_node_cmp);
1163 lower_case_prefix = g_ascii_strdown (sym->ident, -1);
1164 g_hash_table_insert (igenerator->type_map, sym->ident, node);
1165 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
1166 lower_case_prefix, node);
1170 /* other symbols */
1171 for (l = igenerator->symbol_list; l != NULL; l = l->next)
1173 CSymbol *sym = l->data;
1174 if (sym->ident[0] == '_')
1176 /* ignore private / reserved symbols */
1177 continue;
1179 if (sym->type == CSYMBOL_TYPE_FUNCTION)
1181 g_igenerator_process_function_symbol (igenerator, sym);
1183 else if (sym->type == CSYMBOL_TYPE_CONST)
1185 g_igenerator_process_constant (igenerator, sym);
1190 void
1191 g_igenerator_add_symbol (GIGenerator * igenerator, CSymbol * symbol)
1193 GList *l;
1195 /* only add symbols of main file */
1196 gboolean found_filename = FALSE;
1198 if (igenerator->current_filename)
1200 for (l = igenerator->filenames; l != NULL; l = l->next)
1202 if (strcmp (l->data, igenerator->current_filename) == 0)
1204 found_filename = TRUE;
1205 break;
1210 symbol->directives = g_slist_reverse (igenerator->directives);
1211 igenerator->directives = NULL;
1213 /* that's not very optimized ! */
1214 for (l = igenerator->symbol_list; l != NULL; l = l->next)
1216 CSymbol *other_symbol = (CSymbol *)l->data;
1217 if (g_str_equal (other_symbol->ident, symbol->ident)
1218 && other_symbol->type == symbol->type)
1220 g_printerr ("Dropping %s duplicate\n", symbol->ident);
1221 return;
1225 if (found_filename || igenerator->macro_scan)
1227 igenerator->symbol_list =
1228 g_list_prepend (igenerator->symbol_list, symbol);
1231 if (symbol->type == CSYMBOL_TYPE_TYPEDEF)
1234 g_hash_table_insert (igenerator->typedef_table, symbol->ident, symbol);
1236 else if (symbol->type == CSYMBOL_TYPE_STRUCT
1237 || symbol->type == CSYMBOL_TYPE_UNION
1238 || symbol->type == CSYMBOL_TYPE_ENUM)
1240 g_hash_table_insert (igenerator->struct_or_union_or_enum_table,
1241 symbol->ident, symbol);
1245 gboolean
1246 g_igenerator_is_typedef (GIGenerator * igenerator, const char *name)
1248 gboolean b = g_hash_table_lookup (igenerator->typedef_table, name) != NULL;
1249 return b;
1252 void
1253 g_igenerator_generate (GIGenerator * igenerator,
1254 const gchar * filename,
1255 GList *libraries)
1257 GList *l;
1259 for (l = igenerator->symbol_list; l != NULL; l = l->next)
1261 CSymbol *sym = l->data;
1262 if (sym->type == CSYMBOL_TYPE_FUNCTION
1263 && g_str_has_suffix (sym->ident, "_get_type"))
1265 if (sym->base_type->child_list == NULL)
1267 // ignore get_type functions with parameters
1268 igenerator->get_type_symbols =
1269 g_list_prepend (igenerator->get_type_symbols, sym->ident);
1274 /* ensure to initialize GObject */
1275 g_type_class_ref (G_TYPE_OBJECT);
1277 for (l = libraries; l; l = l->next)
1278 g_igenerator_process_module (igenerator, (const gchar*)l->data);
1280 g_igenerator_process_symbols (igenerator);
1282 g_idl_writer_save_file (igenerator->module, filename);
1285 static int
1286 eat_hspace (FILE * f)
1288 int c;
1291 c = fgetc (f);
1293 while (c == ' ' || c == '\t');
1294 return c;
1297 static int
1298 eat_line (FILE * f, int c)
1300 while (c != EOF && c != '\n')
1302 c = fgetc (f);
1304 if (c == '\n')
1306 c = fgetc (f);
1307 if (c == ' ' || c == '\t')
1309 c = eat_hspace (f);
1312 return c;
1315 static int
1316 read_identifier (FILE * f, int c, char **identifier)
1318 GString *id = g_string_new ("");
1319 while (isalnum (c) || c == '_')
1321 g_string_append_c (id, c);
1322 c = fgetc (f);
1324 *identifier = g_string_free (id, FALSE);
1325 return c;
1328 static void
1329 g_igenerator_parse_macros (GIGenerator * igenerator)
1331 GError *error = NULL;
1332 char *tmp_name = NULL;
1333 FILE *fmacros =
1334 fdopen (g_file_open_tmp ("gen-introspect-XXXXXX.h", &tmp_name, &error),
1335 "w+");
1336 g_unlink (tmp_name);
1338 GList *l;
1339 for (l = igenerator->filenames; l != NULL; l = l->next)
1341 FILE *f = fopen (l->data, "r");
1342 int line = 1;
1344 GString *define_line;
1345 char *str;
1346 gboolean error_line = FALSE;
1347 int c = eat_hspace (f);
1348 while (c != EOF)
1350 if (c != '#')
1352 /* ignore line */
1353 c = eat_line (f, c);
1354 line++;
1355 continue;
1358 /* print current location */
1359 str = g_strescape (l->data, "");
1360 fprintf (fmacros, "# %d \"%s\"\n", line, str);
1361 g_free (str);
1363 c = eat_hspace (f);
1364 c = read_identifier (f, c, &str);
1365 if (strcmp (str, "define") != 0 || (c != ' ' && c != '\t'))
1367 g_free (str);
1368 /* ignore line */
1369 c = eat_line (f, c);
1370 line++;
1371 continue;
1373 g_free (str);
1374 c = eat_hspace (f);
1375 c = read_identifier (f, c, &str);
1376 if (strlen (str) == 0 || (c != ' ' && c != '\t' && c != '('))
1378 g_free (str);
1379 /* ignore line */
1380 c = eat_line (f, c);
1381 line++;
1382 continue;
1384 define_line = g_string_new ("#define ");
1385 g_string_append (define_line, str);
1386 g_free (str);
1387 if (c == '(')
1389 while (c != ')')
1391 g_string_append_c (define_line, c);
1392 c = fgetc (f);
1393 if (c == EOF || c == '\n')
1395 error_line = TRUE;
1396 break;
1399 if (error_line)
1401 g_string_free (define_line, TRUE);
1402 /* ignore line */
1403 c = eat_line (f, c);
1404 line++;
1405 continue;
1408 g_assert (c == ')');
1409 g_string_append_c (define_line, c);
1410 c = fgetc (f);
1412 /* found function-like macro */
1413 fprintf (fmacros, "%s\n", define_line->str);
1415 g_string_free (define_line, TRUE);
1416 /* ignore rest of line */
1417 c = eat_line (f, c);
1418 line++;
1419 continue;
1421 if (c != ' ' && c != '\t')
1423 g_string_free (define_line, TRUE);
1424 /* ignore line */
1425 c = eat_line (f, c);
1426 line++;
1427 continue;
1429 while (c != EOF && c != '\n')
1431 g_string_append_c (define_line, c);
1432 c = fgetc (f);
1433 if (c == '\\')
1435 c = fgetc (f);
1436 if (c == '\n')
1438 /* fold lines when seeing backslash new-line sequence */
1439 c = fgetc (f);
1441 else
1443 g_string_append_c (define_line, '\\');
1448 /* found object-like macro */
1449 fprintf (fmacros, "%s\n", define_line->str);
1451 c = eat_line (f, c);
1452 line++;
1455 fclose (f);
1458 igenerator->macro_scan = TRUE;
1459 rewind (fmacros);
1461 g_igenerator_parse_file (igenerator, fmacros);
1462 fclose (fmacros);
1464 igenerator->macro_scan = FALSE;
1467 static void
1468 g_igenerator_add_module (GIGenerator *igenerator,
1469 GIdlModule *module)
1471 GList *l;
1473 for (l = module->entries; l; l = l->next)
1475 GIdlNode *node = (GIdlNode*)l->data;
1477 if (node->type == G_IDL_NODE_OBJECT)
1479 GIdlNodeInterface *object = (GIdlNodeInterface*)node;
1480 gchar *name;
1481 if (strcmp(module->name, igenerator->namespace) == 0)
1482 name = g_strdup (node->name);
1483 else
1484 name = g_strdup_printf ("%s.%s", module->name, node->name);
1485 g_hash_table_insert (igenerator->symbols,
1486 g_strdup (object->gtype_name),
1487 name);
1492 static void
1493 g_igenerator_add_include_idl (GIGenerator *igenerator,
1494 const gchar *filename)
1496 GList *l;
1497 GList *modules;
1499 GError *error = NULL;
1501 modules = g_idl_parse_file (filename, &error);
1502 if (error)
1504 g_printerr ("An error occurred while parsing %s: %s\n",
1505 filename, error->message);
1506 return;
1509 for (l = modules; l; l = l->next)
1511 GIdlModule *module = (GIdlModule*)l->data;
1512 g_igenerator_add_module (igenerator, module);
1516 static FILE *
1517 g_igenerator_start_preprocessor (GIGenerator *igenerator,
1518 GList *cpp_options)
1520 int cpp_out = -1, cpp_in = -1;
1521 int cpp_argc = 0;
1522 char **cpp_argv;
1523 GList *l;
1524 GError *error = NULL;
1525 FILE *f, *out;
1526 GPid pid;
1527 int status = 0;
1528 int read_bytes;
1529 int i;
1530 char **buffer;
1531 int tmp;
1532 char *tmpname;
1534 cpp_argv = g_new0 (char *, g_list_length (cpp_options) + 5);
1535 cpp_argv[cpp_argc++] = "cpp";
1536 cpp_argv[cpp_argc++] = "-C";
1538 /* Disable GCC extensions as we cannot parse them yet */
1539 cpp_argv[cpp_argc++] = "-U__GNUC__";
1541 /* Help system headers cope with the lack of __GNUC__ by pretending to be lint */
1542 cpp_argv[cpp_argc++] = "-Dlint";
1544 for (l = cpp_options; l; l = l->next)
1545 cpp_argv[cpp_argc++] = (char*)l->data;
1547 cpp_argv[cpp_argc++] = NULL;
1549 if (igenerator->verbose)
1551 GString *args = g_string_new ("");
1553 for (i = 0; i < cpp_argc - 1; i++)
1555 g_string_append (args, cpp_argv[i]);
1556 if (i < cpp_argc - 2)
1557 g_string_append_c (args, ' ');
1560 g_printf ("Executing '%s'\n", args->str);
1561 g_string_free (args, FALSE);
1563 g_spawn_async_with_pipes (NULL, cpp_argv, NULL,
1564 G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
1565 NULL, NULL, &pid, &cpp_in, &cpp_out, NULL, &error);
1567 g_free (cpp_argv);
1568 if (error != NULL)
1570 g_error ("%s", error->message);
1571 return NULL;
1574 f = fdopen (cpp_in, "w");
1576 for (l = igenerator->filenames; l != NULL; l = l->next)
1578 if (igenerator->verbose)
1579 g_printf ("Pre-processing %s\n", (char*)l->data);
1581 fprintf (f, "#include <%s>\n", (char *) l->data);
1585 fclose (f);
1586 close (cpp_in);
1588 tmp = g_file_open_tmp (NULL, &tmpname, &error);
1589 if (error != NULL)
1591 g_error ("%s", error->message);
1592 return NULL;
1595 buffer = g_malloc0 (4096 * sizeof (char));
1597 while (1)
1599 read_bytes = read (cpp_out, buffer, 4096);
1600 if (read_bytes == 0)
1601 break;
1602 write (tmp, buffer, read_bytes);
1605 g_free (buffer);
1607 close (cpp_out);
1609 #ifndef _WIN32
1610 if (waitpid (pid, &status, 0) > 0)
1611 #else
1612 /* We don't want to include <windows.h> as it clashes horribly
1613 * with token names from scannerparser.h. So just declare
1614 * WaitForSingleObject, GetExitCodeProcess and INFINITE here.
1616 extern unsigned long __stdcall WaitForSingleObject(void*, int);
1617 extern int __stdcall GetExitCodeProcess(void*, int*);
1618 #define INFINITE 0xffffffff
1620 WaitForSingleObject (pid, INFINITE);
1622 if (GetExitCodeProcess (pid, &status))
1623 #endif
1625 if (status != 0)
1627 g_spawn_close_pid (pid);
1628 #ifndef _WIN32
1629 kill (pid, SIGKILL);
1630 #endif
1632 g_error ("cpp returned error code: %d\n", status);
1633 unlink (tmpname);
1634 g_free (tmpname);
1635 return NULL;
1639 f = fdopen (tmp, "r");
1640 if (!f)
1642 g_error ("%s", strerror (errno));
1643 unlink (tmpname);
1644 g_free (tmpname);
1645 return NULL;
1647 rewind (f);
1648 unlink (tmpname);
1649 g_free (tmpname);
1651 return f;
1655 void
1656 g_igenerator_set_verbose (GIGenerator *igenerator,
1657 gboolean verbose)
1659 igenerator->verbose = verbose;
1663 main (int argc, char **argv)
1665 GOptionContext *ctx;
1666 gchar *namespace = NULL;
1667 gchar *shared_library = NULL;
1668 gchar **include_idls = NULL;
1669 gchar *output = NULL;
1670 gboolean verbose = FALSE;
1672 GIGenerator *igenerator;
1673 int gopt_argc, i;
1674 char **gopt_argv;
1675 GList *filenames = NULL;
1676 GError *error = NULL;
1677 GList *l, *libraries = NULL;
1678 GList *cpp_options = NULL;
1679 char *buffer;
1680 size_t size;
1681 FILE *tmp;
1682 GOptionEntry entries[] =
1684 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
1685 "Be verbose" },
1686 { "output", 'o', 0, G_OPTION_ARG_STRING, &output,
1687 "write output here instead of stdout", "FILE" },
1688 { "namespace", 'n', 0, G_OPTION_ARG_STRING, &namespace,
1689 "Namespace of the module, like 'Gtk'", "NAMESPACE" },
1690 { "shared-library", 0, 0, G_OPTION_ARG_FILENAME, &shared_library,
1691 "Shared library which contains the symbols", "FILE" },
1692 { "include-idl", 0, 0, G_OPTION_ARG_STRING_ARRAY, &include_idls,
1693 "Other gidls to include", "IDL" },
1694 { NULL }
1697 gopt_argc = 1;
1698 gopt_argv = (char**)g_malloc (argc * sizeof (char*));
1699 gopt_argv[0] = argv[0];
1701 for (i = 1; i < argc; i++)
1703 if (argv[i][0] == '-')
1705 switch (argv[i][1])
1707 case 'I':
1708 case 'D':
1709 case 'U':
1710 cpp_options = g_list_prepend (cpp_options, g_strdup (argv[i]));
1711 break;
1712 case 'p':
1713 /*ignore -pthread*/
1714 if (0==strcmp("-pthread", argv[i]))
1715 break;
1716 default:
1717 gopt_argv[gopt_argc++] = argv[i];
1718 break;
1721 else if (g_str_has_suffix (argv[i], ".h"))
1723 gchar* filename;
1725 if (!g_path_is_absolute (argv[i]))
1727 gchar *dir = g_get_current_dir ();
1728 filename = g_strdup_printf ("%s/%s", dir,
1729 argv[i]);
1730 g_free (dir);
1732 else
1733 filename = g_strdup (argv[i]);
1735 filenames = g_list_append (filenames, g_realpath(filename));
1736 g_free(filename);
1738 else if (g_str_has_suffix (argv[i], ".la") ||
1739 g_str_has_suffix (argv[i], ".so") ||
1740 g_str_has_suffix (argv[i], ".dll"))
1742 libraries = g_list_prepend (libraries, g_strdup (argv[i]));
1744 else
1746 gopt_argv[gopt_argc++] = argv[i];
1750 ctx = g_option_context_new ("");
1751 g_option_context_add_main_entries (ctx, entries, NULL);
1753 if (!g_option_context_parse (ctx, &gopt_argc, &gopt_argv, &error))
1755 g_printerr ("Parsing error: %s\n", error->message);
1756 g_option_context_free (ctx);
1757 return 1;
1760 g_free (gopt_argv);
1761 g_option_context_free (ctx);
1763 if (!namespace)
1765 g_printerr ("ERROR: namespace must be specified\n");
1766 return 1;
1769 igenerator = g_igenerator_new (namespace, shared_library);
1771 if (verbose)
1772 g_igenerator_set_verbose (igenerator, TRUE);
1774 if (!filenames)
1776 g_printerr ("ERROR: Need at least one header file.\n");
1777 g_igenerator_free (igenerator);
1778 return 1;
1780 igenerator->filenames = filenames;
1781 cpp_options = g_list_reverse (cpp_options);
1782 libraries = g_list_reverse (libraries);
1784 if (include_idls)
1786 for (i = 0; i < g_strv_length (include_idls); i++)
1787 g_igenerator_add_include_idl (igenerator, include_idls[i]);
1790 tmp = g_igenerator_start_preprocessor (igenerator, cpp_options);
1791 if (!tmp)
1793 g_error ("ERROR in pre-processor.\n");
1794 g_igenerator_free (igenerator);
1795 return 1;
1798 if (!g_igenerator_parse_file (igenerator, tmp))
1800 fclose (tmp);
1801 g_igenerator_free (igenerator);
1802 return 1;
1805 g_igenerator_parse_macros (igenerator);
1807 g_igenerator_generate (igenerator, output, libraries);
1809 fclose (tmp);
1810 g_igenerator_free (igenerator);
1812 return 0;