Logo Search packages:      
Sourcecode: vala-0.12 version File versions  Download package

scanner.c

/* 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 <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <glib-object.h>
#include <signal.h>
#include <sys/wait.h> /* waitpid */
#include <gmodule.h>
#include "scanner.h"
#include "gidlparser.h"
#include "gidlmodule.h"
#include "gidlnode.h"
#include "gidlwriter.h"
#include "grealpath.h"


typedef GType (*TypeFunction) (void);

static void g_igenerator_parse_macros (GIGenerator * igenerator);

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 *
create_node_from_gtype (GType type_id)
{
  GIdlNodeType *node;
  GType fundamental;

  node = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);

  fundamental = g_type_fundamental (type_id);
  switch (fundamental)
    {
    case G_TYPE_STRING:
      node->unparsed = g_strdup ("char*");
      break;
    case G_TYPE_INTERFACE:
    case G_TYPE_BOXED:
    case G_TYPE_OBJECT:
      node->unparsed = g_strdup_printf ("%s*", g_type_name (type_id));
      break;
    case G_TYPE_PARAM:
      node->unparsed = g_strdup ("GParamSpec*");
      break;
    default:
      if (fundamental == G_TYPE_STRV)
      node->unparsed = g_strdup ("char*[]");
      else
      node->unparsed = g_strdup (g_type_name (type_id));
      break;
    }

  return node;
}

static GIdlNodeType *
create_node_from_ctype (CType * ctype)
{
  GIdlNodeType *node;

  node = (GIdlNodeType *) g_idl_node_new (G_IDL_NODE_TYPE);

  switch (ctype->type)
    {
    case CTYPE_VOID:
      node->unparsed = g_strdup ("void");
      break;
    case CTYPE_BASIC_TYPE:
      node->unparsed = g_strdup (ctype->name);
      break;
    case CTYPE_TYPEDEF:
      node->unparsed = g_strdup (ctype->name);
      break;
    case CTYPE_STRUCT:
      if (ctype->name == NULL)
      /* anonymous struct */
      node->unparsed = g_strdup ("gpointer");
      else
      node->unparsed = g_strdup_printf ("struct %s", ctype->name);
      break;
    case CTYPE_UNION:
      if (ctype->name == NULL)
      /* anonymous union */
      node->unparsed = g_strdup ("gpointer");
      else
      node->unparsed = g_strdup_printf ("union %s", ctype->name);
      break;
    case CTYPE_ENUM:
      if (ctype->name == NULL)
      /* anonymous enum */
      node->unparsed = g_strdup ("gint");
      else
      node->unparsed = g_strdup_printf ("enum %s", ctype->name);
      break;
    case CTYPE_POINTER:
      if (ctype->base_type->type == CTYPE_FUNCTION)
      /* anonymous function pointer */
      node->unparsed = g_strdup ("GCallback");
      else
      {
        GIdlNodeType *gibasetype = create_node_from_ctype (ctype->base_type);
        node->unparsed = g_strdup_printf ("%s*", gibasetype->unparsed);
      }
      break;
    case CTYPE_ARRAY:
      {
      GIdlNodeType *gibasetype = create_node_from_ctype (ctype->base_type);
      node->unparsed = g_strdup_printf ("%s[]", gibasetype->unparsed);
      break;
      }
    default:
      node->unparsed = g_strdup ("unknown");
      break;
    }

  return node;
}

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 * node, GType type_id)
{
  int i;
  guint n_properties;
  GParamSpec **properties;

  if (node->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 (node->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;
      node->members =
      g_list_insert_sorted (node->members, giprop,
                        (GCompareFunc) g_idl_node_cmp);
      giprop->type = create_node_from_gtype (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 * node, 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);
      node->members =
      g_list_insert_sorted (node->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 = create_node_from_gtype (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 = create_node_from_gtype (signal_query.param_types[j]);
      }
      gisig->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
      gisig->result->type = create_node_from_gtype (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 *node;
  guint n_type_interfaces;
  GType *type_interfaces;
  int i;

  node = (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_OBJECT);
  node->node.name = g_strdup (g_type_name (type_id));
  igenerator->module->entries =
    g_list_insert_sorted (igenerator->module->entries, node,
                    (GCompareFunc) g_idl_node_cmp);
  g_hash_table_insert (igenerator->type_map, node->node.name,
                   node);
  g_hash_table_insert (igenerator->type_by_lower_case_prefix,
                   lower_case_prefix, node);
  alt_lower_case_prefix = g_ascii_strdown (node->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, node);
    }
  else
    {
      g_free (alt_lower_case_prefix);
    }

  node->gtype_name = node->node.name;
  node->gtype_init = g_strdup (symbol_name);
  node->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';
      }
      node->interfaces =
      g_list_append (node->interfaces, iface_name);
    }
  
  g_hash_table_insert (igenerator->symbols,
                   g_strdup (node->gtype_name),
                   /* FIXME: Strip igenerator->namespace */
                   g_strdup (node->node.name));
  
  g_igenerator_process_properties (igenerator, node, type_id);
  g_igenerator_process_signals (igenerator, node, type_id);
}

static void
g_igenerator_create_interface (GIGenerator *igenerator,
                         const char *symbol_name,
                         GType type_id,
                         char *lower_case_prefix)

{
  GIdlNodeInterface *node;
  gboolean is_gobject = FALSE;
  guint n_iface_prereqs;
  GType *iface_prereqs;
  int i;

  node = (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_INTERFACE);
  node->node.name = g_strdup (g_type_name (type_id));
  
  /* workaround for AtkImplementorIface */
  if (g_str_has_suffix (node->node.name, "Iface"))
    {
      node->node.name[strlen (node->node.name) -
                  strlen ("Iface")] = '\0';
    }
  igenerator->module->entries =
    g_list_insert_sorted (igenerator->module->entries, node,
                    (GCompareFunc) g_idl_node_cmp);
  g_hash_table_insert (igenerator->type_map, node->node.name,
                   node);
  g_hash_table_insert (igenerator->type_by_lower_case_prefix,
                   lower_case_prefix, node);
  node->gtype_name = node->node.name;
  node->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;
      }
      node->prerequisites =
      g_list_append (node->prerequisites,
                   g_strdup (g_type_name (iface_prereqs[i])));
    }
  
  if (is_gobject)
    g_igenerator_process_properties (igenerator, node, type_id);
  else
    g_type_default_interface_ref (type_id);

  g_igenerator_process_signals (igenerator, node, type_id);
}

static void
g_igenerator_create_boxed (GIGenerator *igenerator,
                     const char *symbol_name,
                     GType type_id,
                     char *lower_case_prefix)
{
  GIdlNodeBoxed *node =
    (GIdlNodeBoxed *) g_idl_node_new (G_IDL_NODE_BOXED);
  node->node.name = g_strdup (g_type_name (type_id));
  igenerator->module->entries =
    g_list_insert_sorted (igenerator->module->entries, node,
                    (GCompareFunc) g_idl_node_cmp);
  g_hash_table_insert (igenerator->type_map, node->node.name,
                   node);
  g_hash_table_insert (igenerator->type_by_lower_case_prefix,
                   lower_case_prefix, node);
  node->gtype_name = node->node.name;
  node->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 *node;
  int i;
  GEnumClass *type_class;
  
  node = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_ENUM);
  node->node.name = g_strdup (g_type_name (type_id));
  igenerator->module->entries =
    g_list_insert_sorted (igenerator->module->entries, node,
                    (GCompareFunc) g_idl_node_cmp);
  g_hash_table_insert (igenerator->type_map, node->node.name,
                   node);
  g_hash_table_insert (igenerator->type_by_lower_case_prefix,
                   lower_case_prefix, node);
  node->gtype_name = node->node.name;
  node->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);
      node->values = g_list_append (node->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 *node;
  GFlagsClass *type_class;
  int i;
  
  node = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_FLAGS);
  node->node.name = g_strdup (g_type_name (type_id));
  igenerator->module->entries =
    g_list_insert_sorted (igenerator->module->entries, node,
                    (GCompareFunc) g_idl_node_cmp);
  g_hash_table_insert (igenerator->type_map, node->node.name,
                   node);
  g_hash_table_insert (igenerator->type_by_lower_case_prefix,
                   lower_case_prefix, node);
  node->gtype_name = node->node.name;
  node->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);
      node->values = g_list_append (node->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 void
g_igenerator_process_function_symbol (GIGenerator * igenerator, CSymbol * sym)
{
  GIdlNodeFunction *func;
  char *last_underscore;
  GList *param_l;
  int i;
  GSList *l;

  func = (GIdlNodeFunction *) g_idl_node_new (G_IDL_NODE_FUNCTION);
  
  /* check whether this is a type method */
  last_underscore = strrchr (sym->ident, '_');

  while (last_underscore != NULL)
    {
      char *prefix;
      GIdlNode *node;

      prefix = g_strndup (sym->ident, last_underscore - sym->ident);
      prefix = str_replace (prefix, "_", "");

      node = g_hash_table_lookup (igenerator->type_by_lower_case_prefix,
                          prefix);
      if (node != NULL )
      {
        func->node.name = g_strdup (last_underscore + 1);

        /* ignore get_type functions in registered types */
        if (strcmp (func->node.name, "get_type") == 0)
          return;

        if ((node->type == G_IDL_NODE_OBJECT ||
             node->type == G_IDL_NODE_BOXED) &&
            g_str_has_prefix (func->node.name, "new"))
          func->is_constructor = TRUE;
        else
          func->is_method = TRUE;
        if (g_idl_node_can_have_member (node))
          {
            g_idl_node_add_member (node, func);
            break;
          }
        else
          {
            /* reset function attributes */
            g_free (func->node.name);
            func->node.name = NULL;
            func->is_constructor = FALSE;
            func->is_method = FALSE;
          }
      }
      else if (strcmp (igenerator->lower_case_namespace, prefix) == 0)
      {
        func->node.name = g_strdup (last_underscore + 1);
        igenerator->module->entries =
          g_list_insert_sorted (igenerator->module->entries, func,
                          (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 (func->node.name == NULL)
    {
      func->node.name = sym->ident;
      func->is_constructor = FALSE;
      func->is_method = FALSE;
      igenerator->module->entries =
      g_list_insert_sorted (igenerator->module->entries, func,
                        (GCompareFunc) g_idl_node_cmp);
    }

  func->symbol = sym->ident;
  func->result = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
  func->result->type = create_node_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;

      param = (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
      param->type = create_node_from_ctype (param_sym->base_type);

      if (param_sym->ident == NULL)
      param->node.name = g_strdup_printf ("p%d", i);
      else
      param->node.name = param_sym->ident;

      func->parameters = g_list_append (func->parameters, param);
    }

  for (l = sym->directives; l; l = l->next)
    {
      CDirective *directive = (CDirective*)l->data;

      if (!strcmp (directive->name, "deprecated"))
      func->deprecated = TRUE;
      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 *node =
    (GIdlNodeStruct *) g_idl_node_new (G_IDL_NODE_STRUCT);
  GList *member_l;
  char *lower_case_prefix;

  node->node.name = sym->ident;
  igenerator->module->entries =
    g_list_insert_sorted (igenerator->module->entries, node,
                    (GCompareFunc) g_idl_node_cmp);
  lower_case_prefix = g_ascii_strdown (sym->ident, -1);
  g_hash_table_insert (igenerator->type_map, sym->ident, node);
  g_hash_table_insert (igenerator->type_by_lower_case_prefix,
                   lower_case_prefix, node);

  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);

      node->members = g_list_append (node->members, gifield);
      gifield->node.name = member->ident;
      gifield->type = create_node_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 *type;
  
  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;
    }
  
  type = g_hash_table_lookup (igenerator->type_map, sym->ident);
  if (type != NULL)
    {
      /* struct of a GTypeInstance */
      if (!opaque_type
        && (type->type == G_IDL_NODE_OBJECT
            || type->type == G_IDL_NODE_INTERFACE))
      {
        GIdlNodeInterface *node = (GIdlNodeInterface *) type;
        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);
            node->members = g_list_append (node->members, gifield);
            gifield->node.name = member->ident;
            gifield->type = create_node_from_ctype (member->base_type);
          }
      }
      else if (type->type == G_IDL_NODE_BOXED)
      {
        GIdlNodeBoxed *node = (GIdlNodeBoxed *) type;
        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);
            node->members = g_list_append (node->members, gifield);
            gifield->node.name = member->ident;
            gifield->type = create_node_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 *node;

      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"));
      }
      type = g_hash_table_lookup (igenerator->type_map, base_name);
      if (type == NULL
        || (type->type != G_IDL_NODE_OBJECT
            && type->type != G_IDL_NODE_INTERFACE))
      {
        g_igenerator_process_unregistered_struct_typedef (igenerator, sym,
                                              struct_type);
        return;
      }
      node = (GIdlNodeInterface *) type;

      /* 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 = node->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;
            node->members =
            g_list_insert_sorted (node->members, givfunc,
                              (GCompareFunc) g_idl_node_cmp);
            givfunc->result =
            (GIdlNodeParam *) g_idl_node_new (G_IDL_NODE_PARAM);
            givfunc->result->type =
            create_node_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 = create_node_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 *type;
  
  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;
    }

  type = g_hash_table_lookup (igenerator->type_map, sym->ident);
  if (type != NULL)
    {
      g_assert (type->type == G_IDL_NODE_BOXED);
      GIdlNodeBoxed *node = (GIdlNodeBoxed *) type;
      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);
        node->members = g_list_append (node->members, gifield);
        gifield->node.name = member->ident;
        gifield->type = create_node_from_ctype (member->base_type);
      }
    }
  else
    {
      GIdlNodeUnion *node =
      (GIdlNodeUnion *) g_idl_node_new (G_IDL_NODE_UNION);
      char *lower_case_prefix;
      GList *member_l;
      
      node->node.name = sym->ident;
      igenerator->module->entries =
      g_list_insert_sorted (igenerator->module->entries, node,
                        (GCompareFunc) g_idl_node_cmp);
      lower_case_prefix = g_ascii_strdown (sym->ident, -1);
      g_hash_table_insert (igenerator->type_map, sym->ident, node);
      g_hash_table_insert (igenerator->type_by_lower_case_prefix,
                     lower_case_prefix, node);

      node->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);
        node->members = g_list_append (node->members, gifield);
        gifield->node.name = member->ident;
        gifield->type = create_node_from_ctype (member->base_type);
      }
    }
}

static void
g_igenerator_process_enum_typedef (GIGenerator * igenerator, CSymbol * sym)
{
  CType *enum_type;
  GList *member_l;
  GIdlNodeEnum *node;
  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;
    }
  
  node = g_hash_table_lookup (igenerator->type_map, sym->ident);
  if (node != NULL)
    {
      return;
    }

  node = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_ENUM);
  node->node.name = sym->ident;
  igenerator->module->entries =
    g_list_insert_sorted (igenerator->module->entries, node,
                    (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);
      node->values = g_list_append (node->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 =
    create_node_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 = create_node_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 *node =
            (GIdlNodeStruct *) g_idl_node_new (G_IDL_NODE_STRUCT);
            char *lower_case_prefix;
            
            node->node.name = sym->ident;
            igenerator->module->entries =
            g_list_insert_sorted (igenerator->module->entries, node,
                              (GCompareFunc) g_idl_node_cmp);
            lower_case_prefix = g_ascii_strdown (sym->ident, -1);
            g_hash_table_insert (igenerator->type_map, sym->ident, node);
            g_hash_table_insert (igenerator->type_by_lower_case_prefix,
                           lower_case_prefix, node);
          }
      }
    }
  /* 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)
{
  GList *l;

  /* only add symbols of main file */
  gboolean found_filename = FALSE;

  if (igenerator->current_filename)
    {
      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;

  /* that's not very optimized ! */
  for (l = igenerator->symbol_list; l != NULL; l = l->next)
    {
      CSymbol *other_symbol = (CSymbol *)l->data;
      if (g_str_equal (other_symbol->ident, symbol->ident)
          && other_symbol->type == symbol->type)
        {
          g_printerr ("Dropping %s duplicate\n", symbol->ident);
          return;
        }
  }

  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 ("%s", 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 ("%s", 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;
          case 'p':
            /*ignore -pthread*/
            if (0==strcmp("-pthread", 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, g_realpath(filename));
        g_free(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 1;
    }
  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;
}


Generated by  Doxygen 1.6.0   Back to index