summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorRob Taylor <rob.taylor@codethink.co.uk>2008-02-08 15:31:03 +0000
committerRobert James Taylor <robtaylor@src.gnome.org>2008-02-08 15:31:03 +0000
commitb935261f387dffa2c7006fe1be04820004810e87 (patch)
tree0c077cee05c725e1e56309374a1ceea8d8881b7d /tools
parentc6c15af80d8a6d34e5c77d3111c638126edb3d45 (diff)
downloadgobject-introspection-b935261f387dffa2c7006fe1be04820004810e87.tar.gz
Added: Added: Renamed to tools/Makefile.am: Renamed to tools/compiler.c:
2008-02-08 Rob Taylor <rob.taylor@codethink.co.uk> * Makefile.am: * configure.ac: * gidl/Makefile.am: Added: * girepository/Makefile.am: Added: * src/Makefile.am: Renamed to tools/Makefile.am: * src/compiler.c: Renamed to tools/compiler.c: * src/g-idl-offsets.pl: Renamed to tools/g-idl-offsets.pl: * src/generate.c: Renamed to tools/generate.c: * src/gidlmodule.c: Renamed to tools/gidlmodule.c: * src/gidlmodule.h: Renamed to tools/gidlmodule.h: * src/gidlnode.c: Renamed to tools/gidlnode.c: * src/gidlnode.h: Renamed to tools/gidlnode.h: * src/gidlparser.c: Renamed to tools/gidlparser.c: * src/gidlparser.h: Renamed to tools/gidlparser.h: * src/gidlwriter.c: Renamed to tools/gidlwriter.c: * src/gidlwriter.h: Renamed to tools/gidlwriter.h: * src/ginfo.c: Renamed to girepository/ginfo.c: * src/ginvoke.c: Renamed to girepository/ginvoke.c: * src/girepository.c: Renamed to girepository/girepository.c: * src/girepository.h: Renamed to girepository/girepository.h: * src/gmetadata.c: Renamed to girepository/gmetadata.c: * src/gmetadata.h: Renamed to girepository/gmetadata.h: * src/scanner.c: Renamed to tools/scanner.c: * src/scanner.h: Renamed to tools/scanner.h: * src/scannerlexer.l: Renamed to tools/scannerlexer.l: * src/scannerparser.y: Renamed to tools/scannerparser.y: * tests/invoke/Makefile.am: Split src/ into girepository/ and tools/ * Makefile.am: * configure.ac: * girepository/Makefile.am: * tests/Makefile.am: * tests/invoke/Makefile.am: * tests/parser/Makefile.am: * tests/roundtrips.sh: * tools/Makefile.am: Make distcheck work. svn path=/trunk/; revision=104
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile.am39
-rw-r--r--tools/compiler.c257
-rwxr-xr-xtools/g-idl-offsets.pl258
-rw-r--r--tools/generate.c1223
-rw-r--r--tools/gidlmodule.c215
-rw-r--r--tools/gidlmodule.h48
-rw-r--r--tools/gidlnode.c2050
-rw-r--r--tools/gidlnode.h334
-rw-r--r--tools/gidlparser.c2054
-rw-r--r--tools/gidlparser.h38
-rw-r--r--tools/gidlwriter.c483
-rw-r--r--tools/gidlwriter.h26
-rw-r--r--tools/scanner.c1762
-rw-r--r--tools/scanner.h167
-rw-r--r--tools/scannerlexer.l311
-rw-r--r--tools/scannerparser.y1376
16 files changed, 10641 insertions, 0 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 00000000..eb2d144f
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,39 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = -DGIREPO_DEFAULT_SEARCH_PATH="\"$(libdir)\""
+BUILT_SOURCES = scannerparser.c scannerparser.h scannerlexer.c scannerlexer.h
+CLEANFILES = scannerparser.c scannerparser.h scannerlexer.c scannerlexer.h
+AM_YFLAGS = -d
+
+# Why do I have to do this automake?
+scannerlexer.h: scannerlexer.c
+
+noinst_LTLIBRARIES = libgirepository-parser.la
+bin_PROGRAMS = g-idl-compiler g-idl-generate g-idl-scanner
+
+libgirepository_parser_la_SOURCES = \
+ gidlmodule.c \
+ gidlmodule.h \
+ gidlnode.c \
+ gidlnode.h \
+ gidlparser.c \
+ gidlparser.h
+libgirepository_parser_la_CFLAGS = $(GIREPO_CFLAGS) -I$(top_srcdir)/girepository
+
+g_idl_compiler_SOURCES = compiler.c
+g_idl_compiler_CFLAGS = $(GIREPO_CFLAGS) -I$(top_srcdir)/girepository
+g_idl_compiler_LDADD = $(GIREPO_LIBS) $(top_builddir)/girepository/libgirepository.la libgirepository-parser.la
+
+g_idl_generate_SOURCES = generate.c
+g_idl_generate_CFLAGS = $(GIREPO_CFLAGS) -I$(top_srcdir)/girepository
+g_idl_generate_LDADD = $(GIREPO_LIBS) $(top_builddir)/girepository/libgirepository.la
+
+g_idl_scanner_SOURCES = \
+ scanner.c \
+ scanner.h \
+ scannerlexer.l \
+ scannerparser.y \
+ gidlwriter.c \
+ gidlwriter.h
+g_idl_scanner_CFLAGS = $(GIREPO_CFLAGS) $(SCANNER_CFLAGS) -I$(top_srcdir)/girepository
+g_idl_scanner_LDADD = $(GIREPO_LIBS) $(SCANNER_LIBS) $(top_builddir)/girepository/libgirepository.la libgirepository-parser.la
diff --git a/tools/compiler.c b/tools/compiler.c
new file mode 100644
index 00000000..1c91632e
--- /dev/null
+++ b/tools/compiler.c
@@ -0,0 +1,257 @@
+/* GObject introspection: Metadata compiler
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * 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 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.
+ */
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include "gidlmodule.h"
+#include "gidlnode.h"
+#include "gidlparser.h"
+#include "gmetadata.h"
+
+gboolean raw = FALSE;
+gboolean no_init = FALSE;
+gchar **input = NULL;
+gchar *output = NULL;
+gchar *mname = NULL;
+gchar *shlib = NULL;
+gboolean debug = FALSE;
+gboolean verbose = FALSE;
+
+static gchar *
+format_output (GMetadata *metadata)
+{
+ GString *result;
+ gint i;
+
+ result = g_string_sized_new (6 * metadata->len);
+
+ g_string_append_printf (result, "#include <stdlib.h>\n");
+ g_string_append_printf (result, "#include <girepository.h>\n\n");
+
+ g_string_append_printf (result, "const unsigned char _G_METADATA[] = \n{");
+
+ for (i = 0; i < metadata->len; i++)
+ {
+ if (i > 0)
+ g_string_append (result, ", ");
+
+ if (i % 10 == 0)
+ g_string_append (result, "\n\t");
+
+ g_string_append_printf (result, "0x%.2x", metadata->data[i]);
+ }
+
+ g_string_append_printf (result, "\n};\n\n");
+ g_string_append_printf (result, "const gsize _G_METADATA_SIZE = %u;\n\n",
+ (guint)metadata->len);
+
+ if (!no_init)
+ {
+ g_string_append_printf (result,
+ "__attribute__((constructor)) void\n"
+ "register_metadata (void)\n"
+ "{\n"
+ "\tGMetadata *metadata;\n"
+ "\tmetadata = g_metadata_new_from_const_memory (_G_METADATA, _G_METADATA_SIZE);\n"
+ "\tg_irepository_register (NULL, metadata);\n"
+ "}\n\n");
+
+ g_string_append_printf (result,
+ "__attribute__((destructor)) void\n"
+ "unregister_metadata (void)\n"
+ "{\n"
+ "\tg_irepository_unregister (NULL, \"%s\");\n"
+ "}\n",
+ g_metadata_get_namespace (metadata));
+ }
+
+ return g_string_free (result, FALSE);
+}
+
+static void
+write_out_metadata (gchar *prefix,
+ GMetadata *metadata)
+{
+ FILE *file;
+
+ if (output == NULL)
+ file = stdout;
+ else
+ {
+ gchar *filename;
+
+ if (prefix)
+ filename = g_strdup_printf ("%s-%s", prefix, output);
+ else
+ filename = g_strdup (output);
+ file = g_fopen (filename, "w");
+
+ if (file == NULL)
+ {
+ g_fprintf (stderr, "failed to open '%s': %s\n",
+ filename, g_strerror (errno));
+ g_free (filename);
+
+ return;
+ }
+
+ g_free (filename);
+ }
+
+ if (raw)
+ fwrite (metadata->data, 1, metadata->len, file);
+ else
+ {
+ gchar *code;
+
+ code = format_output (metadata);
+ fputs (code, file);
+ g_free (code);
+ }
+
+ if (output != NULL)
+ fclose (file);
+}
+
+GLogLevelFlags logged_levels;
+
+static void log_handler (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer user_data)
+{
+
+ if (log_level & logged_levels)
+ g_log_default_handler (log_domain, log_level, message, user_data);
+}
+
+static GOptionEntry options[] =
+{
+ { "raw", 0, 0, G_OPTION_ARG_NONE, &raw, "emit raw metadata", NULL },
+ { "code", 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &raw, "emit C code", NULL },
+ { "no-init", 0, 0, G_OPTION_ARG_NONE, &no_init, "do not create _init() function", NULL },
+ { "output", 'o', 0, G_OPTION_ARG_FILENAME, &output, "output file", "FILE" },
+ { "module", 'm', 0, G_OPTION_ARG_STRING, &mname, "module to compile", "NAME" },
+ { "shared-library", 'l', 0, G_OPTION_ARG_FILENAME, &shlib, "shared library", "FILE" },
+ { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, "show debug messages", NULL },
+ { "verbose", 0, 0, G_OPTION_ARG_NONE, &verbose, "show verbose messages", NULL },
+ { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &input, NULL, NULL },
+ { NULL, }
+};
+
+int
+main (int argc, char ** argv)
+{
+ GOptionContext *context;
+ GError *error = NULL;
+ GList *m, *modules;
+ gint i;
+
+ g_metadata_check_sanity ();
+
+ context = g_option_context_new ("");
+ g_option_context_add_main_entries (context, options, NULL);
+ g_option_context_parse (context, &argc, &argv, &error);
+ g_option_context_free (context);
+
+ logged_levels = G_LOG_LEVEL_MASK & ~(G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_DEBUG);
+ if (debug)
+ logged_levels = logged_levels | G_LOG_LEVEL_DEBUG;
+ if (verbose)
+ logged_levels = logged_levels | G_LOG_LEVEL_MESSAGE;
+
+ g_log_set_default_handler (log_handler, NULL);
+
+ if (!input)
+ {
+ g_fprintf (stderr, "no input files\n");
+
+ return 1;
+ }
+
+ modules = NULL;
+ for (i = 0; input[i]; i++)
+ {
+ GList *mods;
+ mods = g_idl_parse_file (input[i], &error);
+
+ if (mods == NULL)
+ {
+ g_fprintf (stderr, "error parsing file %s: %s\n",
+ input[i], error->message);
+
+ return 1;
+ }
+
+ modules = g_list_concat (modules, mods);
+ }
+
+ for (m = modules; m; m = m->next)
+ {
+ GIdlModule *module = m->data;
+ gchar *prefix;
+ GMetadata *metadata;
+
+ if (mname && strcmp (mname, module->name) != 0)
+ continue;
+ if (shlib)
+ {
+ if (module->shared_library)
+ g_free (module->shared_library);
+ module->shared_library = g_strdup (shlib);
+ }
+ metadata = g_idl_module_build_metadata (module, modules);
+ if (metadata == NULL)
+ {
+ g_error ("Failed to build metadata for module '%s'\n", module->name);
+
+ continue;
+ }
+ if (!g_metadata_validate (metadata, &error))
+ g_error ("Invalid metadata for module '%s': %s",
+ module->name, error->message);
+
+
+ if (!mname && (m->next || m->prev) && output)
+ prefix = module->name;
+ else
+ prefix = NULL;
+
+ write_out_metadata (prefix, metadata);
+ g_metadata_free (metadata);
+ metadata = NULL;
+
+ /* when writing to stdout, stop after the first module */
+ if (m->next && !output && !mname)
+ {
+ g_warning ("%d modules omitted\n", g_list_length (modules) - 1);
+
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/tools/g-idl-offsets.pl b/tools/g-idl-offsets.pl
new file mode 100755
index 00000000..55318708
--- /dev/null
+++ b/tools/g-idl-offsets.pl
@@ -0,0 +1,258 @@
+#! /usr/bin/perl -w
+
+use Getopt::Long;
+use XML::Parser;
+
+my $INCLUDES;
+my $PRINT_VERSION;
+my $PRINT_HELP;
+
+%optctl = (includes => \$INCLUDES);
+
+GetOptions(\%optctl, "includes=s");
+
+my $file = shift;
+
+die "Can't find file \"$file\""
+ unless -f $file;
+
+my $parser = new XML::Parser(ErrorContext => 2);
+
+my $structname = "";
+my $classname = "";
+
+open OUTPUT, ">dump-sizes.c" || die "Cannot open dump-sizes.c: $!\n";
+
+print OUTPUT <<EOT;
+#include <glib.h>
+$INCLUDES
+
+int
+main (int argc, char *argv[])
+{
+EOT
+
+$parser->setHandlers(Start => \&start_handler,
+ End => \&end_handler);
+
+$parser->parsefile($file);
+
+print OUTPUT <<EOT;
+
+ return 0;
+}
+EOT
+
+close OUTPUT;
+
+$CC = $ENV{CC} ? $ENV{CC} : "gcc";
+$LD = $ENV{LD} ? $ENV{LD} : $CC;
+$CFLAGS = $ENV{CFLAGS} ? $ENV{CFLAGS} : "";
+$LDFLAGS = $ENV{LDFLAGS} ? $ENV{LDFLAGS} : "";
+
+my $o_file;
+if ($CC =~ /libtool/) {
+ $o_file = "dump-sizes.lo"
+} else {
+ $o_file = "dump-sizes.o"
+}
+
+$command = "$CC $CFLAGS -c -o $o_file dump-sizes.c && $LD -o dump-sizes $o_file $LDFLAGS";
+
+system($command) == 0 or die "Compilation failed\n";
+
+system("./dump-sizes > sizes.out") == 0 or die "Scan failed\n";
+
+#unlink "./dump-sizes.c", "./dump-sizes.o", "./dump-sizes.lo", "./dump-sizes";
+
+my %Sizes;
+
+open SIZES, "<sizes.out" || die "Can't open sizes.out: $!";
+while (<SIZES>) {
+ if (m/(\w*) (\w*) (\d*)/) {
+ $Sizes{$1 . "." . $2} = $3;
+ }
+}
+
+close SIZES;
+
+open OUTPUT2, ">$file.new" || die "Cannot open $file.new: $!\n";
+
+$parser->setHandlers(Start => \&dump_start_handler,
+ End => \&dump_end_handler);
+
+$parser->parsefile($file);
+
+close OUTPUT2;
+
+sub start_handler
+{
+ my $p = shift;
+ my $el = shift;
+ my $name = "";
+ my $cname = "";
+ my $class = "";
+
+ while (@_) {
+ my $att = shift;
+ my $val = shift;
+
+ if ($att eq "name") {
+ $name = $val;
+ }
+ elsif ($att eq "cname") {
+ $cname = $val;
+ }
+ elsif ($att eq "class") {
+ $class = $val;
+ }
+ }
+
+ if (($el eq "object") || ($el eq "interface")) {
+ if (!($cname eq "")) {
+ $structname = $cname;
+ }
+ else {
+ $structname = $name;
+ }
+
+ if (!($class eq "")) {
+ $classname = $class;
+ }
+ elsif ($el eq "object") {
+ $classname = $structname . "Class";
+ }
+ else {
+ $classname = $structname . "Iface";
+ }
+ }
+ elsif ($el eq "field") {
+ if (!($cname eq "")) {
+ need_offset ($structname, $cname);
+ }
+ else {
+ need_offset ($structname, $name);
+ }
+ }
+ elsif ($el eq "vfunc") {
+ if (!($cname eq "")) {
+ need_offset ($classname, $cname);
+ }
+ else {
+ need_offset ($classname, $name);
+ }
+ }
+}
+
+sub end_handler
+{
+ my $p = shift;
+ my $el = shift;
+
+ if (($el eq "object") ||
+ ($el eq "interface") ||
+ ($el eq "boxed") ||
+ ($el eq "struct") ||
+ ($el eq "union")) {
+ $structname = "";
+ $classname = "";
+ }
+}
+
+sub need_offset
+{
+ my $struct = shift;
+ my $name = shift;
+
+ print OUTPUT " g_print (\"$struct $name %d\\n\", G_STRUCT_OFFSET ($struct, $name));\n";
+}
+
+sub write_offset
+{
+ my $struct = shift;
+ my $name = shift;
+
+ print OUTPUT2 " offset=\"" . $Sizes{$struct . "." . $name } . "\""
+}
+
+sub dump_start_handler
+{
+ my $p = shift;
+ my $el = shift;
+ my $name = "";
+ my $cname = "";
+ my $class = "";
+
+ print OUTPUT2 "<$el";
+
+ while (@_) {
+ my $att = shift;
+ my $val = shift;
+
+ print OUTPUT2 " $att=\"$val\"";
+
+ if ($att eq "name") {
+ $name = $val;
+ }
+ elsif ($att eq "cname") {
+ $cname = $val;
+ }
+ elsif ($att eq "class") {
+ $class = $val;
+ }
+ }
+
+ if (($el eq "object") || ($el eq "interface")) {
+ if (!($cname eq "")) {
+ $structname = $cname;
+ }
+ else {
+ $structname = $name;
+ }
+
+ if (!($class eq "")) {
+ $classname = $class;
+ }
+ elsif ($el eq "object") {
+ $classname = $structname . "Class";
+ }
+ else {
+ $classname = $structname . "Iface";
+ }
+ }
+ elsif ($el eq "field") {
+ if (!($cname eq "")) {
+ write_offset ($structname, $cname);
+ }
+ else {
+ write_offset ($structname, $name);
+ }
+ }
+ elsif ($el eq "vfunc") {
+ if (!($cname eq "")) {
+ write_offset ($classname, $cname);
+ }
+ else {
+ write_offset ($classname, $name);
+ }
+ }
+ print OUTPUT2 ">\n";
+}
+
+sub dump_end_handler
+{
+ my $p = shift;
+ my $el = shift;
+
+ if (($el eq "object") ||
+ ($el eq "interface") ||
+ ($el eq "boxed") ||
+ ($el eq "struct") ||
+ ($el eq "union")) {
+ $structname = "";
+ $classname = "";
+ }
+
+ print OUTPUT2 "</$el>\n";
+}
+
diff --git a/tools/generate.c b/tools/generate.c
new file mode 100644
index 00000000..8ae6fc35
--- /dev/null
+++ b/tools/generate.c
@@ -0,0 +1,1223 @@
+/* -*- Mode: C; c-file-style: "gnu"; -*- */
+/* GObject introspection: IDL generator
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * 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 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.
+ */
+
+#include <errno.h>
+#include <dlfcn.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gstdio.h>
+
+#include "girepository.h"
+#include "gmetadata.h"
+
+gboolean raw = FALSE;
+gchar **input = NULL;
+gchar *output = NULL;
+
+static void
+write_type_name (const gchar *namespace,
+ GIBaseInfo *info,
+ FILE *file)
+{
+ if (strcmp (namespace, g_base_info_get_namespace (info)) != 0)
+ g_fprintf (file, "%s.", g_base_info_get_namespace (info));
+
+ g_fprintf (file, "%s", g_base_info_get_name (info));
+}
+
+static void
+write_type_info (const gchar *namespace,
+ GITypeInfo *info,
+ FILE *file)
+{
+ gint tag;
+ gint i;
+ GITypeInfo *type;
+
+ const gchar* basic[] = {
+ "void",
+ "gboolean",
+ "gint8",
+ "guint8",
+ "gint16",
+ "guint16",
+ "gint32",
+ "guint32",
+ "gint64",
+ "guint64",
+ "gint",
+ "guint",
+ "glong",
+ "gulong",
+ "gssize",
+ "gsize",
+ "gfloat",
+ "gdouble",
+ "utf8",
+ "filename"
+ };
+
+ tag = g_type_info_get_tag (info);
+
+ if (tag < 18)
+ g_fprintf (file, "%s%s", basic[tag], g_type_info_is_pointer (info) ? "*" : "");
+ else if (tag < 20)
+ g_fprintf (file, "%s", basic[tag]);
+ else if (tag == 20)
+ {
+ gint length;
+
+ type = g_type_info_get_param_type (info, 0);
+ write_type_info (namespace, type, file);
+ g_fprintf (file, "[");
+
+ length = g_type_info_get_array_length (info);
+
+ if (length >= 0)
+ g_fprintf (file, "length=%d", length);
+
+ if (g_type_info_is_zero_terminated (info))
+ g_fprintf (file, "%szero-terminated=1", length >= 0 ? "," : "");
+
+ g_fprintf (file, "]");
+ g_base_info_unref ((GIBaseInfo *)type);
+ }
+ else if (tag == 21)
+ {
+ GIBaseInfo *iface = g_type_info_get_interface (info);
+ write_type_name (namespace, iface, file);
+ if (g_type_info_is_pointer (info))
+ g_fprintf (file, "*");
+ g_base_info_unref (iface);
+ }
+ else if (tag == 22)
+ {
+ type = g_type_info_get_param_type (info, 0);
+ g_fprintf (file, "GList");
+ if (type)
+ {
+ g_fprintf (file, "<");
+ write_type_info (namespace, type, file);
+ g_fprintf (file, ">");
+ g_base_info_unref ((GIBaseInfo *)type);
+ }
+ g_fprintf (file, "*");
+ }
+ else if (tag == 23)
+ {
+ type = g_type_info_get_param_type (info, 0);
+ g_fprintf (file, "GSList");
+ if (type)
+ {
+ g_fprintf (file, "<");
+ write_type_info (namespace, type, file);
+ g_fprintf (file, ">");
+ g_base_info_unref ((GIBaseInfo *)type);
+ }
+ g_fprintf (file, "*");
+ }
+ else if (tag == 24)
+ {
+ type = g_type_info_get_param_type (info, 0);
+ g_fprintf (file, "GHashTable");
+ if (type)
+ {
+ g_fprintf (file, "<");
+ write_type_info (namespace, type, file);
+ g_base_info_unref ((GIBaseInfo *)type);
+ type = g_type_info_get_param_type (info, 1);
+ g_fprintf (file, ",");
+ write_type_info (namespace, type, file);
+ g_fprintf (file, ">");
+ g_base_info_unref ((GIBaseInfo *)type);
+ }
+ g_fprintf (file, "*");
+ }
+ else if (tag == 25)
+ {
+ gint n;
+
+ g_fprintf (file, "GError");
+ n = g_type_info_get_n_error_domains (info);
+ if (n > 0)
+ {
+ g_fprintf (file, "<");
+ for (i = 0; i < n; i++)
+ {
+ GIErrorDomainInfo *ed = g_type_info_get_error_domain (info, i);
+ if (i > 0)
+ g_fprintf (file, ",");
+ write_type_name (namespace, (GIBaseInfo *)ed, file);
+ g_base_info_unref ((GIBaseInfo *)ed);
+ }
+ g_fprintf (file, ">");
+ }
+ g_fprintf (file, "*");
+ }
+}
+
+static void
+write_constant_value (const gchar *namespace,
+ GITypeInfo *info,
+ GArgument *argument,
+ FILE *file);
+
+static void
+write_field_info (const gchar *namespace,
+ GIFieldInfo *info,
+ GIConstantInfo *branch,
+ FILE *file)
+{
+ const gchar *name;
+ GIFieldInfoFlags flags;
+ gint size;
+ gint offset;
+ GITypeInfo *type;
+ GArgument value;
+
+ name = g_base_info_get_name ((GIBaseInfo *)info);
+ flags = g_field_info_get_flags (info);
+ size = g_field_info_get_size (info);
+ offset = g_field_info_get_offset (info);
+
+ g_fprintf (file,
+ " <field name=\"%s\" readable=\"%s\" writable=\"%s\" ",
+ name,
+ flags & GI_FIELD_IS_READABLE ? "1" : "0",
+ flags & GI_FIELD_IS_WRITABLE ? "1" : "0");
+ if (size)
+ g_fprintf (file, "bits=\"%d\" ", size);
+ g_fprintf (file, "offset=\"%d\" ", offset);
+
+ g_fprintf (file, "type=\"");
+
+ type = g_field_info_get_type (info);
+ write_type_info (namespace, type, file);
+ g_base_info_unref ((GIBaseInfo *)type);
+
+ g_fprintf (file, "\"");
+
+ if (branch)
+ {
+ g_fprintf (file, " branch=\"");
+ type = g_constant_info_get_type (branch);
+ g_constant_info_get_value (branch, &value);
+ write_constant_value (namespace, type, &value, file);
+ g_fprintf (file, "\"");
+ }
+
+ g_fprintf (file," />\n");
+}
+
+static void
+write_callable_info (const gchar *namespace,
+ GICallableInfo *info,
+ FILE *file,
+ gint indent)
+{
+ GITypeInfo *type;
+ gint i;
+
+ g_fprintf (file, "%*s <return-type type=\"", indent, "");
+
+ type = g_callable_info_get_return_type (info);
+ write_type_info (namespace, type, file);
+
+ g_fprintf (file, "\"");
+
+ if (g_type_info_is_pointer (type))
+ {
+ switch (g_callable_info_get_caller_owns (info))
+ {
+ case GI_TRANSFER_NOTHING:
+ g_fprintf (file, " transfer=\"none\"");
+ break;
+ case GI_TRANSFER_CONTAINER:
+ g_fprintf (file, " transfer=\"shallow\"");
+ break;
+ case GI_TRANSFER_EVERYTHING:
+ g_fprintf (file, " transfer=\"full\"");
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+ g_base_info_unref ((GIBaseInfo *)type);
+ if (g_callable_info_may_return_null (info))
+ g_fprintf (file, " null-ok=\"1\"");
+
+ g_fprintf (file, " />\n");
+
+ if (g_callable_info_get_n_args (info) > 0)
+ {
+ g_fprintf (file, "%*s <parameters>\n", indent, "");
+ for (i = 0; i < g_callable_info_get_n_args (info); i++)
+ {
+ GIArgInfo *arg = g_callable_info_get_arg (info, i);
+
+ g_fprintf (file, "%*s <parameter name=\"%s\" type=\"",
+ indent, "", g_base_info_get_name ((GIBaseInfo *) arg));
+
+ type = g_arg_info_get_type (arg);
+ write_type_info (namespace, type, file);
+ g_fprintf (file, "\"");
+
+ if (g_type_info_is_pointer (type))
+ {
+ switch (g_arg_info_get_ownership_transfer (arg))
+ {
+ case GI_TRANSFER_NOTHING:
+ g_fprintf (file, " transfer=\"none\"");
+ break;
+ case GI_TRANSFER_CONTAINER:
+ g_fprintf (file, " transfer=\"shallow\"");
+ break;
+ case GI_TRANSFER_EVERYTHING:
+ g_fprintf (file, " transfer=\"full\"");
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+ g_base_info_unref ((GIBaseInfo *)type);
+
+ g_fprintf (file, " direction=\"");
+ switch (g_arg_info_get_direction (arg))
+ {
+ case GI_DIRECTION_IN:
+ g_fprintf (file, "in");
+ break;
+ case GI_DIRECTION_OUT:
+ g_fprintf (file, "out");
+ break;
+ case GI_DIRECTION_INOUT:
+ g_fprintf (file, "inout");
+ break;
+ }
+ g_fprintf (file, "\"");
+
+ if (g_arg_info_may_be_null (arg))
+ g_fprintf (file, " null-ok=\"1\"");
+
+ if (g_arg_info_is_dipper (arg))
+ g_fprintf (file, " dipper=\"1\"");
+
+ if (g_arg_info_is_return_value (arg))
+ g_fprintf (file, " retval=\"1\"");
+
+ if (g_arg_info_is_optional (arg))
+ g_fprintf (file, " optional=\"1\"");
+
+ g_fprintf (file, " />\n");
+
+ g_base_info_unref ((GIBaseInfo *)arg);
+ }
+
+ g_fprintf (file, "%*s </parameters>\n", indent, "");
+ }
+}
+
+static void
+write_function_info (const gchar *namespace,
+ GIFunctionInfo *info,
+ FILE *file,
+ gint indent)
+{
+ GIFunctionInfoFlags flags;
+ const gchar *tag;
+ const gchar *name;
+ const gchar *symbol;
+ gboolean deprecated;
+
+ flags = g_function_info_get_flags (info);
+ name = g_base_info_get_name ((GIBaseInfo *)info);
+ symbol = g_function_info_get_symbol (info);
+ deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+ if (flags & GI_FUNCTION_IS_CONSTRUCTOR)
+ tag = "constructor";
+ else if (flags & GI_FUNCTION_IS_METHOD)
+ tag = "method";
+ else
+ tag = "function";
+
+ g_fprintf (file, "%*s<%s name=\"%s\" symbol=\"%s\"",
+ indent, "", tag, name, symbol);
+
+ if (flags & GI_FUNCTION_IS_SETTER)
+ g_fprintf (file, " type=\"setter\"");
+ else if (flags & GI_FUNCTION_IS_GETTER)
+ g_fprintf (file, " type=\"getter\"");
+
+ if (deprecated)
+ g_fprintf (file, " deprecated=\"1\"");
+
+ g_fprintf (file, ">\n");
+ write_callable_info (namespace, (GICallableInfo*)info, file, indent);
+ g_fprintf (file, "%*s</%s>\n", indent, "", tag);
+}
+
+static void
+write_callback_info (const gchar *namespace,
+ GICallbackInfo *info,
+ FILE *file,
+ gint indent)
+{
+ const gchar *name;
+ gboolean deprecated;
+
+ name = g_base_info_get_name ((GIBaseInfo *)info);
+ deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+ g_fprintf (file, "%*s<callback name=\"%s\"", indent, "", name);
+
+ if (deprecated)
+ g_fprintf (file, " deprecated=\"1\"");
+
+ g_fprintf (file, ">\n");
+ write_callable_info (namespace, (GICallableInfo*)info, file, indent);
+ g_fprintf (file, "%*s</callback>\n", indent, "");
+}
+
+static void
+write_struct_info (const gchar *namespace,
+ GIStructInfo *info,
+ FILE *file)
+{
+ const gchar *name;
+ const gchar *type_name;
+ const gchar *type_init;
+ gboolean deprecated;
+ gint i;
+
+ name = g_base_info_get_name ((GIBaseInfo *)info);
+ deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+ if (g_base_info_get_type ((GIBaseInfo *)info) == GI_INFO_TYPE_BOXED)
+ {
+ type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
+ type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info);
+
+ g_fprintf (file, " <boxed name=\"%s\" type-name=\"%s\" get-type=\"%s\"", name, type_name, type_init);
+ }
+ else
+ g_fprintf (file, " <struct name=\"%s\"", name);
+
+ if (deprecated)
+ g_fprintf (file, " deprecated=\"1\"");
+
+ g_fprintf (file, ">\n");
+
+ for (i = 0; i < g_struct_info_get_n_fields (info); i++)
+ {
+ GIFieldInfo *field = g_struct_info_get_field (info, i);
+ write_field_info (namespace, field, NULL, file);
+ g_base_info_unref ((GIBaseInfo *)field);
+ }
+
+ for (i = 0; i < g_struct_info_get_n_methods (info); i++)
+ {
+ GIFunctionInfo *function = g_struct_info_get_method (info, i);
+ write_function_info (namespace, function, file, 6);
+ g_base_info_unref ((GIBaseInfo *)function);
+ }
+
+ if (g_base_info_get_type ((GIBaseInfo *)info) == GI_INFO_TYPE_BOXED)
+ g_fprintf (file, " </boxed>\n");
+ else
+ g_fprintf (file, " </struct>\n");
+}
+
+static void
+write_value_info (const gchar *namespace,
+ GIValueInfo *info,
+ FILE *file)
+{
+ const gchar *name;
+ glong value;
+ gboolean deprecated;
+
+ name = g_base_info_get_name ((GIBaseInfo *)info);
+ value = g_value_info_get_value (info);
+ deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+ g_fprintf (file, " <member name=\"%s\" value=\"%ld\"", name, value);
+
+ if (deprecated)
+ g_fprintf (file, " deprecated=\"1\"");
+
+ g_fprintf (file, " />\n");
+}
+
+static void
+write_constant_value (const gchar *namespace,
+ GITypeInfo *type,
+ GArgument *value,
+ FILE *file)
+{
+ switch (g_type_info_get_tag (type))
+ {
+ case GI_TYPE_TAG_BOOLEAN:
+ g_fprintf (file, "%d", value->v_boolean);
+ break;
+ case GI_TYPE_TAG_INT8:
+ g_fprintf (file, "%d", value->v_int8);
+ break;
+ case GI_TYPE_TAG_UINT8:
+ g_fprintf (file, "%d", value->v_uint8);
+ break;
+ case GI_TYPE_TAG_INT16:
+ g_fprintf (file, "%" G_GINT16_FORMAT, value->v_int16);
+ break;
+ case GI_TYPE_TAG_UINT16:
+ g_fprintf (file, "%" G_GUINT16_FORMAT, value->v_uint16);
+ break;
+ case GI_TYPE_TAG_INT32:
+ g_fprintf (file, "%" G_GINT32_FORMAT, value->v_int32);
+ break;
+ case GI_TYPE_TAG_UINT32:
+ g_fprintf (file, "%" G_GUINT32_FORMAT, value->v_uint32);
+ break;
+ case GI_TYPE_TAG_INT64:
+ g_fprintf (file, "%" G_GINT64_FORMAT, value->v_int64);
+ break;
+ case GI_TYPE_TAG_UINT64:
+ g_fprintf (file, "%" G_GUINT64_FORMAT, value->v_uint64);
+ break;
+ case GI_TYPE_TAG_INT:
+ g_fprintf (file, "%d", value->v_int);
+ break;
+ case GI_TYPE_TAG_UINT:
+ g_fprintf (file, "%d", value->v_uint);
+ break;
+ case GI_TYPE_TAG_LONG:
+ g_fprintf (file, "%ld", value->v_long);
+ break;
+ case GI_TYPE_TAG_ULONG:
+ g_fprintf (file, "%ld", value->v_ulong);
+ break;
+ case GI_TYPE_TAG_SSIZE:
+ g_fprintf (file, "%zd", value->v_ssize);
+ break;
+ case GI_TYPE_TAG_SIZE:
+ g_fprintf (file, "%zd", value->v_size);
+ break;
+ case GI_TYPE_TAG_FLOAT:
+ g_fprintf (file, "%f", value->v_float);
+ break;
+ case GI_TYPE_TAG_DOUBLE:
+ g_fprintf (file, "%f", value->v_double);
+ break;
+ case GI_TYPE_TAG_UTF8:
+ case GI_TYPE_TAG_FILENAME:
+ g_fprintf (file, "%s", value->v_string);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+write_constant_info (const gchar *namespace,
+ GIConstantInfo *info,
+ FILE *file,
+ gint indent)
+{
+ GITypeInfo *type;
+ const gchar *name;
+ gboolean deprecated;
+ GArgument value;
+
+ name = g_base_info_get_name ((GIBaseInfo *)info);
+ deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+ g_fprintf (file, "%*s<constant name=\"%s\" type=\"", indent, "", name);
+
+ type = g_constant_info_get_type (info);
+ write_type_info (namespace, type, file);
+ g_fprintf (file, "\" value=\"");
+
+ g_constant_info_get_value (info, &value);
+ write_constant_value (namespace, type, &value, file);
+ g_fprintf (file, "\" />\n");
+
+ g_base_info_unref ((GIBaseInfo *)type);
+}
+
+
+static void
+write_enum_info (const gchar *namespace,
+ GIEnumInfo *info,
+ FILE *file)
+{
+ const gchar *name;
+ const gchar *type_name;
+ const gchar *type_init;
+ gboolean deprecated;
+ gint i;
+
+ name = g_base_info_get_name ((GIBaseInfo *)info);
+ deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+ type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
+ type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info);
+
+ if (g_base_info_get_type ((GIBaseInfo *)info) == GI_INFO_TYPE_ENUM)
+ g_fprintf (file, " <enum ");
+ else
+ g_fprintf (file, " <flags ");
+ g_fprintf (file, "name=\"%s\"", name);
+
+ if (type_init)
+ g_fprintf (file, " type-name=\"%s\" get-type=\"%s\"", type_name, type_init);
+
+ if (deprecated)
+ g_fprintf (file, " deprecated=\"1\"");
+
+ g_fprintf (file, ">\n");
+
+ for (i = 0; i < g_enum_info_get_n_values (info); i++)
+ {
+ GIValueInfo *value = g_enum_info_get_value (info, i);
+ write_value_info (namespace, value, file);
+ g_base_info_unref ((GIBaseInfo *)value);
+ }
+
+ if (g_base_info_get_type ((GIBaseInfo *)info) == GI_INFO_TYPE_ENUM)
+ g_fprintf (file, " </enum>\n");
+ else
+ g_fprintf (file, " </flags>\n");
+}
+
+static void
+write_signal_info (const gchar *namespace,
+ GISignalInfo *info,
+ FILE *file)
+{
+ GSignalFlags flags;
+ const gchar *name;
+ gboolean deprecated;
+
+ name = g_base_info_get_name ((GIBaseInfo *)info);
+ flags = g_signal_info_get_flags (info);
+ deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+ g_fprintf (file, " <signal name=\"%s\"", name);
+
+ if (deprecated)
+ g_fprintf (file, " deprecated=\"1\"");
+
+ if (flags & G_SIGNAL_RUN_FIRST)
+ g_fprintf (file, " when=\"FIRST\"");
+ else if (flags & G_SIGNAL_RUN_LAST)
+ g_fprintf (file, " when=\"LAST\"");
+ else if (flags & G_SIGNAL_RUN_CLEANUP)
+ g_fprintf (file, " when=\"CLEANUP\"");
+
+ if (flags & G_SIGNAL_NO_RECURSE)
+ g_fprintf (file, " no-recurse=\"1\"");
+
+ if (flags & G_SIGNAL_DETAILED)
+ g_fprintf (file, " detailed=\"1\"");
+
+ if (flags & G_SIGNAL_ACTION)
+ g_fprintf (file, " action=\"1\"");
+
+ if (flags & G_SIGNAL_NO_HOOKS)
+ g_fprintf (file, " no-hooks=\"1\"");
+
+ g_fprintf (file, ">\n");
+
+ write_callable_info (namespace, (GICallableInfo*)info, file, 6);
+ g_fprintf (file, " </signal>\n");
+}
+
+static void
+write_vfunc_info (const gchar *namespace,
+ GIVFuncInfo *info,
+ FILE *file)
+{
+ GIVFuncInfoFlags flags;
+ const gchar *name;
+ gboolean deprecated;
+ gint offset;
+
+ name = g_base_info_get_name ((GIBaseInfo *)info);
+ flags = g_vfunc_info_get_flags (info);
+ deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+ offset = g_vfunc_info_get_offset (info);
+
+ g_fprintf (file, " <vfunc name=\"%s\"", name);
+
+ if (deprecated)
+ g_fprintf (file, " deprecated=\"1\"");
+
+ if (flags & GI_VFUNC_MUST_CHAIN_UP)
+ g_fprintf (file, " must-chain-up=\"1\"");
+
+ if (flags & GI_VFUNC_MUST_OVERRIDE)
+ g_fprintf (file, " override=\"always\"");
+ else if (flags & GI_VFUNC_MUST_NOT_OVERRIDE)
+ g_fprintf (file, " override=\"never\"");
+
+ g_fprintf (file, " offset=\"%d\"", offset);
+ g_fprintf (file, ">\n");
+
+ write_callable_info (namespace, (GICallableInfo*)info, file, 6);
+ g_fprintf (file, " </vfunc>\n");
+}
+
+static void
+write_property_info (const gchar *namespace,
+ GIPropertyInfo *info,
+ FILE *file)
+{
+ GParamFlags flags;
+ const gchar *name;
+ gboolean deprecated;
+ GITypeInfo *type;
+
+ name = g_base_info_get_name ((GIBaseInfo *)info);
+ flags = g_property_info_get_flags (info);
+ deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+ g_fprintf (file, " <property name=\"%s\"", name);
+
+ if (deprecated)
+ g_fprintf (file, " deprecated=\"1\"");
+
+ if (flags & G_PARAM_READABLE)
+ g_fprintf (file, " readable=\"1\"");
+ else
+ g_fprintf (file, " readable=\"0\"");
+
+ if (flags & G_PARAM_WRITABLE)
+ g_fprintf (file, " writable=\"1\"");
+ else
+ g_fprintf (file, " writable=\"0\"");
+
+ if (flags & G_PARAM_CONSTRUCT)
+ g_fprintf (file, " construct=\"1\"");
+
+ if (flags & G_PARAM_CONSTRUCT_ONLY)
+ g_fprintf (file, " construct-only=\"1\"");
+
+ type = g_property_info_get_type (info);
+ g_fprintf (file, " type=\"");
+ write_type_info (namespace, type, file);
+ g_fprintf (file, "\"");
+
+ g_fprintf (file, " />\n");
+}
+
+static void
+write_object_info (const gchar *namespace,
+ GIObjectInfo *info,
+ FILE *file)
+{
+ const gchar *name;
+ const gchar *type_name;
+ const gchar *type_init;
+ gboolean deprecated;
+ GIObjectInfo *pnode;
+ gint i;
+
+ name = g_base_info_get_name ((GIBaseInfo *)info);
+ deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+ type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
+ type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info);
+ g_fprintf (file, " <object name=\"%s\"", name);
+
+ pnode = g_object_info_get_parent (info);
+ if (pnode)
+ {
+ g_fprintf (file, " parent=\"");
+ write_type_name (namespace, (GIBaseInfo *)pnode, file);
+ g_fprintf (file, "\"" );
+ g_base_info_unref ((GIBaseInfo *)pnode);
+ }
+
+ g_fprintf (file, " type-name=\"%s\" get-type=\"%s\"", type_name, type_init);
+
+ if (deprecated)
+ g_fprintf (file, " deprecated=\"1\"");
+
+ g_fprintf (file, ">\n");
+
+ if (g_object_info_get_n_interfaces (info) > 0)
+ {
+ g_fprintf (file, " <implements>\n");
+ for (i = 0; i < g_object_info_get_n_interfaces (info); i++)
+ {
+ GIInterfaceInfo *imp = g_object_info_get_interface (info, i);
+ g_fprintf (file, " <interface name=\"");
+ write_type_name (namespace, (GIBaseInfo*)imp, file);
+ g_fprintf (file,"\" />\n");
+ g_base_info_unref ((GIBaseInfo*)imp);
+ }
+ g_fprintf (file, " </implements>\n");
+ }
+
+ for (i = 0; i < g_object_info_get_n_fields (info); i++)
+ {
+ GIFieldInfo *field = g_object_info_get_field (info, i);
+ write_field_info (namespace, field, NULL, file);
+ g_base_info_unref ((GIBaseInfo *)field);
+ }
+
+ for (i = 0; i < g_object_info_get_n_methods (info); i++)
+ {
+ GIFunctionInfo *function = g_object_info_get_method (info, i);
+ write_function_info (namespace, function, file, 6);
+ g_base_info_unref ((GIBaseInfo *)function);
+ }
+
+ for (i = 0; i < g_object_info_get_n_properties (info); i++)
+ {
+ GIPropertyInfo *prop = g_object_info_get_property (info, i);
+ write_property_info (namespace, prop, file);
+ g_base_info_unref ((GIBaseInfo *)prop);
+ }
+
+ for (i = 0; i < g_object_info_get_n_signals (info); i++)
+ {
+ GISignalInfo *signal = g_object_info_get_signal (info, i);
+ write_signal_info (namespace, signal, file);
+ g_base_info_unref ((GIBaseInfo *)signal);
+ }
+
+ for (i = 0; i < g_object_info_get_n_vfuncs (info); i++)
+ {
+ GIVFuncInfo *vfunc = g_object_info_get_vfunc (info, i);
+ write_vfunc_info (namespace, vfunc, file);
+ g_base_info_unref ((GIBaseInfo *)vfunc);
+ }
+
+ for (i = 0; i < g_object_info_get_n_constants (info); i++)
+ {
+ GIConstantInfo *constant = g_object_info_get_constant (info, i);
+ write_constant_info (namespace, constant, file, 6);
+ g_base_info_unref ((GIBaseInfo *)constant);
+ }
+
+ g_fprintf (file, " </object>\n");
+}
+
+static void
+write_interface_info (const gchar *namespace,
+ GIInterfaceInfo *info,
+ FILE *file)
+{
+ const gchar *name;
+ const gchar *type_name;
+ const gchar *type_init;
+ gboolean deprecated;
+ gint i;
+
+ name = g_base_info_get_name ((GIBaseInfo *)info);
+ deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+ type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
+ type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info);
+ g_fprintf (file, " <interface name=\"%s\" type-name=\"%s\" get-type=\"%s\"",
+ name, type_name, type_init);
+
+ if (deprecated)
+ g_fprintf (file, " deprecated=\"1\"");
+
+ g_fprintf (file, ">\n");
+
+ if (g_interface_info_get_n_prerequisites (info) > 0)
+ {
+ g_fprintf (file, " <requires>\n");
+ for (i = 0; i < g_interface_info_get_n_prerequisites (info); i++)
+ {
+ GIBaseInfo *req = g_interface_info_get_prerequisite (info, i);
+
+ if (g_base_info_get_type (req) == GI_INFO_TYPE_INTERFACE)
+ g_fprintf (file, " <interface name=\"");
+ else
+ g_fprintf (file, " <object name=\"");
+ write_type_name (namespace, req, file);
+ g_fprintf (file, "\" />\n");
+ g_base_info_unref (req);
+ }
+ g_fprintf (file, " </requires>\n");
+ }
+
+ for (i = 0; i < g_interface_info_get_n_methods (info); i++)
+ {
+ GIFunctionInfo *function = g_interface_info_get_method (info, i);
+ write_function_info (namespace, function, file, 6);
+ g_base_info_unref ((GIBaseInfo *)function);
+ }
+
+ for (i = 0; i < g_interface_info_get_n_properties (info); i++)
+ {
+ GIPropertyInfo *prop = g_interface_info_get_property (info, i);
+ write_property_info (namespace, prop, file);
+ g_base_info_unref ((GIBaseInfo *)prop);
+ }
+
+ for (i = 0; i < g_interface_info_get_n_signals (info); i++)
+ {
+ GISignalInfo *signal = g_interface_info_get_signal (info, i);
+ write_signal_info (namespace, signal, file);
+ g_base_info_unref ((GIBaseInfo *)signal);
+ }
+
+ for (i = 0; i < g_interface_info_get_n_vfuncs (info); i++)
+ {
+ GIVFuncInfo *vfunc = g_interface_info_get_vfunc (info, i);
+ write_vfunc_info (namespace, vfunc, file);
+ g_base_info_unref ((GIBaseInfo *)vfunc);
+ }
+
+ for (i = 0; i < g_interface_info_get_n_constants (info); i++)
+ {
+ GIConstantInfo *constant = g_interface_info_get_constant (info, i);
+ write_constant_info (namespace, constant, file, 6);
+ g_base_info_unref ((GIBaseInfo *)constant);
+ }
+
+ g_fprintf (file, " </interface>\n");
+}
+
+static void
+write_error_domain_info (const gchar *namespace,
+ GIErrorDomainInfo *info,
+ FILE *file)
+{
+ GIBaseInfo *enum_;
+ const gchar *name, *quark;
+
+ name = g_base_info_get_name ((GIBaseInfo *)info);
+ quark = g_error_domain_info_get_quark (info);
+ enum_ = (GIBaseInfo *)g_error_domain_info_get_codes (info);
+ g_fprintf (file,
+ " <errordomain name=\"%s\" get-quark=\"%s\" codes=\"",
+ name, quark);
+ write_type_name (namespace, enum_, file);
+ g_fprintf (file, "\" />\n");
+ g_base_info_unref (enum_);
+}
+
+static void
+write_union_info (const gchar *namespace,
+ GIUnionInfo *info,
+ FILE *file)
+{
+ const gchar *name;
+ const gchar *type_name;
+ const gchar *type_init;
+ gboolean deprecated;
+ gint i;
+
+ name = g_base_info_get_name ((GIBaseInfo *)info);
+ deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+ type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
+ type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info);
+
+ g_fprintf (file, " <union name=\"%s\"", name);
+
+ if (type_name)
+ g_fprintf (file, " type-name=\"%s\" get-type=\"%s\"", type_name, type_init);
+
+ if (deprecated)
+ g_fprintf (file, " deprecated=\"1\"");
+
+ g_fprintf (file, ">\n");
+
+ if (g_union_info_is_discriminated (info))
+ {
+ gint offset;
+ GITypeInfo *type;
+
+ offset = g_union_info_get_discriminator_offset (info);
+ type = g_union_info_get_discriminator_type (info);
+
+ g_fprintf (file, " <discriminator offset=\"%d\" type=\"", offset);
+ write_type_info (namespace, type, file);
+ g_fprintf (file, "\" />\n");
+ g_base_info_unref ((GIBaseInfo *)type);
+ }
+
+ for (i = 0; i < g_union_info_get_n_fields (info); i++)
+ {
+ GIFieldInfo *field = g_union_info_get_field (info, i);
+ GIConstantInfo *constant = g_union_info_get_discriminator (info, i);
+ write_field_info (namespace, field, constant, file);
+ g_base_info_unref ((GIBaseInfo *)field);
+ if (constant)
+ g_base_info_unref ((GIBaseInfo *)constant);
+ }
+
+ for (i = 0; i < g_union_info_get_n_methods (info); i++)
+ {
+ GIFunctionInfo *function = g_union_info_get_method (info, i);
+ write_function_info (namespace, function, file, 6);
+ g_base_info_unref ((GIBaseInfo *)function);
+ }
+
+ g_fprintf (file, " </union>\n");
+}
+
+static void
+write_repository (GIRepository *repository,
+ gboolean needs_prefix)
+{
+ FILE *file;
+ gchar **namespaces;
+ gchar *ns;
+ gint i, j;
+
+ namespaces = g_irepository_get_namespaces (repository);
+
+ if (output == NULL)
+ file = stdout;
+ else
+ {
+ gchar *filename;
+
+ if (needs_prefix)
+ filename = g_strdup_printf ("%s-%s", namespaces[0], output);
+ else
+ filename = g_strdup (output);
+ file = g_fopen (filename, "w");
+
+ if (file == NULL)
+ {
+ g_fprintf (stderr, "failed to open '%s': %s\n",
+ filename, g_strerror (errno));
+ g_free (filename);
+
+ return;
+ }
+
+ g_free (filename);
+ }
+
+ g_fprintf (file, "<?xml version=\"1.0\"?>\n");
+ g_fprintf (file, "<api version=\"1.0\">\n");
+
+ for (i = 0; namespaces[i]; i++)
+ {
+ const gchar *shared_library;
+ ns = namespaces[i];
+ shared_library = g_irepository_get_shared_library (repository, ns);
+ if (shared_library)
+ g_fprintf (file, " <namespace name=\"%s\" shared-library=\"%s\">\n",
+ ns, shared_library);
+ else
+ g_fprintf (file, " <namespace name=\"%s\">\n", ns);
+
+ for (j = 0; j < g_irepository_get_n_infos (repository, ns); j++)
+ {
+ GIBaseInfo *info = g_irepository_get_info (repository, ns, j);
+ switch (g_base_info_get_type (info))
+ {
+ case GI_INFO_TYPE_FUNCTION:
+ write_function_info (ns, (GIFunctionInfo *)info, file, 4);
+ break;
+
+ case GI_INFO_TYPE_CALLBACK:
+ write_callback_info (ns, (GICallbackInfo *)info, file, 4);
+ break;
+
+ case GI_INFO_TYPE_STRUCT:
+ case GI_INFO_TYPE_BOXED:
+ write_struct_info (ns, (GIStructInfo *)info, file);
+ break;
+
+ case GI_INFO_TYPE_UNION:
+ write_union_info (ns, (GIUnionInfo *)info, file);
+ break;
+
+ case GI_INFO_TYPE_ENUM:
+ case GI_INFO_TYPE_FLAGS:
+ write_enum_info (ns, (GIEnumInfo *)info, file);
+ break;
+
+ case GI_INFO_TYPE_CONSTANT:
+ write_constant_info (ns, (GIConstantInfo *)info, file, 4);
+ break;
+
+ case GI_INFO_TYPE_OBJECT:
+ write_object_info (ns, (GIObjectInfo *)info, file);
+ break;
+
+ case GI_INFO_TYPE_INTERFACE:
+ write_interface_info (ns, (GIInterfaceInfo *)info, file);
+ break;
+
+ case GI_INFO_TYPE_ERROR_DOMAIN:
+ write_error_domain_info (ns, (GIErrorDomainInfo *)info, file);
+ break;
+
+ default:
+ g_error ("unknown info type %d\n", g_base_info_get_type (info));
+ }
+
+ g_base_info_unref (info);
+ }
+
+ g_fprintf (file, " </namespace>\n");
+ }
+
+ g_fprintf (file, "</api>\n");
+
+ if (output != NULL)
+ fclose (file);
+
+ g_strfreev (namespaces);
+}
+
+static GOptionEntry options[] =
+{
+ { "raw", 0, 0, G_OPTION_ARG_NONE, &raw, "handle raw metadata", NULL },
+ { "output", 'o', 0, G_OPTION_ARG_FILENAME, &output, "output file", "FILE" },
+ { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &input, NULL, NULL },
+ { NULL, }
+};
+
+static const guchar *
+load_metadata (const gchar *filename,
+ GModule **dlhandle,
+ gsize *len)
+{
+ guchar *metadata;
+ gsize *metadata_size;
+ GModule *handle;
+
+ handle = g_module_open (filename, G_MODULE_BIND_LOCAL|G_MODULE_BIND_LAZY);
+ if (!g_module_symbol (handle, "_G_METADATA", (gpointer *) &metadata))
+ {
+ g_printerr ("Could not load metadata from '%s': %s\n",
+ filename, g_module_error ());
+ return NULL;
+ }
+
+ if (!g_module_symbol (handle, "_G_METADATA_SIZE", (gpointer *) &metadata_size))
+ {
+ g_printerr ("Could not load metadata from '%s': %s\n",
+ filename, g_module_error ());
+ return NULL;
+ }
+
+ *len = *metadata_size;
+
+ if (dlhandle)
+ *dlhandle = handle;
+
+ return metadata;
+}
+
+int
+main (int argc, char *argv[])
+{
+ GOptionContext *context;
+ GError *error = NULL;
+ gboolean needs_prefix;
+ gint i;
+ GMetadata *data;
+
+ g_type_init ();
+
+ g_metadata_check_sanity ();
+
+ context = g_option_context_new ("");
+ g_option_context_add_main_entries (context, options, NULL);
+ g_option_context_parse (context, &argc, &argv, &error);
+
+ if (!input)
+ {
+ g_fprintf (stderr, "no input files\n");
+
+ return 1;
+ }
+
+ for (i = 0; input[i]; i++)
+ {
+ GModule *dlhandle = NULL;
+ const guchar *metadata;
+ gsize len;
+
+ if (raw)
+ {
+ if (!g_file_get_contents (input[i], (gchar **)&metadata, &len, &error))
+ {
+ g_fprintf (stderr, "failed to read '%s': %s\n",
+ input[i], error->message);
+ g_clear_error (&error);
+ continue;
+ }
+ }
+ else
+ {
+ metadata = load_metadata (input[i], &dlhandle, &len);
+ if (!metadata)
+ {
+ g_fprintf (stderr, "failed to load metadata from '%s'\n",
+ input[i]);
+ continue;
+ }
+ }
+
+ if (input[i + 1] && output)
+ needs_prefix = TRUE;
+ else
+ needs_prefix = FALSE;
+
+ data = g_metadata_new_from_const_memory (metadata, len);
+ {
+ GError *error = NULL;
+ if (!g_metadata_validate (data, &error)) {
+ g_printerr ("metadata not valid: %s\n", error->message);
+ g_clear_error (&error);
+ }
+ }
+ g_irepository_register (g_irepository_get_default (), data);
+ write_repository (g_irepository_get_default (), needs_prefix);
+ g_irepository_unregister (g_irepository_get_default (),
+ g_metadata_get_namespace (data));
+
+ if (dlhandle)
+ {
+ g_module_close (dlhandle);
+ dlhandle = NULL;
+ }
+
+ /* when writing to stdout, stop after the first module */
+ if (input[i + 1] && !output)
+ {
+ g_fprintf (stderr, "warning, %d modules omitted\n",
+ g_strv_length (input) - 1);
+
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/tools/gidlmodule.c b/tools/gidlmodule.c
new file mode 100644
index 00000000..d17a249a
--- /dev/null
+++ b/tools/gidlmodule.c
@@ -0,0 +1,215 @@
+/* GObject introspection: Metadata creation
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * 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 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "gidlmodule.h"
+#include "gidlnode.h"
+
+#define ALIGN_VALUE(this, boundary) \
+ (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
+
+
+GIdlModule *
+g_idl_module_new (const gchar *name, const gchar *shared_library)
+{
+ GIdlModule *module;
+
+ module = g_new (GIdlModule, 1);
+
+ module->name = g_strdup (name);
+ if (shared_library)
+ module->shared_library = g_strdup (shared_library);
+ else
+ module->shared_library = NULL;
+ module->entries = NULL;
+
+ return module;
+}
+
+void
+g_idl_module_free (GIdlModule *module)
+{
+ GList *e;
+
+ g_free (module->name);
+
+ for (e = module->entries; e; e = e->next)
+ g_idl_node_free ((GIdlNode *)e->data);
+
+ g_list_free (module->entries);
+
+ g_free (module);
+}
+
+GMetadata *
+g_idl_module_build_metadata (GIdlModule *module,
+ GList *modules)
+{
+ guchar *metadata;
+ gsize length;
+ gint i;
+ GList *e;
+ Header *header;
+ DirEntry *entry;
+ guint32 header_size;
+ guint32 dir_size;
+ guint32 n_entries;
+ guint32 n_local_entries;
+ guint32 size, offset, offset2, old_offset;
+ GHashTable *strings;
+ GHashTable *types;
+ guchar *data;
+
+ header_size = ALIGN_VALUE (sizeof (Header), 4);
+ n_local_entries = g_list_length (module->entries);
+
+ restart:
+ init_stats ();
+ strings = g_hash_table_new (g_str_hash, g_str_equal);
+ types = g_hash_table_new (g_str_hash, g_str_equal);
+ n_entries = g_list_length (module->entries);
+
+ g_message ("%d entries (%d local)\n", n_entries, n_local_entries);
+
+ dir_size = n_entries * 12;
+ size = header_size + dir_size;
+
+ size += ALIGN_VALUE (strlen (module->name) + 1, 4);
+
+ for (e = module->entries; e; e = e->next)
+ {
+ GIdlNode *node = e->data;
+
+ size += g_idl_node_get_full_size (node);
+ }
+
+ g_message ("allocating %d bytes (%d header, %d directory, %d entries)\n",
+ size, header_size, dir_size, size - header_size - dir_size);
+
+ data = g_malloc0 (size);
+
+ /* fill in header */
+ header = (Header *)data;
+ memcpy (header, G_IDL_MAGIC, 16);
+ header->major_version = 1;
+ header->minor_version = 0;
+ header->reserved = 0;
+ header->n_entries = n_entries;
+ header->n_local_entries = n_local_entries;
+ header->n_annotations = 0;
+ header->annotations = 0; /* filled in later */
+ header->size = 0; /* filled in later */
+ header->namespace = write_string (module->name, strings, data, &header_size);
+ header->shared_library = (module->shared_library?
+ write_string (module->shared_library, strings, data, &header_size)
+ : 0);
+ header->directory = ALIGN_VALUE (header_size, 4);
+ header->entry_blob_size = 12;
+ header->function_blob_size = 16;
+ header->callback_blob_size = 12;
+ header->signal_blob_size = 12;
+ header->vfunc_blob_size = 16;
+ header->arg_blob_size = 12;
+ header->property_blob_size = 12;
+ header->field_blob_size = 12;
+ header->value_blob_size = 12;
+ header->constant_blob_size = 20;
+ header->error_domain_blob_size = 16;
+ header->annotation_blob_size = 12;
+ header->signature_blob_size = 8;
+ header->enum_blob_size = 20;
+ header->struct_blob_size = 20;
+ header->object_blob_size = 32;
+ header->interface_blob_size = 28;
+ header->union_blob_size = 28;
+
+ /* fill in directory and content */
+ entry = (DirEntry *)&data[header->directory];
+
+ offset2 = header->directory + dir_size;
+
+ for (e = module->entries, i = 0; e; e = e->next, i++)
+ {
+ GIdlNode *node = e->data;
+
+ if (strchr (node->name, '.'))
+ {
+ g_error ("Names may not contain '.'");
+ }
+
+ /* we picked up implicit xref nodes, start over */
+ if (i == n_entries)
+ {
+ g_message ("Found implicit cross references, starting over");
+
+ g_hash_table_destroy (strings);
+ g_hash_table_destroy (types);
+ strings = NULL;
+
+ g_free (data);
+ data = NULL;
+
+ goto restart;
+ }
+
+ offset = offset2;
+
+ if (node->type == G_IDL_NODE_XREF)
+ {
+ entry->blob_type = 0;
+ entry->local = FALSE;
+ entry->offset = write_string (((GIdlNodeXRef*)node)->namespace, strings, data, &offset2);
+ entry->name = write_string (node->name, strings, data, &offset2);
+ }
+ else
+ {
+ old_offset = offset;
+ offset2 = offset + g_idl_node_get_size (node);
+
+ entry->blob_type = node->type;
+ entry->local = TRUE;
+ entry->offset = offset;
+ entry->name = write_string (node->name, strings, data, &offset2);
+
+ g_idl_node_build_metadata (node, module, modules,
+ strings, types, data, &offset, &offset2);
+
+ if (offset2 > old_offset + g_idl_node_get_full_size (node))
+ g_error ("left a hole of %d bytes\n", offset2 - old_offset - g_idl_node_get_full_size (node));
+ }
+
+ entry++;
+ }
+
+ dump_stats ();
+ g_hash_table_destroy (strings);
+ g_hash_table_destroy (types);
+
+ header->annotations = offset2;
+
+ g_message ("reallocating to %d bytes", offset2);
+
+ metadata = g_realloc (data, offset2);
+ length = header->size = offset2;
+ return g_metadata_new_from_memory (metadata, length);
+}
+
diff --git a/tools/gidlmodule.h b/tools/gidlmodule.h
new file mode 100644
index 00000000..3564a75f
--- /dev/null
+++ b/tools/gidlmodule.h
@@ -0,0 +1,48 @@
+/* GObject introspection: Parsed IDL
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * 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 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.
+ */
+
+#ifndef __G_IDL_MODULE_H__
+#define __G_IDL_MODULE_H__
+
+#include <glib.h>
+#include "gmetadata.h"
+
+G_BEGIN_DECLS
+
+
+typedef struct _GIdlModule GIdlModule;
+
+struct _GIdlModule
+{
+ gchar *name;
+ gchar *shared_library;
+ GList *entries;
+};
+
+GIdlModule *g_idl_module_new (const gchar *name,
+ const gchar *module_filename);
+void g_idl_module_free (GIdlModule *module);
+
+GMetadata * g_idl_module_build_metadata (GIdlModule *module,
+ GList *modules);
+
+G_END_DECLS
+
+#endif /* __G_IDL_MODULE_H__ */
diff --git a/tools/gidlnode.c b/tools/gidlnode.c
new file mode 100644
index 00000000..f70cffb5
--- /dev/null
+++ b/tools/gidlnode.c
@@ -0,0 +1,2050 @@
+/* GObject introspection: Metadata creation
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * 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 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gidlmodule.h"
+#include "gidlnode.h"
+#include "gmetadata.h"
+
+static gulong string_count = 0;
+static gulong unique_string_count = 0;
+static gulong string_size = 0;
+static gulong unique_string_size = 0;
+static gulong types_count = 0;
+static gulong unique_types_count = 0;
+
+void
+init_stats (void)
+{
+ string_count = 0;
+ unique_string_count = 0;
+ string_size = 0;
+ unique_string_size = 0;
+ types_count = 0;
+ unique_types_count = 0;
+}
+
+void
+dump_stats (void)
+{
+ g_message ("%lu strings (%lu before sharing), %lu bytes (%lu before sharing)",
+ unique_string_count, string_count, unique_string_size, string_size);
+ g_message ("%lu types (%lu before sharing)", unique_types_count, types_count);
+}
+
+#define ALIGN_VALUE(this, boundary) \
+ (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
+
+
+GIdlNode *
+g_idl_node_new (GIdlNodeTypeId type)
+{
+ GIdlNode *node = NULL;
+
+ switch (type)
+ {
+ case G_IDL_NODE_FUNCTION:
+ case G_IDL_NODE_CALLBACK:
+ node = g_malloc0 (sizeof (GIdlNodeFunction));
+ break;
+
+ case G_IDL_NODE_PARAM:
+ node = g_malloc0 (sizeof (GIdlNodeParam));
+ break;
+
+ case G_IDL_NODE_TYPE:
+ node = g_malloc0 (sizeof (GIdlNodeType));
+ break;
+
+ case G_IDL_NODE_OBJECT:
+ case G_IDL_NODE_INTERFACE:
+ node = g_malloc0 (sizeof (GIdlNodeInterface));
+ break;
+
+ case G_IDL_NODE_SIGNAL:
+ node = g_malloc0 (sizeof (GIdlNodeSignal));
+ break;
+
+ case G_IDL_NODE_PROPERTY:
+ node = g_malloc0 (sizeof (GIdlNodeProperty));
+ break;
+
+ case G_IDL_NODE_VFUNC:
+ node = g_malloc0 (sizeof (GIdlNodeFunction));
+ break;
+
+ case G_IDL_NODE_FIELD:
+ node = g_malloc0 (sizeof (GIdlNodeField));
+ break;
+
+ case G_IDL_NODE_ENUM:
+ case G_IDL_NODE_FLAGS:
+ node = g_malloc0 (sizeof (GIdlNodeEnum));
+ break;
+
+ case G_IDL_NODE_BOXED:
+ node = g_malloc0 (sizeof (GIdlNodeBoxed));
+ break;
+
+ case G_IDL_NODE_STRUCT:
+ node = g_malloc0 (sizeof (GIdlNodeStruct));
+ break;
+
+ case G_IDL_NODE_VALUE:
+ node = g_malloc0 (sizeof (GIdlNodeValue));
+ break;
+
+ case G_IDL_NODE_CONSTANT:
+ node = g_malloc0 (sizeof (GIdlNodeConstant));
+ break;
+
+ case G_IDL_NODE_ERROR_DOMAIN:
+ node = g_malloc0 (sizeof (GIdlNodeErrorDomain));
+ break;
+
+ case G_IDL_NODE_XREF:
+ node = g_malloc0 (sizeof (GIdlNodeXRef));
+ break;
+
+ case G_IDL_NODE_UNION:
+ node = g_malloc0 (sizeof (GIdlNodeUnion));
+ break;
+
+ default:
+ g_error ("Unhandled node type %d\n", type);
+ break;
+ }
+
+ node->type = type;
+
+ return node;
+}
+
+void
+g_idl_node_free (GIdlNode *node)
+{
+ GList *l;
+
+ if (node == NULL)
+ return;
+
+ switch (node->type)
+ {
+ case G_IDL_NODE_FUNCTION:
+ case G_IDL_NODE_CALLBACK:
+ {
+ GIdlNodeFunction *function = (GIdlNodeFunction *)node;
+
+ g_free (node->name);
+ g_free (function->symbol);
+ g_idl_node_free ((GIdlNode *)function->result);
+ for (l = function->parameters; l; l = l->next)
+ g_idl_node_free ((GIdlNode *)l->data);
+ g_list_free (function->parameters);
+ }
+ break;
+
+ case G_IDL_NODE_TYPE:
+ {
+ GIdlNodeType *type = (GIdlNodeType *)node;
+
+ g_free (node->name);
+ g_idl_node_free ((GIdlNode *)type->parameter_type1);
+ g_idl_node_free ((GIdlNode *)type->parameter_type2);
+
+ g_free (type->interface);
+ g_strfreev (type->errors);
+
+ }
+ break;
+
+ case G_IDL_NODE_PARAM:
+ {
+ GIdlNodeParam *param = (GIdlNodeParam *)node;
+
+ g_free (node->name);
+ g_idl_node_free ((GIdlNode *)param->type);
+ }
+ break;
+
+ case G_IDL_NODE_PROPERTY:
+ {
+ GIdlNodeProperty *property = (GIdlNodeProperty *)node;
+
+ g_free (node->name);
+ g_idl_node_free ((GIdlNode *)property->type);
+ }
+ break;
+
+ case G_IDL_NODE_SIGNAL:
+ {
+ GIdlNodeSignal *signal = (GIdlNodeSignal *)node;
+
+ g_free (node->name);
+ for (l = signal->parameters; l; l = l->next)
+ g_idl_node_free ((GIdlNode *)l->data);
+ g_list_free (signal->parameters);
+ g_idl_node_free ((GIdlNode *)signal->result);
+ }
+ break;
+
+ case G_IDL_NODE_VFUNC:
+ {
+ GIdlNodeVFunc *vfunc = (GIdlNodeVFunc *)node;
+
+ g_free (node->name);
+ for (l = vfunc->parameters; l; l = l->next)
+ g_idl_node_free ((GIdlNode *)l->data);
+ g_list_free (vfunc->parameters);
+ g_idl_node_free ((GIdlNode *)vfunc->result);
+ }
+ break;
+
+ case G_IDL_NODE_FIELD:
+ {
+ GIdlNodeField *field = (GIdlNodeField *)node;
+
+ g_free (node->name);
+ g_idl_node_free ((GIdlNode *)field->type);
+ }
+ break;
+
+ case G_IDL_NODE_OBJECT:
+ case G_IDL_NODE_INTERFACE:
+ {
+ GIdlNodeInterface *iface = (GIdlNodeInterface *)node;
+
+ g_free (node->name);
+ g_free (iface->gtype_name);
+ g_free (iface->gtype_init);
+
+ g_free (iface->parent);
+
+ for (l = iface->interfaces; l; l = l->next)
+ g_free ((GIdlNode *)l->data);
+ g_list_free (iface->interfaces);
+
+ for (l = iface->members; l; l = l->next)
+ g_idl_node_free ((GIdlNode *)l->data);
+ g_list_free (iface->members);
+
+ }
+ break;
+
+ case G_IDL_NODE_VALUE:
+ {
+ g_free (node->name);
+ }
+ break;
+
+ case G_IDL_NODE_ENUM:
+ case G_IDL_NODE_FLAGS:
+ {
+ GIdlNodeEnum *enum_ = (GIdlNodeEnum *)node;
+
+ g_free (node->name);
+ g_free (enum_->gtype_name);
+ g_free (enum_->gtype_init);
+
+ for (l = enum_->values; l; l = l->next)
+ g_idl_node_free ((GIdlNode *)l->data);
+ g_list_free (enum_->values);
+ }
+ break;
+
+ case G_IDL_NODE_BOXED:
+ {
+ GIdlNodeBoxed *boxed = (GIdlNodeBoxed *)node;
+
+ g_free (node->name);
+ g_free (boxed->gtype_name);
+ g_free (boxed->gtype_init);
+
+ for (l = boxed->members; l; l = l->next)
+ g_idl_node_free ((GIdlNode *)l->data);
+ g_list_free (boxed->members);
+ }
+ break;
+
+ case G_IDL_NODE_STRUCT:
+ {
+ GIdlNodeStruct *struct_ = (GIdlNodeStruct *)node;
+
+ g_free (node->name);
+ for (l = struct_->members; l; l = l->next)
+ g_idl_node_free ((GIdlNode *)l->data);
+ g_list_free (struct_->members);
+ }
+ break;
+
+ case G_IDL_NODE_CONSTANT:
+ {
+ GIdlNodeConstant *constant = (GIdlNodeConstant *)node;
+
+ g_free (node->name);
+ g_free (constant->value);
+ g_idl_node_free ((GIdlNode *)constant->type);
+ }
+ break;
+
+ case G_IDL_NODE_ERROR_DOMAIN:
+ {
+ GIdlNodeErrorDomain *domain = (GIdlNodeErrorDomain *)node;
+
+ g_free (node->name);
+ g_free (domain->getquark);
+ g_free (domain->codes);
+ }
+ break;
+
+ case G_IDL_NODE_XREF:
+ {
+ GIdlNodeXRef *xref = (GIdlNodeXRef *)node;
+
+ g_free (node->name);
+ g_free (xref->namespace);
+ }
+ break;
+
+ case G_IDL_NODE_UNION:
+ {
+ GIdlNodeUnion *union_ = (GIdlNodeUnion *)node;
+
+ g_free (node->name);
+ g_free (union_->gtype_name);
+ g_free (union_->gtype_init);
+
+ g_idl_node_free ((GIdlNode *)union_->discriminator_type);
+ for (l = union_->members; l; l = l->next)
+ g_idl_node_free ((GIdlNode *)l->data);
+ for (l = union_->discriminators; l; l = l->next)
+ g_idl_node_free ((GIdlNode *)l->data);
+ }
+ break;
+
+ default:
+ g_error ("Unhandled node type %d\n", node->type);
+ break;
+ }
+
+ g_free (node);
+}
+
+/* returns the fixed size of the blob */
+guint32
+g_idl_node_get_size (GIdlNode *node)
+{
+ GList *l;
+ gint size, n;
+
+ switch (node->type)
+ {
+ case G_IDL_NODE_CALLBACK:
+ size = 12;
+ break;
+
+ case G_IDL_NODE_FUNCTION:
+ size = 16;
+ break;
+
+ case G_IDL_NODE_PARAM:
+ size = 12;
+ break;
+
+ case G_IDL_NODE_TYPE:
+ size = 4;
+ break;
+
+ case G_IDL_NODE_OBJECT:
+ {
+ GIdlNodeInterface *iface = (GIdlNodeInterface *)node;
+
+ n = g_list_length (iface->interfaces);
+ size = 32 + 2 * (n + (n % 2));
+
+ for (l = iface->members; l; l = l->next)
+ size += g_idl_node_get_size ((GIdlNode *)l->data);
+ }
+ break;
+
+ case G_IDL_NODE_INTERFACE:
+ {
+ GIdlNodeInterface *iface = (GIdlNodeInterface *)node;
+
+ n = g_list_length (iface->prerequisites);
+ size = 28 + 2 * (n + (n % 2));
+
+ for (l = iface->members; l; l = l->next)
+ size += g_idl_node_get_size ((GIdlNode *)l->data);
+ }
+ break;
+
+ case G_IDL_NODE_ENUM:
+ case G_IDL_NODE_FLAGS:
+ {
+ GIdlNodeEnum *enum_ = (GIdlNodeEnum *)node;
+
+ size = 20;
+ for (l = enum_->values; l; l = l->next)
+ size += g_idl_node_get_size ((GIdlNode *)l->data);
+ }
+ break;
+
+ case G_IDL_NODE_VALUE:
+ size = 12;
+ break;
+
+ case G_IDL_NODE_STRUCT:
+ {
+ GIdlNodeStruct *struct_ = (GIdlNodeStruct *)node;
+
+ size = 20;
+ for (l = struct_->members; l; l = l->next)
+ size += g_idl_node_get_size ((GIdlNode *)l->data);
+ }
+ break;
+
+ case G_IDL_NODE_BOXED:
+ {
+ GIdlNodeBoxed *boxed = (GIdlNodeBoxed *)node;
+
+ size = 20;
+ for (l = boxed->members; l; l = l->next)
+ size += g_idl_node_get_size ((GIdlNode *)l->data);
+ }
+ break;
+
+ case G_IDL_NODE_PROPERTY:
+ size = 12;
+ break;
+
+ case G_IDL_NODE_SIGNAL:
+ size = 12;
+ break;
+
+ case G_IDL_NODE_VFUNC:
+ size = 16;
+ break;
+
+ case G_IDL_NODE_FIELD:
+ size = 12;
+ break;
+
+ case G_IDL_NODE_CONSTANT:
+ size = 20;
+ break;
+
+ case G_IDL_NODE_ERROR_DOMAIN:
+ size = 16;
+ break;
+
+ case G_IDL_NODE_XREF:
+ size = 0;
+ break;
+
+ case G_IDL_NODE_UNION:
+ {
+ GIdlNodeUnion *union_ = (GIdlNodeUnion *)node;
+
+ size = 28;
+ for (l = union_->members; l; l = l->next)
+ size += g_idl_node_get_size ((GIdlNode *)l->data);
+ for (l = union_->discriminators; l; l = l->next)
+ size += g_idl_node_get_size ((GIdlNode *)l->data);
+ }
+ break;
+
+ default:
+ g_error ("Unhandled node type %d\n", node->type);
+ size = 0;
+ }
+
+ g_debug ("node %p type %d size %d", node, node->type, size);
+
+ return size;
+}
+
+/* returns the full size of the blob including variable-size parts */
+guint32
+g_idl_node_get_full_size (GIdlNode *node)
+{
+ GList *l;
+ gint size, n;
+
+ g_assert (node != NULL);
+
+ switch (node->type)
+ {
+ case G_IDL_NODE_CALLBACK:
+ {
+ GIdlNodeFunction *function = (GIdlNodeFunction *)node;
+ size = 12;
+ size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ for (l = function->parameters; l; l = l->next)
+ size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+ size += g_idl_node_get_full_size ((GIdlNode *)function->result);
+ }
+ break;
+
+ case G_IDL_NODE_FUNCTION:
+ {
+ GIdlNodeFunction *function = (GIdlNodeFunction *)node;
+ size = 24;
+ size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ size += ALIGN_VALUE (strlen (function->symbol) + 1, 4);
+ for (l = function->parameters; l; l = l->next)
+ size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+ size += g_idl_node_get_full_size ((GIdlNode *)function->result);
+ }
+ break;
+
+ case G_IDL_NODE_PARAM:
+ {
+ GIdlNodeParam *param = (GIdlNodeParam *)node;
+
+ size = 12;
+ if (node->name)
+ size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ size += g_idl_node_get_full_size ((GIdlNode *)param->type);
+ }
+ break;
+
+ case G_IDL_NODE_TYPE:
+ {
+ GIdlNodeType *type = (GIdlNodeType *)node;
+ if (type->tag < TYPE_TAG_ARRAY)
+ size = 4;
+ else
+ {
+ switch (type->tag)
+ {
+ case TYPE_TAG_ARRAY:
+ size = 4 + 4;
+ if (type->parameter_type1)
+ size += g_idl_node_get_full_size ((GIdlNode *)type->parameter_type1);
+ break;
+ case TYPE_TAG_INTERFACE:
+ size = 4 + 4;
+ break;
+ case TYPE_TAG_LIST:
+ case TYPE_TAG_SLIST:
+ size = 4 + 4;
+ if (type->parameter_type1)
+ size += g_idl_node_get_full_size ((GIdlNode *)type->parameter_type1);
+ break;
+ case TYPE_TAG_HASH:
+ size = 4 + 4 + 4;
+ if (type->parameter_type1)
+ size += g_idl_node_get_full_size ((GIdlNode *)type->parameter_type1);
+ if (type->parameter_type2)
+ size += g_idl_node_get_full_size ((GIdlNode *)type->parameter_type2);
+ break;
+ case TYPE_TAG_ERROR:
+ {
+ gint n;
+
+ if (type->errors)
+ n = g_strv_length (type->errors);
+ else
+ n = 0;
+
+ size = 4 + 4 + 2 * (n + n % 2);
+ }
+ break;
+ default:
+ g_error ("Unknown type tag %d\n", type->tag);
+ break;
+ }
+ }
+ }
+ break;
+
+ case G_IDL_NODE_OBJECT:
+ {
+ GIdlNodeInterface *iface = (GIdlNodeInterface *)node;
+
+ n = g_list_length (iface->interfaces);
+ size = 32;
+ if (iface->parent)
+ size += ALIGN_VALUE (strlen (iface->parent) + 1, 4);
+ size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ size += ALIGN_VALUE (strlen (iface->gtype_name) + 1, 4);
+ size += ALIGN_VALUE (strlen (iface->gtype_init) + 1, 4);
+ size += 2 * (n + (n % 2));
+
+ for (l = iface->members; l; l = l->next)
+ size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+ }
+ break;
+
+ case G_IDL_NODE_INTERFACE:
+ {
+ GIdlNodeInterface *iface = (GIdlNodeInterface *)node;
+
+ n = g_list_length (iface->prerequisites);
+ size = 28;
+ size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ size += ALIGN_VALUE (strlen (iface->gtype_name) + 1, 4);
+ size += ALIGN_VALUE (strlen (iface->gtype_init) + 1, 4);
+ size += 2 * (n + (n % 2));
+
+ for (l = iface->members; l; l = l->next)
+ size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+ }
+ break;
+
+ case G_IDL_NODE_ENUM:
+ case G_IDL_NODE_FLAGS:
+ {
+ GIdlNodeEnum *enum_ = (GIdlNodeEnum *)node;
+
+ size = 20;
+ size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ if (enum_->gtype_name)
+ {
+ size += ALIGN_VALUE (strlen (enum_->gtype_name) + 1, 4);
+ size += ALIGN_VALUE (strlen (enum_->gtype_init) + 1, 4);
+ }
+
+ for (l = enum_->values; l; l = l->next)
+ size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+ }
+ break;
+
+ case G_IDL_NODE_VALUE:
+ {
+ size = 12;
+ size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ }
+ break;
+
+ case G_IDL_NODE_STRUCT:
+ {
+ GIdlNodeStruct *struct_ = (GIdlNodeStruct *)node;
+
+ size = 20;
+ size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ for (l = struct_->members; l; l = l->next)
+ size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+ }
+ break;
+
+ case G_IDL_NODE_BOXED:
+ {
+ GIdlNodeBoxed *boxed = (GIdlNodeBoxed *)node;
+
+ size = 20;
+ size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ if (boxed->gtype_name)
+ {
+ size += ALIGN_VALUE (strlen (boxed->gtype_name) + 1, 4);
+ size += ALIGN_VALUE (strlen (boxed->gtype_init) + 1, 4);
+ }
+ for (l = boxed->members; l; l = l->next)
+ size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+ }
+ break;
+
+ case G_IDL_NODE_PROPERTY:
+ {
+ GIdlNodeProperty *prop = (GIdlNodeProperty *)node;
+
+ size = 12;
+ size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ size += g_idl_node_get_full_size ((GIdlNode *)prop->type);
+ }
+ break;
+
+ case G_IDL_NODE_SIGNAL:
+ {
+ GIdlNodeSignal *signal = (GIdlNodeSignal *)node;
+
+ size = 12;
+ size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ for (l = signal->parameters; l; l = l->next)
+ size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+ size += g_idl_node_get_full_size ((GIdlNode *)signal->result);
+ }
+ break;
+
+ case G_IDL_NODE_VFUNC:
+ {
+ GIdlNodeVFunc *vfunc = (GIdlNodeVFunc *)node;
+
+ size = 16;
+ size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ for (l = vfunc->parameters; l; l = l->next)
+ size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+ size += g_idl_node_get_full_size ((GIdlNode *)vfunc->result);
+ }
+ break;
+
+ case G_IDL_NODE_FIELD:
+ {
+ GIdlNodeField *field = (GIdlNodeField *)node;
+
+ size = 12;
+ size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ size += g_idl_node_get_full_size ((GIdlNode *)field->type);
+ }
+ break;
+
+ case G_IDL_NODE_CONSTANT:
+ {
+ GIdlNodeConstant *constant = (GIdlNodeConstant *)node;
+
+ size = 20;
+ size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ /* FIXME non-string values */
+ size += ALIGN_VALUE (strlen (constant->value) + 1, 4);
+ size += g_idl_node_get_full_size ((GIdlNode *)constant->type);
+ }
+ break;
+
+ case G_IDL_NODE_ERROR_DOMAIN:
+ {
+ GIdlNodeErrorDomain *domain = (GIdlNodeErrorDomain *)node;
+
+ size = 16;
+ size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ size += ALIGN_VALUE (strlen (domain->getquark) + 1, 4);
+ }
+ break;
+
+ case G_IDL_NODE_XREF:
+ {
+ GIdlNodeXRef *xref = (GIdlNodeXRef *)node;
+
+ size = 0;
+ size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ size += ALIGN_VALUE (strlen (xref->namespace) + 1, 4);
+ }
+ break;
+
+ case G_IDL_NODE_UNION:
+ {
+ GIdlNodeUnion *union_ = (GIdlNodeUnion *)node;
+
+ size = 28;
+ size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ for (l = union_->members; l; l = l->next)
+ size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+ for (l = union_->discriminators; l; l = l->next)
+ size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+ }
+ break;
+
+ default:
+ g_error ("Unknown type tag %d\n", node->type);
+ size = 0;
+ }
+
+ g_debug ("node %p type %d full size %d", node, node->type, size);
+
+ return size;
+}
+
+int
+g_idl_node_cmp (GIdlNode *node,
+ GIdlNode *other)
+{
+ if (node->type < other->type)
+ return -1;
+ else if (node->type > other->type)
+ return 1;
+ else
+ return strcmp (node->name, other->name);
+}
+
+void
+g_idl_node_add_member (GIdlNode *node,
+ GIdlNodeFunction *member)
+{
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (member != NULL);
+
+ switch (node->type)
+ {
+ case G_IDL_NODE_OBJECT:
+ case G_IDL_NODE_INTERFACE:
+ {
+ GIdlNodeInterface *iface = (GIdlNodeInterface *)node;
+ iface->members =
+ g_list_insert_sorted (iface->members, member,
+ (GCompareFunc) g_idl_node_cmp);
+ break;
+ }
+ case G_IDL_NODE_BOXED:
+ {
+ GIdlNodeBoxed *boxed = (GIdlNodeBoxed *)node;
+ boxed->members =
+ g_list_insert_sorted (boxed->members, member,
+ (GCompareFunc) g_idl_node_cmp);
+ break;
+ }
+ case G_IDL_NODE_STRUCT:
+ {
+ GIdlNodeStruct *struct_ = (GIdlNodeStruct *)node;
+ struct_->members =
+ g_list_insert_sorted (struct_->members, member,
+ (GCompareFunc) g_idl_node_cmp);
+ break;
+ }
+ case G_IDL_NODE_UNION:
+ {
+ GIdlNodeUnion *union_ = (GIdlNodeUnion *)node;
+ union_->members =
+ g_list_insert_sorted (union_->members, member,
+ (GCompareFunc) g_idl_node_cmp);
+ break;
+ }
+ default:
+ g_error ("Cannot add a member to unknown type tag type %d\n",
+ node->type);
+ break;
+ }
+}
+
+static gint64
+parse_int_value (const gchar *str)
+{
+ return strtoll (str, NULL, 0);
+}
+
+static guint64
+parse_uint_value (const gchar *str)
+{
+ return strtoull (str, NULL, 0);
+}
+
+static gdouble
+parse_float_value (const gchar *str)
+{
+ return strtod (str, NULL);
+}
+
+static gboolean
+parse_boolean_value (const gchar *str)
+{
+ if (strcmp (str, "TRUE") == 0)
+ return TRUE;
+
+ if (strcmp (str, "FALSE") == 0)
+ return FALSE;
+
+ return parse_int_value (str) ? TRUE : FALSE;
+}
+
+static GIdlNode *
+find_entry_node (GIdlModule *module,
+ GList *modules,
+ const gchar *name,
+ guint16 *idx)
+
+{
+ GList *l;
+ gint i;
+ gchar **names;
+ gint n_names;
+ GIdlNode *result = NULL;
+
+ names = g_strsplit (name, ".", 0);
+ n_names = g_strv_length (names);
+ if (n_names > 2)
+ g_error ("Too many name parts");
+
+ for (l = module->entries, i = 1; l; l = l->next, i++)
+ {
+ GIdlNode *node = (GIdlNode *)l->data;
+
+ if (n_names > 1)
+ {
+ if (node->type != G_IDL_NODE_XREF)
+ continue;
+
+ if (((GIdlNodeXRef *)node)->namespace == NULL ||
+ strcmp (((GIdlNodeXRef *)node)->namespace, names[0]) != 0)
+ continue;
+ }
+
+ if (strcmp (node->name, names[n_names - 1]) == 0)
+ {
+ if (idx)
+ *idx = i;
+
+ result = node;
+ goto out;
+ }
+ }
+
+ if (n_names > 1)
+ {
+ GIdlNode *node = g_idl_node_new (G_IDL_NODE_XREF);
+
+ ((GIdlNodeXRef *)node)->namespace = g_strdup (names[0]);
+ node->name = g_strdup (names[1]);
+
+ module->entries = g_list_append (module->entries, node);
+
+ if (idx)
+ *idx = g_list_length (module->entries);
+
+ result = node;
+
+ goto out;
+ }
+
+ g_warning ("Entry %s not found", name);
+
+ out:
+
+ g_strfreev (names);
+
+ return result;
+}
+
+static guint16
+find_entry (GIdlModule *module,
+ GList *modules,
+ const gchar *name)
+{
+ guint16 idx = 0;
+
+ find_entry_node (module, modules, name, &idx);
+
+ return idx;
+}
+
+static void
+serialize_type (GIdlModule *module,
+ GList *modules,
+ GIdlNodeType *node,
+ GString *str)
+{
+ gint i;
+ const gchar* basic[] = {
+ "void",
+ "gboolean",
+ "gint8",
+ "guint8",
+ "gint16",
+ "guint16",
+ "gint32",
+ "guint32",
+ "gint64",
+ "guint64",
+ "gint",
+ "guint",
+ "glong",
+ "gulong",
+ "gssize",
+ "gsize",
+ "gfloat",
+ "gdouble",
+ "utf8",
+ "filename"
+ };
+
+ if (node->tag < 20)
+ {
+ g_string_append_printf (str, "%s%s",
+ basic[node->tag], node->is_pointer ? "*" : "");
+ }
+ else if (node->tag == 20)
+ {
+ serialize_type (module, modules, node->parameter_type1, str);
+ g_string_append (str, "[");
+
+ if (node->has_length)
+ g_string_append_printf (str, "length=%d", node->length);
+
+ if (node->zero_terminated)
+ g_string_append_printf (str, "%szero-terminated=1",
+ node->has_length ? "," : "");
+
+ g_string_append (str, "]");
+ }
+ else if (node->tag == 21)
+ {
+ GIdlNode *iface;
+ gchar *name;
+
+ iface = find_entry_node (module, modules, node->interface, NULL);
+ if (iface)
+ name = iface->name;
+ else
+ {
+ g_warning ("Interface for type reference %s not found", node->interface);
+ name = node->interface;
+ }
+
+ g_string_append_printf (str, "%s%s", name, node->is_pointer ? "*" : "");
+ }
+ else if (node->tag == 22)
+ {
+ g_string_append (str, "GList");
+ if (node->parameter_type1)
+ {
+ g_string_append (str, "<");
+ serialize_type (module, modules, node->parameter_type1, str);
+ g_string_append (str, ">");
+ }
+ }
+ else if (node->tag == 23)
+ {
+ g_string_append (str, "GSList");
+ if (node->parameter_type1)
+ {
+ g_string_append (str, "<");
+ serialize_type (module, modules, node->parameter_type1, str);
+ g_string_append (str, ">");
+ }
+ }
+ else if (node->tag == 24)
+ {
+ g_string_append (str, "GHashTable<");
+ if (node->parameter_type1)
+ {
+ g_string_append (str, "<");
+ serialize_type (module, modules, node->parameter_type1, str);
+ g_string_append (str, ",");
+ serialize_type (module, modules, node->parameter_type2, str);
+ g_string_append (str, ">");
+ }
+ }
+ else if (node->tag == 25)
+ {
+ g_string_append (str, "GError");
+ if (node->errors)
+ {
+ g_string_append (str, "<");
+ for (i = 0; node->errors[i]; i++)
+ {
+ if (i > 0)
+ g_string_append (str, ",");
+ g_string_append (str, node->errors[i]);
+ }
+ g_string_append (str, ">");
+ }
+ }
+}
+
+void
+g_idl_node_build_metadata (GIdlNode *node,
+ GIdlModule *module,
+ GList *modules,
+ GHashTable *strings,
+ GHashTable *types,
+ guchar *data,
+ guint32 *offset,
+ guint32 *offset2)
+{
+ GList *l;
+ guint32 old_offset = *offset;
+ guint32 old_offset2 = *offset2;
+
+ switch (node->type)
+ {
+ case G_IDL_NODE_TYPE:
+ {
+ GIdlNodeType *type = (GIdlNodeType *)node;
+ SimpleTypeBlob *blob = (SimpleTypeBlob *)&data[*offset];
+
+ *offset += 4;
+
+ if (type->tag < TYPE_TAG_ARRAY)
+ {
+ blob->reserved = 0;
+ blob->reserved2 = 0;
+ blob->pointer = type->is_pointer;
+ blob->reserved3 = 0;
+ blob->tag = type->tag;
+ }
+ else
+ {
+ GString *str;
+ gchar *s;
+ gpointer value;
+
+ str = g_string_new (0);
+ serialize_type (module, modules, type, str);
+ s = g_string_free (str, FALSE);
+
+ types_count += 1;
+ value = g_hash_table_lookup (types, s);
+ if (value)
+ {
+ blob->offset = GPOINTER_TO_INT (value);
+ g_free (s);
+ }
+ else
+ {
+ unique_types_count += 1;
+ g_hash_table_insert (types, s, GINT_TO_POINTER(*offset2));
+
+ blob->offset = *offset2;
+ switch (type->tag)
+ {
+ case TYPE_TAG_ARRAY:
+ {
+ ArrayTypeBlob *array = (ArrayTypeBlob *)&data[*offset2];
+ guint32 pos;
+
+ array->pointer = 1;
+ array->reserved = 0;
+ array->tag = type->tag;
+ array->zero_terminated = type->zero_terminated;
+ array->has_length = type->has_length;
+ array->reserved2 = 0;
+ array->length = type->length;
+
+ pos = *offset2 + 4;
+ *offset2 += 8;
+
+ g_idl_node_build_metadata ((GIdlNode *)type->parameter_type1,
+ module, modules, strings, types,
+ data, &pos, offset2);
+ }
+ break;
+
+ case TYPE_TAG_INTERFACE:
+ {
+ InterfaceTypeBlob *iface = (InterfaceTypeBlob *)&data[*offset2];
+ *offset2 += 4;
+
+ iface->pointer = type->is_pointer;
+ iface->reserved = 0;
+ iface->tag = type->tag;
+ iface->reserved2 = 0;
+ iface->interface = find_entry (module, modules, type->interface);
+
+ }
+ break;
+
+ case TYPE_TAG_LIST:
+ case TYPE_TAG_SLIST:
+ {
+ ParamTypeBlob *param = (ParamTypeBlob *)&data[*offset2];
+ guint32 pos;
+
+ param->pointer = 1;
+ param->reserved = 0;
+ param->tag = type->tag;
+ param->reserved2 = 0;
+ param->n_types = 1;
+
+ pos = *offset2 + 4;
+ *offset2 += 8;
+
+ g_idl_node_build_metadata ((GIdlNode *)type->parameter_type1,
+ module, modules, strings, types,
+ data, &pos, offset2);
+ }
+ break;
+
+ case TYPE_TAG_HASH:
+ {
+ ParamTypeBlob *param = (ParamTypeBlob *)&data[*offset2];
+ guint32 pos;
+
+ param->pointer = 1;
+ param->reserved = 0;
+ param->tag = type->tag;
+ param->reserved2 = 0;
+ param->n_types = 2;
+
+ pos = *offset2 + 4;
+ *offset2 += 12;
+
+ g_idl_node_build_metadata ((GIdlNode *)type->parameter_type1,
+ module, modules, strings, types,
+ data, &pos, offset2);
+ g_idl_node_build_metadata ((GIdlNode *)type->parameter_type2,
+ module, modules, strings, types,
+ data, &pos, offset2);
+ }
+ break;
+
+ case TYPE_TAG_ERROR:
+ {
+ ErrorTypeBlob *blob = (ErrorTypeBlob *)&data[*offset2];
+ gint i;
+
+ blob->pointer = 1;
+ blob->reserved = 0;
+ blob->tag = type->tag;
+ blob->reserved2 = 0;
+ if (type->errors)
+ blob->n_domains = g_strv_length (type->errors);
+ else
+ blob->n_domains = 0;
+
+ *offset2 = ALIGN_VALUE (*offset2 + 4 + 2 * blob->n_domains, 4);
+ for (i = 0; i < blob->n_domains; i++)
+ blob->domains[i] = find_entry (module, modules, type->errors[i]);
+ }
+ break;
+
+ default:
+ g_error ("Unknown type tag %d\n", type->tag);
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case G_IDL_NODE_FIELD:
+ {
+ GIdlNodeField *field = (GIdlNodeField *)node;
+ FieldBlob *blob;
+
+ blob = (FieldBlob *)&data[*offset];
+ *offset += 8;
+
+ blob->name = write_string (node->name, strings, data, offset2);
+ blob->readable = field->readable;
+ blob->writable = field->writable;
+ blob->reserved = 0;
+ blob->bits = 0;
+ blob->struct_offset = field->offset;
+
+ g_idl_node_build_metadata ((GIdlNode *)field->type,
+ module, modules, strings, types,
+ data, offset, offset2);
+ }
+ break;
+
+ case G_IDL_NODE_PROPERTY:
+ {
+ GIdlNodeProperty *prop = (GIdlNodeProperty *)node;
+ PropertyBlob *blob = (PropertyBlob *)&data[*offset];
+ *offset += 8;
+
+ blob->name = write_string (node->name, strings, data, offset2);
+ blob->deprecated = prop->deprecated;
+ blob->readable = prop->readable;
+ blob->writable = prop->writable;
+ blob->construct = prop->construct;
+ blob->construct_only = prop->construct_only;
+ blob->reserved = 0;
+
+ g_idl_node_build_metadata ((GIdlNode *)prop->type,
+ module, modules, strings, types,
+ data, offset, offset2);
+ }
+ break;
+
+ case G_IDL_NODE_FUNCTION:
+ {
+ FunctionBlob *blob = (FunctionBlob *)&data[*offset];
+ SignatureBlob *blob2 = (SignatureBlob *)&data[*offset2];
+ GIdlNodeFunction *function = (GIdlNodeFunction *)node;
+ guint32 signature;
+ gint n;
+
+ signature = *offset2;
+ n = g_list_length (function->parameters);
+
+ *offset += 16;
+ *offset2 += 8 + n * 12;
+
+ blob->blob_type = BLOB_TYPE_FUNCTION;
+ blob->deprecated = function->deprecated;
+ blob->setter = function->is_setter;
+ blob->getter = function->is_getter;
+ blob->constructor = function->is_constructor;
+ blob->wraps_vfunc = function->wraps_vfunc;
+ blob->reserved = 0;
+ blob->index = 0;
+ blob->name = write_string (node->name, strings, data, offset2);
+ blob->symbol = write_string (function->symbol, strings, data, offset2);
+ blob->signature = signature;
+
+ g_idl_node_build_metadata ((GIdlNode *)function->result->type,
+ module, modules, strings, types,
+ data, &signature, offset2);
+
+ blob2->may_return_null = function->result->null_ok;
+ blob2->caller_owns_return_value = function->result->transfer;
+ blob2->caller_owns_return_container = function->result->shallow_transfer;
+ blob2->reserved = 0;
+ blob2->n_arguments = n;
+
+ signature += 4;
+
+ for (l = function->parameters; l; l = l->next)
+ {
+ GIdlNode *param = (GIdlNode *)l->data;
+
+ g_idl_node_build_metadata (param,
+ module, modules, strings, types,
+ data, &signature, offset2);
+ }
+ }
+ break;
+
+ case G_IDL_NODE_CALLBACK:
+ {
+ CallbackBlob *blob = (CallbackBlob *)&data[*offset];
+ SignatureBlob *blob2 = (SignatureBlob *)&data[*offset2];
+ GIdlNodeFunction *function = (GIdlNodeFunction *)node;
+ guint32 signature;
+ gint n;
+
+ signature = *offset2;
+ n = g_list_length (function->parameters);
+
+ *offset += 12;
+ *offset2 += 8 + n * 12;
+
+ blob->blob_type = BLOB_TYPE_CALLBACK;
+ blob->deprecated = function->deprecated;
+ blob->reserved = 0;
+ blob->name = write_string (node->name, strings, data, offset2);
+ blob->signature = signature;
+
+ g_idl_node_build_metadata ((GIdlNode *)function->result->type,
+ module, modules, strings, types,
+ data, &signature, offset2);
+
+ blob2->may_return_null = function->result->null_ok;
+ blob2->caller_owns_return_value = function->result->transfer;
+ blob2->caller_owns_return_container = function->result->shallow_transfer;
+ blob2->reserved = 0;
+ blob2->n_arguments = n;
+
+ signature += 4;
+
+ for (l = function->parameters; l; l = l->next)
+ {
+ GIdlNode *param = (GIdlNode *)l->data;
+
+ g_idl_node_build_metadata (param,
+ module, modules, strings, types,
+ data, &signature, offset2);
+ }
+ }
+ break;
+
+ case G_IDL_NODE_SIGNAL:
+ {
+ SignalBlob *blob = (SignalBlob *)&data[*offset];
+ SignatureBlob *blob2 = (SignatureBlob *)&data[*offset2];
+ GIdlNodeSignal *signal = (GIdlNodeSignal *)node;
+ guint32 signature;
+ gint n;
+
+ signature = *offset2;
+ n = g_list_length (signal->parameters);
+
+ *offset += 12;
+ *offset2 += 8 + n * 12;
+
+ blob->deprecated = signal->deprecated;
+ blob->run_first = signal->run_first;
+ blob->run_last = signal->run_last;
+ blob->run_cleanup = signal->run_cleanup;
+ blob->no_recurse = signal->no_recurse;
+ blob->detailed = signal->detailed;
+ blob->action = signal->action;
+ blob->no_hooks = signal->no_hooks;
+ blob->has_class_closure = 0; /* FIXME */
+ blob->true_stops_emit = 0; /* FIXME */
+ blob->reserved = 0;
+ blob->class_closure = 0; /* FIXME */
+ blob->name = write_string (node->name, strings, data, offset2);
+ blob->signature = signature;
+
+ g_idl_node_build_metadata ((GIdlNode *)signal->result->type,
+ module, modules, strings, types,
+ data, &signature, offset2);
+
+ blob2->may_return_null = signal->result->null_ok;
+ blob2->caller_owns_return_value = signal->result->transfer;
+ blob2->caller_owns_return_container = signal->result->shallow_transfer;
+ blob2->reserved = 0;
+ blob2->n_arguments = n;
+
+ signature += 4;
+
+ for (l = signal->parameters; l; l = l->next)
+ {
+ GIdlNode *param = (GIdlNode *)l->data;
+
+ g_idl_node_build_metadata (param, module, modules, strings, types,
+ data, &signature, offset2);
+ }
+ }
+ break;
+
+ case G_IDL_NODE_VFUNC:
+ {
+ VFuncBlob *blob = (VFuncBlob *)&data[*offset];
+ SignatureBlob *blob2 = (SignatureBlob *)&data[*offset2];
+ GIdlNodeVFunc *vfunc = (GIdlNodeVFunc *)node;
+ guint32 signature;
+ gint n;
+
+ signature = *offset2;
+ n = g_list_length (vfunc->parameters);
+
+ *offset += 16;
+ *offset2 += 8 + n * 12;
+
+ blob->name = write_string (node->name, strings, data, offset2);
+ blob->must_chain_up = 0; /* FIXME */
+ blob->must_be_implemented = 0; /* FIXME */
+ blob->must_not_be_implemented = 0; /* FIXME */
+ blob->class_closure = 0; /* FIXME */
+ blob->reserved = 0;
+
+ blob->struct_offset = vfunc->offset;
+ blob->reserved2 = 0;
+ blob->signature = signature;
+
+ g_idl_node_build_metadata ((GIdlNode *)vfunc->result->type,
+ module, modules, strings, types,
+ data, &signature, offset2);
+
+ blob2->may_return_null = vfunc->result->null_ok;
+ blob2->caller_owns_return_value = vfunc->result->transfer;
+ blob2->caller_owns_return_container = vfunc->result->shallow_transfer;
+ blob2->reserved = 0;
+ blob2->n_arguments = n;
+
+ signature += 4;
+
+ for (l = vfunc->parameters; l; l = l->next)
+ {
+ GIdlNode *param = (GIdlNode *)l->data;
+
+ g_idl_node_build_metadata (param, module, modules, strings,
+ types, data, &signature, offset2);
+ }
+ }
+ break;
+
+ case G_IDL_NODE_PARAM:
+ {
+ ArgBlob *blob = (ArgBlob *)&data[*offset];
+ GIdlNodeParam *param = (GIdlNodeParam *)node;
+
+ *offset += 8;
+
+ blob->name = write_string (node->name, strings, data, offset2);
+ blob->in = param->in;
+ blob->out = param->out;
+ blob->dipper = param->dipper;
+ blob->null_ok = param->null_ok;
+ blob->optional = param->optional;
+ blob->transfer_ownership = param->transfer;
+ blob->transfer_container_ownership = param->shallow_transfer;
+ blob->return_value = param->retval;
+ blob->reserved = 0;
+
+ g_idl_node_build_metadata ((GIdlNode *)param->type, module, modules,
+ strings, types, data, offset, offset2);
+ }
+ break;
+
+ case G_IDL_NODE_STRUCT:
+ {
+ StructBlob *blob = (StructBlob *)&data[*offset];
+ GIdlNodeStruct *struct_ = (GIdlNodeStruct *)node;
+
+ blob->blob_type = BLOB_TYPE_STRUCT;
+ blob->deprecated = struct_->deprecated;
+ blob->unregistered = TRUE;
+ blob->reserved = 0;
+ blob->name = write_string (node->name, strings, data, offset2);
+ blob->gtype_name = 0;
+ blob->gtype_init = 0;
+
+ blob->n_fields = 0;
+ blob->n_methods = 0;
+
+ *offset += 20;
+ for (l = struct_->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_FIELD)
+ {
+ blob->n_fields++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+
+ for (l = struct_->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_FUNCTION)
+ {
+ blob->n_methods++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+ }
+ break;
+
+ case G_IDL_NODE_BOXED:
+ {
+ StructBlob *blob = (StructBlob *)&data[*offset];
+ GIdlNodeBoxed *boxed = (GIdlNodeBoxed *)node;
+
+ blob->blob_type = BLOB_TYPE_BOXED;
+ blob->deprecated = boxed->deprecated;
+ blob->unregistered = FALSE;
+ blob->reserved = 0;
+ blob->name = write_string (node->name, strings, data, offset2);
+ blob->gtype_name = write_string (boxed->gtype_name, strings, data, offset2);
+ blob->gtype_init = write_string (boxed->gtype_init, strings, data, offset2);
+
+ blob->n_fields = 0;
+ blob->n_methods = 0;
+
+ *offset += 20;
+ for (l = boxed->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_FIELD)
+ {
+ blob->n_fields++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+
+ for (l = boxed->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_FUNCTION)
+ {
+ blob->n_methods++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+ }
+ break;
+
+ case G_IDL_NODE_UNION:
+ {
+ UnionBlob *blob = (UnionBlob *)&data[*offset];
+ GIdlNodeUnion *union_ = (GIdlNodeUnion *)node;
+
+ blob->blob_type = BLOB_TYPE_UNION;
+ blob->deprecated = union_->deprecated;
+ blob->reserved = 0;
+ blob->name = write_string (node->name, strings, data, offset2);
+ if (union_->gtype_name)
+ {
+ blob->unregistered = FALSE;
+ blob->gtype_name = write_string (union_->gtype_name, strings, data, offset2);
+ blob->gtype_init = write_string (union_->gtype_init, strings, data, offset2);
+ }
+ else
+ {
+ blob->unregistered = TRUE;
+ blob->gtype_name = 0;
+ blob->gtype_init = 0;
+ }
+
+ blob->n_fields = 0;
+ blob->n_functions = 0;
+
+ blob->discriminator_offset = union_->discriminator_offset;
+
+ if (union_->discriminator_type)
+ {
+ *offset += 24;
+ blob->discriminated = TRUE;
+ g_idl_node_build_metadata ((GIdlNode *)union_->discriminator_type,
+ module, modules, strings, types,
+ data, offset, offset2);
+ }
+ else
+ {
+ *offset += 28;
+ blob->discriminated = FALSE;
+ blob->discriminator_type.offset = 0;
+ }
+
+
+ for (l = union_->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_FIELD)
+ {
+ blob->n_fields++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+
+ for (l = union_->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_FUNCTION)
+ {
+ blob->n_functions++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+
+ if (union_->discriminator_type)
+ {
+ for (l = union_->discriminators; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+ }
+ break;
+
+ case G_IDL_NODE_ENUM:
+ case G_IDL_NODE_FLAGS:
+ {
+ EnumBlob *blob = (EnumBlob *)&data[*offset];
+ GIdlNodeEnum *enum_ = (GIdlNodeEnum *)node;
+
+ *offset += 20;
+
+ if (node->type == G_IDL_NODE_ENUM)
+ blob->blob_type = BLOB_TYPE_ENUM;
+ else
+ blob->blob_type = BLOB_TYPE_FLAGS;
+
+ blob->deprecated = enum_->deprecated;
+ blob->reserved = 0;
+ blob->name = write_string (node->name, strings, data, offset2);
+ if (enum_->gtype_name)
+ {
+ blob->unregistered = FALSE;
+ blob->gtype_name = write_string (enum_->gtype_name, strings, data, offset2);
+ blob->gtype_init = write_string (enum_->gtype_init, strings, data, offset2);
+ }
+ else
+ {
+ blob->unregistered = TRUE;
+ blob->gtype_name = 0;
+ blob->gtype_init = 0;
+ }
+
+ blob->n_values = 0;
+ blob->reserved2 = 0;
+
+ for (l = enum_->values; l; l = l->next)
+ {
+ GIdlNode *value = (GIdlNode *)l->data;
+
+ blob->n_values++;
+ g_idl_node_build_metadata (value, module, modules, strings, types,
+ data, offset, offset2);
+ }
+ }
+ break;
+
+ case G_IDL_NODE_OBJECT:
+ {
+ ObjectBlob *blob = (ObjectBlob *)&data[*offset];
+ GIdlNodeInterface *object = (GIdlNodeInterface *)node;
+
+ blob->blob_type = BLOB_TYPE_OBJECT;
+ blob->deprecated = object->deprecated;
+ blob->reserved = 0;
+ blob->name = write_string (node->name, strings, data, offset2);
+ blob->gtype_name = write_string (object->gtype_name, strings, data, offset2);
+ blob->gtype_init = write_string (object->gtype_init, strings, data, offset2);
+ if (object->parent)
+ blob->parent = find_entry (module, modules, object->parent);
+ else
+ blob->parent = 0;
+
+ blob->n_interfaces = 0;
+ blob->n_fields = 0;
+ blob->n_properties = 0;
+ blob->n_methods = 0;
+ blob->n_signals = 0;
+ blob->n_vfuncs = 0;
+ blob->n_constants = 0;
+
+ *offset += 32;
+ for (l = object->interfaces; l; l = l->next)
+ {
+ blob->n_interfaces++;
+ *(guint16*)&data[*offset] = find_entry (module, modules, (gchar *)l->data);
+ *offset += 2;
+ }
+
+ *offset = ALIGN_VALUE (*offset, 4);
+ for (l = object->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_FIELD)
+ {
+ blob->n_fields++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+
+ *offset = ALIGN_VALUE (*offset, 4);
+ for (l = object->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_PROPERTY)
+ {
+ blob->n_properties++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+
+ *offset = ALIGN_VALUE (*offset, 4);
+ for (l = object->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_FUNCTION)
+ {
+ blob->n_methods++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+
+ *offset = ALIGN_VALUE (*offset, 4);
+ for (l = object->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_SIGNAL)
+ {
+ blob->n_signals++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+
+ *offset = ALIGN_VALUE (*offset, 4);
+ for (l = object->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_VFUNC)
+ {
+ blob->n_vfuncs++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+
+ *offset = ALIGN_VALUE (*offset, 4);
+ for (l = object->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_CONSTANT)
+ {
+ blob->n_constants++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+ }
+ break;
+
+ case G_IDL_NODE_INTERFACE:
+ {
+ InterfaceBlob *blob = (InterfaceBlob *)&data[*offset];
+ GIdlNodeInterface *iface = (GIdlNodeInterface *)node;
+
+ blob->blob_type = BLOB_TYPE_INTERFACE;
+ blob->deprecated = iface->deprecated;
+ blob->reserved = 0;
+ blob->name = write_string (node->name, strings, data, offset2);
+ blob->gtype_name = write_string (iface->gtype_name, strings, data, offset2);
+ blob->gtype_init = write_string (iface->gtype_init, strings, data, offset2);
+ blob->n_prerequisites = 0;
+ blob->n_properties = 0;
+ blob->n_methods = 0;
+ blob->n_signals = 0;
+ blob->n_vfuncs = 0;
+ blob->n_constants = 0;
+
+ *offset += 28;
+ for (l = iface->prerequisites; l; l = l->next)
+ {
+ blob->n_prerequisites++;
+ *(guint16*)&data[*offset] = find_entry (module, modules, (gchar *)l->data);
+ *offset += 2;
+ }
+
+ *offset = ALIGN_VALUE (*offset, 4);
+ for (l = iface->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_PROPERTY)
+ {
+ blob->n_properties++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+
+ *offset = ALIGN_VALUE (*offset, 4);
+ for (l = iface->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_FUNCTION)
+ {
+ blob->n_methods++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+
+ *offset = ALIGN_VALUE (*offset, 4);
+ for (l = iface->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_SIGNAL)
+ {
+ blob->n_signals++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+
+ *offset = ALIGN_VALUE (*offset, 4);
+ for (l = iface->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_VFUNC)
+ {
+ blob->n_vfuncs++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+
+ *offset = ALIGN_VALUE (*offset, 4);
+ for (l = iface->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_CONSTANT)
+ {
+ blob->n_constants++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+ }
+ break;
+
+
+ case G_IDL_NODE_VALUE:
+ {
+ GIdlNodeValue *value = (GIdlNodeValue *)node;
+ ValueBlob *blob = (ValueBlob *)&data[*offset];
+ *offset += 12;
+
+ blob->deprecated = value->deprecated;
+ blob->reserved = 0;
+ blob->name = write_string (node->name, strings, data, offset2);
+ blob->value = value->value;
+ }
+ break;
+
+ case G_IDL_NODE_ERROR_DOMAIN:
+ {
+ GIdlNodeErrorDomain *domain = (GIdlNodeErrorDomain *)node;
+ ErrorDomainBlob *blob = (ErrorDomainBlob *)&data[*offset];
+ *offset += 16;
+
+ blob->blob_type = BLOB_TYPE_ERROR_DOMAIN;
+ blob->deprecated = domain->deprecated;
+ blob->reserved = 0;
+ blob->name = write_string (node->name, strings, data, offset2);
+ blob->get_quark = write_string (domain->getquark, strings, data, offset2);
+ blob->error_codes = find_entry (module, modules, domain->codes);
+ blob->reserved2 = 0;
+ }
+ break;
+
+ case G_IDL_NODE_CONSTANT:
+ {
+ GIdlNodeConstant *constant = (GIdlNodeConstant *)node;
+ ConstantBlob *blob = (ConstantBlob *)&data[*offset];
+ guint32 pos;
+
+ pos = *offset + 8;
+ *offset += 20;
+
+ blob->blob_type = BLOB_TYPE_CONSTANT;
+ blob->deprecated = constant->deprecated;
+ blob->reserved = 0;
+ blob->name = write_string (node->name, strings, data, offset2);
+
+ blob->offset = *offset2;
+ switch (constant->type->tag)
+ {
+ case TYPE_TAG_BOOLEAN:
+ blob->size = 4;
+ *(gboolean*)&data[blob->offset] = parse_boolean_value (constant->value);
+ break;
+ case TYPE_TAG_INT8:
+ blob->size = 1;
+ *(gint8*)&data[blob->offset] = (gint8) parse_int_value (constant->value);
+ break;
+ case TYPE_TAG_UINT8:
+ blob->size = 1;
+ *(guint8*)&data[blob->offset] = (guint8) parse_uint_value (constant->value);
+ break;
+ case TYPE_TAG_INT16:
+ blob->size = 2;
+ *(gint16*)&data[blob->offset] = (gint16) parse_int_value (constant->value);
+ break;
+ case TYPE_TAG_UINT16:
+ blob->size = 2;
+ *(guint16*)&data[blob->offset] = (guint16) parse_uint_value (constant->value);
+ break;
+ case TYPE_TAG_INT32:
+ blob->size = 4;
+ *(gint32*)&data[blob->offset] = (gint32) parse_int_value (constant->value);
+ break;
+ case TYPE_TAG_UINT32:
+ blob->size = 4;
+ *(guint32*)&data[blob->offset] = (guint32) parse_uint_value (constant->value);
+ break;
+ case TYPE_TAG_INT64:
+ blob->size = 8;
+ *(gint64*)&data[blob->offset] = (gint64) parse_int_value (constant->value);
+ break;
+ case TYPE_TAG_UINT64:
+ blob->size = 8;
+ *(guint64*)&data[blob->offset] = (guint64) parse_uint_value (constant->value);
+ break;
+ case TYPE_TAG_INT:
+ blob->size = sizeof (gint);
+ *(gint*)&data[blob->offset] = (gint) parse_int_value (constant->value);
+ break;
+ case TYPE_TAG_UINT:
+ blob->size = sizeof (guint);
+ *(gint*)&data[blob->offset] = (guint) parse_uint_value (constant->value);
+ break;
+ case TYPE_TAG_SSIZE: /* FIXME */
+ case TYPE_TAG_LONG:
+ blob->size = sizeof (glong);
+ *(glong*)&data[blob->offset] = (glong) parse_int_value (constant->value);
+ break;
+ case TYPE_TAG_SIZE: /* FIXME */
+ case TYPE_TAG_ULONG:
+ blob->size = sizeof (gulong);
+ *(gulong*)&data[blob->offset] = (gulong) parse_uint_value (constant->value);
+ break;
+ case TYPE_TAG_FLOAT:
+ blob->size = sizeof (gfloat);
+ *(gfloat*)&data[blob->offset] = (gfloat) parse_float_value (constant->value);
+ break;
+ case TYPE_TAG_DOUBLE:
+ blob->size = sizeof (gdouble);
+ *(gdouble*)&data[blob->offset] = (gdouble) parse_float_value (constant->value);
+ break;
+ case TYPE_TAG_UTF8:
+ case TYPE_TAG_FILENAME:
+ blob->size = strlen (constant->value) + 1;
+ memcpy (&data[blob->offset], constant->value, blob->size);
+ break;
+ }
+ *offset2 += ALIGN_VALUE (blob->size, 4);
+
+ g_idl_node_build_metadata ((GIdlNode *)constant->type, module, modules,
+ strings, types, data, &pos, offset2);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ g_debug ("node %p type %d, offset %d -> %d, offset2 %d -> %d",
+ node, node->type, old_offset, *offset, old_offset2, *offset2);
+
+ if (*offset2 - old_offset2 + *offset - old_offset > g_idl_node_get_full_size (node))
+ g_error ("exceeding space reservation !!");
+}
+
+/* if str is already in the pool, return previous location, otherwise write str
+ * to the metadata at offset, put it in the pool and update offset. If the
+ * metadata is not large enough to hold the string, reallocate it.
+ */
+guint32
+write_string (const gchar *str,
+ GHashTable *strings,
+ guchar *data,
+ guint32 *offset)
+{
+ gpointer value;
+ guint32 start;
+
+ string_count += 1;
+ string_size += strlen (str);
+
+ value = g_hash_table_lookup (strings, str);
+
+ if (value)
+ return GPOINTER_TO_INT (value);
+
+ unique_string_count += 1;
+ unique_string_size += strlen (str);
+
+ g_hash_table_insert (strings, (gpointer)str, GINT_TO_POINTER (*offset));
+
+ start = *offset;
+ *offset = ALIGN_VALUE (start + strlen (str) + 1, 4);
+
+ strcpy ((gchar*)&data[start], str);
+
+ return start;
+}
+
diff --git a/tools/gidlnode.h b/tools/gidlnode.h
new file mode 100644
index 00000000..4ba97b1b
--- /dev/null
+++ b/tools/gidlnode.h
@@ -0,0 +1,334 @@
+/* GObject introspection: Parsed IDL
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * 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 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.
+ */
+
+#ifndef __G_IDL_NODE_H__
+#define __G_IDL_NODE_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GIdlNode GIdlNode;
+typedef struct _GIdlNodeFunction GIdlNodeFunction;
+typedef struct _GIdlNodeParam GIdlNodeParam;
+typedef struct _GIdlNodeType GIdlNodeType;
+typedef struct _GIdlNodeInterface GIdlNodeInterface;
+typedef struct _GIdlNodeSignal GIdlNodeSignal;
+typedef struct _GIdlNodeProperty GIdlNodeProperty;
+typedef struct _GIdlNodeVFunc GIdlNodeVFunc;
+typedef struct _GIdlNodeField GIdlNodeField;
+typedef struct _GIdlNodeValue GIdlNodeValue;
+typedef struct _GIdlNodeEnum GIdlNodeEnum;
+typedef struct _GIdlNodeBoxed GIdlNodeBoxed;
+typedef struct _GIdlNodeStruct GIdlNodeStruct;
+typedef struct _GIdlNodeConstant GIdlNodeConstant;
+typedef struct _GIdlNodeErrorDomain GIdlNodeErrorDomain;
+typedef struct _GIdlNodeXRef GIdlNodeXRef;
+typedef struct _GIdlNodeUnion GIdlNodeUnion;
+
+typedef enum
+{
+ G_IDL_NODE_INVALID,
+ G_IDL_NODE_FUNCTION,
+ G_IDL_NODE_CALLBACK,
+ G_IDL_NODE_STRUCT,
+ G_IDL_NODE_BOXED,
+ G_IDL_NODE_ENUM,
+ G_IDL_NODE_FLAGS,
+ G_IDL_NODE_OBJECT,
+ G_IDL_NODE_INTERFACE,
+ G_IDL_NODE_CONSTANT,
+ G_IDL_NODE_ERROR_DOMAIN,
+ G_IDL_NODE_UNION,
+ G_IDL_NODE_PARAM,
+ G_IDL_NODE_TYPE,
+ G_IDL_NODE_PROPERTY,
+ G_IDL_NODE_SIGNAL,
+ G_IDL_NODE_VALUE,
+ G_IDL_NODE_VFUNC,
+ G_IDL_NODE_FIELD,
+ G_IDL_NODE_XREF
+} GIdlNodeTypeId;
+
+struct _GIdlNode
+{
+ GIdlNodeTypeId type;
+ gchar *name;
+};
+
+struct _GIdlNodeXRef
+{
+ GIdlNode node;
+
+ gchar *namespace;
+};
+
+struct _GIdlNodeFunction
+{
+ GIdlNode node;
+
+ gboolean deprecated;
+
+ gboolean is_method;
+ gboolean is_setter;
+ gboolean is_getter;
+ gboolean is_constructor;
+ gboolean wraps_vfunc;
+
+ gchar *symbol;
+
+ GIdlNodeParam *result;
+ GList *parameters;
+};
+
+struct _GIdlNodeType
+{
+ GIdlNode node;
+
+ gboolean is_pointer;
+ gboolean is_basic;
+ gboolean is_array;
+ gboolean is_glist;
+ gboolean is_gslist;
+ gboolean is_ghashtable;
+ gboolean is_interface;
+ gboolean is_error;
+ gint tag;
+
+ gchar *unparsed;
+
+ gboolean zero_terminated;
+ gboolean has_length;
+ gint length;
+
+ GIdlNodeType *parameter_type1;
+ GIdlNodeType *parameter_type2;
+
+ gchar *interface;
+ gchar **errors;
+};
+
+struct _GIdlNodeParam
+{
+ GIdlNode node;
+
+ gboolean in;
+ gboolean out;
+ gboolean dipper;
+ gboolean optional;
+ gboolean retval;
+ gboolean null_ok;
+ gboolean transfer;
+ gboolean shallow_transfer;
+
+ GIdlNodeType *type;
+};
+
+struct _GIdlNodeProperty
+{
+ GIdlNode node;
+
+ gboolean deprecated;
+
+ gchar *name;
+ gboolean readable;
+ gboolean writable;
+ gboolean construct;
+ gboolean construct_only;
+
+ GIdlNodeType *type;
+};
+
+struct _GIdlNodeSignal
+{
+ GIdlNode node;
+
+ gboolean deprecated;
+
+ gboolean run_first;
+ gboolean run_last;
+ gboolean run_cleanup;
+ gboolean no_recurse;
+ gboolean detailed;
+ gboolean action;
+ gboolean no_hooks;
+
+ gboolean has_class_closure;
+ gboolean true_stops_emit;
+
+ gint class_closure;
+
+ GList *parameters;
+ GIdlNodeParam *result;
+};
+
+struct _GIdlNodeVFunc
+{
+ GIdlNode node;
+
+ gboolean must_chain_up;
+ gboolean must_be_implemented;
+ gboolean must_not_be_implemented;
+ gboolean is_class_closure;
+
+ GList *parameters;
+ GIdlNodeParam *result;
+
+ gint offset;
+};
+
+struct _GIdlNodeField
+{
+ GIdlNode node;
+
+ gboolean readable;
+ gboolean writable;
+ gint bits;
+ gint offset;
+
+ GIdlNodeType *type;
+};
+
+struct _GIdlNodeInterface
+{
+ GIdlNode node;
+
+ gboolean deprecated;
+
+ gchar *gtype_name;
+ gchar *gtype_init;
+
+ gchar *parent;
+
+ GList *interfaces;
+ GList *prerequisites;
+
+ GList *members;
+};
+
+struct _GIdlNodeValue
+{
+ GIdlNode node;
+
+ gboolean deprecated;
+
+ guint32 value;
+};
+
+struct _GIdlNodeConstant
+{
+ GIdlNode node;
+
+ gboolean deprecated;
+
+ GIdlNodeType *type;
+
+ gchar *value;
+};
+
+struct _GIdlNodeEnum
+{
+ GIdlNode node;
+
+ gboolean deprecated;
+
+ gchar *gtype_name;
+ gchar *gtype_init;
+
+ GList *values;
+};
+
+struct _GIdlNodeBoxed
+{
+ GIdlNode node;
+
+ gboolean deprecated;
+
+ gchar *gtype_name;
+ gchar *gtype_init;
+
+ GList *members;
+};
+
+struct _GIdlNodeStruct
+{
+ GIdlNode node;
+
+ gboolean deprecated;
+
+ GList *members;
+};
+
+struct _GIdlNodeUnion
+{
+ GIdlNode node;
+
+ gboolean deprecated;
+
+ GList *members;
+ GList *discriminators;
+
+ gchar *gtype_name;
+ gchar *gtype_init;
+
+ gint discriminator_offset;
+ GIdlNodeType *discriminator_type;
+};
+
+
+struct _GIdlNodeErrorDomain
+{
+ GIdlNode node;
+
+ gboolean deprecated;
+
+ gchar *name;
+ gchar *getquark;
+ gchar *codes;
+};
+
+
+GIdlNode *g_idl_node_new (GIdlNodeTypeId type);
+void g_idl_node_free (GIdlNode *node);
+guint32 g_idl_node_get_size (GIdlNode *node);
+guint32 g_idl_node_get_full_size (GIdlNode *node);
+void g_idl_node_build_metadata (GIdlNode *node,
+ GIdlModule *module,
+ GList *modules,
+ GHashTable *strings,
+ GHashTable *types,
+ guchar *data,
+ guint32 *offset,
+ guint32 *offset2);
+int g_idl_node_cmp (GIdlNode *node,
+ GIdlNode *other);
+void g_idl_node_add_member (GIdlNode *node,
+ GIdlNodeFunction *member);
+guint32 write_string (const gchar *str,
+ GHashTable *strings,
+ guchar *data,
+ guint32 *offset);
+
+void init_stats (void);
+void dump_stats (void);
+
+G_END_DECLS
+
+#endif /* __G_IDL_NODE_H__ */
diff --git a/tools/gidlparser.c b/tools/gidlparser.c
new file mode 100644
index 00000000..3d529261
--- /dev/null
+++ b/tools/gidlparser.c
@@ -0,0 +1,2054 @@
+/* GObject introspection: A parser for the XML IDL format
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * 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 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib.h>
+#include "gidlmodule.h"
+#include "gidlnode.h"
+#include "gmetadata.h"
+
+typedef enum
+{
+ STATE_START,
+ STATE_END,
+ STATE_ROOT,
+ STATE_NAMESPACE,
+ STATE_FUNCTION,
+ STATE_PARAMETERS,
+ STATE_OBJECT,
+ STATE_INTERFACE,
+ STATE_IMPLEMENTS,
+ STATE_REQUIRES,
+ STATE_ENUM,
+ STATE_BOXED,
+ STATE_STRUCT,
+ STATE_SIGNAL,
+ STATE_ERRORDOMAIN,
+ STATE_UNION
+} ParseState;
+
+typedef struct _ParseContext ParseContext;
+struct _ParseContext
+{
+ ParseState state;
+ ParseState prev_state;
+
+ GList *modules;
+
+ GIdlModule *current_module;
+ GIdlNode *current_node;
+};
+
+#define MISSING_ATTRIBUTE(error,element,attribute) \
+ g_set_error (error, \
+ G_MARKUP_ERROR, \
+ G_MARKUP_ERROR_INVALID_CONTENT, \
+ "The attribute '%s' on the element '%s' must be specified", \
+ attribute, element)
+
+static const gchar *
+find_attribute (const gchar *name,
+ const gchar **attribute_names,
+ const gchar **attribute_values)
+{
+ gint i;
+
+ for (i = 0; attribute_names[i] != NULL; i++)
+ if (strcmp (attribute_names[i], name) == 0)
+ return attribute_values[i];
+
+ return 0;
+}
+
+static GIdlNodeType *
+parse_type_internal (gchar *str, gchar **rest)
+{
+ gint i;
+
+ static struct {
+ const gchar *str;
+ gint tag;
+ gboolean pointer;
+ } basic[] = {
+ { "void", TYPE_TAG_VOID, 0 },
+ { "gpointer", TYPE_TAG_VOID, 1 },
+ { "gboolean", TYPE_TAG_BOOLEAN, 0 },
+#if 0
+ { "char", TYPE_TAG_INT8, 0 },
+ { "gchar", TYPE_TAG_INT8, 0 },
+ { "guchar", TYPE_TAG_UINT8, 0 },
+#endif
+ { "int8_t", TYPE_TAG_INT8, 0 },
+ { "int8", TYPE_TAG_INT8, 0 },
+ { "gint8", TYPE_TAG_INT8, 0 },
+ { "uint8_t", TYPE_TAG_UINT8, 0 },
+ { "uint8", TYPE_TAG_UINT8, 0 },
+ { "guint8", TYPE_TAG_UINT8, 0 },
+ { "int16_t", TYPE_TAG_INT16, 0 },
+ { "int16", TYPE_TAG_INT16, 0 },
+ { "gint16", TYPE_TAG_INT16, 0 },
+ { "uint16_t", TYPE_TAG_UINT16, 0 },
+ { "uint16", TYPE_TAG_UINT16, 0 },
+ { "guint16", TYPE_TAG_UINT16, 0 },
+ { "int32_t", TYPE_TAG_INT32, 0 },
+ { "int32", TYPE_TAG_INT32, 0 },
+ { "gint32", TYPE_TAG_INT32, 0 },
+ { "uint32_t", TYPE_TAG_UINT32, 0 },
+ { "uint32", TYPE_TAG_UINT32, 0 },
+ { "guint32", TYPE_TAG_UINT32, 0 },
+ { "int64_t", TYPE_TAG_INT64, 0 },
+ { "int64", TYPE_TAG_INT64, 0 },
+ { "gint64", TYPE_TAG_INT64, 0 },
+ { "uint64_t", TYPE_TAG_UINT64, 0 },
+ { "uint64", TYPE_TAG_UINT64, 0 },
+ { "guint64", TYPE_TAG_UINT64, 0 },
+ { "int", TYPE_TAG_INT, 0 },
+ { "gint", TYPE_TAG_INT, 0 },
+ { "uint", TYPE_TAG_UINT, 0 },
+ { "guint", TYPE_TAG_UINT, 0 },
+ { "long", TYPE_TAG_LONG, 0 },
+ { "glong", TYPE_TAG_LONG, 0 },
+ { "ulong", TYPE_TAG_ULONG, 0 },
+ { "gulong", TYPE_TAG_ULONG, 0 },
+ { "ssize_t", TYPE_TAG_SSIZE, 0 },
+ { "gssize", TYPE_TAG_SSIZE, 0 },
+ { "size_t", TYPE_TAG_SIZE, 0 },
+ { "gsize", TYPE_TAG_SIZE, 0 },
+ { "float", TYPE_TAG_FLOAT, 0 },
+ { "gfloat", TYPE_TAG_FLOAT, 0 },
+ { "double", TYPE_TAG_DOUBLE, 0 },
+ { "gdouble", TYPE_TAG_DOUBLE, 0 },
+ { "utf8", TYPE_TAG_UTF8, 1 },
+ { "gchar*", TYPE_TAG_UTF8, 1 },
+ { "filename", TYPE_TAG_FILENAME,1 }
+ };
+
+ gint n_basic = G_N_ELEMENTS (basic);
+ gchar *start, *end;
+
+ GIdlNodeType *type;
+
+ type = (GIdlNodeType *)g_idl_node_new (G_IDL_NODE_TYPE);
+
+ str = g_strstrip (str);
+
+ type->unparsed = g_strdup (str);
+
+ *rest = str;
+ for (i = 0; i < n_basic; i++)
+ {
+ if (g_str_has_prefix (*rest, basic[i].str))
+ {
+ type->is_basic = TRUE;
+ type->tag = basic[i].tag;
+ type->is_pointer = basic[i].pointer;
+
+ *rest += strlen(basic[i].str);
+ *rest = g_strchug (*rest);
+ if (**rest == '*' && !type->is_pointer)
+ {
+ type->is_pointer = TRUE;
+ (*rest)++;
+ }
+
+ break;
+ }
+ }
+
+ if (i < n_basic)
+ /* found a basic type */;
+ else if (g_str_has_prefix (*rest, "GList") ||
+ g_str_has_prefix (*rest, "GSList"))
+ {
+ if (g_str_has_prefix (*rest, "GList"))
+ {
+ type->tag = TYPE_TAG_LIST;
+ type->is_glist = TRUE;
+ type->is_pointer = TRUE;
+ *rest += strlen ("GList");
+ }
+ else
+ {
+ type->tag = TYPE_TAG_SLIST;
+ type->is_gslist = TRUE;
+ type->is_pointer = TRUE;
+ *rest += strlen ("GSList");
+ }
+
+ *rest = g_strchug (*rest);
+
+ if (**rest == '<')
+ {
+ (*rest)++;
+
+ type->parameter_type1 = parse_type_internal (*rest, rest);
+ if (type->parameter_type1 == NULL)
+ goto error;
+
+ *rest = g_strchug (*rest);
+
+ if ((*rest)[0] != '>')
+ goto error;
+ (*rest)++;
+ }
+ }
+ else if (g_str_has_prefix (*rest, "GHashTable"))
+ {
+ type->tag = TYPE_TAG_HASH;
+ type->is_ghashtable = TRUE;
+ type->is_pointer = TRUE;
+ *rest += strlen ("GHashTable");
+
+ *rest = g_strchug (*rest);
+
+ if (**rest == '<')
+ {
+ (*rest)++;
+
+ type->parameter_type1 = parse_type_internal (*rest, rest);
+ if (type->parameter_type1 == NULL)
+ goto error;
+
+ *rest = g_strchug (*rest);
+
+ if ((*rest)[0] != ',')
+ goto error;
+ (*rest)++;
+
+ type->parameter_type2 = parse_type_internal (*rest, rest);
+ if (type->parameter_type2 == NULL)
+ goto error;
+
+ if ((*rest)[0] != '>')
+ goto error;
+ (*rest)++;
+ }
+ }
+ else if (g_str_has_prefix (*rest, "GError"))
+ {
+ type->tag = TYPE_TAG_ERROR;
+ type->is_error = TRUE;
+ type->is_pointer = TRUE;
+ *rest += strlen ("GError");
+
+ *rest = g_strchug (*rest);
+
+ if (**rest == '<')
+ {
+ (*rest)++;
+
+ end = strchr (*rest, '>');
+ str = g_strndup (*rest, end - *rest);
+ type->errors = g_strsplit (str, ",", 0);
+ g_free (str);
+
+ *rest = end + 1;
+ }
+ }
+ else
+ {
+ type->tag = TYPE_TAG_INTERFACE;
+ type->is_interface = TRUE;
+ start = *rest;
+
+ /* must be an interface type */
+ while (g_ascii_isalnum (**rest) ||
+ **rest == '.' ||
+ **rest == '-' ||
+ **rest == '_' ||
+ **rest == ':')
+ (*rest)++;
+
+ type->interface = g_strndup (start, *rest - start);
+
+ *rest = g_strchug (*rest);
+ if (**rest == '*')
+ {
+ type->is_pointer = TRUE;
+ (*rest)++;
+ }
+ }
+
+ *rest = g_strchug (*rest);
+ if (g_str_has_prefix (*rest, "["))
+ {
+ GIdlNodeType *array;
+
+ array = (GIdlNodeType *)g_idl_node_new (G_IDL_NODE_TYPE);
+
+ array->tag = TYPE_TAG_ARRAY;
+ array->is_pointer = TRUE;
+ array->is_array = TRUE;
+
+ array->parameter_type1 = type;
+
+ array->zero_terminated = FALSE;
+ array->has_length = FALSE;
+ array->length = 0;
+
+ if (!g_str_has_prefix (*rest, "[]"))
+ {
+ gchar *end, *str, **opts;
+
+ end = strchr (*rest, ']');
+ str = g_strndup (*rest + 1, (end - *rest) - 1);
+ opts = g_strsplit (str, ",", 0);
+
+ *rest = end + 1;
+
+ for (i = 0; opts[i]; i++)
+ {
+ gchar **vals;
+
+ vals = g_strsplit (opts[i], "=", 0);
+
+ if (strcmp (vals[0], "zero-terminated") == 0)
+ array->zero_terminated = (strcmp (vals[1], "1") == 0);
+ else if (strcmp (vals[0], "length") == 0)
+ {
+ array->has_length = TRUE;
+ array->length = atoi (vals[1]);
+ }
+
+ g_strfreev (vals);
+ }
+
+ g_free (str);
+ g_strfreev (opts);
+ }
+
+ type = array;
+ }
+
+ return type;
+
+ error:
+ g_idl_node_free ((GIdlNode *)type);
+
+ return NULL;
+}
+
+static GIdlNodeType *
+parse_type (const gchar *type)
+{
+ gchar *str;
+ gchar *rest;
+ GIdlNodeType *node;
+
+ str = g_strdup (type);
+ node = parse_type_internal (str, &rest);
+ g_free (str);
+
+ return node;
+}
+
+static gboolean
+start_boxed (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if (strcmp (element_name, "boxed") == 0 &&
+ ctx->state == STATE_NAMESPACE)
+ {
+ const gchar *name;
+ const gchar *typename;
+ const gchar *typeinit;
+ const gchar *deprecated;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+ typename = find_attribute ("type-name", attribute_names, attribute_values);
+ typeinit = find_attribute ("get-type", attribute_names, attribute_values);
+ deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else if (typename == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "type-name");
+ else if (typeinit == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "get-type");
+ else
+ {
+ GIdlNodeBoxed *boxed;
+
+ boxed = (GIdlNodeBoxed *) g_idl_node_new (G_IDL_NODE_BOXED);
+
+ ((GIdlNode *)boxed)->name = g_strdup (name);
+ boxed->gtype_name = g_strdup (typename);
+ boxed->gtype_init = g_strdup (typeinit);
+ if (deprecated && strcmp (deprecated, "1") == 0)
+ boxed->deprecated = TRUE;
+ else
+ boxed->deprecated = FALSE;
+
+ ctx->current_node = (GIdlNode *)boxed;
+ ctx->current_module->entries =
+ g_list_append (ctx->current_module->entries, boxed);
+
+ ctx->state = STATE_BOXED;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+start_function (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if ((ctx->state == STATE_NAMESPACE &&
+ (strcmp (element_name, "function") == 0 ||
+ strcmp (element_name, "callback") == 0)) ||
+ ((ctx->state == STATE_OBJECT ||
+ ctx->state == STATE_INTERFACE ||
+ ctx->state == STATE_BOXED ||
+ ctx->state == STATE_STRUCT ||
+ ctx->state == STATE_UNION) &&
+ strcmp (element_name, "method") == 0) ||
+ ((ctx->state == STATE_OBJECT ||
+ ctx->state == STATE_BOXED) &&
+ strcmp (element_name, "constructor") == 0))
+ {
+ const gchar *name;
+ const gchar *symbol;
+ const gchar *deprecated;
+ const gchar *type;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+ symbol = find_attribute ("symbol", attribute_names, attribute_values);
+ deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+ type = find_attribute ("type", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else if (strcmp (element_name, "callback") != 0 && symbol == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "symbol");
+ else
+ {
+ GIdlNodeFunction *function;
+
+ function = (GIdlNodeFunction *) g_idl_node_new (G_IDL_NODE_FUNCTION);
+
+ ((GIdlNode *)function)->name = g_strdup (name);
+ function->symbol = g_strdup (symbol);
+ function->parameters = NULL;
+ if (deprecated && strcmp (deprecated, "1") == 0)
+ function->deprecated = TRUE;
+ else
+ function->deprecated = FALSE;
+
+ if (strcmp (element_name, "method") == 0 ||
+ strcmp (element_name, "constructor") == 0)
+ {
+ function->is_method = TRUE;
+
+ if (type && strcmp (type, "setter") == 0)
+ function->is_setter = TRUE;
+ else if (type && strcmp (type, "getter") == 0)
+ function->is_getter = TRUE;
+
+ if (strcmp (element_name, "constructor") == 0)
+ function->is_constructor = TRUE;
+ else
+ function->is_constructor = FALSE;
+ }
+ else
+ {
+ function->is_method = FALSE;
+ function->is_setter = FALSE;
+ function->is_getter = FALSE;
+ function->is_constructor = FALSE;
+ if (strcmp (element_name, "callback") == 0)
+ ((GIdlNode *)function)->type = G_IDL_NODE_CALLBACK;
+ }
+
+ if (ctx->current_node == NULL)
+ {
+ ctx->current_module->entries =
+ g_list_append (ctx->current_module->entries, function);
+ }
+ else
+ switch (ctx->current_node->type)
+ {
+ case G_IDL_NODE_INTERFACE:
+ case G_IDL_NODE_OBJECT:
+ {
+ GIdlNodeInterface *iface;
+
+ iface = (GIdlNodeInterface *)ctx->current_node;
+ iface->members = g_list_append (iface->members, function);
+ }
+ break;
+ case G_IDL_NODE_BOXED:
+ {
+ GIdlNodeBoxed *boxed;
+
+ boxed = (GIdlNodeBoxed *)ctx->current_node;
+ boxed->members = g_list_append (boxed->members, function);
+ }
+ break;
+ case G_IDL_NODE_STRUCT:
+ {
+ GIdlNodeStruct *struct_;
+
+ struct_ = (GIdlNodeStruct *)ctx->current_node;
+ struct_->members = g_list_append (struct_->members, function); }
+ break;
+ case G_IDL_NODE_UNION:
+ {
+ GIdlNodeUnion *union_;
+
+ union_ = (GIdlNodeUnion *)ctx->current_node;
+ union_->members = g_list_append (union_->members, function);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ ctx->current_node = (GIdlNode *)function;
+ ctx->state = STATE_FUNCTION;
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+start_parameter (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if (strcmp (element_name, "parameter") == 0 &&
+ ctx->state == STATE_PARAMETERS)
+ {
+ const gchar *type;
+ const gchar *name;
+ const gchar *direction;
+ const gchar *retval;
+ const gchar *dipper;
+ const gchar *optional;
+ const gchar *nullok;
+ const gchar *transfer;
+
+ type = find_attribute ("type", attribute_names, attribute_values);
+ name = find_attribute ("name", attribute_names, attribute_values);
+ direction = find_attribute ("direction", attribute_names, attribute_values);
+ retval = find_attribute ("retval", attribute_names, attribute_values);
+ dipper = find_attribute ("dipper", attribute_names, attribute_values);
+ optional = find_attribute ("optional", attribute_names, attribute_values);
+ nullok = find_attribute ("null-ok", attribute_names, attribute_values);
+ transfer = find_attribute ("transfer", attribute_names, attribute_values);
+
+ if (type == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "type");
+ else if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else
+ {
+ GIdlNodeParam *param;
+
+ param = (GIdlNodeParam *)g_idl_node_new (G_IDL_NODE_PARAM);
+
+ if (direction && strcmp (direction, "out") == 0)
+ {
+ param->in = FALSE;
+ param->out = TRUE;
+ }
+ else if (direction && strcmp (direction, "inout") == 0)
+ {
+ param->in = TRUE;
+ param->out = TRUE;
+ }
+ else
+ {
+ param->in = TRUE;
+ param->out = FALSE;
+ }
+
+ if (retval && strcmp (retval, "1") == 0)
+ param->retval = TRUE;
+ else
+ param->retval = FALSE;
+
+ if (dipper && strcmp (dipper, "1") == 0)
+ param->dipper = TRUE;
+ else
+ param->dipper = FALSE;
+
+ if (optional && strcmp (optional, "1") == 0)
+ param->optional = TRUE;
+ else
+ param->optional = FALSE;
+
+ if (nullok && strcmp (nullok, "1") == 0)
+ param->null_ok = TRUE;
+ else
+ param->null_ok = FALSE;
+
+ if (transfer && strcmp (transfer, "none") == 0)
+ {
+ param->transfer = FALSE;
+ param->shallow_transfer = FALSE;
+ }
+ else if (transfer && strcmp (transfer, "shallow") == 0)
+ {
+ param->transfer = FALSE;
+ param->shallow_transfer = TRUE;
+ }
+ else
+ {
+ param->transfer = TRUE;
+ param->shallow_transfer = FALSE;
+ }
+
+ ((GIdlNode *)param)->name = g_strdup (name);
+ param->type = parse_type (type);
+
+ switch (ctx->current_node->type)
+ {
+ case G_IDL_NODE_FUNCTION:
+ case G_IDL_NODE_CALLBACK:
+ {
+ GIdlNodeFunction *func;
+
+ func = (GIdlNodeFunction *)ctx->current_node;
+ func->parameters = g_list_append (func->parameters, param);
+ }
+ break;
+ case G_IDL_NODE_SIGNAL:
+ {
+ GIdlNodeSignal *signal;
+
+ signal = (GIdlNodeSignal *)ctx->current_node;
+ signal->parameters = g_list_append (signal->parameters, param);
+ }
+ break;
+ case G_IDL_NODE_VFUNC:
+ {
+ GIdlNodeVFunc *vfunc;
+
+ vfunc = (GIdlNodeVFunc *)ctx->current_node;
+ vfunc->parameters = g_list_append (vfunc->parameters, param);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+start_field (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if (strcmp (element_name, "field") == 0 &&
+ (ctx->state == STATE_OBJECT ||
+ ctx->state == STATE_BOXED ||
+ ctx->state == STATE_STRUCT ||
+ ctx->state == STATE_UNION))
+ {
+ const gchar *name;
+ const gchar *type;
+ const gchar *readable;
+ const gchar *writable;
+ const gchar *bits;
+ const gchar *branch;
+ const gchar *offset;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+ type = find_attribute ("type", attribute_names, attribute_values);
+ readable = find_attribute ("readable", attribute_names, attribute_values);
+ writable = find_attribute ("writable", attribute_names, attribute_values);
+ bits = find_attribute ("bits", attribute_names, attribute_values);
+ branch = find_attribute ("branch", attribute_names, attribute_values);
+ offset = find_attribute ("offset", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else if (type == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "type");
+ else
+ {
+ GIdlNodeField *field;
+
+ field = (GIdlNodeField *)g_idl_node_new (G_IDL_NODE_FIELD);
+ ((GIdlNode *)field)->name = g_strdup (name);
+ if (readable && strcmp (readable, "1") == 0)
+ field->readable = TRUE;
+ else
+ field->readable = FALSE;
+
+ if (writable && strcmp (writable, "1") == 0)
+ field->writable = TRUE;
+ else
+ field->writable = FALSE;
+
+ if (bits)
+ field->bits = atoi (bits);
+ else
+ field->bits = 0;
+
+ if (offset)
+ field->offset = atoi (offset);
+ else
+ field->offset = 0;
+
+ field->type = parse_type (type);
+
+ switch (ctx->current_node->type)
+ {
+ case G_IDL_NODE_OBJECT:
+ {
+ GIdlNodeInterface *iface;
+
+ iface = (GIdlNodeInterface *)ctx->current_node;
+ iface->members = g_list_append (iface->members, field);
+ }
+ break;
+ case G_IDL_NODE_BOXED:
+ {
+ GIdlNodeBoxed *boxed;
+
+ boxed = (GIdlNodeBoxed *)ctx->current_node;
+ boxed->members = g_list_append (boxed->members, field);
+ }
+ break;
+ case G_IDL_NODE_STRUCT:
+ {
+ GIdlNodeStruct *struct_;
+
+ struct_ = (GIdlNodeStruct *)ctx->current_node;
+ struct_->members = g_list_append (struct_->members, field);
+ }
+ break;
+ case G_IDL_NODE_UNION:
+ {
+ GIdlNodeUnion *union_;
+
+ union_ = (GIdlNodeUnion *)ctx->current_node;
+ union_->members = g_list_append (union_->members, field);
+ if (branch)
+ {
+ GIdlNodeConstant *constant;
+
+ constant = (GIdlNodeConstant *) g_idl_node_new (G_IDL_NODE_CONSTANT);
+ ((GIdlNode *)constant)->name = g_strdup (name);
+ constant->value = g_strdup (branch);
+ constant->type = union_->discriminator_type;
+ constant->deprecated = FALSE;
+
+ union_->discriminators = g_list_append (union_->discriminators, constant);
+ }
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+start_enum (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if ((strcmp (element_name, "enum") == 0 && ctx->state == STATE_NAMESPACE) ||
+ (strcmp (element_name, "flags") == 0 && ctx->state == STATE_NAMESPACE))
+ {
+ const gchar *name;
+ const gchar *typename;
+ const gchar *typeinit;
+ const gchar *deprecated;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+ typename = find_attribute ("type-name", attribute_names, attribute_values);
+ typeinit = find_attribute ("get-type", attribute_names, attribute_values);
+ deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else
+ {
+ GIdlNodeEnum *enum_;
+
+ if (strcmp (element_name, "enum") == 0)
+ enum_ = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_ENUM);
+ else
+ enum_ = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_FLAGS);
+ ((GIdlNode *)enum_)->name = g_strdup (name);
+ enum_->gtype_name = g_strdup (typename);
+ enum_->gtype_init = g_strdup (typeinit);
+ if (deprecated && strcmp (deprecated, "1") == 0)
+ enum_->deprecated = TRUE;
+ else
+ enum_->deprecated = FALSE;
+
+ ctx->current_node = (GIdlNode *) enum_;
+ ctx->current_module->entries =
+ g_list_append (ctx->current_module->entries, enum_);
+
+ ctx->state = STATE_ENUM;
+ }
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+start_property (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if (strcmp (element_name, "property") == 0 &&
+ (ctx->state == STATE_OBJECT ||
+ ctx->state == STATE_INTERFACE))
+ {
+ const gchar *name;
+ const gchar *type;
+ const gchar *readable;
+ const gchar *writable;
+ const gchar *construct;
+ const gchar *construct_only;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+ type = find_attribute ("type", attribute_names, attribute_values);
+ readable = find_attribute ("readable", attribute_names, attribute_values);
+ writable = find_attribute ("writable", attribute_names, attribute_values);
+ construct = find_attribute ("construct", attribute_names, attribute_values);
+ construct_only = find_attribute ("construct-only", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else if (type == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "type");
+ else
+ {
+ GIdlNodeProperty *property;
+ GIdlNodeInterface *iface;
+
+ property = (GIdlNodeProperty *) g_idl_node_new (G_IDL_NODE_PROPERTY);
+
+ ((GIdlNode *)property)->name = g_strdup (name);
+
+ if (readable && strcmp (readable, "1") == 0)
+ property->readable = TRUE;
+ else
+ property->readable = FALSE;
+ if (writable && strcmp (writable, "1") == 0)
+ property->writable = TRUE;
+ else
+ property->writable = FALSE;
+ if (construct && strcmp (construct, "1") == 0)
+ property->construct = TRUE;
+ else
+ property->construct = FALSE;
+ if (construct_only && strcmp (construct_only, "1") == 0)
+ property->construct_only = TRUE;
+ else
+ property->construct_only = FALSE;
+
+ property->type = parse_type (type);
+
+ iface = (GIdlNodeInterface *)ctx->current_node;
+ iface->members = g_list_append (iface->members, property);
+ }
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gint
+parse_value (const gchar *str)
+{
+ gchar *shift_op;
+
+ /* FIXME just a quick hack */
+ shift_op = strstr (str, "<<");
+
+ if (shift_op)
+ {
+ gint base, shift;
+
+ base = strtol (str, NULL, 10);
+ shift = strtol (shift_op + 3, NULL, 10);
+
+ return base << shift;
+ }
+ else
+ return strtol (str, NULL, 10);
+
+ return 0;
+}
+
+static gboolean
+start_member (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if (strcmp (element_name, "member") == 0 &&
+ ctx->state == STATE_ENUM)
+ {
+ const gchar *name;
+ const gchar *value;
+ const gchar *deprecated;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+ value = find_attribute ("value", attribute_names, attribute_values);
+ deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else
+ {
+ GIdlNodeEnum *enum_;
+ GIdlNodeValue *value_;
+
+ value_ = (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
+
+ ((GIdlNode *)value_)->name = g_strdup (name);
+
+ value_->value = parse_value (value);
+
+ if (deprecated && strcmp (deprecated, "1") == 0)
+ value_->deprecated = TRUE;
+ else
+ value_->deprecated = FALSE;
+
+ enum_ = (GIdlNodeEnum *)ctx->current_node;
+ enum_->values = g_list_append (enum_->values, value_);
+ }
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+start_constant (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if (strcmp (element_name, "constant") == 0 &&
+ (ctx->state == STATE_NAMESPACE ||
+ ctx->state == STATE_OBJECT ||
+ ctx->state == STATE_INTERFACE))
+ {
+ const gchar *name;
+ const gchar *type;
+ const gchar *value;
+ const gchar *deprecated;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+ type = find_attribute ("type", attribute_names, attribute_values);
+ value = find_attribute ("value", attribute_names, attribute_values);
+ deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else if (type == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "type");
+ else if (value == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "value");
+ else
+ {
+ GIdlNodeConstant *constant;
+
+ constant = (GIdlNodeConstant *) g_idl_node_new (G_IDL_NODE_CONSTANT);
+
+ ((GIdlNode *)constant)->name = g_strdup (name);
+ constant->value = g_strdup (value);
+
+ constant->type = parse_type (type);
+
+ if (deprecated && strcmp (deprecated, "1") == 0)
+ constant->deprecated = TRUE;
+ else
+ constant->deprecated = FALSE;
+
+ if (ctx->state == STATE_NAMESPACE)
+ {
+ ctx->current_node = (GIdlNode *) constant;
+ ctx->current_module->entries =
+ g_list_append (ctx->current_module->entries, constant);
+ }
+ else
+ {
+ GIdlNodeInterface *iface;
+
+ iface = (GIdlNodeInterface *)ctx->current_node;
+ iface->members = g_list_append (iface->members, constant);
+ }
+ }
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+start_errordomain (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if (strcmp (element_name, "errordomain") == 0 &&
+ ctx->state == STATE_NAMESPACE)
+ {
+ const gchar *name;
+ const gchar *getquark;
+ const gchar *codes;
+ const gchar *deprecated;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+ getquark = find_attribute ("get-quark", attribute_names, attribute_values);
+ codes = find_attribute ("codes", attribute_names, attribute_values);
+ deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else if (getquark == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "getquark");
+ else if (codes == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "codes");
+ else
+ {
+ GIdlNodeErrorDomain *domain;
+
+ domain = (GIdlNodeErrorDomain *) g_idl_node_new (G_IDL_NODE_ERROR_DOMAIN);
+
+ ((GIdlNode *)domain)->name = g_strdup (name);
+ domain->getquark = g_strdup (getquark);
+ domain->codes = g_strdup (codes);
+
+ if (deprecated && strcmp (deprecated, "1") == 0)
+ domain->deprecated = TRUE;
+ else
+ domain->deprecated = FALSE;
+
+ ctx->current_node = (GIdlNode *) domain;
+ ctx->current_module->entries =
+ g_list_append (ctx->current_module->entries, domain);
+
+ ctx->state = STATE_ERRORDOMAIN;
+ }
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+start_interface (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if (strcmp (element_name, "interface") == 0 &&
+ ctx->state == STATE_NAMESPACE)
+ {
+ const gchar *name;
+ const gchar *typename;
+ const gchar *typeinit;
+ const gchar *deprecated;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+ typename = find_attribute ("type-name", attribute_names, attribute_values);
+ typeinit = find_attribute ("get-type", attribute_names, attribute_values);
+ deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else if (typename == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "type-name");
+ else if (typeinit == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "get-type");
+ else
+ {
+ GIdlNodeInterface *iface;
+
+ iface = (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_INTERFACE);
+ ((GIdlNode *)iface)->name = g_strdup (name);
+ iface->gtype_name = g_strdup (typename);
+ iface->gtype_init = g_strdup (typeinit);
+ if (deprecated && strcmp (deprecated, "1") == 0)
+ iface->deprecated = TRUE;
+ else
+ iface->deprecated = FALSE;
+
+ ctx->current_node = (GIdlNode *) iface;
+ ctx->current_module->entries =
+ g_list_append (ctx->current_module->entries, iface);
+
+ ctx->state = STATE_INTERFACE;
+
+ }
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+start_object (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if (strcmp (element_name, "object") == 0 &&
+ ctx->state == STATE_NAMESPACE)
+ {
+ const gchar *name;
+ const gchar *parent;
+ const gchar *typename;
+ const gchar *typeinit;
+ const gchar *deprecated;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+ parent = find_attribute ("parent", attribute_names, attribute_values);
+ typename = find_attribute ("type-name", attribute_names, attribute_values);
+ typeinit = find_attribute ("get-type", attribute_names, attribute_values);
+ deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else if (typename == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "type-name");
+ else if (typeinit == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "get-type");
+ else
+ {
+ GIdlNodeInterface *iface;
+
+ iface = (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_OBJECT);
+ ((GIdlNode *)iface)->name = g_strdup (name);
+ iface->gtype_name = g_strdup (typename);
+ iface->gtype_init = g_strdup (typeinit);
+ iface->parent = g_strdup (parent);
+ if (deprecated && strcmp (deprecated, "1") == 0)
+ iface->deprecated = TRUE;
+ else
+ iface->deprecated = FALSE;
+
+ ctx->current_node = (GIdlNode *) iface;
+ ctx->current_module->entries =
+ g_list_append (ctx->current_module->entries, iface);
+
+ ctx->state = STATE_OBJECT;
+ }
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+start_return_type (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if (strcmp (element_name, "return-type") == 0 &&
+ ctx->state == STATE_FUNCTION)
+ {
+ const gchar *type;
+ const gchar *nullok;
+ const gchar *transfer;
+
+ type = find_attribute ("type", attribute_names, attribute_values);
+ nullok = find_attribute ("null-ok", attribute_names, attribute_values);
+ transfer = find_attribute ("transfer", attribute_names, attribute_values);
+ if (type == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "type");
+ else
+ {
+ GIdlNodeParam *param;
+
+ param = (GIdlNodeParam *)g_idl_node_new (G_IDL_NODE_PARAM);
+ param->in = FALSE;
+ param->out = FALSE;
+ param->retval = TRUE;
+ if (nullok && strcmp (nullok, "1") == 0)
+ param->null_ok = TRUE;
+ else
+ param->null_ok = FALSE;
+ if (transfer && strcmp (transfer, "none") == 0)
+ {
+ param->transfer = FALSE;
+ param->shallow_transfer = FALSE;
+ }
+ else if (transfer && strcmp (transfer, "shallow") == 0)
+ {
+ param->transfer = FALSE;
+ param->shallow_transfer = TRUE;
+ }
+ else
+ {
+ param->transfer = TRUE;
+ param->shallow_transfer = FALSE;
+ }
+
+ param->type = parse_type (type);
+
+ switch (ctx->current_node->type)
+ {
+ case G_IDL_NODE_FUNCTION:
+ case G_IDL_NODE_CALLBACK:
+ {
+ GIdlNodeFunction *func = (GIdlNodeFunction *)ctx->current_node;
+ func->result = param;
+ }
+ break;
+ case G_IDL_NODE_SIGNAL:
+ {
+ GIdlNodeSignal *signal = (GIdlNodeSignal *)ctx->current_node;
+ signal->result = param;
+ }
+ break;
+ case G_IDL_NODE_VFUNC:
+ {
+ GIdlNodeVFunc *vfunc = (GIdlNodeVFunc *)ctx->current_node;
+ vfunc->result = param;
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+start_signal (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if (strcmp (element_name, "signal") == 0 &&
+ (ctx->state == STATE_OBJECT ||
+ ctx->state == STATE_INTERFACE))
+ {
+ const gchar *name;
+ const gchar *when;
+ const gchar *no_recurse;
+ const gchar *detailed;
+ const gchar *action;
+ const gchar *no_hooks;
+ const gchar *has_class_closure;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+ when = find_attribute ("when", attribute_names, attribute_values);
+ no_recurse = find_attribute ("no-recurse", attribute_names, attribute_values);
+ detailed = find_attribute ("detailed", attribute_names, attribute_values);
+ action = find_attribute ("action", attribute_names, attribute_values);
+ no_hooks = find_attribute ("no-hooks", attribute_names, attribute_values);
+ has_class_closure = find_attribute ("has-class-closure", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else if (when == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "when");
+ else
+ {
+ GIdlNodeInterface *iface;
+ GIdlNodeSignal *signal;
+
+ signal = (GIdlNodeSignal *)g_idl_node_new (G_IDL_NODE_SIGNAL);
+
+ ((GIdlNode *)signal)->name = g_strdup (name);
+
+ signal->run_first = FALSE;
+ signal->run_last = FALSE;
+ signal->run_cleanup = FALSE;
+ if (strcmp (when, "FIRST") == 0)
+ signal->run_first = TRUE;
+ else if (strcmp (when, "LAST") == 0)
+ signal->run_last = TRUE;
+ else
+ signal->run_cleanup = TRUE;
+
+ if (no_recurse && strcmp (no_recurse, "1") == 0)
+ signal->no_recurse = TRUE;
+ else
+ signal->no_recurse = FALSE;
+ if (detailed && strcmp (detailed, "1") == 0)
+ signal->detailed = TRUE;
+ else
+ signal->detailed = FALSE;
+ if (action && strcmp (action, "1") == 0)
+ signal->action = TRUE;
+ else
+ signal->action = FALSE;
+ if (no_hooks && strcmp (no_hooks, "1") == 0)
+ signal->no_hooks = TRUE;
+ else
+ signal->no_hooks = FALSE;
+ if (has_class_closure && strcmp (has_class_closure, "1") == 0)
+ signal->has_class_closure = TRUE;
+ else
+ signal->has_class_closure = FALSE;
+
+ iface = (GIdlNodeInterface *)ctx->current_node;
+ iface->members = g_list_append (iface->members, signal);
+
+ ctx->current_node = (GIdlNode *)signal;
+ ctx->state = STATE_FUNCTION;
+ }
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+start_vfunc (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if (strcmp (element_name, "vfunc") == 0 &&
+ (ctx->state == STATE_OBJECT ||
+ ctx->state == STATE_INTERFACE))
+ {
+ const gchar *name;
+ const gchar *must_chain_up;
+ const gchar *override;
+ const gchar *is_class_closure;
+ const gchar *offset;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+ must_chain_up = find_attribute ("must-chain-up", attribute_names, attribute_values);
+ override = find_attribute ("override", attribute_names, attribute_values);
+ is_class_closure = find_attribute ("is-class-closure", attribute_names, attribute_values);
+ offset = find_attribute ("offset", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else
+ {
+ GIdlNodeInterface *iface;
+ GIdlNodeVFunc *vfunc;
+
+ vfunc = (GIdlNodeVFunc *)g_idl_node_new (G_IDL_NODE_VFUNC);
+
+ ((GIdlNode *)vfunc)->name = g_strdup (name);
+
+ if (must_chain_up && strcmp (must_chain_up, "1") == 0)
+ vfunc->must_chain_up = TRUE;
+ else
+ vfunc->must_chain_up = FALSE;
+
+ if (override && strcmp (override, "always") == 0)
+ {
+ vfunc->must_be_implemented = TRUE;
+ vfunc->must_not_be_implemented = FALSE;
+ }
+ else if (override && strcmp (override, "never") == 0)
+ {
+ vfunc->must_be_implemented = FALSE;
+ vfunc->must_not_be_implemented = TRUE;
+ }
+ else
+ {
+ vfunc->must_be_implemented = FALSE;
+ vfunc->must_not_be_implemented = FALSE;
+ }
+
+ if (is_class_closure && strcmp (is_class_closure, "1") == 0)
+ vfunc->is_class_closure = TRUE;
+ else
+ vfunc->is_class_closure = FALSE;
+
+ if (offset)
+ vfunc->offset = atoi (offset);
+ else
+ vfunc->offset = 0;
+
+ iface = (GIdlNodeInterface *)ctx->current_node;
+ iface->members = g_list_append (iface->members, vfunc);
+
+ ctx->current_node = (GIdlNode *)vfunc;
+ ctx->state = STATE_FUNCTION;
+ }
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+static gboolean
+start_struct (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if (strcmp (element_name, "struct") == 0 &&
+ ctx->state == STATE_NAMESPACE)
+ {
+ const gchar *name;
+ const gchar *deprecated;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+ deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else
+ {
+ GIdlNodeStruct *struct_;
+
+ struct_ = (GIdlNodeStruct *) g_idl_node_new (G_IDL_NODE_STRUCT);
+
+ ((GIdlNode *)struct_)->name = g_strdup (name);
+ if (deprecated && strcmp (deprecated, "1") == 0)
+ struct_->deprecated = TRUE;
+ else
+ struct_->deprecated = FALSE;
+
+ ctx->current_node = (GIdlNode *)struct_;
+ ctx->current_module->entries =
+ g_list_append (ctx->current_module->entries, struct_);
+
+ ctx->state = STATE_STRUCT;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+static gboolean
+start_union (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if (strcmp (element_name, "union") == 0 &&
+ ctx->state == STATE_NAMESPACE)
+ {
+ const gchar *name;
+ const gchar *deprecated;
+ const gchar *typename;
+ const gchar *typeinit;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+ deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+ typename = find_attribute ("type-name", attribute_names, attribute_values);
+ typeinit = find_attribute ("get-type", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else
+ {
+ GIdlNodeUnion *union_;
+
+ union_ = (GIdlNodeUnion *) g_idl_node_new (G_IDL_NODE_UNION);
+
+ ((GIdlNode *)union_)->name = g_strdup (name);
+ union_->gtype_name = g_strdup (typename);
+ union_->gtype_init = g_strdup (typeinit);
+ if (deprecated && strcmp (deprecated, "1") == 0)
+ union_->deprecated = TRUE;
+ else
+ union_->deprecated = FALSE;
+
+ ctx->current_node = (GIdlNode *)union_;
+ ctx->current_module->entries =
+ g_list_append (ctx->current_module->entries, union_);
+
+ ctx->state = STATE_UNION;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+start_discriminator (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if (strcmp (element_name, "discriminator") == 0 &&
+ ctx->state == STATE_UNION)
+ {
+ const gchar *type;
+ const gchar *offset;
+
+ type = find_attribute ("type", attribute_names, attribute_values);
+ offset = find_attribute ("offset", attribute_names, attribute_values);
+ if (type == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "type");
+ else if (offset == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "offset");
+ {
+ ((GIdlNodeUnion *)ctx->current_node)->discriminator_type
+ = parse_type (type);
+ ((GIdlNodeUnion *)ctx->current_node)->discriminator_offset
+ = atoi (offset);
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+start_element_handler (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error)
+{
+ ParseContext *ctx = user_data;
+ gint line_number, char_number;
+
+ switch (element_name[0])
+ {
+ case 'a':
+ if (strcmp (element_name, "api") == 0 && ctx->state == STATE_START)
+ {
+ const gchar *version;
+
+ version = find_attribute ("version", attribute_names, attribute_values);
+
+ if (version == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "version");
+ else if (strcmp (version, "1.0") != 0)
+ g_set_error (error,
+ G_MARKUP_ERROR,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ "Unsupported version '%s'",
+ version);
+ else
+ ctx->state = STATE_ROOT;
+
+ goto out;
+ }
+ break;
+
+ case 'b':
+ if (start_boxed (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ break;
+
+ case 'c':
+ if (start_function (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ else if (start_constant (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ break;
+
+ case 'd':
+ if (start_discriminator (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ break;
+
+ case 'e':
+ if (start_enum (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ else if (start_errordomain (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ break;
+
+ case 'f':
+ if (start_function (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ else if (start_field (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ else if (start_enum (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+
+ break;
+
+ case 'i':
+ if (start_interface (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ if (strcmp (element_name, "implements") == 0 &&
+ ctx->state == STATE_OBJECT)
+ {
+ ctx->state = STATE_IMPLEMENTS;
+
+ goto out;
+ }
+ else if (strcmp (element_name, "interface") == 0 &&
+ ctx->state == STATE_IMPLEMENTS)
+ {
+ const gchar *name;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else
+ {
+ GIdlNodeInterface *iface;
+
+ iface = (GIdlNodeInterface *)ctx->current_node;
+ iface ->interfaces = g_list_append (iface->interfaces, g_strdup (name));
+ }
+
+ goto out;
+ }
+ else if (strcmp (element_name, "interface") == 0 &&
+ ctx->state == STATE_REQUIRES)
+ {
+ const gchar *name;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else
+ {
+ GIdlNodeInterface *iface;
+
+ iface = (GIdlNodeInterface *)ctx->current_node;
+ iface ->prerequisites = g_list_append (iface->prerequisites, g_strdup (name));
+ }
+
+ goto out;
+ }
+ break;
+
+ case 'm':
+ if (start_function (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ else if (start_member (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ break;
+
+ case 'n':
+ if (strcmp (element_name, "namespace") == 0 && ctx->state == STATE_ROOT)
+ {
+ const gchar *name, *shared_library;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+ shared_library = find_attribute ("shared-library", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else
+ {
+ ctx->current_module = g_idl_module_new (name, shared_library);
+ ctx->modules = g_list_append (ctx->modules, ctx->current_module);
+
+ ctx->state = STATE_NAMESPACE;
+ }
+
+ goto out;
+ }
+ break;
+
+ case 'o':
+ if (start_object (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ else if (strcmp (element_name, "object") == 0 &&
+ ctx->state == STATE_REQUIRES)
+ {
+ const gchar *name;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else
+ {
+ GIdlNodeInterface *iface;
+
+ iface = (GIdlNodeInterface *)ctx->current_node;
+ iface ->prerequisites = g_list_append (iface->prerequisites, g_strdup (name));
+ }
+
+ goto out;
+ }
+ break;
+
+ case 'p':
+ if (start_property (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ else if (strcmp (element_name, "parameters") == 0 &&
+ ctx->state == STATE_FUNCTION)
+ {
+ ctx->state = STATE_PARAMETERS;
+
+ goto out;
+ }
+ else if (start_parameter (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+
+ break;
+
+ case 'r':
+ if (start_return_type (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ else if (strcmp (element_name, "requires") == 0 &&
+ ctx->state == STATE_INTERFACE)
+ {
+ ctx->state = STATE_REQUIRES;
+
+ goto out;
+ }
+
+ break;
+
+ case 's':
+ if (start_signal (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ else if (start_struct (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+
+ break;
+
+ case 'u':
+ if (start_union (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ break;
+
+ case 'v':
+ if (start_vfunc (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ break;
+ }
+
+ g_markup_parse_context_get_position (context, &line_number, &char_number);
+
+ g_set_error (error,
+ G_MARKUP_ERROR,
+ G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ "Unexpected start tag '%s' on line %d char %d",
+ element_name,
+ line_number, char_number);
+
+ out: ;
+
+}
+
+static void
+end_element_handler (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ ParseContext *ctx = user_data;
+
+ switch (ctx->state)
+ {
+ case STATE_START:
+ case STATE_END:
+ /* no need to GError here, GMarkup already catches this */
+ break;
+
+ case STATE_ROOT:
+ ctx->state = STATE_END;
+ break;
+
+ case STATE_NAMESPACE:
+ if (strcmp (element_name, "namespace") == 0)
+ {
+ ctx->current_module = NULL;
+ ctx->state = STATE_ROOT;
+ }
+ break;
+
+ case STATE_FUNCTION:
+ if (strcmp (element_name, "return-type") == 0)
+ /* do nothing */ ;
+
+ else if (ctx->current_node == g_list_last (ctx->current_module->entries)->data)
+ {
+ ctx->current_node = NULL;
+ ctx->state = STATE_NAMESPACE;
+ }
+ else
+ {
+ ctx->current_node = g_list_last (ctx->current_module->entries)->data;
+ if (ctx->current_node->type == G_IDL_NODE_INTERFACE)
+ ctx->state = STATE_INTERFACE;
+ else if (ctx->current_node->type == G_IDL_NODE_OBJECT)
+ ctx->state = STATE_OBJECT;
+ else if (ctx->current_node->type == G_IDL_NODE_BOXED)
+ ctx->state = STATE_BOXED;
+ else if (ctx->current_node->type == G_IDL_NODE_STRUCT)
+ ctx->state = STATE_STRUCT;
+ else if (ctx->current_node->type == G_IDL_NODE_UNION)
+ ctx->state = STATE_UNION;
+ }
+ break;
+
+ case STATE_OBJECT:
+ if (strcmp (element_name, "object") == 0)
+ {
+ ctx->current_node = NULL;
+ ctx->state = STATE_NAMESPACE;
+ }
+ break;
+
+ case STATE_ERRORDOMAIN:
+ if (strcmp (element_name, "errordomain") == 0)
+ {
+ ctx->current_node = NULL;
+ ctx->state = STATE_NAMESPACE;
+ }
+ break;
+
+ case STATE_INTERFACE:
+ if (strcmp (element_name, "interface") == 0)
+ {
+ ctx->current_node = NULL;
+ ctx->state = STATE_NAMESPACE;
+ }
+ break;
+
+ case STATE_ENUM:
+ if (strcmp (element_name, "enum") == 0 ||
+ strcmp (element_name, "flags") == 0)
+ {
+ ctx->current_node = NULL;
+ ctx->state = STATE_NAMESPACE;
+ }
+ break;
+
+ case STATE_BOXED:
+ if (strcmp (element_name, "boxed") == 0)
+ {
+ ctx->current_node = NULL;
+ ctx->state = STATE_NAMESPACE;
+ }
+ break;
+
+ case STATE_STRUCT:
+ if (strcmp (element_name, "struct") == 0)
+ {
+ ctx->current_node = NULL;
+ ctx->state = STATE_NAMESPACE;
+ }
+ break;
+ case STATE_UNION:
+ if (strcmp (element_name, "union") == 0)
+ {
+ ctx->current_node = NULL;
+ ctx->state = STATE_NAMESPACE;
+ }
+ break;
+
+ case STATE_IMPLEMENTS:
+ if (strcmp (element_name, "implements") == 0)
+ ctx->state = STATE_OBJECT;
+ break;
+ case STATE_REQUIRES:
+ if (strcmp (element_name, "requires") == 0)
+ ctx->state = STATE_INTERFACE;
+ break;
+ case STATE_PARAMETERS:
+ if (strcmp (element_name, "parameters") == 0)
+ ctx->state = STATE_FUNCTION;
+ break;
+ default:
+ g_error ("Unhandled state %d in end_element_handler\n", ctx->state);
+ }
+}
+
+static void
+text_handler (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ /* FIXME warn about non-whitespace text */
+}
+
+static void
+cleanup (GMarkupParseContext *context,
+ GError *error,
+ gpointer user_data)
+{
+ ParseContext *ctx = user_data;
+ GList *m;
+
+ for (m = ctx->modules; m; m = m->next)
+ g_idl_module_free (m->data);
+ g_list_free (ctx->modules);
+ ctx->modules = NULL;
+
+ ctx->current_module = NULL;
+}
+
+static GMarkupParser parser =
+{
+ start_element_handler,
+ end_element_handler,
+ text_handler,
+ NULL,
+ cleanup
+};
+
+GList *
+g_idl_parse_string (const gchar *buffer,
+ gssize length,
+ GError **error)
+{
+ ParseContext ctx = { 0 };
+ GMarkupParseContext *context;
+
+ ctx.state = STATE_START;
+
+ context = g_markup_parse_context_new (&parser, 0, &ctx, NULL);
+ if (!g_markup_parse_context_parse (context, buffer, length, error))
+ goto out;
+
+ if (!g_markup_parse_context_end_parse (context, error))
+ goto out;
+
+ out:
+
+ g_markup_parse_context_free (context);
+
+ return ctx.modules;
+}
+
+GList *
+g_idl_parse_file (const gchar *filename,
+ GError **error)
+{
+ gchar *buffer;
+ gsize length;
+ GList *modules;
+
+ if (!g_file_get_contents (filename, &buffer, &length, error))
+ return NULL;
+
+ modules = g_idl_parse_string (buffer, length, error);
+
+ g_free (buffer);
+
+ return modules;
+}
+
+
diff --git a/tools/gidlparser.h b/tools/gidlparser.h
new file mode 100644
index 00000000..2d71aaa0
--- /dev/null
+++ b/tools/gidlparser.h
@@ -0,0 +1,38 @@
+/* GObject introspection: A parser for the XML IDL format
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * 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 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.
+ */
+
+#ifndef __G_IDL_PARSER_H__
+#define __G_IDL_PARSER_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+
+GList *g_idl_parse_string (const gchar *buffer,
+ gssize length,
+ GError **error);
+GList *g_idl_parse_file (const gchar *filename,
+ GError **error);
+
+
+G_END_DECLS
+
+#endif /* __G_IDL_PARSER_H__ */
diff --git a/tools/gidlwriter.c b/tools/gidlwriter.c
new file mode 100644
index 00000000..d46762bc
--- /dev/null
+++ b/tools/gidlwriter.c
@@ -0,0 +1,483 @@
+/* GObject introspection: gen-introspect
+ *
+ * Copyright (C) 2007 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 <stdio.h>
+#include <glib.h>
+#include "scanner.h"
+#include "gidlnode.h"
+
+typedef struct {
+ int indent;
+ FILE *output;
+} GIdlWriter;
+
+static void node_generate (GIdlWriter * writer, GIdlNode * node);
+
+static void
+g_writer_write_inline (GIdlWriter * writer, const char *s)
+{
+ fprintf (writer->output, "%s", s);
+}
+
+static void
+g_writer_write (GIdlWriter * writer, const char *s)
+{
+ int i;
+ for (i = 0; i < writer->indent; i++)
+ {
+ fprintf (writer->output, "\t");
+ }
+
+ g_writer_write_inline (writer, s);
+}
+
+static void
+g_writer_write_indent (GIdlWriter * writer, const char *s)
+{
+ g_writer_write (writer, s);
+ writer->indent++;
+}
+
+static void
+g_writer_write_unindent (GIdlWriter * writer, const char *s)
+{
+ writer->indent--;
+ g_writer_write (writer, s);
+}
+
+static void
+field_generate (GIdlWriter * writer, GIdlNodeField * node)
+{
+ char *markup =
+ g_markup_printf_escaped ("<field name=\"%s\" type=\"%s\"/>\n",
+ node->node.name, node->type->unparsed);
+ g_writer_write (writer, markup);
+ g_free (markup);
+}
+
+static void
+value_generate (GIdlWriter * writer, GIdlNodeValue * node)
+{
+ char *markup =
+ g_markup_printf_escaped ("<member name=\"%s\" value=\"%d\"/>\n",
+ node->node.name, node->value);
+ g_writer_write (writer, markup);
+ g_free (markup);
+}
+
+static void
+constant_generate (GIdlWriter * writer, GIdlNodeConstant * node)
+{
+ char *markup =
+ g_markup_printf_escaped
+ ("<constant name=\"%s\" type=\"%s\" value=\"%s\"/>\n", node->node.name,
+ node->type->unparsed, node->value);
+ g_writer_write (writer, markup);
+ g_free (markup);
+}
+
+static void
+property_generate (GIdlWriter * writer, GIdlNodeProperty * node)
+{
+ char *markup =
+ g_markup_printf_escaped ("<property name=\"%s\" "
+ "type=\"%s\" "
+ "readable=\"%s\" "
+ "writable=\"%s\" "
+ "construct=\"%s\" "
+ "construct-only=\"%s\"/>\n",
+ node->node.name,
+ node->type->unparsed,
+ node->readable ? "1" : "0",
+ node->writable ? "1" : "0",
+ node->construct ? "1" : "0",
+ node->construct_only ? "1" : "0");
+ g_writer_write (writer, markup);
+ g_free (markup);
+}
+
+static void
+function_generate (GIdlWriter * writer, GIdlNodeFunction * node)
+{
+ const char *tag_name;
+ GString *markup_s;
+ gchar *markup;
+
+ if (node->node.type == G_IDL_NODE_CALLBACK)
+ tag_name = "callback";
+ else if (node->is_constructor)
+ tag_name = "constructor";
+ else if (node->is_method)
+ tag_name = "method";
+ else
+ tag_name = "function";
+
+ markup_s = g_string_new ("<");
+ g_string_append_printf (markup_s,
+ "%s name=\"%s\"",
+ tag_name, node->node.name);
+
+ if (node->node.type != G_IDL_NODE_CALLBACK)
+ g_string_append_printf (markup_s,
+ g_markup_printf_escaped (" symbol=\"%s\"", node->symbol));
+
+ if (node->deprecated)
+ g_string_append_printf (markup_s, " deprecated=\"1\"");
+
+ g_string_append (markup_s, ">\n");
+
+ g_writer_write_indent (writer, markup_s->str);
+ g_string_free (markup_s, TRUE);
+
+ markup =
+ g_markup_printf_escaped ("<return-type type=\"%s\"/>\n",
+ node->result->type->unparsed);
+ g_writer_write (writer, markup);
+ g_free (markup);
+
+ if (node->parameters != NULL)
+ {
+ GList *l;
+ g_writer_write_indent (writer, "<parameters>\n");
+ for (l = node->parameters; l != NULL; l = l->next)
+ {
+ GIdlNodeParam *param = l->data;
+ markup =
+ g_markup_printf_escaped ("<parameter name=\"%s\" type=\"%s\"/>\n",
+ param->node.name, param->type->unparsed);
+ g_writer_write (writer, markup);
+ g_free (markup);
+ }
+ g_writer_write_unindent (writer, "</parameters>\n");
+ }
+ markup = g_strdup_printf ("</%s>\n", tag_name);
+ g_writer_write_unindent (writer, markup);
+ g_free (markup);
+}
+
+static void
+vfunc_generate (GIdlWriter * writer, GIdlNodeVFunc * node)
+{
+ char *markup =
+ g_markup_printf_escaped ("<vfunc name=\"%s\">\n", node->node.name);
+ g_writer_write_indent (writer, markup);
+ g_free (markup);
+ markup =
+ g_markup_printf_escaped ("<return-type type=\"%s\"/>\n",
+ node->result->type->unparsed);
+ g_writer_write (writer, markup);
+ g_free (markup);
+ if (node->parameters != NULL)
+ {
+ GList *l;
+ g_writer_write_indent (writer, "<parameters>\n");
+ for (l = node->parameters; l != NULL; l = l->next)
+ {
+ GIdlNodeParam *param = l->data;
+ markup =
+ g_markup_printf_escaped ("<parameter name=\"%s\" type=\"%s\"/>\n",
+ param->node.name, param->type->unparsed);
+ g_writer_write (writer, markup);
+ g_free (markup);
+ }
+ g_writer_write_unindent (writer, "</parameters>\n");
+ }
+ g_writer_write_unindent (writer, "</vfunc>\n");
+}
+
+static void
+signal_generate (GIdlWriter * writer, GIdlNodeSignal * node)
+{
+ char *markup;
+ const char *when = "LAST";
+ if (node->run_first)
+ {
+ when = "FIRST";
+ }
+ else if (node->run_cleanup)
+ {
+ when = "CLEANUP";
+ }
+ markup =
+ g_markup_printf_escaped ("<signal name=\"%s\" when=\"%s\">\n",
+ node->node.name, when);
+ g_writer_write_indent (writer, markup);
+ g_free (markup);
+ markup =
+ g_markup_printf_escaped ("<return-type type=\"%s\"/>\n",
+ node->result->type->unparsed);
+ g_writer_write (writer, markup);
+ g_free (markup);
+ if (node->parameters != NULL)
+ {
+ GList *l;
+ g_writer_write_indent (writer, "<parameters>\n");
+ for (l = node->parameters; l != NULL; l = l->next)
+ {
+ GIdlNodeParam *param = l->data;
+ markup =
+ g_markup_printf_escaped ("<parameter name=\"%s\" type=\"%s\"/>\n",
+ param->node.name, param->type->unparsed);
+ g_writer_write (writer, markup);
+ g_free (markup);
+ }
+ g_writer_write_unindent (writer, "</parameters>\n");
+ }
+ g_writer_write_unindent (writer, "</signal>\n");
+}
+
+static void
+interface_generate (GIdlWriter * writer, GIdlNodeInterface * node)
+{
+ GList *l;
+ char *markup;
+ if (node->node.type == G_IDL_NODE_OBJECT)
+ {
+ markup =
+ g_markup_printf_escaped ("<object name=\"%s\" "
+ "parent=\"%s\" "
+ "type-name=\"%s\" "
+ "get-type=\"%s\">\n",
+ node->node.name,
+ node->parent,
+ node->gtype_name,
+ node->gtype_init);
+ }
+ else if (node->node.type == G_IDL_NODE_INTERFACE)
+ {
+ markup =
+ g_markup_printf_escaped
+ ("<interface name=\"%s\" type-name=\"%s\" get-type=\"%s\">\n",
+ node->node.name, node->gtype_name, node->gtype_init);
+ }
+
+ g_writer_write_indent (writer, markup);
+ g_free (markup);
+ if (node->node.type == G_IDL_NODE_OBJECT && node->interfaces != NULL)
+ {
+ GList *l;
+ g_writer_write_indent (writer, "<implements>\n");
+ for (l = node->interfaces; l != NULL; l = l->next)
+ {
+ markup =
+ g_markup_printf_escaped ("<interface name=\"%s\"/>\n",
+ (char *) l->data);
+ g_writer_write (writer, markup);
+ g_free (markup);
+ }
+ g_writer_write_unindent (writer, "</implements>\n");
+ }
+ else if (node->node.type == G_IDL_NODE_INTERFACE
+ && node->prerequisites != NULL)
+ {
+ GList *l;
+ g_writer_write_indent (writer, "<requires>\n");
+ for (l = node->prerequisites; l != NULL; l = l->next)
+ {
+ markup =
+ g_markup_printf_escaped ("<interface name=\"%s\"/>\n",
+ (char *) l->data);
+ g_writer_write (writer, markup);
+ g_free (markup);
+ }
+ g_writer_write_unindent (writer, "</requires>\n");
+ }
+
+ for (l = node->members; l != NULL; l = l->next)
+ {
+ node_generate (writer, l->data);
+ }
+
+ if (node->node.type == G_IDL_NODE_OBJECT)
+ {
+ g_writer_write_unindent (writer, "</object>\n");
+ }
+ else if (node->node.type == G_IDL_NODE_INTERFACE)
+ {
+ g_writer_write_unindent (writer, "</interface>\n");
+ }
+}
+
+static void
+struct_generate (GIdlWriter * writer, GIdlNodeStruct * node)
+{
+ GList *l;
+ char *markup =
+ g_markup_printf_escaped ("<struct name=\"%s\">\n", node->node.name);
+ g_writer_write_indent (writer, markup);
+ g_free (markup);
+ for (l = node->members; l != NULL; l = l->next)
+ {
+ node_generate (writer, l->data);
+ }
+ g_writer_write_unindent (writer, "</struct>\n");
+}
+
+static void
+union_generate (GIdlWriter * writer, GIdlNodeUnion * node)
+{
+ GList *l;
+ char *markup =
+ g_markup_printf_escaped ("<union name=\"%s\">\n", node->node.name);
+ g_writer_write_indent (writer, markup);
+ g_free (markup);
+ for (l = node->members; l != NULL; l = l->next)
+ {
+ node_generate (writer, l->data);
+ }
+ g_writer_write_unindent (writer, "</union>\n");
+}
+
+static void
+boxed_generate (GIdlWriter * writer, GIdlNodeBoxed * node)
+{
+ GList *l;
+ char *markup =
+ g_markup_printf_escaped
+ ("<boxed name=\"%s\" type-name=\"%s\" get-type=\"%s\">\n",
+ node->node.name, node->gtype_name, node->gtype_init);
+ g_writer_write_indent (writer, markup);
+ g_free (markup);
+ for (l = node->members; l != NULL; l = l->next)
+ {
+ node_generate (writer, l->data);
+ }
+ g_writer_write_unindent (writer, "</boxed>\n");
+}
+
+static void
+enum_generate (GIdlWriter * writer, GIdlNodeEnum * node)
+{
+ GList *l;
+ char *markup;
+ const char *tag_name = NULL;
+
+ if (node->node.type == G_IDL_NODE_ENUM)
+ {
+ tag_name = "enum";
+ }
+ else if (node->node.type == G_IDL_NODE_FLAGS)
+ {
+ tag_name = "flags";
+ }
+ markup =
+ g_markup_printf_escaped ("<%s name=\"%s\">\n", tag_name, node->node.name);
+ g_writer_write_indent (writer, markup);
+ g_free (markup);
+
+ for (l = node->values; l != NULL; l = l->next)
+ {
+ node_generate (writer, l->data);
+ }
+
+ markup = g_strdup_printf ("</%s>\n", tag_name);
+ g_writer_write_unindent (writer, markup);
+ g_free (markup);
+}
+
+static void
+node_generate (GIdlWriter * writer, GIdlNode * node)
+{
+ switch (node->type)
+ {
+ case G_IDL_NODE_FUNCTION:
+ case G_IDL_NODE_CALLBACK:
+ function_generate (writer, (GIdlNodeFunction *) node);
+ break;
+ case G_IDL_NODE_VFUNC:
+ vfunc_generate (writer, (GIdlNodeVFunc *) node);
+ break;
+ case G_IDL_NODE_OBJECT:
+ case G_IDL_NODE_INTERFACE:
+ interface_generate (writer, (GIdlNodeInterface *) node);
+ break;
+ case G_IDL_NODE_STRUCT:
+ struct_generate (writer, (GIdlNodeStruct *) node);
+ break;
+ case G_IDL_NODE_UNION:
+ union_generate (writer, (GIdlNodeUnion *) node);
+ break;
+ case G_IDL_NODE_BOXED:
+ boxed_generate (writer, (GIdlNodeBoxed *) node);
+ break;
+ case G_IDL_NODE_ENUM:
+ case G_IDL_NODE_FLAGS:
+ enum_generate (writer, (GIdlNodeEnum *) node);
+ break;
+ case G_IDL_NODE_PROPERTY:
+ property_generate (writer, (GIdlNodeProperty *) node);
+ break;
+ case G_IDL_NODE_FIELD:
+ field_generate (writer, (GIdlNodeField *) node);
+ break;
+ case G_IDL_NODE_SIGNAL:
+ signal_generate (writer, (GIdlNodeSignal *) node);
+ break;
+ case G_IDL_NODE_VALUE:
+ value_generate (writer, (GIdlNodeValue *) node);
+ break;
+ case G_IDL_NODE_CONSTANT:
+ constant_generate (writer, (GIdlNodeConstant *) node);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+g_writer_write_module (GIdlWriter * writer, GIdlModule * module)
+{
+ GList *l;
+ char *markup =
+ g_markup_printf_escaped ("<namespace name=\"%s\">\n", module->name);
+ g_writer_write_indent (writer, markup);
+ g_free (markup);
+ for (l = module->entries; l != NULL; l = l->next)
+ {
+ node_generate (writer, l->data);
+ }
+ g_writer_write_unindent (writer, "</namespace>\n");
+}
+
+void
+g_idl_writer_save_file (GIdlModule *module,
+ const gchar *filename)
+{
+ GIdlWriter *writer;
+
+ writer = g_new0 (GIdlWriter, 1);
+
+ if (!filename)
+ writer->output = stdout;
+ else
+ writer->output = fopen (filename, "w");
+
+ g_writer_write (writer, "<?xml version=\"1.0\"?>\n");
+ g_writer_write_indent (writer, "<api version=\"1.0\">\n");
+ g_writer_write_module (writer, module);
+ g_writer_write_unindent (writer, "</api>\n");
+
+ if (filename)
+ fclose (writer->output);
+}
diff --git a/tools/gidlwriter.h b/tools/gidlwriter.h
new file mode 100644
index 00000000..5d41a0c6
--- /dev/null
+++ b/tools/gidlwriter.h
@@ -0,0 +1,26 @@
+/* GObject introspection: IDL writer
+ *
+ * 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 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.
+ */
+
+#ifndef __G_IDL_WRITER_H__
+#define __G_IDL_WRITER_H__
+
+void g_idl_writer_save_file (GIdlModule *module, const gchar *filename);
+
+#endif /* __G_IDL_WRITER_H__ */
diff --git a/tools/scanner.c b/tools/scanner.c
new file mode 100644
index 00000000..abbe2156
--- /dev/null
+++ b/tools/scanner.c
@@ -0,0 +1,1762 @@
+/* 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 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;
+
+ g_idl_node_add_member (node, func);
+ break;
+ }
+ 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)
+{
+ /* 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;
+}
+
diff --git a/tools/scanner.h b/tools/scanner.h
new file mode 100644
index 00000000..b2140759
--- /dev/null
+++ b/tools/scanner.h
@@ -0,0 +1,167 @@
+/* GObject introspection: gen-introspect
+ *
+ * Copyright (C) 2007 Jürg Billeter
+ *
+ * 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>
+ */
+
+#ifndef __GEN_INTROSPECT_H__
+#define __GEN_INTROSPECT_H__
+
+#include <glib.h>
+#include "gidlmodule.h"
+
+G_BEGIN_DECLS typedef struct _GIGenerator GIGenerator;
+typedef struct _CSymbol CSymbol;
+typedef struct _CType CType;
+typedef struct _CDirective CDirective;
+
+struct _GIGenerator
+{
+ /* parameters */
+ char *namespace;
+ char *shared_library;
+ char *lower_case_namespace;
+ gboolean verbose;
+
+ /* specified files to be parsed */
+ GList *filenames;
+ /* source reference of current lexer position */
+ char *current_filename;
+ GList *symbol_list;
+ GHashTable *typedef_table;
+ GHashTable *struct_or_union_or_enum_table;
+
+ GIdlModule *module;
+ GList *get_type_symbols;
+ GHashTable *type_map;
+ GHashTable *type_by_lower_case_prefix;
+
+ GHashTable *symbols; /* typename -> module.name */
+
+ /* scanner variables */
+ gboolean macro_scan;
+ GSList *directives; /* list of CDirective for the current symbol */
+};
+
+typedef enum
+{
+ CSYMBOL_TYPE_INVALID,
+ CSYMBOL_TYPE_CONST,
+ CSYMBOL_TYPE_OBJECT,
+ CSYMBOL_TYPE_FUNCTION,
+ CSYMBOL_TYPE_STRUCT,
+ CSYMBOL_TYPE_UNION,
+ CSYMBOL_TYPE_ENUM,
+ CSYMBOL_TYPE_TYPEDEF
+} CSymbolType;
+
+struct _CSymbol
+{
+ CSymbolType type;
+ int id;
+ char *ident;
+ CType *base_type;
+ gboolean const_int_set;
+ int const_int;
+ char *const_string;
+ GSList *directives; /* list of CDirective */
+};
+
+typedef enum
+{
+ CTYPE_INVALID,
+ CTYPE_VOID,
+ CTYPE_BASIC_TYPE,
+ CTYPE_TYPEDEF,
+ CTYPE_STRUCT,
+ CTYPE_UNION,
+ CTYPE_ENUM,
+ CTYPE_POINTER,
+ CTYPE_ARRAY,
+ CTYPE_FUNCTION
+} CTypeType;
+
+typedef enum
+{
+ STORAGE_CLASS_NONE = 0,
+ STORAGE_CLASS_TYPEDEF = 1 << 1,
+ STORAGE_CLASS_EXTERN = 1 << 2,
+ STORAGE_CLASS_STATIC = 1 << 3,
+ STORAGE_CLASS_AUTO = 1 << 4,
+ STORAGE_CLASS_REGISTER = 1 << 5
+} StorageClassSpecifier;
+
+typedef enum
+{
+ TYPE_QUALIFIER_NONE = 0,
+ TYPE_QUALIFIER_CONST = 1 << 1,
+ TYPE_QUALIFIER_RESTRICT = 1 << 2,
+ TYPE_QUALIFIER_VOLATILE = 1 << 3
+} TypeQualifier;
+
+typedef enum
+{
+ FUNCTION_NONE = 0,
+ FUNCTION_INLINE = 1 << 1
+} FunctionSpecifier;
+
+typedef enum
+{
+ UNARY_ADDRESS_OF,
+ UNARY_POINTER_INDIRECTION,
+ UNARY_PLUS,
+ UNARY_MINUS,
+ UNARY_BITWISE_COMPLEMENT,
+ UNARY_LOGICAL_NEGATION
+} UnaryOperator;
+
+struct _CType
+{
+ CTypeType type;
+ StorageClassSpecifier storage_class_specifier;
+ TypeQualifier type_qualifier;
+ FunctionSpecifier function_specifier;
+ char *name;
+ CType *base_type;
+ GList *child_list;
+};
+
+struct _CDirective {
+ char *name;
+ char *value;
+};
+
+CSymbol * csymbol_new (CSymbolType type);
+gboolean csymbol_get_const_boolean (CSymbol *symbol);
+void csymbol_free (CSymbol *symbol);
+CDirective * cdirective_new (const gchar *name,
+ const gchar *value);
+void cdirective_free (CDirective *directive);
+
+gboolean g_igenerator_parse_file (GIGenerator *igenerator,
+ FILE *file);
+void g_igenerator_set_verbose (GIGenerator *igenerator,
+ gboolean verbose);
+void g_igenerator_add_symbol (GIGenerator *igenerator,
+ CSymbol *symbol);
+gboolean g_igenerator_is_typedef (GIGenerator *igenerator,
+ const char *name);
+G_END_DECLS
+#endif
diff --git a/tools/scannerlexer.l b/tools/scannerlexer.l
new file mode 100644
index 00000000..114b736c
--- /dev/null
+++ b/tools/scannerlexer.l
@@ -0,0 +1,311 @@
+/* -*- Mode: C -*-
+/* GObject introspection: C lexer
+ *
+ * Copyright (c) 1997 Sandro Sigala <ssigala@globalnet.it>
+ * Copyright (c) 2007-2008 Jürg Billeter <j@bitron.ch>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+%{
+#include <ctype.h>
+#include <stdio.h>
+
+#include "scanner.h"
+#include "scannerparser.h"
+
+int lineno;
+
+extern int yylex (GIGenerator *igenerator);
+#define YY_DECL int yylex (GIGenerator *igenerator)
+static int yywrap (void);
+static void parse_comment (GIGenerator *igenerator);
+static void process_directive (GIGenerator *igenerator);
+static int check_identifier (GIGenerator *igenerator, const char *);
+%}
+
+intsuffix ([uU][lL]?)|([lL][uU]?)
+fracconst ([0-9]*\.[0-9]+)|([0-9]+\.)
+exppart [eE][-+]?[0-9]+
+floatsuffix [fFlL]
+chartext ([^\'])|(\\.)
+stringtext ([^\"])|(\\.)
+
+%%
+
+"\n" { ++lineno; } /* " */
+[\t\f\v\r ]+ { /* Ignore whitespace. */ }
+
+"/*" { parse_comment(igenerator); }
+"//".* { }
+
+"#define "[a-zA-Z_][a-zA-Z_0-9]*"(" { yyless (yyleng - 1); return FUNCTION_MACRO; }
+"#define "[a-zA-Z_][a-zA-Z_0-9]* { return OBJECT_MACRO; }
+
+"#" { process_directive(igenerator); }
+
+"{" { return '{'; }
+"<%" { return '{'; }
+"}" { return '}'; }
+"%>" { return '}'; }
+"[" { return '['; }
+"<:" { return '['; }
+"]" { return ']'; }
+":>" { return ']'; }
+"(" { return '('; }
+")" { return ')'; }
+";" { return ';'; }
+":" { return ':'; }
+"..." { return ELLIPSIS; }
+"?" { return '?'; }
+"." { return '.'; }
+"+" { return '+'; }
+"-" { return '-'; }
+"*" { return '*'; }
+"/" { return '/'; }
+"%" { return '%'; }
+"^" { return '^'; }
+"&" { return '&'; }
+"|" { return '|'; }
+"~" { return '~'; }
+"!" { return '!'; }
+"=" { return '='; }
+"<" { return '<'; }
+">" { return '>'; }
+"+=" { return ADDEQ; }
+"-=" { return SUBEQ; }
+"*=" { return MULEQ; }
+"/=" { return DIVEQ; }
+"%=" { return MODEQ; }
+"^=" { return XOREQ; }
+"&=" { return ANDEQ; }
+"|=" { return OREQ; }
+"<<" { return SL; }
+">>" { return SR; }
+"<<=" { return SLEQ; }
+">>=" { return SREQ; }
+"==" { return EQ; }
+"!=" { return NOTEQ; }
+"<=" { return LTEQ; }
+">=" { return GTEQ; }
+"&&" { return ANDAND; }
+"||" { return OROR; }
+"++" { return PLUSPLUS; }
+"--" { return MINUSMINUS; }
+"," { return ','; }
+"->" { return ARROW; }
+
+[a-zA-Z_][a-zA-Z_0-9]* { if (igenerator->macro_scan) return IDENTIFIER; else REJECT; }
+
+"auto" { return AUTO; }
+"break" { return BREAK; }
+"case" { return CASE; }
+"char" { return CHAR; }
+"const" { return CONST; }
+"continue" { return CONTINUE; }
+"default" { return DEFAULT; }
+"do" { return DO; }
+"double" { return DOUBLE; }
+"else" { return ELSE; }
+"enum" { return ENUM; }
+"extern" { return EXTERN; }
+"float" { return FLOAT; }
+"for" { return FOR; }
+"goto" { return GOTO; }
+"if" { return IF; }
+"inline" { return INLINE; }
+"int" { return INT; }
+"long" { return LONG; }
+"register" { return REGISTER; }
+"restrict" { return RESTRICT; }
+"return" { return RETURN; }
+"short" { return SHORT; }
+"signed" { return SIGNED; }
+"sizeof" { return SIZEOF; }
+"static" { return STATIC; }
+"struct" { return STRUCT; }
+"switch" { return SWITCH; }
+"typedef" { return TYPEDEF; }
+"union" { return UNION; }
+"unsigned" { return UNSIGNED; }
+"void" { return VOID; }
+"volatile" { return VOLATILE; }
+"while" { return WHILE; }
+
+[a-zA-Z_][a-zA-Z_0-9]* { return check_identifier(igenerator, yytext); }
+
+"0"[xX][0-9a-fA-F]+{intsuffix}? { return INTEGER; }
+"0"[0-7]+{intsuffix}? { return INTEGER; }
+[0-9]+{intsuffix}? { return INTEGER; }
+
+{fracconst}{exppart}?{floatsuffix}? { return FLOATING; }
+[0-9]+{exppart}{floatsuffix}? { return FLOATING; }
+
+"'"{chartext}*"'" { return CHARACTER; }
+"L'"{chartext}*"'" { return CHARACTER; }
+
+"\""{stringtext}*"\"" { return STRING; }
+"L\""{stringtext}*"\"" { return STRING; }
+
+. { fprintf(stderr, "%s:%d: unexpected character `%c'\n", igenerator->current_filename, lineno, yytext[0]); }
+
+%%
+
+static int yywrap (void)
+{
+ return 1;
+}
+
+static void parse_gtkdoc (GIGenerator *igenerator, int *c1, int *c2)
+{
+ gboolean isline = FALSE;
+ gchar line[256];
+ int i;
+ gchar **parts;
+ CDirective *directive;
+ char *name, *value;
+
+ i = 0;
+ do {
+ *c1 = *c2;
+ if (*c1 == '\n')
+ {
+ isline = TRUE;
+ break;
+ }
+ if (i >= 256)
+ break;
+ line[i++] = *c1;
+ *c2 = input();
+
+ } while (*c2 != EOF && !(*c1 == '*' && *c2 == '/'));
+
+ if (!isline)
+ return;
+
+ line[i] = '\0';
+
+ parts = g_strsplit (line, ": ", 2);
+
+ if (g_strv_length (parts) == 2)
+ {
+ name = parts[0];
+ value = parts[1];
+ }
+ else /* parts == 1 */
+ {
+ name = parts[0];
+ value = NULL;
+ }
+
+ directive = cdirective_new (name, value);
+ igenerator->directives = g_slist_prepend (igenerator->directives,
+ directive);
+
+ g_strfreev (parts);
+}
+
+static void parse_comment (GIGenerator *igenerator)
+{
+ int c1, c2;
+
+ c1 = input();
+ c2 = input();
+
+ while (c2 != EOF && !(c1 == '*' && c2 == '/'))
+ {
+ if (c1 == '\n')
+ ++lineno;
+ c1 = c2;
+ c2 = input();
+
+ if (c1 == ' ' && c2 == '@')
+ {
+ c1 = c2;
+ c2 = input();
+ parse_gtkdoc (igenerator, &c1, &c2);
+ }
+ }
+}
+
+static int check_identifier (GIGenerator *igenerator, const char *s)
+{
+ /*
+ * This function checks if `s' is a type name or an
+ * identifier.
+ */
+
+ if (g_igenerator_is_typedef (igenerator, s)) {
+ return TYPEDEF_NAME;
+ } else if (strcmp (s, "__builtin_va_list") == 0) {
+ return TYPEDEF_NAME;
+ }
+
+ return IDENTIFIER;
+}
+
+static void process_directive (GIGenerator *igenerator)
+{
+ /* extract current filename from #line directives */
+ GString *filename_builder;
+ gboolean in_string, found_filename;
+
+ lineno = 0;
+ found_filename = FALSE;
+ in_string = FALSE;
+ filename_builder = g_string_new ("");
+
+ int c = input ();
+ while (c != EOF && c != '\n') {
+ if (!in_string) {
+ if (c == '\"') {
+ in_string = TRUE;
+ found_filename = TRUE;
+ } else if (c >= '0' && c <= '9') {
+ if (!found_filename) {
+ lineno = lineno * 10 + (c - '0');
+ }
+ }
+ } else {
+ if (c == '\"') {
+ in_string = FALSE;
+ } else if (c == '\\') {
+ g_string_append_c (filename_builder, c);
+ c = input ();
+ g_string_append_c (filename_builder, c);
+ } else {
+ g_string_append_c (filename_builder, c);
+ }
+ }
+ c = input ();
+ }
+
+ if (filename_builder->len > 0) {
+ char *filename = g_strcompress (filename_builder->str);
+ g_free (igenerator->current_filename);
+ igenerator->current_filename = filename;
+ }
+
+ g_string_free (filename_builder, TRUE);
+}
+
diff --git a/tools/scannerparser.y b/tools/scannerparser.y
new file mode 100644
index 00000000..fae5067d
--- /dev/null
+++ b/tools/scannerparser.y
@@ -0,0 +1,1376 @@
+/* GObject introspection: C parser
+ *
+ * Copyright (c) 1997 Sandro Sigala <ssigala@globalnet.it>
+ * Copyright (c) 2007 Jürg Billeter <j@bitron.ch>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+%{
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "scanner.h"
+
+extern FILE *yyin;
+extern int lineno;
+extern char *yytext;
+
+extern int yylex (GIGenerator *igenerator);
+static void yyerror(GIGenerator *igenerator, const char *s);
+
+static int last_enum_value = -1;
+static GHashTable *const_table = NULL;
+
+CSymbol *
+csymbol_new (CSymbolType type)
+{
+ CSymbol *s = g_new0 (CSymbol, 1);
+ s->type = type;
+ return s;
+}
+
+static void
+ctype_free (CType * type)
+{
+ g_free (type);
+ g_free (type->name);
+ g_list_foreach (type->child_list, (GFunc)ctype_free, NULL);
+ g_list_free (type->child_list);
+}
+
+void
+csymbol_free (CSymbol * symbol)
+{
+ g_free (symbol->ident);
+ ctype_free (symbol->base_type);
+ g_free (symbol->const_string);
+ g_free (symbol);
+ g_slist_foreach (symbol->directives, (GFunc)cdirective_free, NULL);
+ g_slist_free (symbol->directives);
+}
+
+gboolean
+csymbol_get_const_boolean (CSymbol * symbol)
+{
+ return (symbol->const_int_set && symbol->const_int) || symbol->const_string;
+}
+
+CType *
+ctype_new (CTypeType type)
+{
+ CType *t = g_new0 (CType, 1);
+ t->type = type;
+ return t;
+}
+
+CType *
+ctype_copy (CType * type)
+{
+ return g_memdup (type, sizeof (CType));
+}
+
+CType *
+cbasic_type_new (const char *name)
+{
+ CType *basic_type = ctype_new (CTYPE_BASIC_TYPE);
+ basic_type->name = g_strdup (name);
+ return basic_type;
+}
+
+CType *
+ctypedef_new (const char *name)
+{
+ CType *typedef_ = ctype_new (CTYPE_TYPEDEF);
+ typedef_->name = g_strdup (name);
+ return typedef_;
+}
+
+CType *
+cstruct_new (const char *name)
+{
+ CType *struct_ = ctype_new (CTYPE_STRUCT);
+ struct_->name = g_strdup (name);
+ return struct_;
+}
+
+CType *
+cunion_new (const char *name)
+{
+ CType *union_ = ctype_new (CTYPE_UNION);
+ union_->name = g_strdup (name);
+ return union_;
+}
+
+CType *
+cenum_new (const char *name)
+{
+ CType *enum_ = ctype_new (CTYPE_ENUM);
+ enum_->name = g_strdup (name);
+ return enum_;
+}
+
+CType *
+cpointer_new (CType * base_type)
+{
+ CType *pointer = ctype_new (CTYPE_POINTER);
+ pointer->base_type = ctype_copy (base_type);
+ return pointer;
+}
+
+CType *
+carray_new (void)
+{
+ CType *array = ctype_new (CTYPE_ARRAY);
+ return array;
+}
+
+CType *
+cfunction_new (void)
+{
+ CType *func = ctype_new (CTYPE_FUNCTION);
+ return func;
+}
+
+/* use specified type as base type of symbol */
+static void
+csymbol_merge_type (CSymbol *symbol, CType *type)
+{
+ CType **foundation_type = &(symbol->base_type);
+ while (*foundation_type != NULL) {
+ foundation_type = &((*foundation_type)->base_type);
+ }
+ *foundation_type = ctype_copy (type);
+}
+
+CDirective *
+cdirective_new (const gchar *name,
+ const gchar *value)
+{
+ CDirective *directive;
+
+ directive = g_slice_new (CDirective);
+ directive->name = g_strdup (name);
+ directive->value = g_strdup (value);
+ return directive;
+}
+
+void
+cdirective_free (CDirective *directive)
+{
+ g_free (directive->name);
+ g_free (directive->value);
+ g_slice_free (CDirective, directive);
+}
+
+%}
+
+%error-verbose
+%union {
+ char *str;
+ GList *list;
+ CSymbol *symbol;
+ CType *ctype;
+ StorageClassSpecifier storage_class_specifier;
+ TypeQualifier type_qualifier;
+ FunctionSpecifier function_specifier;
+ UnaryOperator unary_operator;
+}
+
+%parse-param { GIGenerator* igenerator }
+%lex-param { GIGenerator* igenerator }
+
+%token <str> IDENTIFIER "identifier"
+%token <str> TYPEDEF_NAME "typedef-name"
+
+%token INTEGER FLOATING CHARACTER STRING
+
+%token ELLIPSIS ADDEQ SUBEQ MULEQ DIVEQ MODEQ XOREQ ANDEQ OREQ SL SR
+%token SLEQ SREQ EQ NOTEQ LTEQ GTEQ ANDAND OROR PLUSPLUS MINUSMINUS ARROW
+
+%token AUTO BREAK CASE CHAR CONST CONTINUE DEFAULT DO DOUBLE ELSE ENUM
+%token EXTERN FLOAT FOR GOTO IF INLINE INT LONG REGISTER RESTRICT RETURN SHORT
+%token SIGNED SIZEOF STATIC STRUCT SWITCH TYPEDEF UNION UNSIGNED VOID VOLATILE
+%token WHILE
+
+%token FUNCTION_MACRO OBJECT_MACRO
+
+%start translation_unit
+
+%type <ctype> declaration_specifiers
+%type <ctype> enum_specifier
+%type <ctype> pointer
+%type <ctype> specifier_qualifier_list
+%type <ctype> struct_or_union
+%type <ctype> struct_or_union_specifier
+%type <ctype> type_specifier
+%type <str> identifier
+%type <str> typedef_name
+%type <str> identifier_or_typedef_name
+%type <symbol> abstract_declarator
+%type <symbol> init_declarator
+%type <symbol> declarator
+%type <symbol> enumerator
+%type <symbol> direct_abstract_declarator
+%type <symbol> direct_declarator
+%type <symbol> parameter_declaration
+%type <symbol> struct_declarator
+%type <list> enumerator_list
+%type <list> identifier_list
+%type <list> init_declarator_list
+%type <list> parameter_type_list
+%type <list> parameter_list
+%type <list> struct_declaration
+%type <list> struct_declaration_list
+%type <list> struct_declarator_list
+%type <storage_class_specifier> storage_class_specifier
+%type <type_qualifier> type_qualifier
+%type <type_qualifier> type_qualifier_list
+%type <function_specifier> function_specifier
+%type <symbol> expression
+%type <symbol> constant_expression
+%type <symbol> conditional_expression
+%type <symbol> logical_and_expression
+%type <symbol> logical_or_expression
+%type <symbol> inclusive_or_expression
+%type <symbol> exclusive_or_expression
+%type <symbol> multiplicative_expression
+%type <symbol> additive_expression
+%type <symbol> shift_expression
+%type <symbol> relational_expression
+%type <symbol> equality_expression
+%type <symbol> and_expression
+%type <symbol> cast_expression
+%type <symbol> assignment_expression
+%type <symbol> unary_expression
+%type <symbol> postfix_expression
+%type <symbol> primary_expression
+%type <unary_operator> unary_operator
+%type <str> function_macro
+%type <str> object_macro
+%type <symbol> strings
+
+%%
+
+/* A.2.1 Expressions. */
+
+primary_expression
+ : identifier
+ {
+ $$ = g_hash_table_lookup (const_table, $1);
+ if ($$ == NULL) {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ }
+ | INTEGER
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ if (g_str_has_prefix (yytext, "0x") && strlen (yytext) > 2) {
+ $$->const_int = strtol (yytext + 2, NULL, 16);
+ } else if (g_str_has_prefix (yytext, "0") && strlen (yytext) > 1) {
+ $$->const_int = strtol (yytext + 1, NULL, 8);
+ } else {
+ $$->const_int = atoi (yytext);
+ }
+ }
+ | CHARACTER
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | FLOATING
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | strings
+ | '(' expression ')'
+ {
+ $$ = $2;
+ }
+ ;
+
+/* concatenate adjacent string literal tokens */
+strings
+ : STRING
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ yytext[strlen (yytext) - 1] = '\0';
+ $$->const_string = g_strcompress (yytext + 1);
+ }
+ | strings STRING
+ {
+ char *strings, *string2;
+ $$ = $1;
+ yytext[strlen (yytext) - 1] = '\0';
+ string2 = g_strcompress (yytext + 1);
+ strings = g_strconcat ($$->const_string, string2, NULL);
+ g_free ($$->const_string);
+ g_free (string2);
+ $$->const_string = strings;
+ }
+ ;
+
+identifier
+ : IDENTIFIER
+ {
+ $$ = g_strdup (yytext);
+ }
+ ;
+
+identifier_or_typedef_name
+ : identifier
+ | typedef_name
+ ;
+
+postfix_expression
+ : primary_expression
+ | postfix_expression '[' expression ']'
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | postfix_expression '(' argument_expression_list ')'
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | postfix_expression '(' ')'
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | postfix_expression '.' identifier_or_typedef_name
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | postfix_expression ARROW identifier_or_typedef_name
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | postfix_expression PLUSPLUS
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | postfix_expression MINUSMINUS
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ ;
+
+argument_expression_list
+ : assignment_expression
+ | argument_expression_list ',' assignment_expression
+ ;
+
+unary_expression
+ : postfix_expression
+ | PLUSPLUS unary_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | MINUSMINUS unary_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | unary_operator cast_expression
+ {
+ switch ($1) {
+ case UNARY_PLUS:
+ $$ = $2;
+ break;
+ case UNARY_MINUS:
+ $$ = $2;
+ $$->const_int = -$2->const_int;
+ break;
+ case UNARY_BITWISE_COMPLEMENT:
+ $$ = $2;
+ $$->const_int = ~$2->const_int;
+ break;
+ case UNARY_LOGICAL_NEGATION:
+ $$ = $2;
+ $$->const_int = !csymbol_get_const_boolean ($2);
+ break;
+ default:
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ break;
+ }
+ }
+ | SIZEOF unary_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | SIZEOF '(' type_name ')'
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ ;
+
+unary_operator
+ : '&'
+ {
+ $$ = UNARY_ADDRESS_OF;
+ }
+ | '*'
+ {
+ $$ = UNARY_POINTER_INDIRECTION;
+ }
+ | '+'
+ {
+ $$ = UNARY_PLUS;
+ }
+ | '-'
+ {
+ $$ = UNARY_MINUS;
+ }
+ | '~'
+ {
+ $$ = UNARY_BITWISE_COMPLEMENT;
+ }
+ | '!'
+ {
+ $$ = UNARY_LOGICAL_NEGATION;
+ }
+ ;
+
+cast_expression
+ : unary_expression
+ | '(' type_name ')' cast_expression
+ {
+ $$ = $4;
+ }
+ ;
+
+multiplicative_expression
+ : cast_expression
+ | multiplicative_expression '*' cast_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int * $3->const_int;
+ }
+ | multiplicative_expression '/' cast_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ if ($3->const_int != 0) {
+ $$->const_int = $1->const_int / $3->const_int;
+ }
+ }
+ | multiplicative_expression '%' cast_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int % $3->const_int;
+ }
+ ;
+
+additive_expression
+ : multiplicative_expression
+ | additive_expression '+' multiplicative_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int + $3->const_int;
+ }
+ | additive_expression '-' multiplicative_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int - $3->const_int;
+ }
+ ;
+
+shift_expression
+ : additive_expression
+ | shift_expression SL additive_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int << $3->const_int;
+ }
+ | shift_expression SR additive_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int >> $3->const_int;
+ }
+ ;
+
+relational_expression
+ : shift_expression
+ | relational_expression '<' shift_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int < $3->const_int;
+ }
+ | relational_expression '>' shift_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int > $3->const_int;
+ }
+ | relational_expression LTEQ shift_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int <= $3->const_int;
+ }
+ | relational_expression GTEQ shift_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int >= $3->const_int;
+ }
+ ;
+
+equality_expression
+ : relational_expression
+ | equality_expression EQ relational_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int == $3->const_int;
+ }
+ | equality_expression NOTEQ relational_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int != $3->const_int;
+ }
+ ;
+
+and_expression
+ : equality_expression
+ | and_expression '&' equality_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int & $3->const_int;
+ }
+ ;
+
+exclusive_or_expression
+ : and_expression
+ | exclusive_or_expression '^' and_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int ^ $3->const_int;
+ }
+ ;
+
+inclusive_or_expression
+ : exclusive_or_expression
+ | inclusive_or_expression '|' exclusive_or_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int | $3->const_int;
+ }
+ ;
+
+logical_and_expression
+ : inclusive_or_expression
+ | logical_and_expression ANDAND inclusive_or_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = csymbol_get_const_boolean ($1) && csymbol_get_const_boolean ($3);
+ }
+ ;
+
+logical_or_expression
+ : logical_and_expression
+ | logical_or_expression OROR logical_and_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = csymbol_get_const_boolean ($1) || csymbol_get_const_boolean ($3);
+ }
+ ;
+
+conditional_expression
+ : logical_or_expression
+ | logical_or_expression '?' expression ':' conditional_expression
+ {
+ $$ = csymbol_get_const_boolean ($1) ? $3 : $5;
+ }
+ ;
+
+assignment_expression
+ : conditional_expression
+ | unary_expression assignment_operator assignment_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ ;
+
+assignment_operator
+ : '='
+ | MULEQ
+ | DIVEQ
+ | MODEQ
+ | ADDEQ
+ | SUBEQ
+ | SLEQ
+ | SREQ
+ | ANDEQ
+ | XOREQ
+ | OREQ
+ ;
+
+expression
+ : assignment_expression
+ | expression ',' assignment_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ ;
+
+constant_expression
+ : conditional_expression
+ ;
+
+/* A.2.2 Declarations. */
+
+declaration
+ : declaration_specifiers init_declarator_list ';'
+ {
+ GList *l;
+ for (l = $2; l != NULL; l = l->next) {
+ CSymbol *sym = l->data;
+ csymbol_merge_type (sym, $1);
+ if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF) {
+ sym->type = CSYMBOL_TYPE_TYPEDEF;
+ } else if (sym->base_type->type == CTYPE_FUNCTION) {
+ sym->type = CSYMBOL_TYPE_FUNCTION;
+ } else {
+ sym->type = CSYMBOL_TYPE_OBJECT;
+ }
+ g_igenerator_add_symbol (igenerator, sym);
+ }
+ }
+ | declaration_specifiers ';'
+ ;
+
+declaration_specifiers
+ : storage_class_specifier declaration_specifiers
+ {
+ $$ = $2;
+ $$->storage_class_specifier |= $1;
+ }
+ | storage_class_specifier
+ {
+ $$ = ctype_new (CTYPE_INVALID);
+ $$->storage_class_specifier |= $1;
+ }
+ | type_specifier declaration_specifiers
+ {
+ $$ = $1;
+ $$->base_type = $2;
+ }
+ | type_specifier
+ | type_qualifier declaration_specifiers
+ {
+ $$ = $2;
+ $$->type_qualifier |= $1;
+ }
+ | type_qualifier
+ {
+ $$ = ctype_new (CTYPE_INVALID);
+ $$->type_qualifier |= $1;
+ }
+ | function_specifier declaration_specifiers
+ {
+ $$ = $2;
+ $$->function_specifier |= $1;
+ }
+ | function_specifier
+ {
+ $$ = ctype_new (CTYPE_INVALID);
+ $$->function_specifier |= $1;
+ }
+ ;
+
+init_declarator_list
+ : init_declarator
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | init_declarator_list ',' init_declarator
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+init_declarator
+ : declarator
+ | declarator '=' initializer
+ ;
+
+storage_class_specifier
+ : TYPEDEF
+ {
+ $$ = STORAGE_CLASS_TYPEDEF;
+ }
+ | EXTERN
+ {
+ $$ = STORAGE_CLASS_EXTERN;
+ }
+ | STATIC
+ {
+ $$ = STORAGE_CLASS_STATIC;
+ }
+ | AUTO
+ {
+ $$ = STORAGE_CLASS_AUTO;
+ }
+ | REGISTER
+ {
+ $$ = STORAGE_CLASS_REGISTER;
+ }
+ ;
+
+type_specifier
+ : VOID
+ {
+ $$ = ctype_new (CTYPE_VOID);
+ }
+ | CHAR
+ {
+ $$ = cbasic_type_new ("char");
+ }
+ | SHORT
+ {
+ $$ = cbasic_type_new ("short");
+ }
+ | INT
+ {
+ $$ = cbasic_type_new ("int");
+ }
+ | LONG
+ {
+ $$ = cbasic_type_new ("long");
+ }
+ | FLOAT
+ {
+ $$ = cbasic_type_new ("float");
+ }
+ | DOUBLE
+ {
+ $$ = cbasic_type_new ("double");
+ }
+ | SIGNED
+ {
+ $$ = cbasic_type_new ("signed");
+ }
+ | UNSIGNED
+ {
+ $$ = cbasic_type_new ("unsigned");
+ }
+ | struct_or_union_specifier
+ | enum_specifier
+ | typedef_name
+ {
+ $$ = ctypedef_new ($1);
+ }
+ ;
+
+struct_or_union_specifier
+ : struct_or_union identifier_or_typedef_name '{' struct_declaration_list '}'
+ {
+ $$ = $1;
+ $$->name = $2;
+ $$->child_list = $4;
+
+ CSymbol *sym = csymbol_new (CSYMBOL_TYPE_INVALID);
+ if ($$->type == CTYPE_STRUCT) {
+ sym->type = CSYMBOL_TYPE_STRUCT;
+ } else if ($$->type == CTYPE_UNION) {
+ sym->type = CSYMBOL_TYPE_UNION;
+ } else {
+ g_assert_not_reached ();
+ }
+ sym->ident = g_strdup ($$->name);
+ sym->base_type = ctype_copy ($$);
+ g_igenerator_add_symbol (igenerator, sym);
+ }
+ | struct_or_union '{' struct_declaration_list '}'
+ {
+ $$ = $1;
+ $$->child_list = $3;
+ }
+ | struct_or_union identifier_or_typedef_name
+ {
+ $$ = $1;
+ $$->name = $2;
+ }
+ ;
+
+struct_or_union
+ : STRUCT
+ {
+ $$ = cstruct_new (NULL);
+ }
+ | UNION
+ {
+ $$ = cunion_new (NULL);
+ }
+ ;
+
+struct_declaration_list
+ : struct_declaration
+ | struct_declaration_list struct_declaration
+ {
+ $$ = g_list_concat ($1, $2);
+ }
+ ;
+
+struct_declaration
+ : specifier_qualifier_list struct_declarator_list ';'
+ {
+ GList *l;
+ $$ = NULL;
+ for (l = $2; l != NULL; l = l->next) {
+ CSymbol *sym = l->data;
+ if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF) {
+ sym->type = CSYMBOL_TYPE_TYPEDEF;
+ }
+ csymbol_merge_type (sym, $1);
+ $$ = g_list_append ($$, sym);
+ }
+ }
+ ;
+
+specifier_qualifier_list
+ : type_specifier specifier_qualifier_list
+ {
+ $$ = $1;
+ $$->base_type = $2;
+ }
+ | type_specifier
+ | type_qualifier specifier_qualifier_list
+ {
+ $$ = $2;
+ $$->type_qualifier |= $1;
+ }
+ | type_qualifier
+ {
+ $$ = ctype_new (CTYPE_INVALID);
+ $$->type_qualifier |= $1;
+ }
+ ;
+
+struct_declarator_list
+ : struct_declarator
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | struct_declarator_list ',' struct_declarator
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+struct_declarator
+ : /* empty, support for anonymous structs and unions */
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | declarator
+ | ':' constant_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | declarator ':' constant_expression
+ ;
+
+enum_specifier
+ : ENUM identifier_or_typedef_name '{' enumerator_list '}'
+ {
+ $$ = cenum_new ($2);
+ $$->child_list = $4;
+ last_enum_value = -1;
+ }
+ | ENUM '{' enumerator_list '}'
+ {
+ $$ = cenum_new (NULL);
+ $$->child_list = $3;
+ last_enum_value = -1;
+ }
+ | ENUM identifier_or_typedef_name '{' enumerator_list ',' '}'
+ {
+ $$ = cenum_new ($2);
+ $$->child_list = $4;
+ last_enum_value = -1;
+ }
+ | ENUM '{' enumerator_list ',' '}'
+ {
+ $$ = cenum_new (NULL);
+ $$->child_list = $3;
+ last_enum_value = -1;
+ }
+ | ENUM identifier_or_typedef_name
+ {
+ $$ = cenum_new ($2);
+ }
+ ;
+
+enumerator_list
+ : enumerator
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | enumerator_list ',' enumerator
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+enumerator
+ : identifier
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_OBJECT);
+ $$->ident = $1;
+ $$->const_int_set = TRUE;
+ $$->const_int = ++last_enum_value;
+ g_hash_table_insert (const_table, g_strdup ($$->ident), $$);
+ }
+ | identifier '=' constant_expression
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_OBJECT);
+ $$->ident = $1;
+ $$->const_int_set = TRUE;
+ $$->const_int = $3->const_int;
+ last_enum_value = $$->const_int;
+ g_hash_table_insert (const_table, g_strdup ($$->ident), $$);
+ }
+ ;
+
+type_qualifier
+ : CONST
+ {
+ $$ = TYPE_QUALIFIER_CONST;
+ }
+ | RESTRICT
+ {
+ $$ = TYPE_QUALIFIER_RESTRICT;
+ }
+ | VOLATILE
+ {
+ $$ = TYPE_QUALIFIER_VOLATILE;
+ }
+ ;
+
+function_specifier
+ : INLINE
+ {
+ $$ = FUNCTION_INLINE;
+ }
+ ;
+
+declarator
+ : pointer direct_declarator
+ {
+ $$ = $2;
+ csymbol_merge_type ($$, $1);
+ }
+ | direct_declarator
+ ;
+
+direct_declarator
+ : identifier
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ $$->ident = $1;
+ }
+ | '(' declarator ')'
+ {
+ $$ = $2;
+ }
+ | direct_declarator '[' assignment_expression ']'
+ {
+ $$ = $1;
+ csymbol_merge_type ($$, carray_new ());
+ }
+ | direct_declarator '[' ']'
+ {
+ $$ = $1;
+ csymbol_merge_type ($$, carray_new ());
+ }
+ | direct_declarator '(' parameter_type_list ')'
+ {
+ CType *func = cfunction_new ();
+ // ignore (void) parameter list
+ if ($3 != NULL && ($3->next != NULL || ((CSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
+ func->child_list = $3;
+ }
+ $$ = $1;
+ csymbol_merge_type ($$, func);
+ }
+ | direct_declarator '(' identifier_list ')'
+ {
+ CType *func = cfunction_new ();
+ func->child_list = $3;
+ $$ = $1;
+ csymbol_merge_type ($$, func);
+ }
+ | direct_declarator '(' ')'
+ {
+ CType *func = cfunction_new ();
+ $$ = $1;
+ csymbol_merge_type ($$, func);
+ }
+ ;
+
+pointer
+ : '*' type_qualifier_list
+ {
+ $$ = cpointer_new (NULL);
+ $$->type_qualifier = $2;
+ }
+ | '*'
+ {
+ $$ = cpointer_new (NULL);
+ }
+ | '*' type_qualifier_list pointer
+ {
+ $$ = cpointer_new ($3);
+ $$->type_qualifier = $2;
+ }
+ | '*' pointer
+ {
+ $$ = cpointer_new ($2);
+ }
+ ;
+
+type_qualifier_list
+ : type_qualifier
+ | type_qualifier_list type_qualifier
+ {
+ $$ = $1 | $2;
+ }
+ ;
+
+parameter_type_list
+ : parameter_list
+ | parameter_list ',' ELLIPSIS
+ ;
+
+parameter_list
+ : parameter_declaration
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | parameter_list ',' parameter_declaration
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+parameter_declaration
+ : declaration_specifiers declarator
+ {
+ $$ = $2;
+ csymbol_merge_type ($$, $1);
+ }
+ | declaration_specifiers abstract_declarator
+ {
+ $$ = $2;
+ csymbol_merge_type ($$, $1);
+ }
+ | declaration_specifiers
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ $$->base_type = $1;
+ }
+ ;
+
+identifier_list
+ : identifier
+ {
+ CSymbol *sym = csymbol_new (CSYMBOL_TYPE_INVALID);
+ sym->ident = $1;
+ $$ = g_list_append (NULL, sym);
+ }
+ | identifier_list ',' identifier
+ {
+ CSymbol *sym = csymbol_new (CSYMBOL_TYPE_INVALID);
+ sym->ident = $3;
+ $$ = g_list_append ($1, sym);
+ }
+ ;
+
+type_name
+ : specifier_qualifier_list
+ | specifier_qualifier_list abstract_declarator
+ ;
+
+abstract_declarator
+ : pointer
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ csymbol_merge_type ($$, $1);
+ }
+ | direct_abstract_declarator
+ | pointer direct_abstract_declarator
+ {
+ $$ = $2;
+ csymbol_merge_type ($$, $1);
+ }
+ ;
+
+direct_abstract_declarator
+ : '(' abstract_declarator ')'
+ {
+ $$ = $2;
+ }
+ | '[' ']'
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ csymbol_merge_type ($$, carray_new ());
+ }
+ | '[' assignment_expression ']'
+ {
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ csymbol_merge_type ($$, carray_new ());
+ }
+ | direct_abstract_declarator '[' ']'
+ {
+ $$ = $1;
+ csymbol_merge_type ($$, carray_new ());
+ }
+ | direct_abstract_declarator '[' assignment_expression ']'
+ {
+ $$ = $1;
+ csymbol_merge_type ($$, carray_new ());
+ }
+ | '(' ')'
+ {
+ CType *func = cfunction_new ();
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ csymbol_merge_type ($$, func);
+ }
+ | '(' parameter_type_list ')'
+ {
+ CType *func = cfunction_new ();
+ // ignore (void) parameter list
+ if ($2 != NULL && ($2->next != NULL || ((CSymbol *) $2->data)->base_type->type != CTYPE_VOID)) {
+ func->child_list = $2;
+ }
+ $$ = csymbol_new (CSYMBOL_TYPE_INVALID);
+ csymbol_merge_type ($$, func);
+ }
+ | direct_abstract_declarator '(' ')'
+ {
+ CType *func = cfunction_new ();
+ $$ = $1;
+ csymbol_merge_type ($$, func);
+ }
+ | direct_abstract_declarator '(' parameter_type_list ')'
+ {
+ CType *func = cfunction_new ();
+ // ignore (void) parameter list
+ if ($3 != NULL && ($3->next != NULL || ((CSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
+ func->child_list = $3;
+ }
+ $$ = $1;
+ csymbol_merge_type ($$, func);
+ }
+ ;
+
+typedef_name
+ : TYPEDEF_NAME
+ {
+ $$ = g_strdup (yytext);
+ }
+ ;
+
+initializer
+ : assignment_expression
+ | '{' initializer_list '}'
+ | '{' initializer_list ',' '}'
+ ;
+
+initializer_list
+ : initializer
+ | initializer_list ',' initializer
+ ;
+
+/* A.2.3 Statements. */
+
+statement
+ : labeled_statement
+ | compound_statement
+ | expression_statement
+ | selection_statement
+ | iteration_statement
+ | jump_statement
+ ;
+
+labeled_statement
+ : identifier_or_typedef_name ':' statement
+ | CASE constant_expression ':' statement
+ | DEFAULT ':' statement
+ ;
+
+compound_statement
+ : '{' '}'
+ | '{' block_item_list '}'
+ ;
+
+block_item_list
+ : block_item
+ | block_item_list block_item
+ ;
+
+block_item
+ : declaration
+ | statement
+ ;
+
+expression_statement
+ : ';'
+ | expression ';'
+ ;
+
+selection_statement
+ : IF '(' expression ')' statement
+ | IF '(' expression ')' statement ELSE statement
+ | SWITCH '(' expression ')' statement
+ ;
+
+iteration_statement
+ : WHILE '(' expression ')' statement
+ | DO statement WHILE '(' expression ')' ';'
+ | FOR '(' ';' ';' ')' statement
+ | FOR '(' expression ';' ';' ')' statement
+ | FOR '(' ';' expression ';' ')' statement
+ | FOR '(' expression ';' expression ';' ')' statement
+ | FOR '(' ';' ';' expression ')' statement
+ | FOR '(' expression ';' ';' expression ')' statement
+ | FOR '(' ';' expression ';' expression ')' statement
+ | FOR '(' expression ';' expression ';' expression ')' statement
+ ;
+
+jump_statement
+ : GOTO identifier_or_typedef_name ';'
+ | CONTINUE ';'
+ | BREAK ';'
+ | RETURN ';'
+ | RETURN expression ';'
+ ;
+
+/* A.2.4 External definitions. */
+
+translation_unit
+ : external_declaration
+ | translation_unit external_declaration
+ ;
+
+external_declaration
+ : function_definition
+ | declaration
+ | macro
+ ;
+
+function_definition
+ : declaration_specifiers declarator declaration_list compound_statement
+ | declaration_specifiers declarator compound_statement
+ ;
+
+declaration_list
+ : declaration
+ | declaration_list declaration
+ ;
+
+/* Macros */
+
+function_macro
+ : FUNCTION_MACRO
+ {
+ $$ = g_strdup (yytext + strlen ("#define "));
+ }
+ ;
+
+object_macro
+ : OBJECT_MACRO
+ {
+ $$ = g_strdup (yytext + strlen ("#define "));
+ }
+ ;
+
+function_macro_define
+ : function_macro '(' identifier_list ')'
+ ;
+
+object_macro_define
+ : object_macro constant_expression
+ {
+ if ($2->const_int_set || $2->const_string != NULL) {
+ $2->ident = $1;
+ g_igenerator_add_symbol (igenerator, $2);
+ }
+ }
+ ;
+
+macro
+ : function_macro_define
+ | object_macro_define
+ | error
+ ;
+
+%%
+
+static void
+yyerror (GIGenerator *igenerator, const char *s)
+{
+ /* ignore errors while doing a macro scan as not all object macros
+ * have valid expressions */
+ if (!igenerator->macro_scan)
+ {
+ fprintf(stderr, "%s:%d: %s\n",
+ igenerator->current_filename, lineno, s);
+ }
+}
+
+gboolean
+g_igenerator_parse_file (GIGenerator *igenerator, FILE *file)
+{
+ g_return_val_if_fail (file != NULL, FALSE);
+
+ const_table = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+
+ lineno = 1;
+ yyin = file;
+ yyparse (igenerator);
+
+ g_hash_table_destroy (const_table);
+ const_table = NULL;
+
+ yyin = NULL;
+
+ return TRUE;
+}
+
+