summaryrefslogtreecommitdiff
path: root/gobject-introspection/scanner.c
diff options
context:
space:
mode:
authorJuerg Billeter <j@bitron.ch>2008-01-11 21:44:01 +0000
committerJürg Billeter <juergbi@src.gnome.org>2008-01-11 21:44:01 +0000
commit2549f2b773a9d91a8c11d947019ce81d822207c9 (patch)
tree69d140e8e49323d93e627442873ad48fe1ca8be2 /gobject-introspection/scanner.c
parent93b91d12979c0343b1240f06be989b1e44a2ba0f (diff)
downloadvala-2549f2b773a9d91a8c11d947019ce81d822207c9.tar.gz
update from gobject-introspection SVN, fixes bug 505920
2008-01-11 Juerg Billeter <j@bitron.ch> * gobject-introspection/: update from gobject-introspection SVN, fixes bug 505920 * vapigen/vala-gen-introspect/vala-gen-introspect.in: fix to work with updated gobject-introspection svn path=/trunk/; revision=829
Diffstat (limited to 'gobject-introspection/scanner.c')
-rw-r--r--gobject-introspection/scanner.c1824
1 files changed, 1824 insertions, 0 deletions
diff --git a/gobject-introspection/scanner.c b/gobject-introspection/scanner.c
new file mode 100644
index 000000000..58885791a
--- /dev/null
+++ b/gobject-introspection/scanner.c
@@ -0,0 +1,1824 @@
+/* GObject introspection: scanner
+ *
+ * Copyright (C) 2007-2008 Jürg Billeter
+ * Copyright (C) 2007 Johan Dahlin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author:
+ * Jürg Billeter <j@bitron.ch>
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+#include <sys/wait.h> /* waitpid */
+#include <gmodule.h>
+#include "scanner.h"
+#include "gidlparser.h"
+#include "gidlmodule.h"
+#include "gidlnode.h"
+#include "gidlwriter.h"
+
+typedef GType (*TypeFunction) (void);
+
+static void g_igenerator_parse_macros (GIGenerator * igenerator);
+
+static int
+g_idl_node_cmp (GIdlNode * a, GIdlNode * b)
+{
+ if (a->type < b->type)
+ {
+ return -1;
+ }
+ else if (a->type > b->type)
+ {
+ return 1;
+ }
+ else
+ {
+ return strcmp (a->name, b->name);
+ }
+}
+
+static GIGenerator *
+g_igenerator_new (const gchar *namespace,
+ const gchar *shared_library)
+{
+ GIGenerator *igenerator = g_new0 (GIGenerator, 1);
+ igenerator->namespace = g_strdup (namespace);
+ igenerator->shared_library = g_strdup (shared_library);
+ igenerator->lower_case_namespace =
+ g_ascii_strdown (igenerator->namespace, -1);
+ igenerator->module = g_idl_module_new (namespace, shared_library);
+
+ igenerator->typedef_table = g_hash_table_new (g_str_hash, g_str_equal);
+ igenerator->struct_or_union_or_enum_table =
+ g_hash_table_new (g_str_hash, g_str_equal);
+
+ igenerator->type_map = g_hash_table_new (g_str_hash, g_str_equal);
+ igenerator->type_by_lower_case_prefix =
+ g_hash_table_new (g_str_hash, g_str_equal);
+ igenerator->symbols = g_hash_table_new (g_str_hash, g_str_equal);
+
+ return igenerator;
+}
+
+static void
+g_igenerator_free (GIGenerator *generator)
+{
+ g_free (generator->namespace);
+ g_free (generator->shared_library);
+ g_free (generator->lower_case_namespace);
+#if 0
+ g_idl_module_free (generator->module);
+#endif
+ g_hash_table_destroy (generator->typedef_table);
+ g_hash_table_destroy (generator->struct_or_union_or_enum_table);
+ g_hash_table_destroy (generator->type_map);
+ g_hash_table_destroy (generator->type_by_lower_case_prefix);
+ g_hash_table_destroy (generator->symbols);
+ g_list_foreach (generator->filenames, (GFunc)g_free, NULL);
+ g_list_free (generator->filenames);
+#if 0
+ g_list_foreach (generator->symbol_list, (GFunc)csymbol_free, NULL);
+ g_list_free (generator->symbol_list);
+#endif
+ g_free (generator);
+}
+
+static GIdlNodeType *
+get_type_from_type_id (GType type_id)
+{
+ GIdlNodeType *gitype = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
+
+ GType type_fundamental = g_type_fundamental (type_id);
+
+ if (type_fundamental == G_TYPE_STRING)
+ {
+ gitype->unparsed = g_strdup ("char*");
+ }
+ else if (type_id == G_TYPE_STRV)
+ {
+ gitype->unparsed = g_strdup ("char*[]");
+ }
+ else if (type_fundamental == G_TYPE_INTERFACE
+ || type_fundamental == G_TYPE_BOXED
+ || type_fundamental == G_TYPE_OBJECT)
+ {
+ gitype->unparsed = g_strdup_printf ("%s*", g_type_name (type_id));
+ }
+ else if (type_fundamental == G_TYPE_PARAM)
+ {
+ gitype->unparsed = g_strdup ("GParamSpec*");
+ }
+ else
+ {
+ gitype->unparsed = g_strdup (g_type_name (type_id));
+ }
+
+ return gitype;
+}
+
+static char *
+str_replace (const char *str, const char *needle, const char *replacement)
+{
+ char **strings = g_strsplit (str, needle, 0);
+ char *result = g_strjoinv (replacement, strings);
+ g_strfreev (strings);
+ return result;
+}
+
+static void
+g_igenerator_process_properties (GIGenerator * igenerator,
+ GIdlNodeInterface * ginode, GType type_id)
+{
+ int i;
+ guint n_properties;
+ GParamSpec **properties;
+
+ if (ginode->node.type == G_IDL_NODE_OBJECT)
+ {
+ GObjectClass *type_class = g_type_class_ref (type_id);
+ properties = g_object_class_list_properties (type_class, &n_properties);
+ }
+ else if (ginode->node.type == G_IDL_NODE_INTERFACE)
+ {
+ GTypeInterface *iface = g_type_default_interface_ref (type_id);
+ properties = g_object_interface_list_properties (iface, &n_properties);
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+
+ for (i = 0; i < n_properties; i++)
+ {
+ GIdlNodeProperty *giprop;
+
+ /* ignore inherited properties */
+ if (properties[i]->owner_type != type_id)
+ {
+ continue;
+ }
+ giprop = (GIdlNodeProperty *) g_idl_node_new (G_IDL_NODE_PROPERTY);
+ giprop->node.name = properties[i]->name;
+ ginode->members =
+ g_list_insert_sorted (ginode->members, giprop,
+ (GCompareFunc) g_idl_node_cmp);
+ giprop->type = get_type_from_type_id (properties[i]->value_type);
+ giprop->readable = (properties[i]->flags & G_PARAM_READABLE) != 0;
+ giprop->writable = (properties[i]->flags & G_PARAM_WRITABLE) != 0;
+ giprop->construct = (properties[i]->flags & G_PARAM_CONSTRUCT) != 0;
+ giprop->construct_only =
+ (properties[i]->flags & G_PARAM_CONSTRUCT_ONLY) != 0;
+ }
+}
+
+static void
+g_igenerator_process_signals (GIGenerator * igenerator,
+ GIdlNodeInterface * ginode, GType type_id)
+{
+ int i, j;
+ guint n_signal_ids;
+ guint *signal_ids = g_signal_list_ids (type_id, &n_signal_ids);
+
+ for (i = 0; i < n_signal_ids; i++)
+ {
+ GSignalQuery signal_query;
+ GIdlNodeSignal *gisig;
+ GIdlNodeParam *giparam;
+
+ g_signal_query (signal_ids[i], &signal_query);
+ gisig = (GIdlNodeSignal *) g_idl_node_new (G_IDL_NODE_SIGNAL);
+ gisig->node.name = g_strdup (signal_query.signal_name);
+ ginode->members =
+ g_list_insert_sorted (ginode->members, gisig,
+ (GCompareFunc) g_idl_node_cmp);
+
+ gisig->run_first =
+ (signal_query.signal_flags & G_SIGNAL_RUN_FIRST) != 0;
+ gisig->run_last = (signal_query.signal_flags & G_SIGNAL_RUN_LAST) != 0;
+ gisig->run_cleanup =
+ (signal_query.signal_flags & G_SIGNAL_RUN_CLEANUP) != 0;
+
+ /* add sender parameter */
+ giparam = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+ gisig->parameters = g_list_append (gisig->parameters, giparam);
+ giparam->node.name = g_strdup ("object");
+ giparam->type = get_type_from_type_id (type_id);
+
+ for (j = 0; j < signal_query.n_params; j++)
+ {
+ giparam = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+ gisig->parameters = g_list_append (gisig->parameters, giparam);
+ giparam->node.name = g_strdup_printf ("p%d", j);
+ giparam->type = get_type_from_type_id (signal_query.param_types[j]);
+ }
+ gisig->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+ gisig->result->type = get_type_from_type_id (signal_query.return_type);
+ }
+}
+
+static const gchar *
+lookup_symbol (GIGenerator *igenerator, const gchar *typename)
+{
+ const gchar *name =
+ g_hash_table_lookup (igenerator->symbols, typename);
+
+ if (!name)
+ {
+ g_printerr ("Unknown symbol: %s\n", typename);
+ return typename;
+ }
+
+ return name;
+}
+
+static void
+g_igenerator_create_object (GIGenerator *igenerator,
+ const char *symbol_name,
+ GType type_id,
+ char *lower_case_prefix)
+
+{
+ char *alt_lower_case_prefix;
+ GIdlNodeInterface *ginode;
+ guint n_type_interfaces;
+ GType *type_interfaces;
+ int i;
+
+ ginode = (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_OBJECT);
+ ginode->node.name = g_strdup (g_type_name (type_id));
+ igenerator->module->entries =
+ g_list_insert_sorted (igenerator->module->entries, ginode,
+ (GCompareFunc) g_idl_node_cmp);
+ g_hash_table_insert (igenerator->type_map, ginode->node.name,
+ ginode);
+ g_hash_table_insert (igenerator->type_by_lower_case_prefix,
+ lower_case_prefix, ginode);
+ alt_lower_case_prefix = g_ascii_strdown (ginode->node.name, -1);
+
+ if (strcmp (alt_lower_case_prefix, lower_case_prefix) != 0)
+ {
+ /* alternative prefix sometimes necessary, for example
+ * for GdkWindow
+ */
+ g_hash_table_insert (igenerator->type_by_lower_case_prefix,
+ alt_lower_case_prefix, ginode);
+ }
+ else
+ {
+ g_free (alt_lower_case_prefix);
+ }
+
+ ginode->gtype_name = ginode->node.name;
+ ginode->gtype_init = g_strdup (symbol_name);
+ ginode->parent = g_strdup (lookup_symbol (igenerator,
+ g_type_name (g_type_parent (type_id))));
+
+ type_interfaces = g_type_interfaces (type_id, &n_type_interfaces);
+ for (i = 0; i < n_type_interfaces; i++)
+ {
+ char *iface_name =
+ g_strdup (g_type_name (type_interfaces[i]));
+ /* workaround for AtkImplementorIface */
+ if (g_str_has_suffix (iface_name, "Iface"))
+ {
+ iface_name[strlen (iface_name) - strlen ("Iface")] =
+ '\0';
+ }
+ ginode->interfaces =
+ g_list_append (ginode->interfaces, iface_name);
+ }
+
+ g_hash_table_insert (igenerator->symbols,
+ g_strdup (ginode->gtype_name),
+ /* FIXME: Strip igenerator->namespace */
+ g_strdup (ginode->node.name));
+
+ g_igenerator_process_properties (igenerator, ginode, type_id);
+ g_igenerator_process_signals (igenerator, ginode, type_id);
+}
+
+static void
+g_igenerator_create_interface (GIGenerator *igenerator,
+ const char *symbol_name,
+ GType type_id,
+ char *lower_case_prefix)
+
+{
+ GIdlNodeInterface *ginode;
+ gboolean is_gobject = FALSE;
+ guint n_iface_prereqs;
+ GType *iface_prereqs;
+ int i;
+
+ ginode = (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_INTERFACE);
+ ginode->node.name = g_strdup (g_type_name (type_id));
+
+ /* workaround for AtkImplementorIface */
+ if (g_str_has_suffix (ginode->node.name, "Iface"))
+ {
+ ginode->node.name[strlen (ginode->node.name) -
+ strlen ("Iface")] = '\0';
+ }
+ igenerator->module->entries =
+ g_list_insert_sorted (igenerator->module->entries, ginode,
+ (GCompareFunc) g_idl_node_cmp);
+ g_hash_table_insert (igenerator->type_map, ginode->node.name,
+ ginode);
+ g_hash_table_insert (igenerator->type_by_lower_case_prefix,
+ lower_case_prefix, ginode);
+ ginode->gtype_name = ginode->node.name;
+ ginode->gtype_init = g_strdup (symbol_name);
+
+ iface_prereqs =
+ g_type_interface_prerequisites (type_id, &n_iface_prereqs);
+
+ for (i = 0; i < n_iface_prereqs; i++)
+ {
+ if (g_type_fundamental (iface_prereqs[i]) == G_TYPE_OBJECT)
+ {
+ is_gobject = TRUE;
+ }
+ ginode->prerequisites =
+ g_list_append (ginode->prerequisites,
+ g_strdup (g_type_name (iface_prereqs[i])));
+ }
+
+ if (is_gobject)
+ g_igenerator_process_properties (igenerator, ginode, type_id);
+ else
+ g_type_default_interface_ref (type_id);
+
+ g_igenerator_process_signals (igenerator, ginode, type_id);
+}
+
+static void
+g_igenerator_create_boxed (GIGenerator *igenerator,
+ const char *symbol_name,
+ GType type_id,
+ char *lower_case_prefix)
+{
+ GIdlNodeBoxed *ginode =
+ (GIdlNodeBoxed *) g_idl_node_new (G_IDL_NODE_BOXED);
+ ginode->node.name = g_strdup (g_type_name (type_id));
+ igenerator->module->entries =
+ g_list_insert_sorted (igenerator->module->entries, ginode,
+ (GCompareFunc) g_idl_node_cmp);
+ g_hash_table_insert (igenerator->type_map, ginode->node.name,
+ ginode);
+ g_hash_table_insert (igenerator->type_by_lower_case_prefix,
+ lower_case_prefix, ginode);
+ ginode->gtype_name = ginode->node.name;
+ ginode->gtype_init = g_strdup (symbol_name);
+}
+
+static void
+g_igenerator_create_enum (GIGenerator *igenerator,
+ const char *symbol_name,
+ GType type_id,
+ char *lower_case_prefix)
+{
+ GIdlNodeEnum *ginode;
+ int i;
+ GEnumClass *type_class;
+
+ ginode = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_ENUM);
+ ginode->node.name = g_strdup (g_type_name (type_id));
+ igenerator->module->entries =
+ g_list_insert_sorted (igenerator->module->entries, ginode,
+ (GCompareFunc) g_idl_node_cmp);
+ g_hash_table_insert (igenerator->type_map, ginode->node.name,
+ ginode);
+ g_hash_table_insert (igenerator->type_by_lower_case_prefix,
+ lower_case_prefix, ginode);
+ ginode->gtype_name = ginode->node.name;
+ ginode->gtype_init = g_strdup (symbol_name);
+
+ type_class = g_type_class_ref (type_id);
+
+ for (i = 0; i < type_class->n_values; i++)
+ {
+ GIdlNodeValue *gival =
+ (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
+ ginode->values = g_list_append (ginode->values, gival);
+ gival->node.name =
+ g_strdup (type_class->values[i].value_name);
+ gival->value = type_class->values[i].value;
+ }
+}
+
+static void
+g_igenerator_create_flags (GIGenerator *igenerator,
+ const char *symbol_name,
+ GType type_id,
+ char *lower_case_prefix)
+{
+ GIdlNodeEnum *ginode;
+ GFlagsClass *type_class;
+ int i;
+
+ ginode = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_FLAGS);
+ ginode->node.name = g_strdup (g_type_name (type_id));
+ igenerator->module->entries =
+ g_list_insert_sorted (igenerator->module->entries, ginode,
+ (GCompareFunc) g_idl_node_cmp);
+ g_hash_table_insert (igenerator->type_map, ginode->node.name,
+ ginode);
+ g_hash_table_insert (igenerator->type_by_lower_case_prefix,
+ lower_case_prefix, ginode);
+ ginode->gtype_name = ginode->node.name;
+ ginode->gtype_init = g_strdup (symbol_name);
+
+ type_class = g_type_class_ref (type_id);
+
+ for (i = 0; i < type_class->n_values; i++)
+ {
+ GIdlNodeValue *gival =
+ (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
+ ginode->values = g_list_append (ginode->values, gival);
+ gival->node.name =
+ g_strdup (type_class->values[i].value_name);
+ gival->value = type_class->values[i].value;
+ }
+}
+
+static gboolean
+g_igenerator_process_module_symbol (GIGenerator *igenerator,
+ GModule *module,
+ const gchar *symbol_name)
+{
+ TypeFunction type_fun;
+ GType type_id;
+ GType type_fundamental;
+ char *lower_case_prefix;
+
+ /* ignore already processed functions */
+ if (symbol_name == NULL)
+ return FALSE;
+
+ if (!g_module_symbol (module,
+ symbol_name,
+ (gpointer *) & type_fun))
+ return FALSE;
+
+ type_id = type_fun ();
+ type_fundamental = g_type_fundamental (type_id);
+ lower_case_prefix =
+ str_replace (g_strndup
+ (symbol_name,
+ strlen (symbol_name) - strlen ("_get_type")),
+ "_", "");
+
+ switch (type_fundamental)
+ {
+ case G_TYPE_OBJECT:
+ g_igenerator_create_object (igenerator, symbol_name, type_id,
+ lower_case_prefix);
+ break;
+ case G_TYPE_INTERFACE:
+ g_igenerator_create_interface (igenerator, symbol_name, type_id,
+ lower_case_prefix);
+ break;
+ case G_TYPE_BOXED:
+ g_igenerator_create_boxed (igenerator, symbol_name, type_id,
+ lower_case_prefix);
+ break;
+ case G_TYPE_ENUM:
+ g_igenerator_create_enum (igenerator, symbol_name, type_id,
+ lower_case_prefix);
+ break;
+ case G_TYPE_FLAGS:
+ g_igenerator_create_flags (igenerator, symbol_name, type_id,
+ lower_case_prefix);
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+static void
+g_igenerator_process_module (GIGenerator * igenerator,
+ const gchar *filename)
+{
+ GModule *module;
+ GList *l;
+
+ module = g_module_open (filename,
+ G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+
+ if (module == NULL)
+ {
+ g_critical ("Couldn't open module: %s", filename);
+ return;
+ }
+
+ for (l = igenerator->get_type_symbols; l != NULL; l = l->next)
+ {
+ if (g_igenerator_process_module_symbol (igenerator,
+ module, (const char *)l->data))
+ /* symbol found, ignore in future iterations */
+ l->data = NULL;
+ }
+}
+
+static GIdlNodeType *
+get_type_from_ctype (CType * ctype)
+{
+ GIdlNodeType *gitype = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
+ if (ctype->type == CTYPE_VOID)
+ {
+ gitype->unparsed = g_strdup ("void");
+ }
+ else if (ctype->type == CTYPE_BASIC_TYPE)
+ {
+ gitype->unparsed = g_strdup (ctype->name);
+ }
+ else if (ctype->type == CTYPE_TYPEDEF)
+ {
+ gitype->unparsed = g_strdup (ctype->name);
+ }
+ else if (ctype->type == CTYPE_STRUCT)
+ {
+ if (ctype->name == NULL)
+ {
+ /* anonymous struct */
+ gitype->unparsed = g_strdup ("gpointer");
+ }
+ else
+ {
+ gitype->unparsed = g_strdup_printf ("struct %s", ctype->name);
+ }
+ }
+ else if (ctype->type == CTYPE_UNION)
+ {
+ if (ctype->name == NULL)
+ {
+ /* anonymous union */
+ gitype->unparsed = g_strdup ("gpointer");
+ }
+ else
+ {
+ gitype->unparsed = g_strdup_printf ("union %s", ctype->name);
+ }
+ }
+ else if (ctype->type == CTYPE_ENUM)
+ {
+ if (ctype->name == NULL)
+ {
+ /* anonymous enum */
+ gitype->unparsed = g_strdup ("gint");
+ }
+ else
+ {
+ gitype->unparsed = g_strdup_printf ("enum %s", ctype->name);
+ }
+ }
+ else if (ctype->type == CTYPE_POINTER)
+ {
+ if (ctype->base_type->type == CTYPE_FUNCTION)
+ {
+ /* anonymous function pointer */
+ gitype->unparsed = g_strdup ("GCallback");
+ }
+ else
+ {
+ GIdlNodeType *gibasetype = get_type_from_ctype (ctype->base_type);
+ gitype->unparsed = g_strdup_printf ("%s*", gibasetype->unparsed);
+ }
+ }
+ else if (ctype->type == CTYPE_ARRAY)
+ {
+ GIdlNodeType *gibasetype = get_type_from_ctype (ctype->base_type);
+ gitype->unparsed = g_strdup_printf ("%s[]", gibasetype->unparsed);
+ }
+ else
+ {
+ gitype->unparsed = g_strdup ("unknown");
+ }
+ return gitype;
+}
+
+static void
+g_igenerator_process_function_symbol (GIGenerator * igenerator, CSymbol * sym)
+{
+ GIdlNodeFunction *gifunc =
+ (GIdlNodeFunction *) g_idl_node_new (G_IDL_NODE_FUNCTION);
+ /* check whether this is a type method */
+ char *last_underscore = strrchr (sym->ident, '_');
+ GList *param_l;
+ int i;
+ GSList *l;
+
+ while (last_underscore != NULL)
+ {
+ char *prefix =
+ str_replace (g_strndup (sym->ident, last_underscore - sym->ident),
+ "_", "");
+ GIdlNode *ginode =
+ g_hash_table_lookup (igenerator->type_by_lower_case_prefix, prefix);
+ if (ginode != NULL)
+ {
+ gifunc->node.name = g_strdup (last_underscore + 1);
+ if (strcmp (gifunc->node.name, "get_type") == 0)
+ {
+ /* ignore get_type functions in registered types */
+ return;
+ }
+ if ((ginode->type == G_IDL_NODE_OBJECT
+ || ginode->type == G_IDL_NODE_BOXED)
+ && g_str_has_prefix (gifunc->node.name, "new"))
+ {
+ gifunc->is_constructor = TRUE;
+ }
+ else
+ {
+ gifunc->is_method = TRUE;
+ }
+ if (ginode->type == G_IDL_NODE_OBJECT
+ || ginode->type == G_IDL_NODE_INTERFACE)
+ {
+ GIdlNodeInterface *giiface = (GIdlNodeInterface *) ginode;
+ giiface->members =
+ g_list_insert_sorted (giiface->members, gifunc,
+ (GCompareFunc) g_idl_node_cmp);
+ break;
+ }
+ else if (ginode->type == G_IDL_NODE_BOXED)
+ {
+ GIdlNodeBoxed *giboxed = (GIdlNodeBoxed *) ginode;
+ giboxed->members =
+ g_list_insert_sorted (giboxed->members, gifunc,
+ (GCompareFunc) g_idl_node_cmp);
+ break;
+ }
+ else if (ginode->type == G_IDL_NODE_STRUCT)
+ {
+ GIdlNodeStruct *gistruct = (GIdlNodeStruct *) ginode;
+ gistruct->members =
+ g_list_insert_sorted (gistruct->members, gifunc,
+ (GCompareFunc) g_idl_node_cmp);
+ break;
+ }
+ else if (ginode->type == G_IDL_NODE_UNION)
+ {
+ GIdlNodeUnion *giunion = (GIdlNodeUnion *) ginode;
+ giunion->members =
+ g_list_insert_sorted (giunion->members, gifunc,
+ (GCompareFunc) g_idl_node_cmp);
+ break;
+ }
+ }
+ else if (strcmp (igenerator->lower_case_namespace, prefix) == 0)
+ {
+ gifunc->node.name = g_strdup (last_underscore + 1);
+ gifunc->is_constructor = FALSE;
+ gifunc->is_method = FALSE;
+ igenerator->module->entries =
+ g_list_insert_sorted (igenerator->module->entries, gifunc,
+ (GCompareFunc) g_idl_node_cmp);
+ break;
+ }
+ last_underscore =
+ g_utf8_strrchr (sym->ident, last_underscore - sym->ident, '_');
+ }
+
+ /* create a namespace function if no prefix matches */
+ if (gifunc->node.name == NULL)
+ {
+ gifunc->node.name = sym->ident;
+ gifunc->is_constructor = FALSE;
+ gifunc->is_method = FALSE;
+ igenerator->module->entries =
+ g_list_insert_sorted (igenerator->module->entries, gifunc,
+ (GCompareFunc) g_idl_node_cmp);
+ }
+
+ gifunc->symbol = sym->ident;
+ gifunc->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+ gifunc->result->type = get_type_from_ctype (sym->base_type->base_type);
+
+ for (param_l = sym->base_type->child_list, i = 1; param_l != NULL;
+ param_l = param_l->next, i++)
+ {
+ CSymbol *param_sym = param_l->data;
+ GIdlNodeParam *param =
+ (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+ if (param_sym->ident == NULL)
+ {
+ param->node.name = g_strdup_printf ("p%d", i);
+ }
+ else
+ {
+ param->node.name = param_sym->ident;
+ }
+ param->type = get_type_from_ctype (param_sym->base_type);
+ gifunc->parameters = g_list_append (gifunc->parameters, param);
+ }
+
+ for (l = sym->directives; l; l = l->next)
+ {
+ CDirective *directive = (CDirective*)l->data;
+
+ if (!strcmp (directive->name, "deprecated"))
+ gifunc->deprecated = strcmp (directive->value, "1") == 0;
+ else
+ g_printerr ("Unknown function directive: %s\n",
+ directive->name);
+ }
+}
+
+static void
+g_igenerator_process_unregistered_struct_typedef (GIGenerator * igenerator,
+ CSymbol * sym,
+ CType * struct_type)
+{
+ GIdlNodeStruct *ginode =
+ (GIdlNodeStruct *) g_idl_node_new (G_IDL_NODE_STRUCT);
+ GList *member_l;
+ char *lower_case_prefix;
+
+ ginode->node.name = sym->ident;
+ igenerator->module->entries =
+ g_list_insert_sorted (igenerator->module->entries, ginode,
+ (GCompareFunc) g_idl_node_cmp);
+ lower_case_prefix = g_ascii_strdown (sym->ident, -1);
+ g_hash_table_insert (igenerator->type_map, sym->ident, ginode);
+ g_hash_table_insert (igenerator->type_by_lower_case_prefix,
+ lower_case_prefix, ginode);
+
+ for (member_l = struct_type->child_list; member_l != NULL;
+ member_l = member_l->next)
+ {
+ CSymbol *member = member_l->data;
+ GIdlNodeField *gifield =
+ (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
+
+ ginode->members = g_list_append (ginode->members, gifield);
+ gifield->node.name = member->ident;
+ gifield->type = get_type_from_ctype (member->base_type);
+ }
+}
+
+static void
+g_igenerator_process_struct_typedef (GIGenerator * igenerator, CSymbol * sym)
+{
+ CType *struct_type = sym->base_type;
+ gboolean opaque_type = FALSE;
+ GIdlNode *gitype;
+
+ if (struct_type->child_list == NULL)
+ {
+ CSymbol *struct_symbol;
+ g_assert (struct_type->name != NULL);
+ struct_symbol =
+ g_hash_table_lookup (igenerator->struct_or_union_or_enum_table,
+ struct_type->name);
+ if (struct_symbol != NULL)
+ {
+ struct_type = struct_symbol->base_type;
+ }
+ }
+
+ if (struct_type->child_list == NULL)
+ {
+ opaque_type = TRUE;
+ }
+
+ gitype = g_hash_table_lookup (igenerator->type_map, sym->ident);
+ if (gitype != NULL)
+ {
+ /* struct of a GTypeInstance */
+ if (!opaque_type
+ && (gitype->type == G_IDL_NODE_OBJECT
+ || gitype->type == G_IDL_NODE_INTERFACE))
+ {
+ GIdlNodeInterface *ginode = (GIdlNodeInterface *) gitype;
+ GList *member_l;
+ /* ignore first field => parent */
+ for (member_l = struct_type->child_list->next; member_l != NULL;
+ member_l = member_l->next)
+ {
+ CSymbol *member = member_l->data;
+ /* ignore private / reserved members */
+ if (member->ident[0] == '_'
+ || g_str_has_prefix (member->ident, "priv"))
+ {
+ continue;
+ }
+ GIdlNodeField *gifield =
+ (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
+ ginode->members = g_list_append (ginode->members, gifield);
+ gifield->node.name = member->ident;
+ gifield->type = get_type_from_ctype (member->base_type);
+ }
+ }
+ else if (gitype->type == G_IDL_NODE_BOXED)
+ {
+ GIdlNodeBoxed *ginode = (GIdlNodeBoxed *) gitype;
+ GList *member_l;
+ for (member_l = struct_type->child_list; member_l != NULL;
+ member_l = member_l->next)
+ {
+ CSymbol *member = member_l->data;
+ GIdlNodeField *gifield =
+ (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
+ ginode->members = g_list_append (ginode->members, gifield);
+ gifield->node.name = member->ident;
+ gifield->type = get_type_from_ctype (member->base_type);
+ }
+ }
+ }
+ else if (!opaque_type
+ && (g_str_has_suffix (sym->ident, "Class")
+ || g_str_has_suffix (sym->ident, "Iface")
+ || g_str_has_suffix (sym->ident, "Interface")))
+ {
+ char *base_name;
+ GList *member_l;
+ GIdlNodeInterface *ginode;
+
+ if (g_str_has_suffix (sym->ident, "Interface"))
+ {
+ base_name =
+ g_strndup (sym->ident,
+ strlen (sym->ident) - strlen ("Interface"));
+ }
+ else
+ {
+ base_name =
+ g_strndup (sym->ident, strlen (sym->ident) - strlen ("Class"));
+ }
+ gitype = g_hash_table_lookup (igenerator->type_map, base_name);
+ if (gitype == NULL
+ || (gitype->type != G_IDL_NODE_OBJECT
+ && gitype->type != G_IDL_NODE_INTERFACE))
+ {
+ g_igenerator_process_unregistered_struct_typedef (igenerator, sym,
+ struct_type);
+ return;
+ }
+ ginode = (GIdlNodeInterface *) gitype;
+
+ /* ignore first field => parent */
+ for (member_l = struct_type->child_list->next; member_l != NULL;
+ member_l = member_l->next)
+ {
+ CSymbol *member = member_l->data;
+ /* ignore private / reserved members */
+ if (member->ident[0] == '_')
+ {
+ continue;
+ }
+ if (member->base_type->type == CTYPE_POINTER
+ && member->base_type->base_type->type == CTYPE_FUNCTION)
+ {
+ /* ignore default handlers of signals */
+ gboolean found_signal = FALSE;
+ GList *type_member_l;
+ GList *param_l;
+ int i;
+ GIdlNodeVFunc *givfunc;
+
+ for (type_member_l = ginode->members; type_member_l != NULL;
+ type_member_l = type_member_l->next)
+ {
+ GIdlNode *type_member = type_member_l->data;
+ char *normalized_name =
+ str_replace (type_member->name, "-", "_");
+ if (type_member->type == G_IDL_NODE_SIGNAL
+ && strcmp (normalized_name, member->ident) == 0)
+ {
+ GList *vfunc_param_l;
+ GList *sig_param_l;
+ GIdlNodeSignal *sig = (GIdlNodeSignal *) type_member;
+ found_signal = TRUE;
+ /* set signal parameter names */
+ for (vfunc_param_l =
+ member->base_type->base_type->child_list,
+ sig_param_l = sig->parameters;
+ vfunc_param_l != NULL && sig_param_l != NULL;
+ vfunc_param_l = vfunc_param_l->next, sig_param_l =
+ sig_param_l->next)
+ {
+ CSymbol *vfunc_param = vfunc_param_l->data;
+ GIdlNodeParam *sig_param = sig_param_l->data;
+ if (vfunc_param->ident != NULL)
+ {
+ g_free (sig_param->node.name);
+ sig_param->node.name =
+ g_strdup (vfunc_param->ident);
+ }
+ }
+ break;
+ }
+ }
+ if (found_signal)
+ {
+ continue;
+ }
+
+ givfunc = (GIdlNodeVFunc *) g_idl_node_new (G_IDL_NODE_VFUNC);
+ givfunc->node.name = member->ident;
+ ginode->members =
+ g_list_insert_sorted (ginode->members, givfunc,
+ (GCompareFunc) g_idl_node_cmp);
+ givfunc->result =
+ (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+ givfunc->result->type =
+ get_type_from_ctype (member->base_type->base_type->base_type);
+ for (param_l = member->base_type->base_type->child_list, i = 1;
+ param_l != NULL; param_l = param_l->next, i++)
+ {
+ CSymbol *param_sym = param_l->data;
+ GIdlNodeParam *param =
+ (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+ if (param_sym->ident == NULL)
+ {
+ param->node.name = g_strdup_printf ("p%d", i);
+ }
+ else
+ {
+ param->node.name = param_sym->ident;
+ }
+ param->type = get_type_from_ctype (param_sym->base_type);
+ givfunc->parameters =
+ g_list_append (givfunc->parameters, param);
+ }
+ }
+ }
+ }
+ else if (g_str_has_suffix (sym->ident, "Private"))
+ {
+ /* ignore private structs */
+ }
+ else
+ {
+ g_igenerator_process_unregistered_struct_typedef (igenerator, sym,
+ struct_type);
+ }
+}
+
+static void
+g_igenerator_process_union_typedef (GIGenerator * igenerator, CSymbol * sym)
+{
+ CType *union_type = sym->base_type;
+ gboolean opaque_type = FALSE;
+ GIdlNode *gitype;
+
+ if (union_type->child_list == NULL)
+ {
+ g_assert (union_type->name != NULL);
+ CSymbol *union_symbol =
+ g_hash_table_lookup (igenerator->struct_or_union_or_enum_table,
+ union_type->name);
+ if (union_symbol != NULL)
+ {
+ union_type = union_symbol->base_type;
+ }
+ }
+ if (union_type->child_list == NULL)
+ {
+ opaque_type = TRUE;
+ }
+
+ gitype = g_hash_table_lookup (igenerator->type_map, sym->ident);
+ if (gitype != NULL)
+ {
+ g_assert (gitype->type == G_IDL_NODE_BOXED);
+ GIdlNodeBoxed *ginode = (GIdlNodeBoxed *) gitype;
+ GList *member_l;
+ for (member_l = union_type->child_list; member_l != NULL;
+ member_l = member_l->next)
+ {
+ CSymbol *member = member_l->data;
+ GIdlNodeField *gifield =
+ (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
+ ginode->members = g_list_append (ginode->members, gifield);
+ gifield->node.name = member->ident;
+ gifield->type = get_type_from_ctype (member->base_type);
+ }
+ }
+ else
+ {
+ GIdlNodeUnion *ginode =
+ (GIdlNodeUnion *) g_idl_node_new (G_IDL_NODE_UNION);
+ char *lower_case_prefix;
+ GList *member_l;
+
+ ginode->node.name = sym->ident;
+ igenerator->module->entries =
+ g_list_insert_sorted (igenerator->module->entries, ginode,
+ (GCompareFunc) g_idl_node_cmp);
+ lower_case_prefix = g_ascii_strdown (sym->ident, -1);
+ g_hash_table_insert (igenerator->type_map, sym->ident, ginode);
+ g_hash_table_insert (igenerator->type_by_lower_case_prefix,
+ lower_case_prefix, ginode);
+
+ ginode->node.name = sym->ident;
+ for (member_l = union_type->child_list; member_l != NULL;
+ member_l = member_l->next)
+ {
+ CSymbol *member = member_l->data;
+ GIdlNodeField *gifield =
+ (GIdlNodeField *) g_idl_node_new (G_IDL_NODE_FIELD);
+ ginode->members = g_list_append (ginode->members, gifield);
+ gifield->node.name = member->ident;
+ gifield->type = get_type_from_ctype (member->base_type);
+ }
+ }
+}
+
+static void
+g_igenerator_process_enum_typedef (GIGenerator * igenerator, CSymbol * sym)
+{
+ CType *enum_type;
+ GList *member_l;
+ GIdlNodeEnum *ginode;
+ CSymbol *enum_symbol;
+
+ enum_type = sym->base_type;
+ if (enum_type->child_list == NULL)
+ {
+ g_assert (enum_type->name != NULL);
+ enum_symbol =
+ g_hash_table_lookup (igenerator->struct_or_union_or_enum_table,
+ enum_type->name);
+ if (enum_symbol != NULL)
+ {
+ enum_type = enum_symbol->base_type;
+ }
+ }
+ if (enum_type->child_list == NULL)
+ {
+ /* opaque type */
+ return;
+ }
+
+ ginode = g_hash_table_lookup (igenerator->type_map, sym->ident);
+ if (ginode != NULL)
+ {
+ return;
+ }
+
+ ginode = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_ENUM);
+ ginode->node.name = sym->ident;
+ igenerator->module->entries =
+ g_list_insert_sorted (igenerator->module->entries, ginode,
+ (GCompareFunc) g_idl_node_cmp);
+
+ for (member_l = enum_type->child_list; member_l != NULL;
+ member_l = member_l->next)
+ {
+ CSymbol *member = member_l->data;
+ GIdlNodeValue *gival =
+ (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
+ ginode->values = g_list_append (ginode->values, gival);
+ gival->node.name = member->ident;
+ gival->value = member->const_int;
+ }
+}
+
+static void
+g_igenerator_process_function_typedef (GIGenerator * igenerator,
+ CSymbol * sym)
+{
+ GList *param_l;
+ int i;
+
+ /* handle callback types */
+ GIdlNodeFunction *gifunc =
+ (GIdlNodeFunction *) g_idl_node_new (G_IDL_NODE_CALLBACK);
+
+ gifunc->node.name = sym->ident;
+ igenerator->module->entries =
+ g_list_insert_sorted (igenerator->module->entries, gifunc,
+ (GCompareFunc) g_idl_node_cmp);
+
+ gifunc->symbol = sym->ident;
+ gifunc->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+ gifunc->result->type =
+ get_type_from_ctype (sym->base_type->base_type->base_type);
+
+ for (param_l = sym->base_type->base_type->child_list, i = 1;
+ param_l != NULL; param_l = param_l->next, i++)
+ {
+ CSymbol *param_sym = param_l->data;
+ GIdlNodeParam *param =
+ (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
+ if (param_sym->ident == NULL)
+ {
+ param->node.name = g_strdup_printf ("p%d", i);
+ }
+ else
+ {
+ param->node.name = param_sym->ident;
+ }
+ param->type = get_type_from_ctype (param_sym->base_type);
+ gifunc->parameters = g_list_append (gifunc->parameters, param);
+ }
+}
+
+static void
+g_igenerator_process_constant (GIGenerator * igenerator, CSymbol * sym)
+{
+ GIdlNodeConstant *giconst =
+ (GIdlNodeConstant *) g_idl_node_new (G_IDL_NODE_CONSTANT);
+ giconst->node.name = sym->ident;
+ igenerator->module->entries =
+ g_list_insert_sorted (igenerator->module->entries, giconst,
+ (GCompareFunc) g_idl_node_cmp);
+
+ giconst->type = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);
+ if (sym->const_int_set)
+ {
+ giconst->type->unparsed = g_strdup ("int");
+ giconst->value = g_strdup_printf ("%d", sym->const_int);
+ }
+ else if (sym->const_string != NULL)
+ {
+ giconst->type->unparsed = g_strdup ("char*");
+ giconst->value = sym->const_string;
+ }
+}
+
+static void
+g_igenerator_process_symbols (GIGenerator * igenerator)
+{
+ GList *l;
+ /* process type symbols first to ensure complete type hashtables */
+ /* type symbols */
+ for (l = igenerator->symbol_list; l != NULL; l = l->next)
+ {
+ CSymbol *sym = l->data;
+ if (sym->ident[0] == '_')
+ {
+ /* ignore private / reserved symbols */
+ continue;
+ }
+ if (sym->type == CSYMBOL_TYPE_TYPEDEF)
+ {
+ if (sym->base_type->type == CTYPE_STRUCT)
+ {
+ g_igenerator_process_struct_typedef (igenerator, sym);
+ }
+ else if (sym->base_type->type == CTYPE_UNION)
+ {
+ g_igenerator_process_union_typedef (igenerator, sym);
+ }
+ else if (sym->base_type->type == CTYPE_ENUM)
+ {
+ g_igenerator_process_enum_typedef (igenerator, sym);
+ }
+ else if (sym->base_type->type == CTYPE_POINTER
+ && sym->base_type->base_type->type == CTYPE_FUNCTION)
+ {
+ g_igenerator_process_function_typedef (igenerator, sym);
+ }
+ else
+ {
+ GIdlNodeStruct *ginode =
+ (GIdlNodeStruct *) g_idl_node_new (G_IDL_NODE_STRUCT);
+ char *lower_case_prefix;
+
+ ginode->node.name = sym->ident;
+ igenerator->module->entries =
+ g_list_insert_sorted (igenerator->module->entries, ginode,
+ (GCompareFunc) g_idl_node_cmp);
+ lower_case_prefix = g_ascii_strdown (sym->ident, -1);
+ g_hash_table_insert (igenerator->type_map, sym->ident, ginode);
+ g_hash_table_insert (igenerator->type_by_lower_case_prefix,
+ lower_case_prefix, ginode);
+ }
+ }
+ }
+ /* other symbols */
+ for (l = igenerator->symbol_list; l != NULL; l = l->next)
+ {
+ CSymbol *sym = l->data;
+ if (sym->ident[0] == '_')
+ {
+ /* ignore private / reserved symbols */
+ continue;
+ }
+ if (sym->type == CSYMBOL_TYPE_FUNCTION)
+ {
+ g_igenerator_process_function_symbol (igenerator, sym);
+ }
+ else if (sym->type == CSYMBOL_TYPE_CONST)
+ {
+ g_igenerator_process_constant (igenerator, sym);
+ }
+ }
+}
+
+void
+g_igenerator_add_symbol (GIGenerator * igenerator, CSymbol * symbol)
+{
+ /* only add symbols of main file */
+ gboolean found_filename = FALSE;
+ GList *l;
+ for (l = igenerator->filenames; l != NULL; l = l->next)
+ {
+ if (strcmp (l->data, igenerator->current_filename) == 0)
+ {
+ found_filename = TRUE;
+ break;
+ }
+ }
+
+ symbol->directives = g_slist_reverse (igenerator->directives);
+ igenerator->directives = NULL;
+
+ if (found_filename || igenerator->macro_scan)
+ {
+ igenerator->symbol_list =
+ g_list_prepend (igenerator->symbol_list, symbol);
+ }
+
+ if (symbol->type == CSYMBOL_TYPE_TYPEDEF)
+
+ {
+ g_hash_table_insert (igenerator->typedef_table, symbol->ident, symbol);
+ }
+ else if (symbol->type == CSYMBOL_TYPE_STRUCT
+ || symbol->type == CSYMBOL_TYPE_UNION
+ || symbol->type == CSYMBOL_TYPE_ENUM)
+ {
+ g_hash_table_insert (igenerator->struct_or_union_or_enum_table,
+ symbol->ident, symbol);
+ }
+}
+
+gboolean
+g_igenerator_is_typedef (GIGenerator * igenerator, const char *name)
+{
+ gboolean b = g_hash_table_lookup (igenerator->typedef_table, name) != NULL;
+ return b;
+}
+
+void
+g_igenerator_generate (GIGenerator * igenerator,
+ const gchar * filename,
+ GList *libraries)
+{
+ GList *l;
+
+ for (l = igenerator->symbol_list; l != NULL; l = l->next)
+ {
+ CSymbol *sym = l->data;
+ if (sym->type == CSYMBOL_TYPE_FUNCTION
+ && g_str_has_suffix (sym->ident, "_get_type"))
+ {
+ if (sym->base_type->child_list == NULL)
+ {
+ // ignore get_type functions with parameters
+ igenerator->get_type_symbols =
+ g_list_prepend (igenerator->get_type_symbols, sym->ident);
+ }
+ }
+ }
+
+ /* ensure to initialize GObject */
+ g_type_class_ref (G_TYPE_OBJECT);
+
+ for (l = libraries; l; l = l->next)
+ g_igenerator_process_module (igenerator, (const gchar*)l->data);
+
+ g_igenerator_process_symbols (igenerator);
+
+ g_idl_writer_save_file (igenerator->module, filename);
+}
+
+static int
+eat_hspace (FILE * f)
+{
+ int c;
+ do
+ {
+ c = fgetc (f);
+ }
+ while (c == ' ' || c == '\t');
+ return c;
+}
+
+static int
+eat_line (FILE * f, int c)
+{
+ while (c != EOF && c != '\n')
+ {
+ c = fgetc (f);
+ }
+ if (c == '\n')
+ {
+ c = fgetc (f);
+ if (c == ' ' || c == '\t')
+ {
+ c = eat_hspace (f);
+ }
+ }
+ return c;
+}
+
+static int
+read_identifier (FILE * f, int c, char **identifier)
+{
+ GString *id = g_string_new ("");
+ while (isalnum (c) || c == '_')
+ {
+ g_string_append_c (id, c);
+ c = fgetc (f);
+ }
+ *identifier = g_string_free (id, FALSE);
+ return c;
+}
+
+static void
+g_igenerator_parse_macros (GIGenerator * igenerator)
+{
+ GError *error = NULL;
+ char *tmp_name = NULL;
+ FILE *fmacros =
+ fdopen (g_file_open_tmp ("gen-introspect-XXXXXX.h", &tmp_name, &error),
+ "w+");
+ g_unlink (tmp_name);
+
+ GList *l;
+ for (l = igenerator->filenames; l != NULL; l = l->next)
+ {
+ FILE *f = fopen (l->data, "r");
+ int line = 1;
+
+ GString *define_line;
+ char *str;
+ gboolean error_line = FALSE;
+ int c = eat_hspace (f);
+ while (c != EOF)
+ {
+ if (c != '#')
+ {
+ /* ignore line */
+ c = eat_line (f, c);
+ line++;
+ continue;
+ }
+
+ /* print current location */
+ str = g_strescape (l->data, "");
+ fprintf (fmacros, "# %d \"%s\"\n", line, str);
+ g_free (str);
+
+ c = eat_hspace (f);
+ c = read_identifier (f, c, &str);
+ if (strcmp (str, "define") != 0 || (c != ' ' && c != '\t'))
+ {
+ g_free (str);
+ /* ignore line */
+ c = eat_line (f, c);
+ line++;
+ continue;
+ }
+ g_free (str);
+ c = eat_hspace (f);
+ c = read_identifier (f, c, &str);
+ if (strlen (str) == 0 || (c != ' ' && c != '\t' && c != '('))
+ {
+ g_free (str);
+ /* ignore line */
+ c = eat_line (f, c);
+ line++;
+ continue;
+ }
+ define_line = g_string_new ("#define ");
+ g_string_append (define_line, str);
+ g_free (str);
+ if (c == '(')
+ {
+ while (c != ')')
+ {
+ g_string_append_c (define_line, c);
+ c = fgetc (f);
+ if (c == EOF || c == '\n')
+ {
+ error_line = TRUE;
+ break;
+ }
+ }
+ if (error_line)
+ {
+ g_string_free (define_line, TRUE);
+ /* ignore line */
+ c = eat_line (f, c);
+ line++;
+ continue;
+ }
+
+ g_assert (c == ')');
+ g_string_append_c (define_line, c);
+ c = fgetc (f);
+
+ /* found function-like macro */
+ fprintf (fmacros, "%s\n", define_line->str);
+
+ g_string_free (define_line, TRUE);
+ /* ignore rest of line */
+ c = eat_line (f, c);
+ line++;
+ continue;
+ }
+ if (c != ' ' && c != '\t')
+ {
+ g_string_free (define_line, TRUE);
+ /* ignore line */
+ c = eat_line (f, c);
+ line++;
+ continue;
+ }
+ while (c != EOF && c != '\n')
+ {
+ g_string_append_c (define_line, c);
+ c = fgetc (f);
+ if (c == '\\')
+ {
+ c = fgetc (f);
+ if (c == '\n')
+ {
+ /* fold lines when seeing backslash new-line sequence */
+ c = fgetc (f);
+ }
+ else
+ {
+ g_string_append_c (define_line, '\\');
+ }
+ }
+ }
+
+ /* found object-like macro */
+ fprintf (fmacros, "%s\n", define_line->str);
+
+ c = eat_line (f, c);
+ line++;
+ }
+
+ fclose (f);
+ }
+
+ igenerator->macro_scan = TRUE;
+ rewind (fmacros);
+
+ g_igenerator_parse_file (igenerator, fmacros);
+ fclose (fmacros);
+
+ igenerator->macro_scan = FALSE;
+}
+
+static void
+g_igenerator_add_module (GIGenerator *igenerator,
+ GIdlModule *module)
+{
+ GList *l;
+
+ for (l = module->entries; l; l = l->next)
+ {
+ GIdlNode *node = (GIdlNode*)l->data;
+
+ if (node->type == G_IDL_NODE_OBJECT)
+ {
+ GIdlNodeInterface *object = (GIdlNodeInterface*)node;
+ gchar *name;
+ if (strcmp(module->name, igenerator->namespace) == 0)
+ name = g_strdup (node->name);
+ else
+ name = g_strdup_printf ("%s.%s", module->name, node->name);
+ g_hash_table_insert (igenerator->symbols,
+ g_strdup (object->gtype_name),
+ name);
+ }
+ }
+}
+
+static void
+g_igenerator_add_include_idl (GIGenerator *igenerator,
+ const gchar *filename)
+{
+ GList *l;
+ GList *modules;
+
+ GError *error = NULL;
+
+ modules = g_idl_parse_file (filename, &error);
+ if (error)
+ {
+ g_printerr ("An error occured while parsing %s: %s\n",
+ filename, error->message);
+ return;
+ }
+
+ for (l = modules; l; l = l->next)
+ {
+ GIdlModule *module = (GIdlModule*)l->data;
+ g_igenerator_add_module (igenerator, module);
+ }
+}
+
+static FILE *
+g_igenerator_start_preprocessor (GIGenerator *igenerator,
+ GList *cpp_options)
+{
+ int cpp_out = -1, cpp_in = -1;
+ int cpp_argc = 0;
+ char **cpp_argv;
+ GList *l;
+ GError *error = NULL;
+ FILE *f, *out;
+ GPid pid;
+ int status = 0;
+ int read_bytes;
+ int i;
+ char **buffer;
+ int tmp;
+ char *tmpname;
+
+ cpp_argv = g_new0 (char *, g_list_length (cpp_options) + 4);
+ cpp_argv[cpp_argc++] = "cpp";
+ cpp_argv[cpp_argc++] = "-C";
+
+ /* Disable GCC extensions as we cannot parse them yet */
+ cpp_argv[cpp_argc++] = "-U__GNUC__";
+
+ for (l = cpp_options; l; l = l->next)
+ cpp_argv[cpp_argc++] = (char*)l->data;
+
+ cpp_argv[cpp_argc++] = NULL;
+
+ if (igenerator->verbose)
+ {
+ GString *args = g_string_new ("");
+
+ for (i = 0; i < cpp_argc - 1; i++)
+ {
+ g_string_append (args, cpp_argv[i]);
+ if (i < cpp_argc - 2)
+ g_string_append_c (args, ' ');
+ }
+
+ g_printf ("Executing '%s'\n", args->str);
+ g_string_free (args, FALSE);
+ }
+ g_spawn_async_with_pipes (NULL, cpp_argv, NULL,
+ G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL, NULL, &pid, &cpp_in, &cpp_out, NULL, &error);
+
+ g_free (cpp_argv);
+ if (error != NULL)
+ {
+ g_error ("%s", error->message);
+ return NULL;
+ }
+
+ f = fdopen (cpp_in, "w");
+
+ for (l = igenerator->filenames; l != NULL; l = l->next)
+ {
+ if (igenerator->verbose)
+ g_printf ("Pre-processing %s\n", (char*)l->data);
+
+ fprintf (f, "#include <%s>\n", (char *) l->data);
+
+ }
+
+ fclose (f);
+ close (cpp_in);
+
+ tmp = g_file_open_tmp (NULL, &tmpname, &error);
+ if (error != NULL)
+ {
+ g_error (error->message);
+ return NULL;
+ }
+
+ buffer = g_malloc0 (4096 * sizeof (char));
+
+ while (1)
+ {
+ read_bytes = read (cpp_out, buffer, 4096);
+ if (read_bytes == 0)
+ break;
+ write (tmp, buffer, read_bytes);
+ }
+
+ g_free (buffer);
+
+ close (cpp_out);
+
+ if (waitpid (pid, &status, 0) > 0)
+ {
+ if (status != 0)
+ {
+ g_spawn_close_pid (pid);
+ kill (pid, SIGKILL);
+
+ g_error ("cpp returned error code: %d\n", status);
+ unlink (tmpname);
+ g_free (tmpname);
+ return NULL;
+ }
+ }
+
+ f = fdopen (tmp, "r");
+ if (!f)
+ {
+ g_error (strerror (errno));
+ unlink (tmpname);
+ g_free (tmpname);
+ return NULL;
+ }
+ rewind (f);
+ unlink (tmpname);
+ g_free (tmpname);
+
+ return f;
+}
+
+
+void
+g_igenerator_set_verbose (GIGenerator *igenerator,
+ gboolean verbose)
+{
+ igenerator->verbose = verbose;
+}
+
+int
+main (int argc, char **argv)
+{
+ GOptionContext *ctx;
+ gchar *namespace = NULL;
+ gchar *shared_library = NULL;
+ gchar **include_idls = NULL;
+ gchar *output = NULL;
+ gboolean verbose = FALSE;
+
+ GIGenerator *igenerator;
+ int gopt_argc, i;
+ char **gopt_argv;
+ GList *filenames = NULL;
+ GError *error = NULL;
+ GList *l, *libraries = NULL;
+ GList *cpp_options = NULL;
+ char *buffer;
+ size_t size;
+ FILE *tmp;
+ GOptionEntry entries[] =
+ {
+ { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
+ "Be verbose" },
+ { "output", 'o', 0, G_OPTION_ARG_STRING, &output,
+ "write output here instead of stdout", "FILE" },
+ { "namespace", 'n', 0, G_OPTION_ARG_STRING, &namespace,
+ "Namespace of the module, like 'Gtk'", "NAMESPACE" },
+ { "shared-library", 0, 0, G_OPTION_ARG_FILENAME, &shared_library,
+ "Shared library which contains the symbols", "FILE" },
+ { "include-idl", 0, 0, G_OPTION_ARG_STRING_ARRAY, &include_idls,
+ "Other gidls to include", "IDL" },
+ { NULL }
+ };
+
+ gopt_argc = 1;
+ gopt_argv = (char**)g_malloc (argc * sizeof (char*));
+ gopt_argv[0] = argv[0];
+
+ for (i = 1; i < argc; i++)
+ {
+ if (argv[i][0] == '-')
+ {
+ switch (argv[i][1])
+ {
+ case 'I':
+ case 'D':
+ case 'U':
+ cpp_options = g_list_prepend (cpp_options, g_strdup (argv[i]));
+ break;
+ default:
+ gopt_argv[gopt_argc++] = argv[i];
+ break;
+ }
+ }
+ else if (g_str_has_suffix (argv[i], ".h"))
+ {
+ gchar* filename;
+
+ if (!g_path_is_absolute (argv[i]))
+ {
+ gchar *dir = g_get_current_dir ();
+ filename = g_strdup_printf ("%s/%s", dir,
+ argv[i]);
+ g_free (dir);
+ }
+ else
+ filename = g_strdup (argv[i]);
+
+ filenames = g_list_append (filenames, filename);
+ }
+ else if (g_str_has_suffix (argv[i], ".la") ||
+ g_str_has_suffix (argv[i], ".so") ||
+ g_str_has_suffix (argv[i], ".dll"))
+ {
+ libraries = g_list_prepend (libraries, g_strdup (argv[i]));
+ }
+ else
+ {
+ gopt_argv[gopt_argc++] = argv[i];
+ }
+ }
+
+ ctx = g_option_context_new ("");
+ g_option_context_add_main_entries (ctx, entries, NULL);
+
+ if (!g_option_context_parse (ctx, &gopt_argc, &gopt_argv, &error))
+ {
+ g_printerr ("Parsing error: %s\n", error->message);
+ g_option_context_free (ctx);
+ return 1;
+ }
+
+ g_free (gopt_argv);
+ g_option_context_free (ctx);
+
+ if (!namespace)
+ {
+ g_printerr ("ERROR: namespace must be specified\n");
+ return 1;
+ }
+
+ igenerator = g_igenerator_new (namespace, shared_library);
+
+ if (verbose)
+ g_igenerator_set_verbose (igenerator, TRUE);
+
+ if (!filenames)
+ {
+ g_printerr ("ERROR: Need at least one header file.\n");
+ g_igenerator_free (igenerator);
+ return 0;
+ }
+ igenerator->filenames = filenames;
+ cpp_options = g_list_reverse (cpp_options);
+ libraries = g_list_reverse (libraries);
+
+ g_type_init ();
+
+ /* initialize threading as this may be required by libraries that we'll use
+ * libsoup-2.2 is an example of that.
+ */
+ g_thread_init (NULL);
+
+ if (include_idls)
+ {
+ for (i = 0; i < g_strv_length (include_idls); i++)
+ g_igenerator_add_include_idl (igenerator, include_idls[i]);
+ }
+
+ tmp = g_igenerator_start_preprocessor (igenerator, cpp_options);
+ if (!tmp)
+ {
+ g_error ("ERROR in pre-processor.\n");
+ g_igenerator_free (igenerator);
+ return 1;
+ }
+
+ if (!g_igenerator_parse_file (igenerator, tmp))
+ {
+ fclose (tmp);
+ g_igenerator_free (igenerator);
+ return 1;
+ }
+
+ g_igenerator_parse_macros (igenerator);
+
+ g_igenerator_generate (igenerator, output, libraries);
+
+ fclose (tmp);
+ g_igenerator_free (igenerator);
+
+ return 0;
+}
+