1 /* GObject introspection: scanner
2 *
3 * Copyright (C) 2007-2008 Jürg Billeter
4 * Copyright (C) 2007 Johan Dahlin
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 *
21 * Author:
22 * Jürg Billeter <j@bitron.ch>
23 */
24
25 #include <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"
41
42 #ifndef _WIN32
43 #include <sys/wait.h> /* waitpid */
44 #endif
45
46
47 typedef GType (*TypeFunction) (void);
48
49 static void g_igenerator_parse_macros (GIGenerator * igenerator);
50
51 static GIGenerator *
g_igenerator_new(const gchar * namespace,const gchar * shared_library)52 g_igenerator_new (const gchar *namespace,
53 const gchar *shared_library)
54 {
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);
61
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);
65
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);
70
71 return igenerator;
72 }
73
74 static void
g_igenerator_free(GIGenerator * generator)75 g_igenerator_free (GIGenerator *generator)
76 {
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);
95 }
96
97 static GIdlNodeType *
create_node_from_gtype(GType type_id)98 create_node_from_gtype (GType type_id)
99 {
100 GIdlNodeType *node;
101 GType fundamental;
102
103 node = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
104
105 fundamental = g_type_fundamental (type_id);
106 switch (fundamental)
107 {
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;
125 }
126
127 return node;
128 }
129
130 static GIdlNodeType *
create_node_from_ctype(CType * ctype)131 create_node_from_ctype (CType * ctype)
132 {
133 GIdlNodeType *node;
134
135 node = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
136
137 switch (ctype->type)
138 {
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
174 {
175 GIdlNodeType *gibasetype = create_node_from_ctype (ctype->base_type);
176 node->unparsed = g_strdup_printf ("%s*", gibasetype->unparsed);
177 }
178 break;
179 case CTYPE_ARRAY:
180 {
181 GIdlNodeType *gibasetype = create_node_from_ctype (ctype->base_type);
182 node->unparsed = g_strdup_printf ("%s[]", gibasetype->unparsed);
183 break;
184 }
185 default:
186 node->unparsed = g_strdup ("unknown");
187 break;
188 }
189
190 return node;
191 }
192
193 static char *
str_replace(const char * str,const char * needle,const char * replacement)194 str_replace (const char *str, const char *needle, const char *replacement)
195 {
196 char **strings = g_strsplit (str, needle, 0);
197 char *result = g_strjoinv (replacement, strings);
198 g_strfreev (strings);
199 return result;
200 }
201
202 static void
g_igenerator_process_properties(GIGenerator * igenerator,GIdlNodeInterface * node,GType type_id)203 g_igenerator_process_properties (GIGenerator * igenerator,
204 GIdlNodeInterface * node, GType type_id)
205 {
206 int i;
207 guint n_properties;
208 GParamSpec **properties;
209
210 if (node->node.type == G_IDL_NODE_OBJECT)
211 {
212 GObjectClass *type_class = g_type_class_ref (type_id);
213 properties = g_object_class_list_properties (type_class, &n_properties);
214 }
215 else if (node->node.type == G_IDL_NODE_INTERFACE)
216 {
217 GTypeInterface *iface = g_type_default_interface_ref (type_id);
218 properties = g_object_interface_list_properties (iface, &n_properties);
219 }
220 else
221 {
222 g_assert_not_reached ();
223 }
224
225 for (i = 0; i < n_properties; i++)
226 {
227 GIdlNodeProperty *giprop;
228
229 /* ignore inherited properties */
230 if (properties[i]->owner_type != type_id)
231 {
232 continue;
233 }
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;
245 }
246 }
247
248 static void
g_igenerator_process_signals(GIGenerator * igenerator,GIdlNodeInterface * node,GType type_id)249 g_igenerator_process_signals (GIGenerator * igenerator,
250 GIdlNodeInterface * node, GType type_id)
251 {
252 int i, j;
253 guint n_signal_ids;
254 guint *signal_ids = g_signal_list_ids (type_id, &n_signal_ids);
255
256 for (i = 0; i < n_signal_ids; i++)
257 {
258 GSignalQuery signal_query;
259 GIdlNodeSignal *gisig;
260 GIdlNodeParam *giparam;
261
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);
268
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;
274
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);
280
281 for (j = 0; j < signal_query.n_params; j++)
282 {
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]);
287 }
288 gisig->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
289 gisig->result->type = create_node_from_gtype (signal_query.return_type);
290 }
291 }
292
293 static const gchar *
lookup_symbol(GIGenerator * igenerator,const gchar * typename)294 lookup_symbol (GIGenerator *igenerator, const gchar *typename)
295 {
296 const gchar *name =
297 g_hash_table_lookup (igenerator->symbols, typename);
298
299 if (!name)
300 {
301 g_printerr ("Unknown symbol: %s\n", typename);
302 return typename;
303 }
304
305 return name;
306 }
307
308 static void
g_igenerator_create_object(GIGenerator * igenerator,const char * symbol_name,GType type_id,char * lower_case_prefix)309 g_igenerator_create_object (GIGenerator *igenerator,
310 const char *symbol_name,
311 GType type_id,
312 char *lower_case_prefix)
313
314 {
315 char *alt_lower_case_prefix;
316 GIdlNodeInterface *node;
317 guint n_type_interfaces;
318 GType *type_interfaces;
319 int i;
320
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);
331
332 if (strcmp (alt_lower_case_prefix, lower_case_prefix) != 0)
333 {
334 /* alternative prefix sometimes necessary, for example
335 * for GdkWindow
336 */
337 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
338 alt_lower_case_prefix, node);
339 }
340 else
341 {
342 g_free (alt_lower_case_prefix);
343 }
344
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))));
349
350 type_interfaces = g_type_interfaces (type_id, &n_type_interfaces);
351 for (i = 0; i < n_type_interfaces; i++)
352 {
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"))
357 {
358 iface_name[strlen (iface_name) - strlen ("Iface")] =
359 '\0';
360 }
361 node->interfaces =
362 g_list_append (node->interfaces, iface_name);
363 }
364
365 g_hash_table_insert (igenerator->symbols,
366 g_strdup (node->gtype_name),
367 /* FIXME: Strip igenerator->namespace */
368 g_strdup (node->node.name));
369
370 g_igenerator_process_properties (igenerator, node, type_id);
371 g_igenerator_process_signals (igenerator, node, type_id);
372 }
373
374 static void
g_igenerator_create_interface(GIGenerator * igenerator,const char * symbol_name,GType type_id,char * lower_case_prefix)375 g_igenerator_create_interface (GIGenerator *igenerator,
376 const char *symbol_name,
377 GType type_id,
378 char *lower_case_prefix)
379
380 {
381 GIdlNodeInterface *node;
382 gboolean is_gobject = FALSE;
383 guint n_iface_prereqs;
384 GType *iface_prereqs;
385 int i;
386
387 node = (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_INTERFACE);
388 node->node.name = g_strdup (g_type_name (type_id));
389
390 /* workaround for AtkImplementorIface */
391 if (g_str_has_suffix (node->node.name, "Iface"))
392 {
393 node->node.name[strlen (node->node.name) -
394 strlen ("Iface")] = '\0';
395 }
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);
405
406 iface_prereqs =
407 g_type_interface_prerequisites (type_id, &n_iface_prereqs);
408
409 for (i = 0; i < n_iface_prereqs; i++)
410 {
411 if (g_type_fundamental (iface_prereqs[i]) == G_TYPE_OBJECT)
412 {
413 is_gobject = TRUE;
414 }
415 node->prerequisites =
416 g_list_append (node->prerequisites,
417 g_strdup (g_type_name (iface_prereqs[i])));
418 }
419
420 if (is_gobject)
421 g_igenerator_process_properties (igenerator, node, type_id);
422 else
423 g_type_default_interface_ref (type_id);
424
425 g_igenerator_process_signals (igenerator, node, type_id);
426 }
427
428 static void
g_igenerator_create_boxed(GIGenerator * igenerator,const char * symbol_name,GType type_id,char * lower_case_prefix)429 g_igenerator_create_boxed (GIGenerator *igenerator,
430 const char *symbol_name,
431 GType type_id,
432 char *lower_case_prefix)
433 {
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);
446 }
447
448 static void
g_igenerator_create_enum(GIGenerator * igenerator,const char * symbol_name,GType type_id,char * lower_case_prefix)449 g_igenerator_create_enum (GIGenerator *igenerator,
450 const char *symbol_name,
451 GType type_id,
452 char *lower_case_prefix)
453 {
454 GIdlNodeEnum *node;
455 int i;
456 GEnumClass *type_class;
457
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);
469
470 type_class = g_type_class_ref (type_id);
471
472 for (i = 0; i < type_class->n_values; i++)
473 {
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;
480 }
481 }
482
483 static void
g_igenerator_create_flags(GIGenerator * igenerator,const char * symbol_name,GType type_id,char * lower_case_prefix)484 g_igenerator_create_flags (GIGenerator *igenerator,
485 const char *symbol_name,
486 GType type_id,
487 char *lower_case_prefix)
488 {
489 GIdlNodeEnum *node;
490 GFlagsClass *type_class;
491 int i;
492
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);
504
505 type_class = g_type_class_ref (type_id);
506
507 for (i = 0; i < type_class->n_values; i++)
508 {
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;
515 }
516 }
517
518 static gboolean
g_igenerator_process_module_symbol(GIGenerator * igenerator,GModule * module,const gchar * symbol_name)519 g_igenerator_process_module_symbol (GIGenerator *igenerator,
520 GModule *module,
521 const gchar *symbol_name)
522 {
523 TypeFunction type_fun;
524 GType type_id;
525 GType type_fundamental;
526 char *lower_case_prefix;
527
528 /* ignore already processed functions */
529 if (symbol_name == NULL)
530 return FALSE;
531
532 if (!g_module_symbol (module,
533 symbol_name,
534 (gpointer *) & type_fun))
535 return FALSE;
536
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 "_", "");
544
545 switch (type_fundamental)
546 {
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;
569 }
570 return TRUE;
571 }
572
573 static void
g_igenerator_process_module(GIGenerator * igenerator,const gchar * filename)574 g_igenerator_process_module (GIGenerator * igenerator,
575 const gchar *filename)
576 {
577 GModule *module;
578 GList *l;
579
580 module = g_module_open (filename,
581 G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
582
583 if (module == NULL)
584 {
585 g_critical ("Couldn't open module: %s", filename);
586 return;
587 }
588
589 for (l = igenerator->get_type_symbols; l != NULL; l = l->next)
590 {
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;
595 }
596 }
597
598 static void
g_igenerator_process_function_symbol(GIGenerator * igenerator,CSymbol * sym)599 g_igenerator_process_function_symbol (GIGenerator * igenerator, CSymbol * sym)
600 {
601 GIdlNodeFunction *func;
602 char *last_underscore;
603 GList *param_l;
604 int i;
605 GSList *l;
606
607 func = (GIdlNodeFunction *) g_idl_node_new (G_IDL_NODE_FUNCTION);
608
609 /* check whether this is a type method */
610 last_underscore = strrchr (sym->ident, '_');
611
612 while (last_underscore != NULL)
613 {
614 char *prefix;
615 GIdlNode *node;
616
617 prefix = g_strndup (sym->ident, last_underscore - sym->ident);
618 prefix = str_replace (prefix, "_", "");
619
620 node = g_hash_table_lookup (igenerator->type_by_lower_case_prefix,
621 prefix);
622 if (node != NULL )
623 {
624 func->node.name = g_strdup (last_underscore + 1);
625
626 /* ignore get_type functions in registered types */
627 if (strcmp (func->node.name, "get_type") == 0)
628 return;
629
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))
637 {
638 g_idl_node_add_member (node, func);
639 break;
640 }
641 else
642 {
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;
648 }
649 }
650 else if (strcmp (igenerator->lower_case_namespace, prefix) == 0)
651 {
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;
657 }
658 last_underscore =
659 g_utf8_strrchr (sym->ident, last_underscore - sym->ident, '_');
660 }
661
662 /* create a namespace function if no prefix matches */
663 if (func->node.name == NULL)
664 {
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);
671 }
672
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);
676
677 for (param_l = sym->base_type->child_list, i = 1; param_l != NULL;
678 param_l = param_l->next, i++)
679 {
680 CSymbol *param_sym = param_l->data;
681 GIdlNodeParam *param;
682
683 param = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
684 param->type = create_node_from_ctype (param_sym->base_type);
685
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;
690
691 func->parameters = g_list_append (func->parameters, param);
692 }
693
694 for (l = sym->directives; l; l = l->next)
695 {
696 CDirective *directive = (CDirective*)l->data;
697
698 if (!strcmp (directive->name, "deprecated"))
699 func->deprecated = TRUE;
700 else
701 g_printerr ("Unknown function directive: %s\n",
702 directive->name);
703 }
704 }
705
706 static void
g_igenerator_process_unregistered_struct_typedef(GIGenerator * igenerator,CSymbol * sym,CType * struct_type)707 g_igenerator_process_unregistered_struct_typedef (GIGenerator * igenerator,
708 CSymbol * sym,
709 CType * struct_type)
710 {
711 GIdlNodeStruct *node =
712 (GIdlNodeStruct *) g_idl_node_new (G_IDL_NODE_STRUCT);
713 GList *member_l;
714 char *lower_case_prefix;
715
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);
724
725 for (member_l = struct_type->child_list; member_l != NULL;
726 member_l = member_l->next)
727 {
728 CSymbol *member = member_l->data;
729 GIdlNodeField *gifield =
730 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
731
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);
735 }
736 }
737
738 static void
g_igenerator_process_struct_typedef(GIGenerator * igenerator,CSymbol * sym)739 g_igenerator_process_struct_typedef (GIGenerator * igenerator, CSymbol * sym)
740 {
741 CType *struct_type = sym->base_type;
742 gboolean opaque_type = FALSE;
743 GIdlNode *type;
744
745 if (struct_type->child_list == NULL)
746 {
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)
753 {
754 struct_type = struct_symbol->base_type;
755 }
756 }
757
758 if (struct_type->child_list == NULL)
759 {
760 opaque_type = TRUE;
761 }
762
763 type = g_hash_table_lookup (igenerator->type_map, sym->ident);
764 if (type != NULL)
765 {
766 /* struct of a GTypeInstance */
767 if (!opaque_type
768 && (type->type == G_IDL_NODE_OBJECT
769 || type->type == G_IDL_NODE_INTERFACE))
770 {
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)
776 {
777 CSymbol *member = member_l->data;
778 GIdlNodeField *gifield;
779 /* ignore private / reserved members */
780 if (member->ident[0] == '_'
781 || g_str_has_prefix (member->ident, "priv"))
782 {
783 continue;
784 }
785 gifield =
786 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
787 node->members = g_list_append (node->members, gifield);
788 gifield->node.name = member->ident;
789 gifield->type = create_node_from_ctype (member->base_type);
790 }
791 }
792 else if (type->type == G_IDL_NODE_BOXED)
793 {
794 GIdlNodeBoxed *node = (GIdlNodeBoxed *) type;
795 GList *member_l;
796 for (member_l = struct_type->child_list; member_l != NULL;
797 member_l = member_l->next)
798 {
799 CSymbol *member = member_l->data;
800 GIdlNodeField *gifield =
801 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
802 node->members = g_list_append (node->members, gifield);
803 gifield->node.name = member->ident;
804 gifield->type = create_node_from_ctype (member->base_type);
805 }
806 }
807 }
808 else if (!opaque_type
809 && (g_str_has_suffix (sym->ident, "Class")
810 || g_str_has_suffix (sym->ident, "Iface")
811 || g_str_has_suffix (sym->ident, "Interface")))
812 {
813 char *base_name;
814 GList *member_l;
815 GIdlNodeInterface *node;
816
817 if (g_str_has_suffix (sym->ident, "Interface"))
818 {
819 base_name =
820 g_strndup (sym->ident,
821 strlen (sym->ident) - strlen ("Interface"));
822 }
823 else
824 {
825 base_name =
826 g_strndup (sym->ident, strlen (sym->ident) - strlen ("Class"));
827 }
828 type = g_hash_table_lookup (igenerator->type_map, base_name);
829 if (type == NULL
830 || (type->type != G_IDL_NODE_OBJECT
831 && type->type != G_IDL_NODE_INTERFACE))
832 {
833 g_igenerator_process_unregistered_struct_typedef (igenerator, sym,
834 struct_type);
835 return;
836 }
837 node = (GIdlNodeInterface *) type;
838
839 /* ignore first field => parent */
840 for (member_l = struct_type->child_list->next; member_l != NULL;
841 member_l = member_l->next)
842 {
843 CSymbol *member = member_l->data;
844 /* ignore private / reserved members */
845 if (member->ident[0] == '_')
846 {
847 continue;
848 }
849 if (member->base_type->type == CTYPE_POINTER
850 && member->base_type->base_type->type == CTYPE_FUNCTION)
851 {
852 /* ignore default handlers of signals */
853 gboolean found_signal = FALSE;
854 GList *type_member_l;
855 GList *param_l;
856 int i;
857 GIdlNodeVFunc *givfunc;
858
859 for (type_member_l = node->members; type_member_l != NULL;
860 type_member_l = type_member_l->next)
861 {
862 GIdlNode *type_member = type_member_l->data;
863 char *normalized_name =
864 str_replace (type_member->name, "-", "_");
865 if (type_member->type == G_IDL_NODE_SIGNAL
866 && strcmp (normalized_name, member->ident) == 0)
867 {
868 GList *vfunc_param_l;
869 GList *sig_param_l;
870 GIdlNodeSignal *sig = (GIdlNodeSignal *) type_member;
871 found_signal = TRUE;
872 /* set signal parameter names */
873 for (vfunc_param_l =
874 member->base_type->base_type->child_list,
875 sig_param_l = sig->parameters;
876 vfunc_param_l != NULL && sig_param_l != NULL;
877 vfunc_param_l = vfunc_param_l->next, sig_param_l =
878 sig_param_l->next)
879 {
880 CSymbol *vfunc_param = vfunc_param_l->data;
881 GIdlNodeParam *sig_param = sig_param_l->data;
882 if (vfunc_param->ident != NULL)
883 {
884 g_free (sig_param->node.name);
885 sig_param->node.name =
886 g_strdup (vfunc_param->ident);
887 }
888 }
889 break;
890 }
891 }
892 if (found_signal)
893 {
894 continue;
895 }
896
897 givfunc = (GIdlNodeVFunc *) g_idl_node_new (G_IDL_NODE_VFUNC);
898 givfunc->node.name = member->ident;
899 node->members =
900 g_list_insert_sorted (node->members, givfunc,
901 (GCompareFunc) g_idl_node_cmp);
902 givfunc->result =
903 (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
904 givfunc->result->type =
905 create_node_from_ctype (member->base_type->base_type->base_type);
906 for (param_l = member->base_type->base_type->child_list, i = 1;
907 param_l != NULL; param_l = param_l->next, i++)
908 {
909 CSymbol *param_sym = param_l->data;
910 GIdlNodeParam *param =
911 (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
912 if (param_sym->ident == NULL)
913 {
914 param->node.name = g_strdup_printf ("p%d", i);
915 }
916 else
917 {
918 param->node.name = param_sym->ident;
919 }
920 param->type = create_node_from_ctype (param_sym->base_type);
921 givfunc->parameters =
922 g_list_append (givfunc->parameters, param);
923 }
924 }
925 }
926 }
927 else if (g_str_has_suffix (sym->ident, "Private"))
928 {
929 /* ignore private structs */
930 }
931 else
932 {
933 g_igenerator_process_unregistered_struct_typedef (igenerator, sym,
934 struct_type);
935 }
936 }
937
938 static void
g_igenerator_process_union_typedef(GIGenerator * igenerator,CSymbol * sym)939 g_igenerator_process_union_typedef (GIGenerator * igenerator, CSymbol * sym)
940 {
941 CType *union_type = sym->base_type;
942 gboolean opaque_type = FALSE;
943 GIdlNode *type;
944
945 if (union_type->child_list == NULL)
946 {
947 CSymbol *union_symbol;
948 g_assert (union_type->name != NULL);
949 union_symbol =
950 g_hash_table_lookup (igenerator->struct_or_union_or_enum_table,
951 union_type->name);
952 if (union_symbol != NULL)
953 {
954 union_type = union_symbol->base_type;
955 }
956 }
957 if (union_type->child_list == NULL)
958 {
959 opaque_type = TRUE;
960 }
961
962 type = g_hash_table_lookup (igenerator->type_map, sym->ident);
963 if (type != NULL)
964 {
965 GIdlNodeBoxed *node;
966 GList *member_l;
967 g_assert (type->type == G_IDL_NODE_BOXED);
968 node = (GIdlNodeBoxed *) type;
969 for (member_l = union_type->child_list; member_l != NULL;
970 member_l = member_l->next)
971 {
972 CSymbol *member = member_l->data;
973 GIdlNodeField *gifield =
974 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
975 node->members = g_list_append (node->members, gifield);
976 gifield->node.name = member->ident;
977 gifield->type = create_node_from_ctype (member->base_type);
978 }
979 }
980 else
981 {
982 GIdlNodeUnion *node =
983 (GIdlNodeUnion *) g_idl_node_new (G_IDL_NODE_UNION);
984 char *lower_case_prefix;
985 GList *member_l;
986
987 node->node.name = sym->ident;
988 igenerator->module->entries =
989 g_list_insert_sorted (igenerator->module->entries, node,
990 (GCompareFunc) g_idl_node_cmp);
991 lower_case_prefix = g_ascii_strdown (sym->ident, -1);
992 g_hash_table_insert (igenerator->type_map, sym->ident, node);
993 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
994 lower_case_prefix, node);
995
996 node->node.name = sym->ident;
997 for (member_l = union_type->child_list; member_l != NULL;
998 member_l = member_l->next)
999 {
1000 CSymbol *member = member_l->data;
1001 GIdlNodeField *gifield =
1002 (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
1003 node->members = g_list_append (node->members, gifield);
1004 gifield->node.name = member->ident;
1005 gifield->type = create_node_from_ctype (member->base_type);
1006 }
1007 }
1008 }
1009
1010 static void
g_igenerator_process_enum_typedef(GIGenerator * igenerator,CSymbol * sym)1011 g_igenerator_process_enum_typedef (GIGenerator * igenerator, CSymbol * sym)
1012 {
1013 CType *enum_type;
1014 GList *member_l;
1015 GIdlNodeEnum *node;
1016 CSymbol *enum_symbol;
1017
1018 enum_type = sym->base_type;
1019 if (enum_type->child_list == NULL)
1020 {
1021 g_assert (enum_type->name != NULL);
1022 enum_symbol =
1023 g_hash_table_lookup (igenerator->struct_or_union_or_enum_table,
1024 enum_type->name);
1025 if (enum_symbol != NULL)
1026 {
1027 enum_type = enum_symbol->base_type;
1028 }
1029 }
1030 if (enum_type->child_list == NULL)
1031 {
1032 /* opaque type */
1033 return;
1034 }
1035
1036 node = g_hash_table_lookup (igenerator->type_map, sym->ident);
1037 if (node != NULL)
1038 {
1039 return;
1040 }
1041
1042 node = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_ENUM);
1043 node->node.name = sym->ident;
1044 igenerator->module->entries =
1045 g_list_insert_sorted (igenerator->module->entries, node,
1046 (GCompareFunc) g_idl_node_cmp);
1047
1048 for (member_l = enum_type->child_list; member_l != NULL;
1049 member_l = member_l->next)
1050 {
1051 CSymbol *member = member_l->data;
1052 GIdlNodeValue *gival =
1053 (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
1054 node->values = g_list_append (node->values, gival);
1055 gival->node.name = member->ident;
1056 gival->value = member->const_int;
1057 }
1058 }
1059
1060 static void
g_igenerator_process_function_typedef(GIGenerator * igenerator,CSymbol * sym)1061 g_igenerator_process_function_typedef (GIGenerator * igenerator,
1062 CSymbol * sym)
1063 {
1064 GList *param_l;
1065 int i;
1066
1067 /* handle callback types */
1068 GIdlNodeFunction *gifunc =
1069 (GIdlNodeFunction *) g_idl_node_new (G_IDL_NODE_CALLBACK);
1070
1071 gifunc->node.name = sym->ident;
1072 igenerator->module->entries =
1073 g_list_insert_sorted (igenerator->module->entries, gifunc,
1074 (GCompareFunc) g_idl_node_cmp);
1075
1076 gifunc->symbol = sym->ident;
1077 gifunc->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
1078 gifunc->result->type =
1079 create_node_from_ctype (sym->base_type->base_type->base_type);
1080
1081 for (param_l = sym->base_type->base_type->child_list, i = 1;
1082 param_l != NULL; param_l = param_l->next, i++)
1083 {
1084 CSymbol *param_sym = param_l->data;
1085 GIdlNodeParam *param =
1086 (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
1087 if (param_sym->ident == NULL)
1088 {
1089 param->node.name = g_strdup_printf ("p%d", i);
1090 }
1091 else
1092 {
1093 param->node.name = param_sym->ident;
1094 }
1095 param->type = create_node_from_ctype (param_sym->base_type);
1096 gifunc->parameters = g_list_append (gifunc->parameters, param);
1097 }
1098 }
1099
1100 static void
g_igenerator_process_constant(GIGenerator * igenerator,CSymbol * sym)1101 g_igenerator_process_constant (GIGenerator * igenerator, CSymbol * sym)
1102 {
1103 GIdlNodeConstant *giconst =
1104 (GIdlNodeConstant *) g_idl_node_new (G_IDL_NODE_CONSTANT);
1105 giconst->node.name = sym->ident;
1106 igenerator->module->entries =
1107 g_list_insert_sorted (igenerator->module->entries, giconst,
1108 (GCompareFunc) g_idl_node_cmp);
1109
1110 giconst->type = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
1111 if (sym->const_int_set)
1112 {
1113 giconst->type->unparsed = g_strdup ("int");
1114 giconst->value = g_strdup_printf ("%d", sym->const_int);
1115 }
1116 else if (sym->const_string != NULL)
1117 {
1118 giconst->type->unparsed = g_strdup ("char*");
1119 giconst->value = sym->const_string;
1120 }
1121 }
1122
1123 static void
g_igenerator_process_symbols(GIGenerator * igenerator)1124 g_igenerator_process_symbols (GIGenerator * igenerator)
1125 {
1126 GList *l;
1127 /* process type symbols first to ensure complete type hashtables */
1128 /* type symbols */
1129 for (l = igenerator->symbol_list; l != NULL; l = l->next)
1130 {
1131 CSymbol *sym = l->data;
1132 if (sym->ident[0] == '_')
1133 {
1134 /* ignore private / reserved symbols */
1135 continue;
1136 }
1137 if (sym->type == CSYMBOL_TYPE_TYPEDEF)
1138 {
1139 if (sym->base_type->type == CTYPE_STRUCT)
1140 {
1141 g_igenerator_process_struct_typedef (igenerator, sym);
1142 }
1143 else if (sym->base_type->type == CTYPE_UNION)
1144 {
1145 g_igenerator_process_union_typedef (igenerator, sym);
1146 }
1147 else if (sym->base_type->type == CTYPE_ENUM)
1148 {
1149 g_igenerator_process_enum_typedef (igenerator, sym);
1150 }
1151 else if (sym->base_type->type == CTYPE_POINTER
1152 && sym->base_type->base_type->type == CTYPE_FUNCTION)
1153 {
1154 g_igenerator_process_function_typedef (igenerator, sym);
1155 }
1156 else
1157 {
1158 GIdlNodeStruct *node =
1159 (GIdlNodeStruct *) g_idl_node_new (G_IDL_NODE_STRUCT);
1160 char *lower_case_prefix;
1161
1162 node->node.name = sym->ident;
1163 igenerator->module->entries =
1164 g_list_insert_sorted (igenerator->module->entries, node,
1165 (GCompareFunc) g_idl_node_cmp);
1166 lower_case_prefix = g_ascii_strdown (sym->ident, -1);
1167 g_hash_table_insert (igenerator->type_map, sym->ident, node);
1168 g_hash_table_insert (igenerator->type_by_lower_case_prefix,
1169 lower_case_prefix, node);
1170 }
1171 }
1172 }
1173 /* other symbols */
1174 for (l = igenerator->symbol_list; l != NULL; l = l->next)
1175 {
1176 CSymbol *sym = l->data;
1177 if (sym->ident[0] == '_')
1178 {
1179 /* ignore private / reserved symbols */
1180 continue;
1181 }
1182 if (sym->type == CSYMBOL_TYPE_FUNCTION)
1183 {
1184 g_igenerator_process_function_symbol (igenerator, sym);
1185 }
1186 else if (sym->type == CSYMBOL_TYPE_CONST)
1187 {
1188 g_igenerator_process_constant (igenerator, sym);
1189 }
1190 }
1191 }
1192
1193 void
g_igenerator_add_symbol(GIGenerator * igenerator,CSymbol * symbol)1194 g_igenerator_add_symbol (GIGenerator * igenerator, CSymbol * symbol)
1195 {
1196 GList *l;
1197
1198 /* only add symbols of main file */
1199 gboolean found_filename = FALSE;
1200
1201 if (igenerator->current_filename)
1202 {
1203 for (l = igenerator->filenames; l != NULL; l = l->next)
1204 {
1205 if (strcmp (l->data, igenerator->current_filename) == 0)
1206 {
1207 found_filename = TRUE;
1208 break;
1209 }
1210 }
1211 }
1212
1213 symbol->directives = g_slist_reverse (igenerator->directives);
1214 igenerator->directives = NULL;
1215
1216 /* that's not very optimized ! */
1217 for (l = igenerator->symbol_list; l != NULL; l = l->next)
1218 {
1219 CSymbol *other_symbol = (CSymbol *)l->data;
1220 if (g_str_equal (other_symbol->ident, symbol->ident)
1221 && other_symbol->type == symbol->type)
1222 {
1223 g_printerr ("Dropping %s duplicate\n", symbol->ident);
1224 return;
1225 }
1226 }
1227
1228 if (found_filename || igenerator->macro_scan)
1229 {
1230 igenerator->symbol_list =
1231 g_list_prepend (igenerator->symbol_list, symbol);
1232 }
1233
1234 if (symbol->type == CSYMBOL_TYPE_TYPEDEF)
1235
1236 {
1237 g_hash_table_insert (igenerator->typedef_table, symbol->ident, symbol);
1238 }
1239 else if (symbol->type == CSYMBOL_TYPE_STRUCT
1240 || symbol->type == CSYMBOL_TYPE_UNION
1241 || symbol->type == CSYMBOL_TYPE_ENUM)
1242 {
1243 g_hash_table_insert (igenerator->struct_or_union_or_enum_table,
1244 symbol->ident, symbol);
1245 }
1246 }
1247
1248 gboolean
g_igenerator_is_typedef(GIGenerator * igenerator,const char * name)1249 g_igenerator_is_typedef (GIGenerator * igenerator, const char *name)
1250 {
1251 gboolean b = g_hash_table_lookup (igenerator->typedef_table, name) != NULL;
1252 return b;
1253 }
1254
1255 static void
g_igenerator_generate(GIGenerator * igenerator,const gchar * filename,GList * libraries)1256 g_igenerator_generate (GIGenerator * igenerator,
1257 const gchar * filename,
1258 GList *libraries)
1259 {
1260 GList *l;
1261
1262 for (l = igenerator->symbol_list; l != NULL; l = l->next)
1263 {
1264 CSymbol *sym = l->data;
1265 if (sym->type == CSYMBOL_TYPE_FUNCTION
1266 && g_str_has_suffix (sym->ident, "_get_type"))
1267 {
1268 if (sym->base_type->child_list == NULL)
1269 {
1270 // ignore get_type functions with parameters
1271 igenerator->get_type_symbols =
1272 g_list_prepend (igenerator->get_type_symbols, sym->ident);
1273 }
1274 }
1275 }
1276
1277 /* ensure to initialize GObject */
1278 g_type_class_ref (G_TYPE_OBJECT);
1279
1280 for (l = libraries; l; l = l->next)
1281 g_igenerator_process_module (igenerator, (const gchar*)l->data);
1282
1283 g_igenerator_process_symbols (igenerator);
1284
1285 g_idl_writer_save_file (igenerator->module, filename);
1286 }
1287
1288 static int
eat_hspace(FILE * f)1289 eat_hspace (FILE * f)
1290 {
1291 int c;
1292 do
1293 {
1294 c = fgetc (f);
1295 }
1296 while (c == ' ' || c == '\t');
1297 return c;
1298 }
1299
1300 static int
eat_line(FILE * f,int c)1301 eat_line (FILE * f, int c)
1302 {
1303 while (c != EOF && c != '\n')
1304 {
1305 c = fgetc (f);
1306 }
1307 if (c == '\n')
1308 {
1309 c = fgetc (f);
1310 if (c == ' ' || c == '\t')
1311 {
1312 c = eat_hspace (f);
1313 }
1314 }
1315 return c;
1316 }
1317
1318 static int
read_identifier(FILE * f,int c,char ** identifier)1319 read_identifier (FILE * f, int c, char **identifier)
1320 {
1321 GString *id = g_string_new ("");
1322 while (isalnum (c) || c == '_')
1323 {
1324 g_string_append_c (id, c);
1325 c = fgetc (f);
1326 }
1327 *identifier = g_string_free (id, FALSE);
1328 return c;
1329 }
1330
1331 static void
g_igenerator_parse_macros(GIGenerator * igenerator)1332 g_igenerator_parse_macros (GIGenerator * igenerator)
1333 {
1334 GError *error = NULL;
1335 char *tmp_name = NULL;
1336 GList *l;
1337 FILE *fmacros =
1338 fdopen (g_file_open_tmp ("gen-introspect-XXXXXX.h", &tmp_name, &error),
1339 "w+");
1340 g_unlink (tmp_name);
1341
1342 for (l = igenerator->filenames; l != NULL; l = l->next)
1343 {
1344 FILE *f = fopen (l->data, "r");
1345 int line = 1;
1346
1347 GString *define_line;
1348 char *str;
1349 gboolean error_line = FALSE;
1350 int c = eat_hspace (f);
1351 while (c != EOF)
1352 {
1353 if (c != '#')
1354 {
1355 /* ignore line */
1356 c = eat_line (f, c);
1357 line++;
1358 continue;
1359 }
1360
1361 /* print current location */
1362 str = g_strescape (l->data, "");
1363 fprintf (fmacros, "# %d \"%s\"\n", line, str);
1364 g_free (str);
1365
1366 c = eat_hspace (f);
1367 c = read_identifier (f, c, &str);
1368 if (strcmp (str, "define") != 0 || (c != ' ' && c != '\t'))
1369 {
1370 g_free (str);
1371 /* ignore line */
1372 c = eat_line (f, c);
1373 line++;
1374 continue;
1375 }
1376 g_free (str);
1377 c = eat_hspace (f);
1378 c = read_identifier (f, c, &str);
1379 if (strlen (str) == 0 || (c != ' ' && c != '\t' && c != '('))
1380 {
1381 g_free (str);
1382 /* ignore line */
1383 c = eat_line (f, c);
1384 line++;
1385 continue;
1386 }
1387 define_line = g_string_new ("#define ");
1388 g_string_append (define_line, str);
1389 g_free (str);
1390 if (c == '(')
1391 {
1392 while (c != ')')
1393 {
1394 g_string_append_c (define_line, c);
1395 c = fgetc (f);
1396 if (c == EOF || c == '\n')
1397 {
1398 error_line = TRUE;
1399 break;
1400 }
1401 }
1402 if (error_line)
1403 {
1404 g_string_free (define_line, TRUE);
1405 /* ignore line */
1406 c = eat_line (f, c);
1407 line++;
1408 continue;
1409 }
1410
1411 g_assert (c == ')');
1412 g_string_append_c (define_line, c);
1413 c = fgetc (f);
1414
1415 /* found function-like macro */
1416 fprintf (fmacros, "%s\n", define_line->str);
1417
1418 g_string_free (define_line, TRUE);
1419 /* ignore rest of line */
1420 c = eat_line (f, c);
1421 line++;
1422 continue;
1423 }
1424 if (c != ' ' && c != '\t')
1425 {
1426 g_string_free (define_line, TRUE);
1427 /* ignore line */
1428 c = eat_line (f, c);
1429 line++;
1430 continue;
1431 }
1432 while (c != EOF && c != '\n')
1433 {
1434 g_string_append_c (define_line, c);
1435 c = fgetc (f);
1436 if (c == '\\')
1437 {
1438 c = fgetc (f);
1439 if (c == '\n')
1440 {
1441 /* fold lines when seeing backslash new-line sequence */
1442 c = fgetc (f);
1443 }
1444 else
1445 {
1446 g_string_append_c (define_line, '\\');
1447 }
1448 }
1449 }
1450
1451 /* found object-like macro */
1452 fprintf (fmacros, "%s\n", define_line->str);
1453
1454 c = eat_line (f, c);
1455 line++;
1456 }
1457
1458 fclose (f);
1459 }
1460
1461 igenerator->macro_scan = TRUE;
1462 rewind (fmacros);
1463
1464 g_igenerator_parse_file (igenerator, fmacros);
1465 fclose (fmacros);
1466
1467 igenerator->macro_scan = FALSE;
1468 }
1469
1470 static void
g_igenerator_add_module(GIGenerator * igenerator,GIdlModule * module)1471 g_igenerator_add_module (GIGenerator *igenerator,
1472 GIdlModule *module)
1473 {
1474 GList *l;
1475
1476 for (l = module->entries; l; l = l->next)
1477 {
1478 GIdlNode *node = (GIdlNode*)l->data;
1479
1480 if (node->type == G_IDL_NODE_OBJECT)
1481 {
1482 GIdlNodeInterface *object = (GIdlNodeInterface*)node;
1483 gchar *name;
1484 if (strcmp(module->name, igenerator->namespace) == 0)
1485 name = g_strdup (node->name);
1486 else
1487 name = g_strdup_printf ("%s.%s", module->name, node->name);
1488 g_hash_table_insert (igenerator->symbols,
1489 g_strdup (object->gtype_name),
1490 name);
1491 }
1492 }
1493 }
1494
1495 static void
g_igenerator_add_include_idl(GIGenerator * igenerator,const gchar * filename)1496 g_igenerator_add_include_idl (GIGenerator *igenerator,
1497 const gchar *filename)
1498 {
1499 GList *l;
1500 GList *modules;
1501
1502 GError *error = NULL;
1503
1504 modules = g_idl_parse_file (filename, &error);
1505 if (error)
1506 {
1507 g_printerr ("An error occurred while parsing %s: %s\n",
1508 filename, error->message);
1509 return;
1510 }
1511
1512 for (l = modules; l; l = l->next)
1513 {
1514 GIdlModule *module = (GIdlModule*)l->data;
1515 g_igenerator_add_module (igenerator, module);
1516 }
1517 }
1518
1519 static FILE *
g_igenerator_start_preprocessor(GIGenerator * igenerator,GList * cpp_options)1520 g_igenerator_start_preprocessor (GIGenerator *igenerator,
1521 GList *cpp_options)
1522 {
1523 int cpp_out = -1, cpp_in = -1;
1524 int cpp_argc = 0;
1525 char **cpp_argv;
1526 GList *l;
1527 GError *error = NULL;
1528 FILE *f, *out;
1529 GPid pid;
1530 int status = 0;
1531 int read_bytes;
1532 int i;
1533 char **buffer;
1534 int tmp;
1535 char *tmpname;
1536
1537 cpp_argv = g_new0 (char *, g_list_length (cpp_options) + 5);
1538 cpp_argv[cpp_argc++] = "cpp";
1539 cpp_argv[cpp_argc++] = "-C";
1540
1541 /* Disable GCC extensions as we cannot parse them yet */
1542 cpp_argv[cpp_argc++] = "-U__GNUC__";
1543
1544 /* Help system headers cope with the lack of __GNUC__ by pretending to be lint */
1545 cpp_argv[cpp_argc++] = "-Dlint";
1546
1547 for (l = cpp_options; l; l = l->next)
1548 cpp_argv[cpp_argc++] = (char*)l->data;
1549
1550 cpp_argv[cpp_argc++] = NULL;
1551
1552 if (igenerator->verbose)
1553 {
1554 GString *args = g_string_new ("");
1555
1556 for (i = 0; i < cpp_argc - 1; i++)
1557 {
1558 g_string_append (args, cpp_argv[i]);
1559 if (i < cpp_argc - 2)
1560 g_string_append_c (args, ' ');
1561 }
1562
1563 g_printf ("Executing '%s'\n", args->str);
1564 g_string_free (args, FALSE);
1565 }
1566 g_spawn_async_with_pipes (NULL, cpp_argv, NULL,
1567 G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
1568 NULL, NULL, &pid, &cpp_in, &cpp_out, NULL, &error);
1569
1570 g_free (cpp_argv);
1571 if (error != NULL)
1572 {
1573 g_error ("%s", error->message);
1574 return NULL;
1575 }
1576
1577 f = fdopen (cpp_in, "w");
1578
1579 for (l = igenerator->filenames; l != NULL; l = l->next)
1580 {
1581 if (igenerator->verbose)
1582 g_printf ("Pre-processing %s\n", (char*)l->data);
1583
1584 fprintf (f, "#include <%s>\n", (char *) l->data);
1585
1586 }
1587
1588 fclose (f);
1589 close (cpp_in);
1590
1591 tmp = g_file_open_tmp (NULL, &tmpname, &error);
1592 if (error != NULL)
1593 {
1594 g_error ("%s", error->message);
1595 return NULL;
1596 }
1597
1598 buffer = g_malloc0 (4096 * sizeof (char));
1599
1600 while (1)
1601 {
1602 read_bytes = read (cpp_out, buffer, 4096);
1603 if (read_bytes == 0)
1604 break;
1605 write (tmp, buffer, read_bytes);
1606 }
1607
1608 g_free (buffer);
1609
1610 close (cpp_out);
1611
1612 #ifndef _WIN32
1613 if (waitpid (pid, &status, 0) > 0)
1614 #else
1615 /* We don't want to include <windows.h> as it clashes horribly
1616 * with token names from scannerparser.h. So just declare
1617 * WaitForSingleObject, GetExitCodeProcess and INFINITE here.
1618 */
1619 extern unsigned long __stdcall WaitForSingleObject(void*, int);
1620 extern int __stdcall GetExitCodeProcess(void*, int*);
1621 #define INFINITE 0xffffffff
1622
1623 WaitForSingleObject (pid, INFINITE);
1624
1625 if (GetExitCodeProcess (pid, &status))
1626 #endif
1627 {
1628 if (status != 0)
1629 {
1630 g_spawn_close_pid (pid);
1631 #ifndef _WIN32
1632 kill (pid, SIGKILL);
1633 #endif
1634
1635 g_error ("cpp returned error code: %d\n", status);
1636 unlink (tmpname);
1637 g_free (tmpname);
1638 return NULL;
1639 }
1640 }
1641
1642 f = fdopen (tmp, "r");
1643 if (!f)
1644 {
1645 g_error ("%s", strerror (errno));
1646 unlink (tmpname);
1647 g_free (tmpname);
1648 return NULL;
1649 }
1650 rewind (f);
1651 unlink (tmpname);
1652 g_free (tmpname);
1653
1654 return f;
1655 }
1656
1657
1658 void
g_igenerator_set_verbose(GIGenerator * igenerator,gboolean verbose)1659 g_igenerator_set_verbose (GIGenerator *igenerator,
1660 gboolean verbose)
1661 {
1662 igenerator->verbose = verbose;
1663 }
1664
1665 int
main(int argc,char ** argv)1666 main (int argc, char **argv)
1667 {
1668 GOptionContext *ctx;
1669 gchar *namespace = NULL;
1670 gchar *shared_library = NULL;
1671 gchar **include_idls = NULL;
1672 gchar *output = NULL;
1673 gboolean verbose = FALSE;
1674
1675 GIGenerator *igenerator;
1676 int gopt_argc, i;
1677 char **gopt_argv;
1678 GList *filenames = NULL;
1679 GError *error = NULL;
1680 GList *l, *libraries = NULL;
1681 GList *cpp_options = NULL;
1682 char *buffer;
1683 size_t size;
1684 FILE *tmp;
1685 GOptionEntry entries[] =
1686 {
1687 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
1688 "Be verbose" },
1689 { "output", 'o', 0, G_OPTION_ARG_STRING, &output,
1690 "write output here instead of stdout", "FILE" },
1691 { "namespace", 'n', 0, G_OPTION_ARG_STRING, &namespace,
1692 "Namespace of the module, like 'Gtk'", "NAMESPACE" },
1693 { "shared-library", 0, 0, G_OPTION_ARG_FILENAME, &shared_library,
1694 "Shared library which contains the symbols", "FILE" },
1695 { "include-idl", 0, 0, G_OPTION_ARG_STRING_ARRAY, &include_idls,
1696 "Other gidls to include", "IDL" },
1697 { NULL }
1698 };
1699
1700 gopt_argc = 1;
1701 gopt_argv = (char**)g_malloc (argc * sizeof (char*));
1702 gopt_argv[0] = argv[0];
1703
1704 for (i = 1; i < argc; i++)
1705 {
1706 if (argv[i][0] == '-')
1707 {
1708 switch (argv[i][1])
1709 {
1710 case 'I':
1711 case 'D':
1712 case 'U':
1713 cpp_options = g_list_prepend (cpp_options, g_strdup (argv[i]));
1714 break;
1715 case 'p':
1716 /*ignore -pthread*/
1717 if (0==strcmp("-pthread", argv[i]))
1718 break;
1719 case 'm':
1720 /*ignore -mfpmath=sse -msse -msse2*/
1721 break;
1722 default:
1723 gopt_argv[gopt_argc++] = argv[i];
1724 break;
1725 }
1726 }
1727 else if (g_str_has_suffix (argv[i], ".h"))
1728 {
1729 gchar* filename;
1730
1731 if (!g_path_is_absolute (argv[i]))
1732 {
1733 gchar *dir = g_get_current_dir ();
1734 filename = g_strdup_printf ("%s/%s", dir,
1735 argv[i]);
1736 g_free (dir);
1737 }
1738 else
1739 filename = g_strdup (argv[i]);
1740
1741 filenames = g_list_append (filenames, g_realpath(filename));
1742 g_free(filename);
1743 }
1744 else if (g_str_has_suffix (argv[i], ".la") ||
1745 g_str_has_suffix (argv[i], ".so") ||
1746 g_str_has_suffix (argv[i], ".dll"))
1747 {
1748 libraries = g_list_prepend (libraries, g_strdup (argv[i]));
1749 }
1750 else
1751 {
1752 gopt_argv[gopt_argc++] = argv[i];
1753 }
1754 }
1755
1756 ctx = g_option_context_new ("");
1757 g_option_context_add_main_entries (ctx, entries, NULL);
1758
1759 if (!g_option_context_parse (ctx, &gopt_argc, &gopt_argv, &error))
1760 {
1761 g_printerr ("Parsing error: %s\n", error->message);
1762 g_option_context_free (ctx);
1763 return 1;
1764 }
1765
1766 g_free (gopt_argv);
1767 g_option_context_free (ctx);
1768
1769 if (!namespace)
1770 {
1771 g_printerr ("ERROR: namespace must be specified\n");
1772 return 1;
1773 }
1774
1775 igenerator = g_igenerator_new (namespace, shared_library);
1776
1777 if (verbose)
1778 g_igenerator_set_verbose (igenerator, TRUE);
1779
1780 if (!filenames)
1781 {
1782 g_printerr ("ERROR: Need at least one header file.\n");
1783 g_igenerator_free (igenerator);
1784 return 1;
1785 }
1786 igenerator->filenames = filenames;
1787 cpp_options = g_list_reverse (cpp_options);
1788 libraries = g_list_reverse (libraries);
1789
1790 if (include_idls)
1791 {
1792 for (i = 0; i < g_strv_length (include_idls); i++)
1793 g_igenerator_add_include_idl (igenerator, include_idls[i]);
1794 }
1795
1796 tmp = g_igenerator_start_preprocessor (igenerator, cpp_options);
1797 if (!tmp)
1798 {
1799 g_error ("ERROR in pre-processor.\n");
1800 g_igenerator_free (igenerator);
1801 return 1;
1802 }
1803
1804 if (!g_igenerator_parse_file (igenerator, tmp))
1805 {
1806 fclose (tmp);
1807 g_igenerator_free (igenerator);
1808 return 1;
1809 }
1810
1811 g_igenerator_parse_macros (igenerator);
1812
1813 g_igenerator_generate (igenerator, output, libraries);
1814
1815 fclose (tmp);
1816 g_igenerator_free (igenerator);
1817
1818 return 0;
1819 }
1820
1821