summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorOlivier CrĂȘte <olivier.crete@collabora.co.uk>2008-09-19 14:52:01 -0400
committerOlivier CrĂȘte <olivier.crete@collabora.co.uk>2008-09-19 17:30:52 -0400
commitc383f26e8c5c11a1f7b6628a87a9a40529e6ddc8 (patch)
tree60811ed2919f29d8c0aa3c500d9261f579f3fa58 /common
parent371d353c3a5382e3b9a814769d29249dc58f245a (diff)
downloadfarstream-c383f26e8c5c11a1f7b6628a87a9a40529e6ddc8.tar.gz
Add gst plugin documentation scripts imported from the gst cvs
Diffstat (limited to 'common')
-rw-r--r--common/gst-xmlinspect.py168
-rwxr-xr-xcommon/gstdoc-scangobj1644
-rw-r--r--common/gtk-doc-plugins.mak384
-rw-r--r--common/mangle-tmpl.py158
-rw-r--r--common/plugins.xsl209
-rwxr-xr-xcommon/scangobj-merge.py278
6 files changed, 2841 insertions, 0 deletions
diff --git a/common/gst-xmlinspect.py b/common/gst-xmlinspect.py
new file mode 100644
index 00000000..0d7f6961
--- /dev/null
+++ b/common/gst-xmlinspect.py
@@ -0,0 +1,168 @@
+# -*- Mode: Python -*-
+# vi:si:et:sw=4:sts=4:ts=4
+
+"""
+examine all plugins and elements and output xml documentation for them
+used as part of the plugin documentation build
+"""
+
+import sys
+import os
+import pygst
+pygst.require('0.10')
+import gst
+
+INDENT_SIZE = 2
+
+# all templates
+
+PAD_TEMPLATE = """<caps>
+ <name>%(name)s</name>
+ <direction>%(direction)s</direction>
+ <presence>%(presence)s</presence>
+ <details>%(details)s</details>
+</caps>"""
+
+ELEMENT_TEMPLATE = """<element>
+ <name>%(name)s</name>
+ <longname>%(longname)s</longname>
+ <class>%(class)s</class>
+ <description>%(description)s</description>
+ <author>%(author)s</author>
+ <pads>
+%(pads)s
+ </pads>
+</element>"""
+
+PLUGIN_TEMPLATE = """<plugin>
+ <name>%(name)s</name>
+ <description>%(description)s</description>
+ <filename>%(filename)s</filename>
+ <basename>%(basename)s</basename>
+ <version>%(version)s</version>
+ <license>%(license)s</license>
+ <source>%(source)s</source>
+ <package>%(package)s</package>
+ <origin>%(origin)s</origin>
+ <elements>
+%(elements)s
+ </elements>
+</plugin>"""
+
+def xmlencode(line):
+ """
+ Replace &, <, and >
+ """
+ line = "&amp;".join(line.split("&"))
+ line = "&lt;".join(line.split("<"))
+ line = "&gt;".join(line.split(">"))
+ return line
+
+def get_offset(indent):
+ return " " * INDENT_SIZE * indent
+
+def output_pad_template(pt, indent=0):
+ print "PAD TEMPLATE", pt.name_template
+ paddir = ("unknown","source","sink")
+ padpres = ("always","sometimes","request")
+
+ d = {
+ 'name': xmlencode(pt.name_template),
+ 'direction': xmlencode(paddir[pt.direction]),
+ 'presence': xmlencode(padpres[pt.presence]),
+ 'details': xmlencode(pt.static_caps.string),
+ }
+ block = PAD_TEMPLATE % d
+
+ offset = get_offset(indent)
+ return offset + ("\n" + offset).join(block.split("\n"))
+
+def output_element_factory(elf, indent=0):
+ print "ELEMENT", elf.get_name()
+
+ padsoutput = []
+ padtemplates = elf.get_static_pad_templates()
+ for padtemplate in padtemplates:
+ padsoutput.append(output_pad_template(padtemplate, indent))
+
+ d = {
+ 'name': xmlencode(elf.get_name()),
+ 'longname': xmlencode(elf.get_longname()),
+ 'class': xmlencode(elf.get_klass()),
+ 'description': xmlencode(elf.get_description()),
+ 'author': xmlencode(elf.get_author()),
+ 'pads': "\n".join(padsoutput),
+ }
+ block = ELEMENT_TEMPLATE % d
+
+ offset = get_offset(indent)
+ return offset + ("\n" + offset).join(block.split("\n"))
+
+def output_plugin(plugin, indent=0):
+ print "PLUGIN", plugin.get_name()
+ version = plugin.get_version()
+
+ elements = {}
+ gst.debug('getting features for plugin %s' % plugin.get_name())
+ registry = gst.registry_get_default()
+ features = registry.get_feature_list_by_plugin(plugin.get_name())
+ gst.debug('plugin %s has %d features' % (plugin.get_name(), len(features)))
+ for feature in features:
+ if isinstance(feature, gst.ElementFactory):
+ elements[feature.get_name()] = feature
+ #gst.debug("got features")
+
+ elementsoutput = []
+ keys = elements.keys()
+ keys.sort()
+ for name in keys:
+ feature = elements[name]
+ elementsoutput.append(output_element_factory(feature, indent + 2))
+
+ filename = plugin.get_filename()
+ basename = filename
+ if basename:
+ basename = os.path.basename(basename)
+ d = {
+ 'name': xmlencode(plugin.get_name()),
+ 'description': xmlencode(plugin.get_description()),
+ 'filename': filename,
+ 'basename': basename,
+ 'version': version,
+ 'license': xmlencode(plugin.get_license()),
+ 'source': xmlencode(plugin.get_source()),
+ 'package': xmlencode(plugin.get_package()),
+ 'origin': xmlencode(plugin.get_origin()),
+ 'elements': "\n".join(elementsoutput),
+ }
+ block = PLUGIN_TEMPLATE % d
+
+ offset = get_offset(indent)
+ return offset + ("\n" + offset).join(block.split("\n"))
+
+def main():
+ if len(sys.argv) == 1:
+ sys.stderr.write("Please specify a source module to inspect")
+ sys.exit(1)
+ source = sys.argv[1]
+
+ if len(sys.argv) > 2:
+ os.chdir(sys.argv[2])
+
+ registry = gst.registry_get_default()
+ all = registry.get_plugin_list()
+ for plugin in all:
+ gst.debug("inspecting plugin %s from source %s" % (
+ plugin.get_name(), plugin.get_source()))
+ # this skips gstcoreelements, with bin and pipeline
+ if plugin.get_filename() is None:
+ continue
+ if plugin.get_source() != source:
+ continue
+
+ filename = "plugin-%s.xml" % plugin.get_name()
+ handle = open(filename, "w")
+ handle.write(output_plugin(plugin))
+ handle.close()
+
+main()
diff --git a/common/gstdoc-scangobj b/common/gstdoc-scangobj
new file mode 100755
index 00000000..cb7b731c
--- /dev/null
+++ b/common/gstdoc-scangobj
@@ -0,0 +1,1644 @@
+#!/usr/bin/perl -w
+# -*- cperl -*-
+#
+# gtk-doc - GTK DocBook documentation generator.
+# Copyright (C) 1998 Damon Chaplin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+#
+# This gets information about object heirarchies and signals
+# by compiling a small C program. CFLAGS and LDFLAGS must be
+# set appropriately before running this script.
+#
+# NOTE: the lookup_signal_arg_names() function contains the argument names of
+# standard GTK signal handlers. This may need to be updated for new
+# GTK signals or Gnome widget signals.
+
+use Getopt::Long;
+
+unshift @INC, '/usr/share/gtk-doc/data';
+require "gtkdoc-common.pl";
+
+# Options
+
+# name of documentation module
+my $MODULE;
+my $OUTPUT_DIR;
+my $PRINT_VERSION;
+my $PRINT_HELP;
+my $TYPE_INIT_FUNC="g_type_init ()";
+
+# --nogtkinit is deprecated, as it is the default now anyway.
+%optctl = (module => \$MODULE,
+ source => \$SOURCE,
+ types => \$TYPES_FILE,
+ nogtkinit => \$NO_GTK_INIT,
+ 'type-init-func' => \$TYPE_INIT_FUNC,
+ 'output-dir' => \$OUTPUT_DIR,
+ 'version' => \$PRINT_VERSION,
+ 'help' => \$PRINT_HELP);
+
+GetOptions(\%optctl, "module=s", "source=s", "types:s", "output-dir:s", "nogtkinit", "type-init-func:s", "version", "help");
+
+if ($NO_GTK_INIT) {
+ # Do nothing. This just avoids a warning.
+}
+
+if ($PRINT_VERSION) {
+ print "1.5\n";
+ exit 0;
+}
+
+if (!$MODULE) {
+ $PRINT_HELP = 1;
+}
+
+if ($PRINT_HELP) {
+ print "gstdoc-scangobj version 1.5\n";
+ print "\n--module=MODULE_NAME Name of the doc module being parsed";
+ print "\n--source=SOURCE_NAME Name of the source module for plugins";
+ print "\n--types=FILE The name of the file to store the types in";
+ print "\n--type-init-func=FUNC The init function to call instead of g_type_init ()";
+ print "\n--output-dir=DIRNAME The directory where the results are stored";
+ print "\n--version Print the version of this program";
+ print "\n--help Print this help\n";
+ exit 0;
+}
+
+$OUTPUT_DIR = $OUTPUT_DIR ? $OUTPUT_DIR : ".";
+
+$TYPES_FILE = $TYPES_FILE ? $TYPES_FILE : "$OUTPUT_DIR/$MODULE.types";
+
+open (TYPES, $TYPES_FILE) || die "Cannot open $TYPES_FILE: $!\n";
+open (OUTPUT, ">$MODULE-scan.c") || die "Cannot open $MODULE-scan.c: $!\n";
+
+my $old_signals_filename = "$OUTPUT_DIR/$MODULE.signals";
+my $new_signals_filename = "$OUTPUT_DIR/$MODULE.signals.new";
+my $old_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy";
+my $new_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy.new";
+my $old_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces";
+my $new_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces.new";
+my $old_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites";
+my $new_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites.new";
+my $old_args_filename = "$OUTPUT_DIR/$MODULE.args";
+my $new_args_filename = "$OUTPUT_DIR/$MODULE.args.new";
+
+# write a C program to scan the types
+
+$includes = "";
+@types = ();
+@impl_types = ();
+
+for (<TYPES>) {
+ if (/^#include/) {
+ $includes .= $_;
+ } elsif (/^%/) {
+ next;
+ } elsif (/^\s*$/) {
+ next;
+ } elsif (/^type:(.*)$/) {
+ $t = $1;
+ chomp $t;
+ push @impl_types, $t;
+ } else {
+ chomp;
+ push @types, $_;
+ }
+}
+
+$ntypes = @types + @impl_types;
+
+print OUTPUT <<EOT;
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+$includes
+
+#ifdef GTK_IS_WIDGET_CLASS
+#include <gtk/gtkversion.h>
+#endif
+GType *object_types = NULL;
+
+static GType *
+get_object_types (void)
+{
+ GList *plugins = NULL;
+ GList *factories = NULL;
+ GList *l;
+ GstElementFactory *factory = NULL;
+ GType type;
+
+ gint i = 0;
+
+ /* get a list of features from plugins in our source module */
+ plugins = gst_registry_get_plugin_list (gst_registry_get_default());
+
+ while (plugins) {
+ GList *features;
+ GstPlugin *plugin;
+ const gchar *source;
+
+ plugin = (GstPlugin *) (plugins->data);
+ plugins = g_list_next (plugins);
+ source = gst_plugin_get_source (plugin);
+ /*g_print ("plugin: %s source: %s\\n", plugin->desc.name, source);*/
+ if (!source || strcmp (source, "$SOURCE") != 0) {
+ continue;
+ }
+ g_print ("plugin: %s source: %s\\n", plugin->desc.name, source);
+
+ features =
+ gst_registry_get_feature_list_by_plugin (gst_registry_get_default (),
+ plugin->desc.name);
+ while (features) {
+ GstPluginFeature *feature;
+ feature = GST_PLUGIN_FEATURE (features->data);
+ feature = gst_plugin_feature_load (feature);
+ if (!feature) {
+ g_warning ("Could not load plugin feature %s",
+ gst_plugin_feature_get_name (feature));
+ }
+
+ if (GST_IS_ELEMENT_FACTORY (feature)) {
+ factory = GST_ELEMENT_FACTORY (feature);
+ factories = g_list_prepend (factories, factory);
+ }
+ features = g_list_next (features);
+ }
+ }
+
+ g_message ("number of element factories: %d", g_list_length (factories));
+
+ /* allocate the object_types array to hold them */
+ object_types = g_new0 (GType, g_list_length (factories)+$ntypes+1);
+
+ l = factories;
+ i = 0;
+
+ /* fill it */
+ while (l) {
+ factory = GST_ELEMENT_FACTORY (l->data);
+ type = gst_element_factory_get_element_type (factory);
+ if (type != 0) {
+ g_message ("adding type %p for factory %s", (void *) type, gst_element_factory_get_longname (factory));
+ object_types[i++] = type;
+ } else {
+ g_message ("type info for factory %s not found",
+ gst_element_factory_get_longname (factory));
+ }
+ l = g_list_next (l);
+ }
+
+EOT
+
+# get_type functions:
+for (@types) {
+print OUTPUT <<EOT;
+ type = $_ ();
+ if (type == 0) {
+ g_message ("$_ () didn't return a valid type");
+ }
+ else {
+ object_types[i++] = type;
+ }
+EOT
+}
+
+# Implicit types retrieved from GLib:
+for (@impl_types) {
+print OUTPUT <<EOT;
+ type = g_type_from_name ("$_");
+ if (type == 0) {
+ g_message ("Implicit type $_ not found");
+ }
+ else {
+ object_types[i++] = type;
+ }
+EOT
+}
+
+print OUTPUT <<EOT;
+
+ object_types[i] = 0;
+
+ /* Need to make sure all the types are loaded in and initialize
+ * their signals and properties.
+ */
+ for (i=0; object_types[i]; i++) {
+ if (G_TYPE_IS_CLASSED (object_types[i]))
+ g_type_class_ref (object_types[i]);
+ else {
+ g_warning ("not reffing type: %s", g_type_name (object_types[i]));
+ }
+ }
+
+ return object_types;
+}
+
+/*
+ * This uses GObject type functions to output signal prototypes and the object
+ * hierarchy.
+ */
+
+/* The output files */
+const gchar *signals_filename = "$new_signals_filename";
+const gchar *hierarchy_filename = "$new_hierarchy_filename";
+const gchar *interfaces_filename = "$new_interfaces_filename";
+const gchar *prerequisites_filename = "$new_prerequisites_filename";
+const gchar *args_filename = "$new_args_filename";
+
+
+static void output_signals (void);
+static void output_object_signals (FILE *fp,
+ GType object_type);
+static void output_object_signal (FILE *fp,
+ const gchar *object_class_name,
+ guint signal_id);
+static const gchar * get_type_name (GType type,
+ gboolean * is_pointer);
+static const gchar * get_gdk_event (const gchar * signal_name);
+static const gchar ** lookup_signal_arg_names (const gchar * type,
+ const gchar * signal_name);
+
+static void output_object_hierarchy (void);
+static void output_hierarchy (FILE *fp,
+ GType type,
+ guint level);
+
+static void output_object_interfaces (void);
+static void output_interfaces (FILE *fp,
+ GType type);
+
+static void output_interface_prerequisites (void);
+static void output_prerequisites (FILE *fp,
+ GType type);
+
+static void output_args (void);
+static void output_object_args (FILE *fp, GType object_type);
+
+int
+main (int argc, char *argv[])
+{
+ /* Silence the compiler: */
+ if (argv != argv) argc = argc;
+
+ $TYPE_INIT_FUNC;
+
+ get_object_types ();
+
+ output_signals ();
+ output_object_hierarchy ();
+ output_object_interfaces ();
+ output_interface_prerequisites ();
+ output_args ();
+
+ return 0;
+}
+
+
+static void
+output_signals (void)
+{
+ FILE *fp;
+ gint i;
+
+ fp = fopen (signals_filename, "w");
+ if (fp == NULL)
+ {
+ g_warning ("Couldn't open output file: %s : %s", signals_filename, strerror(errno));
+ return;
+ }
+
+ for (i = 0; object_types[i]; i++)
+ output_object_signals (fp, object_types[i]);
+
+ fclose (fp);
+}
+
+static gint
+compare_signals (const void *a, const void *b)
+{
+ const guint *signal_a = a;
+ const guint *signal_b = b;
+
+ return strcmp (g_signal_name (*signal_a), g_signal_name (*signal_b));
+}
+
+/* This outputs all the signals of one object. */
+static void
+output_object_signals (FILE *fp, GType object_type)
+{
+ const gchar *object_class_name;
+ guint *signals, n_signals;
+ guint sig;
+
+ if (G_TYPE_IS_INSTANTIATABLE (object_type) ||
+ G_TYPE_IS_INTERFACE (object_type))
+ {
+
+ object_class_name = g_type_name (object_type);
+
+ signals = g_signal_list_ids (object_type, &n_signals);
+ qsort (signals, n_signals, sizeof (guint), compare_signals);
+
+ for (sig = 0; sig < n_signals; sig++)
+ {
+ output_object_signal (fp, object_class_name, signals[sig]);
+ }
+ g_free (signals);
+ }
+}
+
+
+/* This outputs one signal. */
+static void
+output_object_signal (FILE *fp,
+ const gchar *object_name,
+ guint signal_id)
+{
+ GSignalQuery query_info;
+ const gchar *type_name, *ret_type, *object_arg, *arg_name;
+ gchar *pos, *object_arg_lower;
+ gboolean is_pointer;
+ gchar ret_type_buffer[1024], buffer[1024];
+ guint i, param;
+ const gchar **arg_names;
+ gint param_num, widget_num, event_num, callback_num;
+ gint *arg_num;
+ gchar signal_name[128];
+ gchar flags[16];
+
+ /* g_print ("Object: %s Signal: %u\\n", object_name, signal_id);*/
+
+ param_num = 1;
+ widget_num = event_num = callback_num = 0;
+
+ g_signal_query (signal_id, &query_info);
+
+ /* Output the return type and function name. */
+ ret_type = get_type_name (query_info.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE, &is_pointer);
+ sprintf (ret_type_buffer, "%s%s", ret_type, is_pointer ? "*" : "");
+
+ /* Output the signal object type and the argument name. We assume the
+ type is a pointer - I think that is OK. We remove "Gtk" or "Gnome" and
+ convert to lower case for the argument name. */
+ pos = buffer;
+ sprintf (pos, "%s ", object_name);
+ pos += strlen (pos);
+
+ if (!strncmp (object_name, "Gtk", 3))
+ object_arg = object_name + 3;
+ else if (!strncmp (object_name, "Gnome", 5))
+ object_arg = object_name + 5;
+ else
+ object_arg = object_name;
+
+ object_arg_lower = g_ascii_strdown (object_arg, -1);
+ sprintf (pos, "*%s\\n", object_arg_lower);
+ pos += strlen (pos);
+ if (!strncmp (object_arg_lower, "widget", 6))
+ widget_num = 2;
+ g_free(object_arg_lower);
+
+ /* Convert signal name to use underscores rather than dashes '-'. */
+ strcpy (signal_name, query_info.signal_name);
+ for (i = 0; signal_name[i]; i++)
+ {
+ if (signal_name[i] == '-')
+ signal_name[i] = '_';
+ }
+
+ /* Output the signal parameters. */
+ arg_names = lookup_signal_arg_names (object_name, signal_name);
+
+ for (param = 0; param < query_info.n_params; param++)
+ {
+ if (arg_names)
+ {
+ sprintf (pos, "%s\\n", arg_names[param]);
+ pos += strlen (pos);
+ }
+ else
+ {
+ type_name = get_type_name (query_info.param_types[param] & ~G_SIGNAL_TYPE_STATIC_SCOPE, &is_pointer);
+
+ /* Most arguments to the callback are called "arg1", "arg2", etc.
+ GdkWidgets are called "widget", "widget2", ...
+ GdkEvents are called "event", "event2", ...
+ GtkCallbacks are called "callback", "callback2", ... */
+ if (!strcmp (type_name, "GtkWidget"))
+ {
+ arg_name = "widget";
+ arg_num = &widget_num;
+ }
+ else if (!strcmp (type_name, "GdkEvent"))
+ {
+ type_name = get_gdk_event (signal_name);
+ arg_name = "event";
+ arg_num = &event_num;
+ is_pointer = TRUE;
+ }
+ else if (!strcmp (type_name, "GtkCallback")
+ || !strcmp (type_name, "GtkCCallback"))
+ {
+ arg_name = "callback";
+ arg_num = &callback_num;
+ }
+ else
+ {
+ arg_name = "arg";
+ arg_num = &param_num;
+ }
+ sprintf (pos, "%s ", type_name);
+ pos += strlen (pos);
+
+ if (!arg_num || *arg_num == 0)
+ sprintf (pos, "%s%s\\n", is_pointer ? "*" : " ", arg_name);
+ else
+ sprintf (pos, "%s%s%i\\n", is_pointer ? "*" : " ", arg_name,
+ *arg_num);
+ pos += strlen (pos);
+
+ if (arg_num)
+ {
+ if (*arg_num == 0)
+ *arg_num = 2;
+ else
+ *arg_num += 1;
+ }
+ }
+ }
+
+ pos = flags;
+ /* We use one-character flags for simplicity. */
+ if (query_info.signal_flags & G_SIGNAL_RUN_FIRST)
+ *pos++ = 'f';
+ if (query_info.signal_flags & G_SIGNAL_RUN_LAST)
+ *pos++ = 'l';
+ if (query_info.signal_flags & G_SIGNAL_RUN_CLEANUP)
+ *pos++ = 'c';
+ if (query_info.signal_flags & G_SIGNAL_NO_RECURSE)
+ *pos++ = 'r';
+ if (query_info.signal_flags & G_SIGNAL_DETAILED)
+ *pos++ = 'd';
+ if (query_info.signal_flags & G_SIGNAL_ACTION)
+ *pos++ = 'a';
+ if (query_info.signal_flags & G_SIGNAL_NO_HOOKS)
+ *pos++ = 'h';
+ *pos = 0;
+
+ fprintf (fp,
+ "<SIGNAL>\\n<NAME>%s::%s</NAME>\\n<RETURNS>%s</RETURNS>\\n<FLAGS>%s</FLAGS>\\n%s</SIGNAL>\\n\\n",
+ object_name, query_info.signal_name, ret_type_buffer, flags, buffer);
+}
+
+
+/* Returns the type name to use for a signal argument or return value, given
+ the GtkType from the signal info. It also sets is_pointer to TRUE if the
+ argument needs a '*' since it is a pointer. */
+static const gchar *
+get_type_name (GType type, gboolean * is_pointer)
+{
+ const gchar *type_name;
+
+ *is_pointer = FALSE;
+ type_name = g_type_name (type);
+
+ switch (type) {
+ case G_TYPE_NONE:
+ case G_TYPE_CHAR:
+ case G_TYPE_UCHAR:
+ case G_TYPE_BOOLEAN:
+ case G_TYPE_INT:
+ case G_TYPE_UINT:
+ case G_TYPE_LONG:
+ case G_TYPE_ULONG:
+ case G_TYPE_FLOAT:
+ case G_TYPE_DOUBLE:
+ case G_TYPE_POINTER:
+ /* These all have normal C type names so they are OK. */
+ return type_name;
+
+ case G_TYPE_STRING:
+ /* A GtkString is really a gchar*. */
+ *is_pointer = TRUE;
+ return "gchar";
+
+ case G_TYPE_ENUM:
+ case G_TYPE_FLAGS:
+ /* We use a gint for both of these. Hopefully a subtype with a decent
+ name will be registered and used instead, as GTK+ does itself. */
+ return "gint";
+
+ case G_TYPE_BOXED:
+ /* The boxed type shouldn't be used itself, only subtypes. Though we
+ return 'gpointer' just in case. */
+ return "gpointer";
+
+ case G_TYPE_PARAM:
+ /* A GParam is really a GParamSpec*. */
+ *is_pointer = TRUE;
+ return "GParamSpec";
+
+ default:
+ break;
+ }
+
+ /* For all GObject subclasses we can use the class name with a "*",
+ e.g. 'GtkWidget *'. */
+ if (g_type_is_a (type, G_TYPE_OBJECT))
+ *is_pointer = TRUE;
+
+ if (G_TYPE_IS_CLASSED (type))
+ *is_pointer = TRUE;
+
+ /* All boxed subtypes will be pointers as well. */
+ if (g_type_is_a (type, G_TYPE_BOXED))
+ *is_pointer = TRUE;
+
+ /* All pointer subtypes will be pointers as well. */
+ if (g_type_is_a (type, G_TYPE_POINTER))
+ *is_pointer = TRUE;
+
+ /* But enums are not */
+ if (g_type_is_a (type, G_TYPE_ENUM) ||
+ g_type_is_a (type, G_TYPE_FLAGS))
+ *is_pointer = FALSE;
+
+ return type_name;
+}
+
+
+static const gchar *
+get_gdk_event (const gchar * signal_name)
+{
+ static const gchar *GbGDKEvents[] =
+ {
+ "button_press_event", "GdkEventButton",
+ "button_release_event", "GdkEventButton",
+ "motion_notify_event", "GdkEventMotion",
+ "delete_event", "GdkEvent",
+ "destroy_event", "GdkEvent",
+ "expose_event", "GdkEventExpose",
+ "key_press_event", "GdkEventKey",
+ "key_release_event", "GdkEventKey",
+ "enter_notify_event", "GdkEventCrossing",
+ "leave_notify_event", "GdkEventCrossing",
+ "configure_event", "GdkEventConfigure",
+ "focus_in_event", "GdkEventFocus",
+ "focus_out_event", "GdkEventFocus",
+ "map_event", "GdkEvent",
+ "unmap_event", "GdkEvent",
+ "property_notify_event", "GdkEventProperty",
+ "selection_clear_event", "GdkEventSelection",
+ "selection_request_event", "GdkEventSelection",
+ "selection_notify_event", "GdkEventSelection",
+ "proximity_in_event", "GdkEventProximity",
+ "proximity_out_event", "GdkEventProximity",
+ "drag_begin_event", "GdkEventDragBegin",
+ "drag_request_event", "GdkEventDragRequest",
+ "drag_end_event", "GdkEventDragRequest",
+ "drop_enter_event", "GdkEventDropEnter",
+ "drop_leave_event", "GdkEventDropLeave",
+ "drop_data_available_event", "GdkEventDropDataAvailable",
+ "other_event", "GdkEventOther",
+ "client_event", "GdkEventClient",
+ "no_expose_event", "GdkEventNoExpose",
+ "visibility_notify_event", "GdkEventVisibility",
+ "window_state_event", "GdkEventWindowState",
+ "scroll_event", "GdkEventScroll",
+ NULL
+ };
+
+ gint i;
+
+ for (i = 0; GbGDKEvents[i]; i += 2)
+ {
+ if (!strcmp (signal_name, GbGDKEvents[i]))
+ return GbGDKEvents[i + 1];
+ }
+ return "GdkEvent";
+}
+
+
+/* This returns argument names to use for some known GTK signals.
+ It is passed a widget name, e.g. 'GtkCList' and a signal name, e.g.
+ 'select_row' and it returns a pointer to an array of argument types and
+ names. */
+static const gchar **
+lookup_signal_arg_names (const gchar * type, const gchar * signal_name)
+{
+ /* Each arg array starts with the object type name and the signal name,
+ and then signal arguments follow. */
+ static const gchar *GbArgTable[][16] =
+ {
+ {"GtkCList", "select_row",
+ "gint row",
+ "gint column",
+ "GdkEventButton *event"},
+ {"GtkCList", "unselect_row",
+ "gint row",
+ "gint column",
+ "GdkEventButton *event"},
+ {"GtkCList", "click_column",
+ "gint column"},
+
+ {"GtkCList", "resize_column",
+ "gint column",
+ "gint width"},
+
+ {"GtkCList", "extend_selection",
+ "GtkScrollType scroll_type",
+ "gfloat position",
+ "gboolean auto_start_selection"},
+ {"GtkCList", "scroll_vertical",
+ "GtkScrollType scroll_type",
+ "gfloat position"},
+ {"GtkCList", "scroll_horizontal",
+ "GtkScrollType scroll_type",
+ "gfloat position"},
+
+ {"GtkCTree", "tree_select_row",
+ "GtkCTreeNode *node",
+ "gint column"},
+ {"GtkCTree", "tree_unselect_row",
+ "GtkCTreeNode *node",
+ "gint column"},
+ {"GtkCTree", "tree_expand",
+ "GtkCTreeNode *node"},
+ {"GtkCTree", "tree_collapse",
+ "GtkCTreeNode *node"},
+ {"GtkCTree", "tree_move",
+ "GtkCTreeNode *node",
+ "GtkCTreeNode *new_parent",
+ "GtkCTreeNode *new_sibling"},
+ {"GtkCTree", "change_focus_row_expansion",
+ "GtkCTreeExpansionType expansion"},
+
+ {"GtkEditable", "insert_text",
+ "gchar *new_text",
+ "gint new_text_length",
+ "gint *position"},
+ {"GtkEditable", "delete_text",
+ "gint start_pos",
+ "gint end_pos"},
+ {"GtkEditable", "set_editable",
+ "gboolean is_editable"},
+ {"GtkEditable", "move_cursor",
+ "gint x",
+ "gint y"},
+ {"GtkEditable", "move_word",
+ "gint num_words"},
+ {"GtkEditable", "move_page",
+ "gint x",
+ "gint y"},
+ {"GtkEditable", "move_to_row",
+ "gint row"},
+ {"GtkEditable", "move_to_column",
+ "gint column"},
+
+ {"GtkEditable", "kill_char",
+ "gint direction"},
+ {"GtkEditable", "kill_word",
+ "gint direction"},
+ {"GtkEditable", "kill_line",
+ "gint direction"},
+
+
+ {"GtkInputDialog", "enable_device",
+ "GdkDevice *deviceid"},
+ {"GtkInputDialog", "disable_device",
+ "GdkDevice *deviceid"},
+
+ {"GtkListItem", "extend_selection",
+ "GtkScrollType scroll_type",
+ "gfloat position",
+ "gboolean auto_start_selection"},
+ {"GtkListItem", "scroll_vertical",
+ "GtkScrollType scroll_type",
+ "gfloat position"},
+ {"GtkListItem", "scroll_horizontal",
+ "GtkScrollType scroll_type",
+ "gfloat position"},
+
+ {"GtkMenuShell", "move_current",
+ "GtkMenuDirectionType direction"},
+ {"GtkMenuShell", "activate_current",
+ "gboolean force_hide"},
+
+
+ {"GtkNotebook", "switch_page",
+ "GtkNotebookPage *page",
+ "guint page_num"},
+ {"GtkStatusbar", "text_pushed",
+ "guint context_id",
+ "gchar *text"},
+ {"GtkStatusbar", "text_popped",
+ "guint context_id",
+ "gchar *text"},
+ {"GtkTipsQuery", "widget_entered",
+ "GtkWidget *widget",
+ "gchar *tip_text",
+ "gchar *tip_private"},
+ {"GtkTipsQuery", "widget_selected",
+ "GtkWidget *widget",
+ "gchar *tip_text",
+ "gchar *tip_private",
+ "GdkEventButton *event"},
+ {"GtkToolbar", "orientation_changed",
+ "GtkOrientation orientation"},
+ {"GtkToolbar", "style_changed",
+ "GtkToolbarStyle style"},
+ {"GtkWidget", "draw",
+ "GdkRectangle *area"},
+ {"GtkWidget", "size_request",
+ "GtkRequisition *requisition"},
+ {"GtkWidget", "size_allocate",
+ "GtkAllocation *allocation"},
+ {"GtkWidget", "state_changed",
+ "GtkStateType state"},
+ {"GtkWidget", "style_set",
+ "GtkStyle *previous_style"},
+
+ {"GtkWidget", "install_accelerator",
+ "gchar *signal_name",
+ "gchar key",
+ "gint modifiers"},
+
+ {"GtkWidget", "add_accelerator",
+ "guint accel_signal_id",
+ "GtkAccelGroup *accel_group",
+ "guint accel_key",
+ "GdkModifierType accel_mods",
+ "GtkAccelFlags accel_flags"},
+
+ {"GtkWidget", "parent_set",
+ "GtkObject *old_parent"},
+
+ {"GtkWidget", "remove_accelerator",
+ "GtkAccelGroup *accel_group",
+ "guint accel_key",
+ "GdkModifierType accel_mods"},
+ {"GtkWidget", "debug_msg",
+ "gchar *message"},
+ {"GtkWindow", "move_resize",
+ "gint *x",
+ "gint *y",
+ "gint width",
+ "gint height"},
+ {"GtkWindow", "set_focus",
+ "GtkWidget *widget"},
+
+ {"GtkWidget", "selection_get",
+ "GtkSelectionData *data",
+ "guint info",
+ "guint time"},
+ {"GtkWidget", "selection_received",
+ "GtkSelectionData *data",
+ "guint time"},
+
+ {"GtkWidget", "drag_begin",
+ "GdkDragContext *drag_context"},
+ {"GtkWidget", "drag_end",
+ "GdkDragContext *drag_context"},
+ {"GtkWidget", "drag_data_delete",
+ "GdkDragContext *drag_context"},
+ {"GtkWidget", "drag_leave",
+ "GdkDragContext *drag_context",
+ "guint time"},
+ {"GtkWidget", "drag_motion",
+ "GdkDragContext *drag_context",
+ "gint x",
+ "gint y",
+ "guint time"},
+ {"GtkWidget", "drag_drop",
+ "GdkDragContext *drag_context",
+ "gint x",
+ "gint y",
+ "guint time"},
+ {"GtkWidget", "drag_data_get",
+ "GdkDragContext *drag_context",
+ "GtkSelectionData *data",
+ "guint info",
+ "guint time"},
+ {"GtkWidget", "drag_data_received",
+ "GdkDragContext *drag_context",
+ "gint x",
+ "gint y",
+ "GtkSelectionData *data",
+ "guint info",
+ "guint time"},
+
+ {NULL}
+ };
+
+ gint i;
+
+ for (i = 0; GbArgTable[i][0]; i++)
+ {
+#if 1
+ if (!strcmp (type, GbArgTable[i][0])
+ && !strcmp (signal_name, GbArgTable[i][1]))
+ return &GbArgTable[i][2];
+#endif
+ }
+ return NULL;
+}
+
+/* This outputs the hierarchy of all objects which have been initialized,
+ i.e. by calling their XXX_get_type() initialization function. */
+static void
+output_object_hierarchy (void)
+{
+ FILE *fp;
+ gint i;
+
+ fp = fopen (hierarchy_filename, "w");
+ if (fp == NULL)
+ {
+ g_warning ("Couldn't open output file: %s : %s", hierarchy_filename, strerror(errno));
+ return;
+ }
+ output_hierarchy (fp, G_TYPE_OBJECT, 0);
+ output_hierarchy (fp, G_TYPE_INTERFACE, 0);
+
+ for (i=0; object_types[i]; i++) {
+ if (!g_type_parent (object_types[i]) &&
+ (object_types[i] != G_TYPE_NONE) &&
+ (object_types[i] != G_TYPE_OBJECT) &&
+ (object_types[i] != G_TYPE_INTERFACE)
+ ) {
+ g_warning ("printing hierarchy for root type: %s",
+ g_type_name (object_types[i]));
+ output_hierarchy (fp, object_types[i], 0);
+ }
+ }
+ /* for debugging
+ for (i=0; object_types[i]; i++) {
+ if(object_types[i] != G_TYPE_NONE) {
+ g_print ("type has not been added to hierarchy: %s\\n",
+ g_type_name (object_types[i]));
+ }
+ }
+ for debugging */
+
+ fclose (fp);
+}
+
+/* This is called recursively to output the hierarchy of a widget. */
+static void
+output_hierarchy (FILE *fp,
+ GType type,
+ guint level)
+{
+ guint i;
+ GType *children;
+ guint n_children;
+
+ if (!type)
+ return;
+
+ /* for debugging
+ for (i=0; object_types[i]; i++) {
+ if(object_types[i] == type) {
+ g_print ("added type to hierarchy (level %d): %s\\n",
+ level, g_type_name (type));
+ object_types[i] = G_TYPE_NONE;
+ break;
+ }
+ }
+ for debugging */
+
+ for (i = 0; i < level; i++)
+ fprintf (fp, " ");
+ fprintf (fp, "%s", g_type_name (type));
+ fprintf (fp, "\\n");
+
+ children = g_type_children (type, &n_children);
+
+ for (i=0; i < n_children; i++) {
+ output_hierarchy (fp, children[i], level + 1);
+ }
+
+ g_free (children);
+}
+
+static void output_object_interfaces (void)
+{
+ guint i;
+ FILE *fp;
+
+ fp = fopen (interfaces_filename, "w");
+ if (fp == NULL)
+ {
+ g_warning ("Couldn't open output file: %s : %s", interfaces_filename, strerror(errno));
+ return;
+ }
+ output_interfaces (fp, G_TYPE_OBJECT);
+
+ for (i = 0; object_types[i]; i++)
+ {
+ if (!g_type_parent (object_types[i]) &&
+ (object_types[i] != G_TYPE_OBJECT) &&
+ G_TYPE_IS_INSTANTIATABLE (object_types[i]))
+ {
+ output_interfaces (fp, object_types[i]);
+ }
+ }
+ fclose (fp);
+}
+
+static void
+output_interfaces (FILE *fp,
+ GType type)
+{
+ guint i;
+ GType *children, *interfaces;
+ guint n_children, n_interfaces;
+
+ if (!type)
+ return;
+
+ interfaces = g_type_interfaces (type, &n_interfaces);
+
+ if (n_interfaces > 0)
+ {
+ fprintf (fp, "%s", g_type_name (type));
+ for (i=0; i < n_interfaces; i++)
+ fprintf (fp, " %s", g_type_name (interfaces[i]));
+ fprintf (fp, "\\n");
+ }
+ g_free (interfaces);
+
+ children = g_type_children (type, &n_children);
+
+ for (i=0; i < n_children; i++)
+ output_interfaces (fp, children[i]);
+
+ g_free (children);
+}
+
+static void output_interface_prerequisites (void)
+{
+ FILE *fp;
+
+ fp = fopen (prerequisites_filename, "w");
+ if (fp == NULL)
+ {
+ g_warning ("Couldn't open output file: %s : %s", prerequisites_filename, strerror(errno));
+ return;
+ }
+ output_prerequisites (fp, G_TYPE_INTERFACE);
+ fclose (fp);
+}
+
+static void
+output_prerequisites (FILE *fp,
+ GType type)
+{
+#if GLIB_CHECK_VERSION(2,1,0)
+ guint i;
+ GType *children, *prerequisites;
+ guint n_children, n_prerequisites;
+
+ if (!type)
+ return;
+
+ prerequisites = g_type_interface_prerequisites (type, &n_prerequisites);
+
+ if (n_prerequisites > 0)
+ {
+ fprintf (fp, "%s", g_type_name (type));
+ for (i=0; i < n_prerequisites; i++)
+ fprintf (fp, " %s", g_type_name (prerequisites[i]));
+ fprintf (fp, "\\n");
+ }
+ g_free (prerequisites);
+
+ children = g_type_children (type, &n_children);
+
+ for (i=0; i < n_children; i++)
+ output_prerequisites (fp, children[i]);
+
+ g_free (children);
+#endif
+}
+
+static void
+output_args (void)
+{
+ FILE *fp;
+ gint i;
+
+ fp = fopen (args_filename, "w");
+ if (fp == NULL)
+ {
+ g_warning ("Couldn't open output file: %s : %s", args_filename, strerror(errno));
+ return;
+ }
+
+ for (i = 0; object_types[i]; i++) {
+ output_object_args (fp, object_types[i]);
+ }
+
+ fclose (fp);
+}
+
+static gint
+compare_param_specs (const void *a, const void *b)
+{
+ GParamSpec *spec_a = *(GParamSpec **)a;
+ GParamSpec *spec_b = *(GParamSpec **)b;
+
+ return strcmp (g_param_spec_get_name (spec_a), g_param_spec_get_name (spec_b));
+}
+
+/* Its common to have unsigned properties restricted
+ * to the signed range. Therefore we make this look
+ * a bit nicer by spelling out the max constants.
+ */
+
+/* Don't use "==" with floats, it might trigger a gcc warning. */
+#define GTKDOC_COMPARE_FLOAT(x, y) (x <= y && x >= y)
+
+static gchar*
+describe_double_constant (gdouble value)
+{
+ gchar *desc;
+
+ if (GTKDOC_COMPARE_FLOAT (value, G_MAXDOUBLE))
+ desc = g_strdup ("G_MAXDOUBLE");
+ else if (GTKDOC_COMPARE_FLOAT (value, G_MINDOUBLE))
+ desc = g_strdup ("G_MINDOUBLE");
+ else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXDOUBLE))
+ desc = g_strdup ("-G_MAXDOUBLE");
+ else if (GTKDOC_COMPARE_FLOAT (value, G_MAXFLOAT))
+ desc = g_strdup ("G_MAXFLOAT");
+ else if (GTKDOC_COMPARE_FLOAT (value, G_MINFLOAT))
+ desc = g_strdup ("G_MINFLOAT");
+ else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXFLOAT))
+ desc = g_strdup ("-G_MAXFLOAT");
+ else
+ desc = g_strdup_printf ("%lg", value);
+
+ return desc;
+}
+
+static gchar*
+describe_signed_constant (gint64 value)
+{
+ gchar *desc;
+
+ if (value == G_MAXINT)
+ desc = g_strdup ("G_MAXINT");
+ else if (value == G_MININT)
+ desc = g_strdup ("G_MININT");
+ else if (value == G_MAXUINT)
+ desc = g_strdup ("G_MAXUINT");
+ else if (value == G_MAXLONG)
+ desc = g_strdup ("G_MAXLONG");
+ else if (value == G_MINLONG)
+ desc = g_strdup ("G_MINLONG");
+ else if (value == G_MAXULONG)
+ desc = g_strdup ("G_MAXULONG");
+ else if (value == G_MAXINT64)
+ desc = g_strdup ("G_MAXINT64");
+ else if (value == G_MININT64)
+ desc = g_strdup ("G_MININT64");
+ else
+ desc = g_strdup_printf ("%" G_GINT64_FORMAT, value);
+
+ return desc;
+}
+
+static gchar*
+describe_unsigned_constant (guint64 value)
+{
+ gchar *desc;
+
+ if (value == G_MAXINT)
+ desc = g_strdup ("G_MAXINT");
+ else if (value == G_MININT)
+ desc = g_strdup ("G_MININT");
+ else if (value == G_MAXUINT)
+ desc = g_strdup ("G_MAXUINT");
+ else if (value == G_MAXLONG)
+ desc = g_strdup ("G_MAXLONG");
+ else if (value == G_MINLONG)
+ desc = g_strdup ("G_MINLONG");
+ else if (value == G_MAXULONG)
+ desc = g_strdup ("G_MAXULONG");
+ else if (value == G_MAXINT64)
+ desc = g_strdup ("G_MAXINT64");
+ else if (value == G_MININT64)
+ desc = g_strdup ("G_MININT64");
+ else if (value == G_MAXUINT64)
+ desc = g_strdup ("G_MAXUINT64");
+ else
+ desc = g_strdup_printf ("%" G_GUINT64_FORMAT, value);
+
+ return desc;
+}
+
+static gchar*
+describe_type (GParamSpec *spec)
+{
+ gchar *desc;
+ gchar *lower;
+ gchar *upper;
+
+ if (G_IS_PARAM_SPEC_CHAR (spec))
+ {
+ GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
+
+ lower = describe_signed_constant (pspec->minimum);
+ upper = describe_signed_constant (pspec->maximum);
+ if (pspec->minimum == G_MININT8 && pspec->maximum == G_MAXINT8)
+ desc = g_strdup ("");
+ else if (pspec->minimum == G_MININT8)
+ desc = g_strdup_printf ("<= %s", upper);
+ else if (pspec->maximum == G_MAXINT8)
+ desc = g_strdup_printf (">= %s", lower);
+ else
+ desc = g_strdup_printf ("[%s,%s]", lower, upper);
+ g_free (lower);
+ g_free (upper);
+ }
+ else if (G_IS_PARAM_SPEC_UCHAR (spec))
+ {
+ GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
+
+ lower = describe_unsigned_constant (pspec->minimum);
+ upper = describe_unsigned_constant (pspec->maximum);
+ if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT8)
+ desc = g_strdup ("");
+ else if (pspec->minimum == 0)
+ desc = g_strdup_printf ("<= %s", upper);
+ else if (pspec->maximum == G_MAXUINT8)
+ desc = g_strdup_printf (">= %s", lower);
+ else
+ desc = g_strdup_printf ("[%s,%s]", lower, upper);
+ g_free (lower);
+ g_free (upper);
+ }
+ else if (G_IS_PARAM_SPEC_INT (spec))
+ {
+ GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
+
+ lower = describe_signed_constant (pspec->minimum);
+ upper = describe_signed_constant (pspec->maximum);
+ if (pspec->minimum == G_MININT && pspec->maximum == G_MAXINT)
+ desc = g_strdup ("");
+ else if (pspec->minimum == G_MININT)
+ desc = g_strdup_printf ("<= %s", upper);
+ else if (pspec->maximum == G_MAXINT)
+ desc = g_strdup_printf (">= %s", lower);
+ else
+ desc = g_strdup_printf ("[%s,%s]", lower, upper);
+ g_free (lower);
+ g_free (upper);
+ }
+ else if (G_IS_PARAM_SPEC_UINT (spec))
+ {
+ GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
+
+ lower = describe_unsigned_constant (pspec->minimum);
+ upper = describe_unsigned_constant (pspec->maximum);
+ if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT)
+ desc = g_strdup ("");
+ else if (pspec->minimum == 0)
+ desc = g_strdup_printf ("<= %s", upper);
+ else if (pspec->maximum == G_MAXUINT)
+ desc = g_strdup_printf (">= %s", lower);
+ else
+ desc = g_strdup_printf ("[%s,%s]", lower, upper);
+ g_free (lower);
+ g_free (upper);
+ }
+ else if (G_IS_PARAM_SPEC_LONG (spec))
+ {
+ GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
+
+ lower = describe_signed_constant (pspec->minimum);
+ upper = describe_signed_constant (pspec->maximum);
+ if (pspec->minimum == G_MINLONG && pspec->maximum == G_MAXLONG)
+ desc = g_strdup ("");
+ else if (pspec->minimum == G_MINLONG)
+ desc = g_strdup_printf ("<= %s", upper);
+ else if (pspec->maximum == G_MAXLONG)
+ desc = g_strdup_printf (">= %s", lower);
+ else
+ desc = g_strdup_printf ("[%s,%s]", lower, upper);
+ g_free (lower);
+ g_free (upper);
+ }
+ else if (G_IS_PARAM_SPEC_ULONG (spec))
+ {
+ GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
+ gchar *upper;
+
+ lower = describe_unsigned_constant (pspec->minimum);
+ upper = describe_unsigned_constant (pspec->maximum);
+ if (pspec->minimum == 0 && pspec->maximum == G_MAXULONG)
+ desc = g_strdup ("");
+ else if (pspec->minimum == 0)
+ desc = g_strdup_printf ("<= %s", upper);
+ else if (pspec->maximum == G_MAXULONG)
+ desc = g_strdup_printf (">= %s", lower);
+ else
+ desc = g_strdup_printf ("[%s,%s]", lower, upper);
+ g_free (lower);
+ g_free (upper);
+ }
+ else if (G_IS_PARAM_SPEC_INT64 (spec))
+ {
+ GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
+
+ lower = describe_signed_constant (pspec->minimum);
+ upper = describe_signed_constant (pspec->maximum);
+ if (pspec->minimum == G_MININT64 && pspec->maximum == G_MAXINT64)
+ desc = g_strdup ("");
+ else if (pspec->minimum == G_MININT64)
+ desc = g_strdup_printf ("<= %s", upper);
+ else if (pspec->maximum == G_MAXINT64)
+ desc = g_strdup_printf (">= %s", lower);
+ else
+ desc = g_strdup_printf ("[%s,%s]", lower, upper);
+ g_free (lower);
+ g_free (upper);
+ }
+ else if (G_IS_PARAM_SPEC_UINT64 (spec))
+ {
+ GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
+
+ lower = describe_unsigned_constant (pspec->minimum);
+ upper = describe_unsigned_constant (pspec->maximum);
+ if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT64)
+ desc = g_strdup ("");
+ else if (pspec->minimum == 0)
+ desc = g_strdup_printf ("<= %s", upper);
+ else if (pspec->maximum == G_MAXUINT64)
+ desc = g_strdup_printf (">= %s", lower);
+ else
+ desc = g_strdup_printf ("[%s,%s]", lower, upper);
+ g_free (lower);
+ g_free (upper);
+ }
+ else if (G_IS_PARAM_SPEC_FLOAT (spec))
+ {
+ GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
+
+ lower = describe_double_constant (pspec->minimum);
+ upper = describe_double_constant (pspec->maximum);
+ if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXFLOAT))
+ {
+ if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT))
+ desc = g_strdup ("");
+ else
+ desc = g_strdup_printf ("<= %s", upper);
+ }
+ else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT))
+ desc = g_strdup_printf (">= %s", lower);
+ else
+ desc = g_strdup_printf ("[%s,%s]", lower, upper);
+ g_free (lower);
+ g_free (upper);
+ }
+ else if (G_IS_PARAM_SPEC_DOUBLE (spec))
+ {
+ GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
+
+ lower = describe_double_constant (pspec->minimum);
+ upper = describe_double_constant (pspec->maximum);
+ if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXDOUBLE))
+ {
+ if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE))
+ desc = g_strdup ("");
+ else
+ desc = g_strdup_printf ("<= %s", upper);
+ }
+ else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE))
+ desc = g_strdup_printf (">= %s", lower);
+ else
+ desc = g_strdup_printf ("[%s,%s]", lower, upper);
+ g_free (lower);
+ g_free (upper);
+ }
+ else
+ {
+ desc = g_strdup ("");
+ }
+
+ return desc;
+}
+
+static gchar*
+describe_default (GParamSpec *spec)
+{
+ gchar *desc;
+
+ if (G_IS_PARAM_SPEC_CHAR (spec))
+ {
+ GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
+
+ desc = g_strdup_printf ("%d", pspec->default_value);
+ }
+ else if (G_IS_PARAM_SPEC_UCHAR (spec))
+ {
+ GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
+
+ desc = g_strdup_printf ("%u", pspec->default_value);
+ }
+ else if (G_IS_PARAM_SPEC_BOOLEAN (spec))
+ {
+ GParamSpecBoolean *pspec = G_PARAM_SPEC_BOOLEAN (spec);
+
+ desc = g_strdup_printf ("%s", pspec->default_value ? "TRUE" : "FALSE");
+ }
+ else if (G_IS_PARAM_SPEC_INT (spec))
+ {
+ GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
+
+ desc = g_strdup_printf ("%d", pspec->default_value);
+ }
+ else if (G_IS_PARAM_SPEC_UINT (spec))
+ {
+ GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
+
+ desc = g_strdup_printf ("%u", pspec->default_value);
+ }
+ else if (G_IS_PARAM_SPEC_LONG (spec))
+ {
+ GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
+
+ desc = g_strdup_printf ("%ld", pspec->default_value);
+ }
+ else if (G_IS_PARAM_SPEC_LONG (spec))
+ {
+ GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
+
+ desc = g_strdup_printf ("%lu", pspec->default_value);
+ }
+ else if (G_IS_PARAM_SPEC_INT64 (spec))
+ {
+ GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
+
+ desc = g_strdup_printf ("%" G_GINT64_FORMAT, pspec->default_value);
+ }
+ else if (G_IS_PARAM_SPEC_UINT64 (spec))
+ {
+ GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
+
+ desc = g_strdup_printf ("%" G_GUINT64_FORMAT, pspec->default_value);
+ }
+ else if (G_IS_PARAM_SPEC_UNICHAR (spec))
+ {
+ GParamSpecUnichar *pspec = G_PARAM_SPEC_UNICHAR (spec);
+
+ if (g_unichar_isprint (pspec->default_value))
+ desc = g_strdup_printf ("'%c'", pspec->default_value);
+ else
+ desc = g_strdup_printf ("%u", pspec->default_value);
+ }
+ else if (G_IS_PARAM_SPEC_ENUM (spec))
+ {
+ GParamSpecEnum *pspec = G_PARAM_SPEC_ENUM (spec);
+
+ GEnumValue *value = g_enum_get_value (pspec->enum_class, pspec->default_value);
+ if (value)
+ desc = g_strdup_printf ("%s", value->value_name);
+ else
+ desc = g_strdup_printf ("%d", pspec->default_value);
+ }
+ else if (G_IS_PARAM_SPEC_FLAGS (spec))
+ {
+ GParamSpecFlags *pspec = G_PARAM_SPEC_FLAGS (spec);
+ guint default_value;
+ GString *acc;
+
+ default_value = pspec->default_value;
+ acc = g_string_new ("");
+
+ while (default_value)
+ {
+ GFlagsValue *value = g_flags_get_first_value (pspec->flags_class, default_value);
+
+ if (!value)
+ break;
+
+ if (acc->len > 0)
+ g_string_append (acc, "|");
+ g_string_append (acc, value->value_name);
+
+ default_value &= ~value->value;
+ }
+
+ if (default_value == 0)
+ desc = g_string_free (acc, FALSE);
+ else
+ {
+ desc = g_strdup_printf ("%d", pspec->default_value);
+ g_string_free (acc, TRUE);
+ }
+ }
+ else if (G_IS_PARAM_SPEC_FLOAT (spec))
+ {
+ GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
+
+ desc = g_strdup_printf ("%g", pspec->default_value);
+ }
+ else if (G_IS_PARAM_SPEC_DOUBLE (spec))
+ {
+ GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
+
+ desc = g_strdup_printf ("%lg", pspec->default_value);
+ }
+ else if (G_IS_PARAM_SPEC_STRING (spec))
+ {
+ GParamSpecString *pspec = G_PARAM_SPEC_STRING (spec);
+
+ if (pspec->default_value)
+ {
+ gchar *esc = g_strescape (pspec->default_value, NULL);
+
+ desc = g_strdup_printf ("\\"%s\\"", esc);
+
+ g_free (esc);
+ }
+ else
+ desc = g_strdup_printf ("NULL");
+ }
+ else
+ {
+ desc = g_strdup ("");
+ }
+
+ return desc;
+}
+
+
+static void
+output_object_args (FILE *fp, GType object_type)
+{
+ gpointer class;
+ const gchar *object_class_name;
+ guint arg;
+ gchar flags[16], *pos;
+ GParamSpec **properties;
+ guint n_properties;
+ gboolean child_prop;
+ gboolean style_prop;
+ gboolean is_pointer;
+ const gchar *type_name;
+ gchar *type_desc;
+ gchar *default_value;
+
+ if (G_TYPE_IS_OBJECT (object_type))
+ {
+ class = g_type_class_peek (object_type);
+ if (!class)
+ return;
+
+ properties = g_object_class_list_properties (class, &n_properties);
+ }
+#if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 3)
+ else if (G_TYPE_IS_INTERFACE (object_type))
+ {
+ class = g_type_default_interface_ref (object_type);
+
+ if (!class)
+ return;
+
+ properties = g_object_interface_list_properties (class, &n_properties);
+ }
+#endif
+ else
+ return;
+
+ object_class_name = g_type_name (object_type);
+
+ child_prop = FALSE;
+ style_prop = FALSE;
+
+ while (TRUE) {
+ qsort (properties, n_properties, sizeof (GParamSpec *), compare_param_specs);
+ for (arg = 0; arg < n_properties; arg++)
+ {
+ GParamSpec *spec = properties[arg];
+ const gchar *nick, *blurb, *dot;
+
+ if (spec->owner_type != object_type)
+ continue;
+
+ pos = flags;
+ /* We use one-character flags for simplicity. */
+ if (child_prop && !style_prop)
+ *pos++ = 'c';
+ if (style_prop)
+ *pos++ = 's';
+ if (spec->flags & G_PARAM_READABLE)
+ *pos++ = 'r';
+ if (spec->flags & G_PARAM_WRITABLE)
+ *pos++ = 'w';
+ if (spec->flags & G_PARAM_CONSTRUCT)
+ *pos++ = 'x';
+ if (spec->flags & G_PARAM_CONSTRUCT_ONLY)
+ *pos++ = 'X';
+ *pos = 0;
+
+ nick = g_param_spec_get_nick (spec);
+ blurb = g_param_spec_get_blurb (spec);
+
+ dot = "";
+ if (blurb) {
+ int str_len = strlen (blurb);
+ if (str_len > 0 && blurb[str_len - 1] != '.')
+ dot = ".";
+ }
+
+ type_desc = describe_type (spec);
+ default_value = describe_default (spec);
+ type_name = get_type_name (spec->value_type, &is_pointer);
+ fprintf (fp, "<ARG>\\n<NAME>%s::%s</NAME>\\n<TYPE>%s%s</TYPE>\\n<RANGE>%s</RANGE>\\n<FLAGS>%s</FLAGS>\\n<NICK>%s</NICK>\\n<BLURB>%s%s</BLURB>\\n<DEFAULT>%s</DEFAULT>\\n</ARG>\\n\\n",
+ object_class_name, g_param_spec_get_name (spec), type_name, is_pointer ? "*" : "", type_desc, flags, nick ? nick : "(null)", blurb ? blurb : "(null)", dot, default_value);
+ g_free (type_desc);
+ g_free (default_value);
+ }
+
+ g_free (properties);
+
+#ifdef GTK_IS_CONTAINER_CLASS
+ if (!child_prop && GTK_IS_CONTAINER_CLASS (class)) {
+ properties = gtk_container_class_list_child_properties (class, &n_properties);
+ child_prop = TRUE;
+ continue;
+ }
+#endif
+
+#ifdef GTK_IS_WIDGET_CLASS
+#if GTK_CHECK_VERSION(2,1,0)
+ if (!style_prop && GTK_IS_WIDGET_CLASS (class)) {
+ properties = gtk_widget_class_list_style_properties (GTK_WIDGET_CLASS (class), &n_properties);
+ style_prop = TRUE;
+ continue;
+ }
+#endif
+#endif
+
+ break;
+ }
+}
+EOT
+
+close OUTPUT;
+
+# Compile and run our file
+
+$CC = $ENV{CC} ? $ENV{CC} : "gcc";
+$LD = $ENV{LD} ? $ENV{LD} : $CC;
+$CFLAGS = $ENV{CFLAGS} ? "$ENV{CFLAGS} -Wall -g" : "-Wall -g";
+$LDFLAGS = $ENV{LDFLAGS} ? $ENV{LDFLAGS} : "";
+
+my $o_file;
+if ($CC =~ /libtool/) {
+ $o_file = "$MODULE-scan.lo"
+} else {
+ $o_file = "$MODULE-scan.o"
+}
+
+print "gtk-doc: Compiling scanner\n";
+$command = "$CC $CFLAGS -c -o $o_file $MODULE-scan.c";
+system($command) == 0 or die "Compilation of scanner failed: $!\n";
+
+print "gtk-doc: Linking scanner\n";
+$command = "$LD -o $MODULE-scan $o_file $LDFLAGS";
+system($command) == 0 or die "Linking of scanner failed: $!\n";
+
+print "gtk-doc: Running scanner $MODULE-scan\n";
+system("sh -c ./$MODULE-scan") == 0 or die "Scan failed: $!\n";
+
+unlink "./$MODULE-scan.c", "./$MODULE-scan.o", "./$MODULE-scan.lo", "./$MODULE-scan";
+
+#&UpdateFileIfChanged ($old_signals_filename, $new_signals_filename, 0);
+&UpdateFileIfChanged ($old_hierarchy_filename, $new_hierarchy_filename, 0);
+&UpdateFileIfChanged ($old_interfaces_filename, $new_interfaces_filename, 0);
+&UpdateFileIfChanged ($old_prerequisites_filename, $new_prerequisites_filename, 0);
+#&UpdateFileIfChanged ($old_args_filename, $new_args_filename, 0);
+
+
diff --git a/common/gtk-doc-plugins.mak b/common/gtk-doc-plugins.mak
new file mode 100644
index 00000000..f673a7fb
--- /dev/null
+++ b/common/gtk-doc-plugins.mak
@@ -0,0 +1,384 @@
+# This is an include file specifically tuned for building documentation
+# for GStreamer plug-ins
+
+help:
+ @echo
+ @echo "If you are a doc maintainer, run 'make update' to update"
+ @echo "the documentation files maintained in CVS"
+ @echo
+ @echo Other useful make targets:
+ @echo
+ @echo check-inspected-versions: make sure the inspected plugin info
+ @echo is up to date before a release
+ @echo
+
+# update the stuff maintained by doc maintainers
+update:
+ $(MAKE) inspect-update
+ $(MAKE) scanobj-update
+
+# We set GPATH here; this gives us semantics for GNU make
+# which are more like other make's VPATH, when it comes to
+# whether a source that is a target of one rule is then
+# searched for in VPATH/GPATH.
+#
+GPATH = $(srcdir)
+
+# thomas: make docs parallel installable
+TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@
+
+EXTRA_DIST = \
+ scanobj-build.stamp \
+ $(srcdir)/inspect/*.xml \
+ inspect.stamp \
+ inspect-build.stamp \
+ $(SCANOBJ_FILES) \
+ $(content_files) \
+ $(extra_files) \
+ $(HTML_IMAGES) \
+ $(DOC_MAIN_SGML_FILE) \
+ $(DOC_OVERRIDES) \
+ $(DOC_MODULE)-sections.txt
+
+MAINTAINER_DOC_STAMPS = \
+ scanobj-build.stamp \
+ inspect-build.stamp \
+ inspect.stamp
+
+# we don't add inspect-build.stamp and scanobj-build.stamp here since they are
+# built manually by docs maintainers and result is commited to CVS
+DOC_STAMPS = \
+ scan-build.stamp \
+ tmpl-build.stamp \
+ sgml-build.stamp \
+ html-build.stamp \
+ scan.stamp \
+ tmpl.stamp \
+ sgml.stamp \
+ html.stamp
+
+# files generated/updated by gtkdoc-scangobj
+SCANOBJ_FILES = \
+ $(DOC_MODULE).signals \
+ $(DOC_MODULE).hierarchy \
+ $(DOC_MODULE).interfaces \
+ $(DOC_MODULE).prerequisites \
+ $(DOC_MODULE).types \
+ $(DOC_MODULE).args
+
+SCANOBJ_FILES_O = \
+ .libs/$(DOC_MODULE)-scan.o
+
+# files generated/updated by gtkdoc-scan
+SCAN_FILES = \
+ $(DOC_MODULE)-sections.txt \
+ $(DOC_MODULE)-overrides.txt \
+ $(DOC_MODULE)-undocumented.txt \
+ $(DOC_MODULE)-decl.txt \
+ $(DOC_MODULE)-decl-list.txt
+
+
+REPORT_FILES = \
+ $(DOC_MODULE)-undocumented.txt \
+ $(DOC_MODULE)-undeclared.txt \
+ $(DOC_MODULE)-unused.txt
+
+# FC3 seems to need -scan.c to be part of CLEANFILES for distcheck
+# no idea why FC4 can do without
+CLEANFILES = \
+ $(SCANOBJ_FILES_O) \
+ $(DOC_MODULE)-scan.c \
+ $(REPORT_FILES) \
+ $(DOC_STAMPS) \
+ inspect-registry.xml
+
+
+if ENABLE_GTK_DOC
+all-local: html-build.stamp
+
+#### scan gobjects; done by documentation maintainer ####
+scanobj-update:
+ -rm scanobj-build.stamp
+ $(MAKE) scanobj-build.stamp
+
+# in the case of non-srcdir builds, the built gst directory gets added
+# to gtk-doc scanning; but only then, to avoid duplicates
+# FIXME: since we don't have the scan step as part of the build anymore,
+# we could remove that
+# TODO: finish elite script that updates the output files of this step
+# instead of rewriting them, so that multiple maintainers can generate
+# a collective set of args and signals
+scanobj-build.stamp: $(SCANOBJ_DEPS) $(basefiles)
+ @echo '*** Scanning GObjects ***'
+ if test x"$(srcdir)" != x. ; then \
+ for f in $(SCANOBJ_FILES); \
+ do \
+ cp $(srcdir)/$$f . ; \
+ done; \
+ else \
+ $(INSPECT_ENVIRONMENT) \
+ CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" \
+ CFLAGS="$(GTKDOC_CFLAGS) $(CFLAGS)" \
+ LDFLAGS="$(GTKDOC_LIBS) $(LDFLAGS)" \
+ $(GST_DOC_SCANOBJ) --type-init-func="gst_init(NULL,NULL)" \
+ --module=$(DOC_MODULE) --source=$(PACKAGE) && \
+ $(PYTHON) \
+ $(top_srcdir)/common/scangobj-merge.py $(DOC_MODULE); \
+ fi
+ touch scanobj-build.stamp
+
+$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(SCANOBJ_FILES_O): scan-build.stamp
+ @true
+
+### inspect GStreamer plug-ins; done by documentation maintainer ###
+
+# only look at the plugins in this module when building inspect .xml stuff
+INSPECT_REGISTRY=$(top_builddir)/docs/plugins/inspect-registry.xml
+INSPECT_ENVIRONMENT=\
+ GST_PLUGIN_SYSTEM_PATH= \
+ GST_PLUGIN_PATH=$(top_builddir)/gst:$(top_builddir)/sys:$(top_builddir)/ext:$(top_builddir)/plugins:$(top_builddir)/src:$(top_builddir)/gnl \
+ GST_REGISTRY=$(INSPECT_REGISTRY)
+
+# update the element and plugin XML descriptions; store in inspect/
+inspect:
+ mkdir inspect
+
+inspect-update: inspect
+ -rm -f $(INSPECT_REGISTRY) inspect-build.stamp
+ $(MAKE) inspect-build.stamp
+
+# FIXME: inspect.stamp should be written to by gst-xmlinspect.py
+# IF the output changed; see gtkdoc-mktmpl
+inspect-build.stamp:
+ @echo '*** Rebuilding plugin inspection files ***'
+ if test x"$(srcdir)" != x. ; then \
+ cp $(srcdir)/inspect.stamp . ; \
+ cp $(srcdir)/inspect-build.stamp . ; \
+ else \
+ $(INSPECT_ENVIRONMENT) $(PYTHON) \
+ $(top_srcdir)/common/gst-xmlinspect.py $(PACKAGE) inspect && \
+ echo -n "timestamp" > inspect.stamp && \
+ touch inspect-build.stamp; \
+ fi
+
+### scan headers; done on every build ###
+scan-build.stamp: $(HFILE_GLOB) $(EXTRA_HFILES) $(basefiles) scanobj-build.stamp inspect-build.stamp
+ if test "x$(top_srcdir)" != "x$(top_builddir)" && \
+ test -d "$(top_builddir)/gst"; \
+ then \
+ export BUILT_OPTIONS="--source-dir=$(top_builddir)/gst"; \
+ fi; \
+ gtkdoc-scan \
+ $(SCAN_OPTIONS) $(EXTRA_HFILES) \
+ --module=$(DOC_MODULE) \
+ $$BUILT_OPTIONS \
+ --ignore-headers="$(IGNORE_HFILES)"; \
+ touch scan-build.stamp
+
+#### update templates; done on every build ####
+
+### FIXME: make this error out again when docs are fixed for 0.9
+# in a non-srcdir build, we need to copy files from the previous step
+# and the files from previous runs of this step
+tmpl-build.stamp: $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_OVERRIDES)
+ @echo '*** Rebuilding template files ***'
+ if test x"$(srcdir)" != x. ; then \
+ for f in $(SCANOBJ_FILES) $(SCAN_FILES); \
+ do \
+ if test -e $(srcdir)/$$f; then cp $(srcdir)/$$f . ; fi; \
+ done; \
+ fi
+ gtkdoc-mktmpl --module=$(DOC_MODULE) | tee tmpl-build.log
+ $(PYTHON) \
+ $(top_srcdir)/common/mangle-tmpl.py $(srcdir)/inspect tmpl
+ @cat $(DOC_MODULE)-unused.txt
+ rm -f tmpl-build.log
+ touch tmpl-build.stamp
+
+tmpl.stamp: tmpl-build.stamp
+ @true
+
+#### build xml; done on every build ####
+
+### FIXME: make this error out again when docs are fixed for 0.9
+sgml-build.stamp: tmpl.stamp inspect.stamp $(CFILE_GLOB) $(top_srcdir)/common/plugins.xsl
+ @echo '*** Building XML ***'
+ @-mkdir -p xml
+ @for a in $(srcdir)/inspect/*.xml; do \
+ xsltproc --stringparam module $(MODULE) \
+ $(top_srcdir)/common/plugins.xsl $$a > xml/`basename $$a`; done
+ @for f in $(EXAMPLE_CFILES); do \
+ $(PYTHON) $(top_srcdir)/common/c-to-xml.py $$f > xml/element-`basename $$f .c`.xml; done
+ gtkdoc-mkdb \
+ --module=$(DOC_MODULE) \
+ --source-dir=$(DOC_SOURCE_DIR) \
+ --main-sgml-file=$(srcdir)/$(DOC_MAIN_SGML_FILE) \
+ --output-format=xml \
+ --ignore-files="$(IGNORE_HFILES) $(IGNORE_CFILES)" \
+ $(MKDB_OPTIONS) \
+ | tee sgml-build.log
+ @if grep "WARNING:" sgml-build.log > /dev/null; then true; fi # exit 1; fi
+ cp ../version.entities xml
+ rm sgml-build.log
+ touch sgml-build.stamp
+
+sgml.stamp: sgml-build.stamp
+ @true
+
+#### build html; done on every step ####
+
+html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files)
+ @echo '*** Building HTML ***'
+ if test -d html; then rm -rf html; fi
+ mkdir html
+ cp $(srcdir)/$(DOC_MAIN_SGML_FILE) html
+ @for f in $(content_files); do cp $(srcdir)/$$f html; done
+ cp -pr xml html
+ cp ../version.entities html
+ cd html && gtkdoc-mkhtml $(DOC_MODULE) $(DOC_MAIN_SGML_FILE) \
+ 2>&1 | tee ../html-build.log
+ @if grep "warning:" html-build.log > /dev/null; then \
+ echo "ERROR"; grep "warning:" html-build.log; exit 1; fi
+ @rm html-build.log
+ mv html/index.sgml html/index.sgml.bak
+ $(SED) "s/ href=\"$(DOC_MODULE)\// href=\"$(DOC_MODULE)-@GST_MAJORMINOR@\//g" html/index.sgml.bak >html/index.sgml
+ rm -f html/index.sgml.bak
+ rm -f html/$(DOC_MAIN_SGML_FILE)
+ rm -rf html/xml
+ rm -f html/version.entities
+ test "x$(HTML_IMAGES)" = "x" || for i in "" $(HTML_IMAGES) ; do \
+ if test "$$i" != ""; then cp $(srcdir)/$$i html ; fi; done
+ @echo '-- Fixing Crossreferences'
+ gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS)
+ touch html-build.stamp
+
+clean-local-gtkdoc:
+ rm -rf xml tmpl html
+# clean files copied for nonsrcdir templates build
+ if test x"$(srcdir)" != x. ; then \
+ rm -rf $(SCANOBJ_FILES) $(SCAN_FILES); \
+ fi
+else
+all-local:
+clean-local-gtkdoc:
+endif
+
+clean-local: clean-local-gtkdoc
+ rm -f *~ *.bak
+ rm -rf .libs
+
+distclean-local: clean
+ rm -rf tmpl/*.sgml.bak
+ rm -rf *.o
+
+MAINTAINERCLEANFILES = $(MAINTAINER_DOC_STAMPS)
+
+# thomas: make docs parallel installable; devhelp requires majorminor too
+install-data-local:
+ (installfiles=`echo $(srcdir)/html/*.sgml $(srcdir)/html/*.html $(srcdir)/html/*.png $(srcdir)/html/*.css`; \
+ if test "$$installfiles" = '$(srcdir)/html/*.sgml $(srcdir)/html/*.html $(srcdir)/html/*.png $(srcdir)/html/*.css'; \
+ then echo '-- Nothing to install' ; \
+ else \
+ $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR); \
+ for i in $$installfiles; do \
+ echo '-- Installing '$$i ; \
+ $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \
+ done; \
+ pngfiles=`echo ./html/*.png`; \
+ if test "$$pngfiles" != './html/*.png'; then \
+ for i in $$pngfiles; do \
+ echo '-- Installing '$$i ; \
+ $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \
+ done; \
+ fi; \
+ echo '-- Installing $(srcdir)/html/$(DOC_MODULE).devhelp' ; \
+ $(INSTALL_DATA) $(srcdir)/html/$(DOC_MODULE).devhelp \
+ $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp; \
+ if test -e $(srcdir)/html/$(DOC_MODULE).devhelp2; then \
+ $(INSTALL_DATA) $(srcdir)/html/$(DOC_MODULE).devhelp2 \
+ $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp2; \
+ fi; \
+ (which gtkdoc-rebase >/dev/null && \
+ gtkdoc-rebase --relative --dest-dir=$(DESTDIR) --html-dir=$(DESTDIR)$(TARGET_DIR)) || true ; \
+ fi)
+uninstall-local:
+ (installfiles=`echo ./html/*.html`; \
+ if test "$$installfiles" = './html/*.html'; \
+ then echo '-- Nothing to uninstall' ; \
+ else \
+ for i in $$installfiles; do \
+ rmfile=`basename $$i` ; \
+ echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/'$$rmfile ; \
+ rm -f $(DESTDIR)$(TARGET_DIR)/$$rmfile; \
+ done; \
+ pngfiles=`echo ./html/*.png`; \
+ if test "$$pngfiles" != './html/*.png'; then \
+ for i in $$pngfiles; do \
+ rmfile=`basename $$i` ; \
+ echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/'$$rmfile ; \
+ rm -f $(DESTDIR)$(TARGET_DIR)/$$rmfile; \
+ done; \
+ fi; \
+ echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE).devhelp' ; \
+ rm -f $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp; \
+ if test -e $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp2; then \
+ rm -f $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp2; \
+ fi; \
+ echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/index.sgml' ; \
+ rm -f $(DESTDIR)$(TARGET_DIR)/index.sgml; \
+ if test -e $(DESTDIR)$(TARGET_DIR)/style.css; then \
+ echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/style.css' ; \
+ rm -f $(DESTDIR)$(TARGET_DIR)/style.css; \
+ fi; \
+ fi)
+ if test -d $(DESTDIR)$(TARGET_DIR); then rmdir -p --ignore-fail-on-non-empty $(DESTDIR)$(TARGET_DIR) 2>/dev/null; fi; true
+
+#
+# Checks
+#
+check-hierarchy: $(DOC_MODULE).hierarchy
+ @if grep ' ' $(DOC_MODULE).hierarchy; then \
+ echo "$(DOC_MODULE).hierarchy contains tabs, please fix"; \
+ /bin/false; \
+ fi
+
+check: check-hierarchy
+
+# wildcard is apparently not portable to other makes, hence the use of find
+inspect_files = $(shell find $(srcdir)/inspect -name '*.xml')
+
+check-inspected-versions:
+ @echo Checking plugin versions of inspected plugin data ...; \
+ fail=0 ; \
+ for each in $(inspect_files) ; do \
+ if (grep -H '<version>' $$each | grep -v '<version>$(VERSION)'); then \
+ echo $$each should be fixed to say version $(VERSION) or be removed ; \
+ echo "sed -i -e 's/<version.*version>/<version>$(VERSION)<\/version>/'" $$each; \
+ echo ; \
+ fail=1; \
+ fi ; \
+ done ; \
+ exit $$fail
+
+#
+# Require gtk-doc when making dist
+#
+if ENABLE_GTK_DOC
+dist-check-gtkdoc:
+else
+dist-check-gtkdoc:
+ @echo "*** gtk-doc must be installed and enabled in order to make dist"
+ @false
+endif
+
+# FIXME: decide whether we want to dist generated html or not
+dist-hook: dist-check-gtkdoc dist-hook-local
+ mkdir $(distdir)/html
+ cp $(srcdir)/html/* $(distdir)/html
+ -cp $(srcdir)/$(DOC_MODULE).types $(distdir)/
+ -cp $(srcdir)/$(DOC_MODULE)-sections.txt $(distdir)/
+ cd $(distdir) && rm -f $(DISTCLEANFILES)
+ -gtkdoc-rebase --online --relative --html-dir=$(distdir)/html
+
+.PHONY : dist-hook-local docs
+
diff --git a/common/mangle-tmpl.py b/common/mangle-tmpl.py
new file mode 100644
index 00000000..6cb52d73
--- /dev/null
+++ b/common/mangle-tmpl.py
@@ -0,0 +1,158 @@
+# -*- Mode: Python -*-
+# vi:si:et:sw=4:sts=4:ts=4
+
+"""
+use the output from gst-xmlinspect.py to mangle tmpl/*.sgml and
+insert/overwrite Short Description and Long Description
+"""
+
+# FIXME: right now it uses pygst and scans on its own;
+# we really should use inspect/*.xml instead since the result of
+# gst-xmlinspect.py is commited by the docs maintainer, who can be
+# expected to have pygst, but this step should be done for every docs build,
+# so no pygst allowed
+
+# read in inspect/*.xml
+# for every tmpl/element-(name).xml: mangle with details from element
+
+import glob
+import re
+import sys
+import os
+
+class Tmpl:
+ def __init__(self, filename):
+ self.filename = filename
+ self._sectionids = []
+ self._sections = {}
+
+ def read(self):
+ """
+ Read and parse the sections from the given file.
+ """
+ lines = open(self.filename).readlines()
+ matcher = re.compile("<!-- ##### SECTION (\S+) ##### -->\n")
+ id = None
+
+ for line in lines:
+ match = matcher.search(line)
+ if match:
+ id = match.expand("\\1")
+ self._sectionids.append(id)
+ self._sections[id] = []
+ else:
+ if not id:
+ sys.stderr.write(
+ "WARNING: line before a SECTION header: %s" % line)
+ else:
+ self._sections[id].append(line)
+
+ def get_section(self, id):
+ """
+ Get the content from the given section.
+ """
+ return self._sections[id]
+
+ def set_section(self, id, content):
+ """
+ Replace the given section id with the given content.
+ """
+ self._sections[id] = content
+
+ def output(self):
+ """
+ Return the output of the current template in the tmpl/*.sgml format.
+ """
+ lines = []
+ for id in self._sectionids:
+ lines.append("<!-- ##### SECTION %s ##### -->\n" % id)
+ for line in self._sections[id]:
+ lines.append(line)
+
+ return "".join(lines)
+
+ def write(self, backup=False):
+ """
+ Write out the template file again, backing up the previous one.
+ """
+ if backup:
+ target = self.filename + ".mangle.bak"
+ os.rename(self.filename, target)
+
+ handle = open(self.filename, "w")
+ handle.write(self.output())
+ handle.close()
+
+import xml.dom.minidom
+
+def get_elements(file):
+ elements = {}
+ doc = xml.dom.minidom.parse(file)
+
+ elem = None
+ for e in doc.childNodes:
+ if e.nodeType == e.ELEMENT_NODE and e.localName == 'plugin':
+ elem = e
+ break
+ if elem == None:
+ return None
+
+ elem2 = None
+ for e in elem.childNodes:
+ if e.nodeType == e.ELEMENT_NODE and e.localName == 'elements':
+ elem2 = e
+ break
+ if elem2 == None:
+ return None
+
+ elem = elem2
+
+ for e in elem.childNodes:
+ if e.nodeType == e.ELEMENT_NODE and e.localName == 'element':
+ name = None
+ description = None
+
+ for e2 in e.childNodes:
+ if e2.nodeType == e2.ELEMENT_NODE and e2.localName == 'name':
+ name = e2.childNodes[0].nodeValue.encode("UTF-8")
+ elif e2.nodeType == e2.ELEMENT_NODE and e2.localName == 'description':
+ description = e2.childNodes[0].nodeValue.encode("UTF-8")
+
+ if name != None and description != None:
+ elements[name] = {'description': description}
+
+ return elements
+
+def main():
+ if not len(sys.argv) == 3:
+ sys.stderr.write('Please specify the inspect/ dir and the tmpl/ dir')
+ sys.exit(1)
+
+ inspectdir = sys.argv[1]
+ tmpldir = sys.argv[2]
+
+ # parse all .xml files; build map of element name -> short desc
+ #for file in glob.glob("inspect/plugin-*.xml"):
+ elements = {}
+ for file in glob.glob("%s/plugin-*.xml" % inspectdir):
+ elements.update(get_elements(file))
+
+ for file in glob.glob("%s/element-*.sgml" % tmpldir):
+ base = os.path.basename(file)
+ element = base[len("element-"):-len(".sgml")]
+ tmpl = Tmpl(file)
+ tmpl.read()
+ if element in elements.keys():
+ description = elements[element]['description']
+ tmpl.set_section("Short_Description", "%s\n\n" % description)
+
+ # put in an include if not yet there
+ line = '<include xmlns="http://www.w3.org/2003/XInclude" href="' + \
+ 'element-' + element + '-details.xml" />\n'
+ section = tmpl.get_section("Long_Description")
+ if not section[0] == line:
+ section.insert(0, line)
+ tmpl.set_section("Long_Description", section)
+ tmpl.write()
+
+main()
diff --git a/common/plugins.xsl b/common/plugins.xsl
new file mode 100644
index 00000000..2eab2204
--- /dev/null
+++ b/common/plugins.xsl
@@ -0,0 +1,209 @@
+<?xml version='1.0'?> <!--*- mode: xml -*-->
+
+<xsl:stylesheet
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:exsl="http://exslt.org/common"
+ xmlns:str="http://exslt.org/strings"
+ extension-element-prefixes="exsl str"
+ version="1.0">
+<xsl:output method="xml" indent="yes"
+ doctype-public ="-//OASIS//DTD DocBook XML V4.1.2//EN"
+ doctype-system = "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"/>
+
+<xsl:param name="module" />
+
+ <xsl:template match="element">
+ <xsl:element name="varlistentry">
+ <xsl:element name="term">
+ <xsl:element name="link">
+ <xsl:attribute name="linkend"><xsl:value-of select="$module" />-plugins-<xsl:value-of select="name"/></xsl:attribute>
+ <xsl:value-of select="name" />
+ </xsl:element>
+ </xsl:element>
+ <xsl:element name="listitem">
+ <xsl:element name="simpara"><xsl:value-of select="description" /></xsl:element>
+ </xsl:element>
+ </xsl:element>
+ <xsl:variable name="name"><xsl:copy-of select="name"/></xsl:variable>
+ <!-- here we write an element-(name)-details.xml file for the element -->
+ <exsl:document href="{concat ('xml/element-', $name, '-details.xml')}" method="xml" indent="yes">
+
+ <xsl:element name="refsynopsisdiv">
+ <xsl:element name="refsect2">
+ <xsl:element name="title">Element Information</xsl:element>
+ <xsl:element name="variablelist">
+
+ <!-- plugin name and link -->
+ <xsl:element name="varlistentry">
+ <xsl:element name="term">plugin</xsl:element>
+ <xsl:element name="listitem">
+ <xsl:element name="simpara">
+ <xsl:element name="link">
+ <xsl:attribute name="linkend">plugin-<xsl:value-of select="../../name"/></xsl:attribute>
+ <xsl:value-of select="../../name" />
+ </xsl:element>
+ </xsl:element>
+ </xsl:element>
+ </xsl:element>
+
+ <xsl:element name="varlistentry">
+ <xsl:element name="term">author</xsl:element>
+ <xsl:element name="listitem">
+ <xsl:element name="simpara"><xsl:value-of select="author" /></xsl:element>
+ </xsl:element>
+ </xsl:element>
+
+ <xsl:element name="varlistentry">
+ <xsl:element name="term">class</xsl:element>
+ <xsl:element name="listitem">
+ <xsl:element name="simpara"><xsl:value-of select="class" /></xsl:element>
+ </xsl:element>
+ </xsl:element>
+
+ </xsl:element> <!-- variablelist -->
+ </xsl:element> <!-- refsect2 -->
+
+ <xsl:element name="refsect2">
+ <xsl:element name="title">Element Pads</xsl:element>
+ <!-- process all caps -->
+ <xsl:for-each select="pads/caps">
+ <xsl:element name="variablelist">
+ <xsl:element name="varlistentry">
+ <xsl:element name="term">name</xsl:element>
+ <xsl:element name="listitem">
+ <xsl:element name="simpara"><xsl:value-of select="name" /></xsl:element>
+ </xsl:element>
+ </xsl:element>
+
+ <xsl:element name="varlistentry">
+ <xsl:element name="term">direction</xsl:element>
+ <xsl:element name="listitem">
+ <xsl:element name="simpara"><xsl:value-of select="direction" /></xsl:element>
+ </xsl:element>
+ </xsl:element>
+
+ <xsl:element name="varlistentry">
+ <xsl:element name="term">presence</xsl:element>
+ <xsl:element name="listitem">
+ <xsl:element name="simpara"><xsl:value-of select="presence" /></xsl:element>
+ </xsl:element>
+ </xsl:element>
+
+ <xsl:for-each select='str:tokenize(details, ";")'>
+ <xsl:element name="varlistentry">
+ <xsl:element name="term">
+ <xsl:if test="position()=1">details</xsl:if>
+ </xsl:element>
+ <xsl:element name="listitem">
+ <xsl:element name="simpara"><xsl:value-of select='.'/></xsl:element>
+ </xsl:element>
+ </xsl:element>
+ </xsl:for-each>
+
+ </xsl:element> <!-- variablelist -->
+
+ <!--xsl:element name="programlisting"><xsl:value-of select="details" /></xsl:element-->
+
+ </xsl:for-each>
+ </xsl:element> <!-- refsect2 -->
+ </xsl:element> <!-- refsynopsisdiv -->
+
+ </exsl:document>
+ </xsl:template>
+
+ <xsl:template match="plugin">
+ <xsl:element name="refentry">
+ <xsl:attribute name="id"><xsl:value-of select="$module" />-plugins-plugin-<xsl:value-of select="name"/></xsl:attribute>
+
+ <xsl:element name="refmeta">
+ <xsl:element name="refentrytitle">
+ <xsl:value-of select="name"/>
+ </xsl:element>
+ <xsl:element name="manvolnum">3</xsl:element>
+ <xsl:element name="refmiscinfo">FIXME Library</xsl:element>
+ </xsl:element> <!-- refmeta -->
+
+ <xsl:element name="refnamediv">
+ <xsl:element name="refname">
+ <xsl:element name="anchor">
+ <xsl:attribute name="id">plugin-<xsl:value-of select="name"/></xsl:attribute>
+ <xsl:value-of select="name"/>
+ </xsl:element>
+ </xsl:element>
+
+ <xsl:element name="refpurpose">
+ <xsl:value-of select="description"/>
+ </xsl:element>
+ </xsl:element>
+
+ <xsl:element name="refsect1">
+ <xsl:element name="title">Plugin Information</xsl:element>
+ <xsl:element name="variablelist">
+
+ <xsl:element name="varlistentry">
+ <xsl:element name="term">filename</xsl:element>
+ <xsl:element name="listitem">
+ <xsl:element name="simpara"><xsl:value-of select="basename" /></xsl:element>
+ </xsl:element>
+ </xsl:element>
+
+ <xsl:element name="varlistentry">
+ <xsl:element name="term">version</xsl:element>
+ <xsl:element name="listitem">
+ <xsl:element name="simpara"><xsl:value-of select="version" /></xsl:element>
+ </xsl:element>
+ </xsl:element>
+
+ <xsl:element name="varlistentry">
+ <xsl:element name="term">run-time license</xsl:element>
+ <xsl:element name="listitem">
+ <xsl:element name="simpara"><xsl:value-of select="license" /></xsl:element>
+ </xsl:element>
+ </xsl:element>
+
+ <xsl:element name="varlistentry">
+ <xsl:element name="term">package</xsl:element>
+ <xsl:element name="listitem">
+ <xsl:element name="simpara"><xsl:value-of select="package" /></xsl:element>
+ </xsl:element>
+ </xsl:element>
+
+ <xsl:element name="varlistentry">
+ <xsl:element name="term">origin</xsl:element>
+ <xsl:element name="listitem">
+ <xsl:element name="simpara">
+ <!-- only show origin as link if it starts with http -->
+ <xsl:choose>
+ <xsl:when test="substring(@href, 1, 4) = 'http'">
+ <xsl:element name="ulink">
+ <xsl:attribute name="url"><xsl:value-of select="origin" /></xsl:attribute>
+ <xsl:value-of select="origin" />
+ </xsl:element>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="origin" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:element>
+ </xsl:element>
+ </xsl:element>
+
+ </xsl:element>
+ </xsl:element>
+
+ <xsl:element name="refsect1">
+ <xsl:element name="title">Elements</xsl:element>
+ <!-- process all elements -->
+ <xsl:element name="variablelist">
+ <xsl:apply-templates select="elements"/>
+ </xsl:element>
+ </xsl:element>
+
+ </xsl:element>
+
+ </xsl:template>
+
+ <!-- ignore -->
+ <xsl:template match="gst-plugin-paths" />
+
+</xsl:stylesheet>
diff --git a/common/scangobj-merge.py b/common/scangobj-merge.py
new file mode 100755
index 00000000..a79b4044
--- /dev/null
+++ b/common/scangobj-merge.py
@@ -0,0 +1,278 @@
+#!/usr/bin/python
+# -*- Mode: Python -*-
+# vi:si:et:sw=4:sts=4:ts=4
+
+"""
+parse, update and write .signals and .args files
+"""
+
+import sys
+import os
+
+def debug(*args):
+ pass
+
+# OrderedDict class based on
+# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747
+# Licensed under the Python License
+class OrderedDict(dict):
+ def __init__(self, dict = None):
+ self._keys = []
+ dict.__init__(self, dict)
+
+ def __delitem__(self, key):
+ dict.__delitem__(self, key)
+ self._keys.remove(key)
+
+ def __setitem__(self, key, item):
+ dict.__setitem__(self, key, item)
+ if key not in self._keys: self._keys.append(key)
+
+ def clear(self):
+ dict.clear(self)
+ self._keys = []
+
+ def copy(self):
+ dict = dict.copy(self)
+ dict._keys = self._keys[:]
+ return dict
+
+ def items(self):
+ return zip(self._keys, self.values())
+
+ def keys(self):
+ return self._keys
+
+ def popitem(self):
+ try:
+ key = self._keys[-1]
+ except IndexError:
+ raise KeyError('dictionary is empty')
+
+ val = self[key]
+ del self[key]
+
+ return (key, val)
+
+ def setdefault(self, key, failobj = None):
+ dict.setdefault(self, key, failobj)
+ if key not in self._keys: self._keys.append(key)
+
+ def update(self, dict):
+ dict.update(self, dict)
+ for key in dict.keys():
+ if key not in self._keys: self._keys.append(key)
+
+ def values(self):
+ return map(self.get, self._keys)
+
+class Object:
+ def __init__(self, name):
+ self._signals = OrderedDict()
+ self._args = OrderedDict()
+ self.name = name
+
+ def __repr__(self):
+ return "<Object %s>" % self.name
+
+ def add_signal(self, signal, overwrite=True):
+ if not overwrite and self._signals.has_key(signal.name):
+ raise IndexError, "signal %s already in %r" % (signal.name, self)
+ self._signals[signal.name] = signal
+
+ def add_arg(self, arg, overwrite=True):
+ if not overwrite and self._args.has_key(arg.name):
+ raise IndexError, "arg %s already in %r" % (arg.name, self)
+ self._args[arg.name] = arg
+
+class Docable:
+ def __init__(self, **kwargs):
+ for key in self.attrs:
+ setattr(self, key, kwargs[key])
+ self.dict = kwargs
+
+ def __repr__(self):
+ return "<%r %s>" % (str(self.__class__), self.name)
+
+class Signal(Docable):
+ attrs = ['name', 'returns', 'args']
+
+class Arg(Docable):
+ attrs = ['name', 'type', 'range', 'flags', 'nick', 'blurb', 'default']
+
+class GDoc:
+ def load_file(self, filename):
+ try:
+ lines = open(filename).readlines()
+ self.load_data("".join(lines))
+ except IOError:
+ print "WARNING - could not read from %s" % filename
+
+ def save_file(self, filename, backup=False):
+ """
+ Save the signals information to the given .signals file if the
+ file content changed.
+ """
+ olddata = None
+ try:
+ lines = open(filename).readlines()
+ olddata = "".join(lines)
+ except IOError:
+ print "WARNING - could not read from %s" % filename
+ newdata = self.get_data()
+ if olddata and olddata == newdata:
+ return
+
+ if olddata:
+ if backup:
+ os.rename(filename, filename + '.bak')
+
+ handle = open(filename, "w")
+ handle.write(newdata)
+ handle.close()
+
+class Signals(GDoc):
+ def __init__(self):
+ self._objects = OrderedDict()
+
+ def load_data(self, data):
+ """
+ Load the .signals lines, creating our list of objects and signals.
+ """
+ import re
+ smatcher = re.compile(
+ '(?s)' # make . match \n
+ '<SIGNAL>\n(.*?)</SIGNAL>\n'
+ )
+ nmatcher = re.compile(
+ '<NAME>'
+ '(?P<object>\S*)' # store object
+ '::'
+ '(?P<signal>\S*)' # store signal
+ '</NAME>'
+ )
+ rmatcher = re.compile(
+ '(?s)' # make . match \n
+ '<RETURNS>(?P<returns>\S*)</RETURNS>\n' # store returns
+ '(?P<args>.*)' # store args
+ )
+ for block in smatcher.findall(data):
+ nmatch = nmatcher.search(block)
+ if nmatch:
+ o = nmatch.group('object')
+ debug("Found object", o)
+ debug("Found signal", nmatch.group('signal'))
+ if not self._objects.has_key(o):
+ object = Object(o)
+ self._objects[o] = object
+
+ rmatch = rmatcher.search(block)
+ if rmatch:
+ dict = rmatch.groupdict().copy()
+ dict['name'] = nmatch.group('signal')
+ signal = Signal(**dict)
+ self._objects[o].add_signal(signal)
+
+ def get_data(self):
+ lines = []
+ for o in self._objects.values():
+ for s in o._signals.values():
+ block = """<SIGNAL>
+<NAME>%(object)s::%(name)s</NAME>
+<RETURNS>%(returns)s</RETURNS>
+%(args)s</SIGNAL>
+"""
+ d = s.dict.copy()
+ d['object'] = o.name
+ lines.append(block % d)
+
+ return "\n".join(lines) + '\n'
+
+class Args(GDoc):
+ def __init__(self):
+ self._objects = OrderedDict()
+
+ def load_data(self, data):
+ """
+ Load the .args lines, creating our list of objects and args.
+ """
+ import re
+ amatcher = re.compile(
+ '(?s)' # make . match \n
+ '<ARG>\n(.*?)</ARG>\n'
+ )
+ nmatcher = re.compile(
+ '<NAME>'
+ '(?P<object>\S*)' # store object
+ '::'
+ '(?P<arg>\S*)' # store arg
+ '</NAME>'
+ )
+ rmatcher = re.compile(
+ '(?s)' # make . match \n
+ '<TYPE>(?P<type>\S*)</TYPE>\n' # store type
+ '<RANGE>(?P<range>.*?)</RANGE>\n' # store range
+ '<FLAGS>(?P<flags>\S*)</FLAGS>\n' # store flags
+ '<NICK>(?P<nick>.*?)</NICK>\n' # store nick
+ '<BLURB>(?P<blurb>.*?)</BLURB>\n' # store blurb
+ '<DEFAULT>(?P<default>.*?)</DEFAULT>\n' # store default
+ )
+ for block in amatcher.findall(data):
+ nmatch = nmatcher.search(block)
+ if nmatch:
+ o = nmatch.group('object')
+ debug("Found object", o)
+ debug("Found arg", nmatch.group('arg'))
+ if not self._objects.has_key(o):
+ object = Object(o)
+ self._objects[o] = object
+
+ rmatch = rmatcher.search(block)
+ if rmatch:
+ dict = rmatch.groupdict().copy()
+ dict['name'] = nmatch.group('arg')
+ arg = Arg(**dict)
+ self._objects[o].add_arg(arg)
+ else:
+ print "ERROR: could not match arg from block %s" % block
+
+ def get_data(self):
+ lines = []
+ for o in self._objects.values():
+ for a in o._args.values():
+ block = """<ARG>
+<NAME>%(object)s::%(name)s</NAME>
+<TYPE>%(type)s</TYPE>
+<RANGE>%(range)s</RANGE>
+<FLAGS>%(flags)s</FLAGS>
+<NICK>%(nick)s</NICK>
+<BLURB>%(blurb)s</BLURB>
+<DEFAULT>%(default)s</DEFAULT>
+</ARG>
+"""
+ d = a.dict.copy()
+ d['object'] = o.name
+ lines.append(block % d)
+
+ return "\n".join(lines) + '\n'
+
+def main(argv):
+ modulename = None
+ try:
+ modulename = argv[1]
+ except IndexError:
+ sys.stderr.write('Pleae provide a documentation module name\n')
+ sys.exit(1)
+
+ print "Merging scangobj output for %s" % modulename
+ signals = Signals()
+ signals.load_file(modulename + '.signals')
+ signals.load_file(modulename + '.signals.new')
+ signals.save_file(modulename + '.signals', backup=True)
+
+ args = Args()
+ args.load_file(modulename + '.args')
+ args.load_file(modulename + '.args.new')
+ args.save_file(modulename + '.args', backup=True)
+
+main(sys.argv)