summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorNicolas Dufresne <nicolas.dufresne@collabora.co.uk>2010-01-14 15:45:21 -0500
committerNicolas Dufresne <nicolas.dufresne@collabora.co.uk>2010-01-14 15:45:21 -0500
commit8c98d90e041ce6d77425a0b6738e9ce83c387f13 (patch)
treebd2def71118d1b1db0945b5aba1555f8b0a21e68 /tools
parent3983d2c6f16a1a6c30494ea1b5a84e7db7c1a3e5 (diff)
downloadtelepathy-haze-8c98d90e041ce6d77425a0b6738e9ce83c387f13.tar.gz
Added specification code generator
The code generator is useful to implement DRAFTed specification that tends to change from time to time. Currently generated interface is MailNotification. Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile.am29
-rw-r--r--tools/c-constants-gen.py154
-rw-r--r--tools/check-c-style.sh56
-rw-r--r--tools/check-coding-style.mk17
-rw-r--r--tools/check-misc.sh13
-rw-r--r--tools/check-whitespace.sh17
-rw-r--r--tools/doc-generator.xsl1199
-rw-r--r--tools/glib-ginterface-gen.py802
-rw-r--r--tools/glib-gtypes-generator.py291
-rw-r--r--tools/glib-interfaces-gen.py119
-rw-r--r--tools/glib-signals-marshal-gen.py55
-rw-r--r--tools/identity.xsl7
-rw-r--r--tools/lcov.am24
-rw-r--r--tools/libglibcodegen.py172
-rw-r--r--tools/libtpcodegen.py215
-rw-r--r--tools/telepathy.am26
-rw-r--r--tools/xep.xsl921
17 files changed, 4116 insertions, 1 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am
index b3a481a..5fe50fd 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,9 +1,36 @@
EXTRA_DIST = \
with-session-bus.sh \
- shave.mk
+ shave.mk \
+ c-constants-gen.py \
+ check-coding-style.mk \
+ check-c-style.sh \
+ check-misc.sh \
+ check-whitespace.sh \
+ doc-generator.xsl \
+ glib-ginterface-gen.py \
+ glib-gtypes-generator.py \
+ glib-interfaces-gen.py \
+ glib-signals-marshal-gen.py \
+ identity.xsl \
+ lcov.am \
+ libglibcodegen.py \
+ libtpcodegen.py \
+ telepathy.am \
+ xep.xsl
+
+CLEANFILES = *.pyc *.pyo
all: $(EXTRA_DIST)
+libglibcodegen.py: libtpcodegen.py
+ test -e $<
+ $(AM_V_GEN)touch $@
+
+glib-ginterface-gen.py glib-gtypes-generator.py glib-interfaces-gen.py \
+glib-signals-marshal-gen.py c-constants-gen.py: %: libglibcodegen.py
+ test -e $<
+ $(AM_V_GEN)touch $@
+
TELEPATHY_GLIB_SRCDIR = $(top_srcdir)/../telepathy-glib
maintainer-update-from-telepathy-glib:
set -e && cd $(srcdir) && \
diff --git a/tools/c-constants-gen.py b/tools/c-constants-gen.py
new file mode 100644
index 0000000..8969ffd
--- /dev/null
+++ b/tools/c-constants-gen.py
@@ -0,0 +1,154 @@
+#!/usr/bin/python
+
+from sys import argv, stdout, stderr
+import xml.dom.minidom
+
+from libglibcodegen import NS_TP, get_docstring, \
+ get_descendant_text, get_by_path
+
+class Generator(object):
+ def __init__(self, prefix, dom):
+ self.prefix = prefix + '_'
+ self.spec = get_by_path(dom, "spec")[0]
+
+ def __call__(self):
+ self.do_header()
+ self.do_body()
+ self.do_footer()
+
+ def write(self, code):
+ stdout.write(code.encode('utf-8'))
+
+ # Header
+ def do_header(self):
+ self.write('/* Generated from ')
+ self.write(get_descendant_text(get_by_path(self.spec, 'title')))
+ version = get_by_path(self.spec, "version")
+ if version:
+ self.write(', version ' + get_descendant_text(version))
+ self.write('\n\n')
+ for copyright in get_by_path(self.spec, 'copyright'):
+ self.write(get_descendant_text(copyright))
+ self.write('\n')
+ self.write(get_descendant_text(get_by_path(self.spec, 'license')))
+ self.write('\n')
+ self.write(get_descendant_text(get_by_path(self.spec, 'docstring')))
+ self.write("""
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+\n""")
+
+ # Body
+ def do_body(self):
+ for elem in self.spec.getElementsByTagNameNS(NS_TP, '*'):
+ if elem.localName == 'flags':
+ self.do_flags(elem)
+ elif elem.localName == 'enum':
+ self.do_enum(elem)
+
+ def do_flags(self, flags):
+ name = flags.getAttribute('plural') or flags.getAttribute('name')
+ value_prefix = flags.getAttribute('singular') or \
+ flags.getAttribute('value-prefix') or \
+ flags.getAttribute('name')
+ self.write("""\
+/**
+ *
+%s:
+""" % (self.prefix + name).replace('_', ''))
+ for flag in get_by_path(flags, 'flag'):
+ self.do_gtkdoc(flag, value_prefix)
+ self.write(' *\n')
+ docstrings = get_by_path(flags, 'docstring')
+ if docstrings:
+ self.write("""\
+ * <![CDATA[%s]]>
+ *
+""" % get_descendant_text(docstrings).replace('\n', ' '))
+ self.write("""\
+ * Bitfield/set of flags generated from the Telepathy specification.
+ */
+typedef enum {
+""")
+ for flag in get_by_path(flags, 'flag'):
+ self.do_val(flag, value_prefix)
+ self.write("""\
+} %s;
+
+""" % (self.prefix + name).replace('_', ''))
+
+ def do_enum(self, enum):
+ name = enum.getAttribute('singular') or enum.getAttribute('name')
+ value_prefix = enum.getAttribute('singular') or \
+ enum.getAttribute('value-prefix') or \
+ enum.getAttribute('name')
+ name_plural = enum.getAttribute('plural') or \
+ enum.getAttribute('name') + 's'
+ self.write("""\
+/**
+ *
+%s:
+""" % (self.prefix + name).replace('_', ''))
+ vals = get_by_path(enum, 'enumvalue')
+ for val in vals:
+ self.do_gtkdoc(val, value_prefix)
+ self.write(' *\n')
+ docstrings = get_by_path(enum, 'docstring')
+ if docstrings:
+ self.write("""\
+ * <![CDATA[%s]]>
+ *
+""" % get_descendant_text(docstrings).replace('\n', ' '))
+ self.write("""\
+ * Bitfield/set of flags generated from the Telepathy specification.
+ */
+typedef enum {
+""")
+ for val in vals:
+ self.do_val(val, value_prefix)
+ self.write("""\
+} %(mixed-name)s;
+
+/**
+ * NUM_%(upper-plural)s:
+ *
+ * 1 higher than the highest valid value of #%(mixed-name)s.
+ */
+#define NUM_%(upper-plural)s (%(last-val)s+1)
+
+""" % {'mixed-name' : (self.prefix + name).replace('_', ''),
+ 'upper-plural' : (self.prefix + name_plural).upper(),
+ 'last-val' : vals[-1].getAttribute('value')})
+
+ def do_val(self, val, value_prefix):
+ name = val.getAttribute('name')
+ suffix = val.getAttribute('suffix')
+ use_name = (self.prefix + value_prefix + '_' + \
+ (suffix or name)).upper()
+ assert not (name and suffix) or name == suffix, \
+ 'Flag/enumvalue name %s != suffix %s' % (name, suffix)
+ self.write(' %s = %s,\n' % (use_name, val.getAttribute('value')))
+
+ def do_gtkdoc(self, node, value_prefix):
+ self.write(' * @')
+ self.write((self.prefix + value_prefix + '_' +
+ node.getAttribute('suffix')).upper())
+ self.write(': <![CDATA[')
+ docstring = get_by_path(node, 'docstring')
+ self.write(get_descendant_text(docstring).replace('\n', ' '))
+ self.write(']]>\n')
+
+ # Footer
+ def do_footer(self):
+ self.write("""
+#ifdef __cplusplus
+}
+#endif
+""")
+
+if __name__ == '__main__':
+ argv = argv[1:]
+ Generator(argv[0], xml.dom.minidom.parse(argv[1]))()
diff --git a/tools/check-c-style.sh b/tools/check-c-style.sh
new file mode 100644
index 0000000..dd62fb7
--- /dev/null
+++ b/tools/check-c-style.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+fail=0
+
+( . "${tools_dir}"/check-misc.sh ) || fail=$?
+
+if grep -n '^ *GError *\*[[:alpha:]_][[:alnum:]_]* *;' "$@"
+then
+ echo "^^^ The above files contain uninitialized GError*s - they should be"
+ echo " initialized to NULL"
+ fail=1
+fi
+
+# The first regex finds function calls like foo() (as opposed to foo ()).
+# It attempts to ignore string constants (may cause false negatives).
+# The second and third ignore block comments (gtkdoc uses foo() as markup).
+# The fourth ignores cpp so you can
+# #define foo(bar) (_real_foo (__FUNC__, bar)) (cpp insists on foo() style).
+if grep -n '^[^"]*[[:lower:]](' "$@" \
+ | grep -v '^[-[:alnum:]_./]*:[[:digit:]]*: *\*' \
+ | grep -v '^[-[:alnum:]_./]*:[[:digit:]]*: */\*' \
+ | grep -v '^[-[:alnum:]_./]*:[[:digit:]]*: *#'
+then
+ echo "^^^ Our coding style is to use function calls like foo (), not foo()"
+ fail=1
+fi
+
+if grep -En '[(][[:alnum:]_]+ ?\*[)][(]?[[:alpha:]_]' "$@"; then
+ echo "^^^ Our coding style is to have a space between a cast and the "
+ echo " thing being cast"
+ fail=1
+fi
+
+# this only spots casts
+if grep -En '[(][[:alnum:]_]+\*+[)]' "$@"; then
+ echo "^^^ Our coding style is to have a space before the * of pointer types"
+ echo " (regex 1)"
+ fail=1
+fi
+# ... and this only spots variable declarations and function return types
+if grep -En '^ *(static |const |)* *[[:alnum:]_]+\*+([[:alnum:]_]|;|$)' \
+ "$@"; then
+ echo "^^^ Our coding style is to have a space before the * of pointer types"
+ echo " (regex 2)"
+ fail=1
+fi
+
+if test -n "$CHECK_FOR_LONG_LINES"
+then
+ if egrep -n '.{80,}' "$@"
+ then
+ echo "^^^ The above files contain long lines"
+ fail=1
+ fi
+fi
+
+exit $fail
diff --git a/tools/check-coding-style.mk b/tools/check-coding-style.mk
new file mode 100644
index 0000000..1c0a60f
--- /dev/null
+++ b/tools/check-coding-style.mk
@@ -0,0 +1,17 @@
+check-coding-style:
+ @fail=0; \
+ if test -n "$(check_misc_sources)"; then \
+ tools_dir=$(top_srcdir)/tools \
+ sh $(top_srcdir)/tools/check-misc.sh \
+ $(addprefix $(srcdir)/,$(check_misc_sources)) || fail=1; \
+ fi; \
+ if test -n "$(check_c_sources)"; then \
+ tools_dir=$(top_srcdir)/tools \
+ sh $(top_srcdir)/tools/check-c-style.sh \
+ $(addprefix $(srcdir)/,$(check_c_sources)) || fail=1; \
+ fi;\
+ if test yes = "$(ENABLE_CODING_STYLE_CHECKS)"; then \
+ exit "$$fail";\
+ else \
+ exit 0;\
+ fi
diff --git a/tools/check-misc.sh b/tools/check-misc.sh
new file mode 100644
index 0000000..89e8e87
--- /dev/null
+++ b/tools/check-misc.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+fail=0
+
+( . "${tools_dir}"/check-whitespace.sh ) || fail=$?
+
+if egrep '(Free\s*Software\s*Foundation.*02139|02111-1307)' "$@"
+then
+ echo "^^^ The above files contain the FSF's old address in GPL headers"
+ fail=1
+fi
+
+exit $fail
diff --git a/tools/check-whitespace.sh b/tools/check-whitespace.sh
new file mode 100644
index 0000000..5348331
--- /dev/null
+++ b/tools/check-whitespace.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+fail=0
+
+if grep -n ' $' "$@"
+then
+ echo "^^^ The above files contain unwanted trailing spaces"
+ fail=1
+fi
+
+if grep -n ' ' "$@"
+then
+ echo "^^^ The above files contain tabs"
+ fail=1
+fi
+
+exit $fail
diff --git a/tools/doc-generator.xsl b/tools/doc-generator.xsl
new file mode 100644
index 0000000..76fc969
--- /dev/null
+++ b/tools/doc-generator.xsl
@@ -0,0 +1,1199 @@
+<!-- Generate HTML documentation from the Telepathy specification.
+The master copy of this stylesheet is in the Telepathy spec repository -
+please make any changes there.
+
+Copyright (C) 2006-2008 Collabora Limited
+
+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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ exclude-result-prefixes="tp html">
+ <!--Don't move the declaration of the HTML namespace up here — XMLNSs
+ don't work ideally in the presence of two things that want to use the
+ absence of a prefix, sadly. -->
+
+ <xsl:param name="allow-undefined-interfaces" select="false()"/>
+
+ <xsl:template match="html:* | @*" mode="html">
+ <xsl:copy>
+ <xsl:apply-templates mode="html"/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="tp:type" mode="html">
+ <xsl:call-template name="tp-type">
+ <xsl:with-param name="tp-type" select="string(.)"/>
+ </xsl:call-template>
+ </xsl:template>
+
+ <!-- tp:dbus-ref: reference a D-Bus interface, signal, method or property -->
+ <xsl:template match="tp:dbus-ref" mode="html">
+ <xsl:variable name="name">
+ <xsl:choose>
+ <xsl:when test="@namespace">
+ <xsl:value-of select="@namespace"/>
+ <xsl:text>.</xsl:text>
+ </xsl:when>
+ </xsl:choose>
+ <xsl:value-of select="string(.)"/>
+ </xsl:variable>
+
+ <xsl:choose>
+ <xsl:when test="//interface[@name=$name]
+ or //interface/method[concat(../@name, '.', @name)=$name]
+ or //interface/signal[concat(../@name, '.', @name)=$name]
+ or //interface/property[concat(../@name, '.', @name)=$name]
+ or //interface[@name=concat($name, '.DRAFT')]
+ or //interface/method[
+ concat(../@name, '.', @name)=concat($name, '.DRAFT')]
+ or //interface/signal[
+ concat(../@name, '.', @name)=concat($name, '.DRAFT')]
+ or //interface/property[
+ concat(../@name, '.', @name)=concat($name, '.DRAFT')]
+ ">
+ <a xmlns="http://www.w3.org/1999/xhtml" href="#{$name}">
+ <xsl:value-of select="string(.)"/>
+ </a>
+ </xsl:when>
+
+ <xsl:when test="$allow-undefined-interfaces">
+ <span xmlns="http://www.w3.org/1999/xhtml" title="defined elsewhere">
+ <xsl:value-of select="string(.)"/>
+ </span>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: cannot find D-Bus interface, method, </xsl:text>
+ <xsl:text>signal or property called '</xsl:text>
+ <xsl:value-of select="$name"/>
+ <xsl:text>'&#10;</xsl:text>
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!-- tp:member-ref: reference a property of the current interface -->
+ <xsl:template match="tp:member-ref" mode="html">
+ <xsl:variable name="prefix" select="concat(ancestor::interface/@name,
+ '.')"/>
+ <xsl:variable name="name" select="string(.)"/>
+
+ <xsl:if test="not(ancestor::interface)">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: Cannot use tp:member-ref when not in an</xsl:text>
+ <xsl:text> &lt;interface&gt;&#10;</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test="ancestor::interface/signal[@name=$name]"/>
+ <xsl:when test="ancestor::interface/method[@name=$name]"/>
+ <xsl:when test="ancestor::interface/property[@name=$name]"/>
+ <xsl:otherwise>
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: interface </xsl:text>
+ <xsl:value-of select="ancestor::interface/@name"/>
+ <xsl:text> has no signal/method/property called </xsl:text>
+ <xsl:value-of select="$name"/>
+ <xsl:text>&#10;</xsl:text>
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <a xmlns="http://www.w3.org/1999/xhtml" href="#{$prefix}{$name}">
+ <xsl:value-of select="$name"/>
+ </a>
+ </xsl:template>
+
+ <xsl:template match="*" mode="identity">
+ <xsl:copy>
+ <xsl:apply-templates mode="identity"/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="tp:docstring">
+ <xsl:apply-templates mode="html"/>
+ </xsl:template>
+
+ <xsl:template match="tp:added">
+ <p class="added" xmlns="http://www.w3.org/1999/xhtml">Added in
+ version <xsl:value-of select="@version"/>.
+ <xsl:apply-templates select="node()" mode="html"/></p>
+ </xsl:template>
+
+ <xsl:template match="tp:changed">
+ <xsl:choose>
+ <xsl:when test="node()">
+ <p class="changed" xmlns="http://www.w3.org/1999/xhtml">Changed in
+ version <xsl:value-of select="@version"/>:
+ <xsl:apply-templates select="node()" mode="html"/></p>
+ </xsl:when>
+ <xsl:otherwise>
+ <p class="changed">Changed in version
+ <xsl:value-of select="@version"/></p>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="tp:deprecated">
+ <p class="deprecated" xmlns="http://www.w3.org/1999/xhtml">Deprecated
+ since version <xsl:value-of select="@version"/>.
+ <xsl:apply-templates select="node()" mode="html"/></p>
+ </xsl:template>
+
+ <xsl:template match="tp:rationale" mode="html">
+ <div xmlns="http://www.w3.org/1999/xhtml" class="rationale">
+ <xsl:apply-templates select="node()" mode="html"/>
+ </div>
+ </xsl:template>
+
+ <xsl:template match="tp:errors">
+ <h1 xmlns="http://www.w3.org/1999/xhtml">Errors</h1>
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="tp:generic-types">
+ <h1 xmlns="http://www.w3.org/1999/xhtml">Generic types</h1>
+ <xsl:call-template name="do-types"/>
+ </xsl:template>
+
+ <xsl:template name="do-types">
+ <xsl:if test="tp:simple-type">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">Simple types</h2>
+ <xsl:apply-templates select="tp:simple-type"/>
+ </xsl:if>
+
+ <xsl:if test="tp:enum">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">Enumerated types:</h2>
+ <xsl:apply-templates select="tp:enum"/>
+ </xsl:if>
+
+ <xsl:if test="tp:flags">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">Sets of flags:</h2>
+ <xsl:apply-templates select="tp:flags"/>
+ </xsl:if>
+
+ <xsl:if test="tp:struct">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">Structure types</h2>
+ <xsl:apply-templates select="tp:struct"/>
+ </xsl:if>
+
+ <xsl:if test="tp:mapping">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">Mapping types</h2>
+ <xsl:apply-templates select="tp:mapping"/>
+ </xsl:if>
+
+ <xsl:if test="tp:external-type">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">Types defined elsewhere</h2>
+ <dl><xsl:apply-templates select="tp:external-type"/></dl>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template match="tp:error">
+ <h2 xmlns="http://www.w3.org/1999/xhtml"><a name="{concat(../@namespace, '.', translate(@name, ' ', ''))}"></a><xsl:value-of select="concat(../@namespace, '.', translate(@name, ' ', ''))"/></h2>
+ <xsl:apply-templates select="tp:docstring"/>
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ </xsl:template>
+
+ <xsl:template match="/tp:spec/tp:copyright">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates mode="text"/>
+ </div>
+ </xsl:template>
+ <xsl:template match="/tp:spec/tp:license">
+ <div xmlns="http://www.w3.org/1999/xhtml" class="license">
+ <xsl:apply-templates mode="html"/>
+ </div>
+ </xsl:template>
+
+ <xsl:template match="tp:copyright"/>
+ <xsl:template match="tp:license"/>
+
+ <xsl:template match="interface">
+ <h1 xmlns="http://www.w3.org/1999/xhtml"><a name="{@name}"></a><xsl:value-of select="@name"/></h1>
+
+ <xsl:if test="@tp:causes-havoc">
+ <p xmlns="http://www.w3.org/1999/xhtml" class="causes-havoc">
+ This interface is <xsl:value-of select="@tp:causes-havoc"/>
+ and is likely to cause havoc to your API/ABI if bindings are generated.
+ Don't include it in libraries that care about compatibility.
+ </p>
+ </xsl:if>
+
+ <xsl:if test="tp:requires">
+ <p>Implementations of this interface must also implement:</p>
+ <ul xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:for-each select="tp:requires">
+ <li><code><a href="#{@interface}"><xsl:value-of select="@interface"/></a></code></li>
+ </xsl:for-each>
+ </ul>
+ </xsl:if>
+
+ <xsl:apply-templates select="tp:docstring" />
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+
+ <xsl:choose>
+ <xsl:when test="method">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">Methods:</h2>
+ <xsl:apply-templates select="method"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <p xmlns="http://www.w3.org/1999/xhtml">Interface has no methods.</p>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="signal">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">Signals:</h2>
+ <xsl:apply-templates select="signal"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <p xmlns="http://www.w3.org/1999/xhtml">Interface has no signals.</p>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="tp:property">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">Telepathy Properties:</h2>
+ <p xmlns="http://www.w3.org/1999/xhtml">Accessed using the
+ <a href="#org.freedesktop.Telepathy.Properties">Telepathy
+ Properties</a> interface.</p>
+ <dl xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="tp:property"/>
+ </dl>
+ </xsl:when>
+ <xsl:otherwise>
+ <p xmlns="http://www.w3.org/1999/xhtml">Interface has no Telepathy
+ properties.</p>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="property">
+ <h2 xmlns="http://www.w3.org/1999/xhtml">D-Bus core Properties:</h2>
+ <p xmlns="http://www.w3.org/1999/xhtml">Accessed using the
+ org.freedesktop.DBus.Properties interface.</p>
+ <dl xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="property"/>
+ </dl>
+ </xsl:when>
+ <xsl:otherwise>
+ <p xmlns="http://www.w3.org/1999/xhtml">Interface has no D-Bus core
+ properties.</p>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:call-template name="do-types"/>
+
+ </xsl:template>
+
+ <xsl:template match="tp:flags">
+
+ <xsl:if test="not(@name) or @name = ''">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: missing @name on a tp:flags type&#10;</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <xsl:if test="not(@type) or @type = ''">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: missing @type on tp:flags type</xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:text>&#10;</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <h3>
+ <a name="type-{@name}">
+ <xsl:value-of select="@name"/>
+ </a>
+ </h3>
+ <xsl:apply-templates select="tp:docstring" />
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ <dl xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:variable name="value-prefix">
+ <xsl:choose>
+ <xsl:when test="@value-prefix">
+ <xsl:value-of select="@value-prefix"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@name"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:for-each select="tp:flag">
+ <dt xmlns="http://www.w3.org/1999/xhtml"><code><xsl:value-of select="concat($value-prefix, '_', @suffix)"/> = <xsl:value-of select="@value"/></code></dt>
+ <xsl:choose>
+ <xsl:when test="tp:docstring">
+ <dd xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="tp:docstring" />
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ </dd>
+ </xsl:when>
+ <xsl:otherwise>
+ <dd xmlns="http://www.w3.org/1999/xhtml">(Undocumented)</dd>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </dl>
+ </xsl:template>
+
+ <xsl:template match="tp:enum">
+
+ <xsl:if test="not(@name) or @name = ''">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: missing @name on a tp:enum type&#10;</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <xsl:if test="not(@type) or @type = ''">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: missing @type on tp:enum type</xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:text>&#10;</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <h3 xmlns="http://www.w3.org/1999/xhtml">
+ <a name="type-{@name}">
+ <xsl:value-of select="@name"/>
+ </a>
+ </h3>
+ <xsl:apply-templates select="tp:docstring" />
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ <dl xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:variable name="value-prefix">
+ <xsl:choose>
+ <xsl:when test="@value-prefix">
+ <xsl:value-of select="@value-prefix"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@name"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:for-each select="tp:enumvalue">
+ <dt xmlns="http://www.w3.org/1999/xhtml"><code><xsl:value-of select="concat($value-prefix, '_', @suffix)"/> = <xsl:value-of select="@value"/></code></dt>
+ <xsl:choose>
+ <xsl:when test="tp:docstring">
+ <dd xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="tp:docstring" />
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ </dd>
+ </xsl:when>
+ <xsl:otherwise>
+ <dd xmlns="http://www.w3.org/1999/xhtml">(Undocumented)</dd>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </dl>
+ </xsl:template>
+
+ <xsl:template match="property">
+
+ <xsl:if test="not(parent::interface)">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: property </xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:text> does not have an interface as parent&#10;</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <xsl:if test="not(@name) or @name = ''">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: missing @name on a property of </xsl:text>
+ <xsl:value-of select="../@name"/>
+ <xsl:text>&#10;</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <xsl:if test="not(@type) or @type = ''">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: missing @type on property </xsl:text>
+ <xsl:value-of select="concat(../@name, '.', @name)"/>
+ <xsl:text>: '</xsl:text>
+ <xsl:value-of select="@access"/>
+ <xsl:text>'&#10;</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <dt xmlns="http://www.w3.org/1999/xhtml">
+ <a name="{concat(../@name, '.', @name)}">
+ <code><xsl:value-of select="@name"/></code>
+ </a>
+ <xsl:text> − </xsl:text>
+ <code><xsl:value-of select="@type"/></code>
+ <xsl:call-template name="parenthesized-tp-type"/>
+ <xsl:text>, </xsl:text>
+ <xsl:choose>
+ <xsl:when test="@access = 'read'">
+ <xsl:text>read-only</xsl:text>
+ </xsl:when>
+ <xsl:when test="@access = 'write'">
+ <xsl:text>write-only</xsl:text>
+ </xsl:when>
+ <xsl:when test="@access = 'readwrite'">
+ <xsl:text>read/write</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: unknown or missing value for </xsl:text>
+ <xsl:text>@access on property </xsl:text>
+ <xsl:value-of select="concat(../@name, '.', @name)"/>
+ <xsl:text>: '</xsl:text>
+ <xsl:value-of select="@access"/>
+ <xsl:text>'&#10;</xsl:text>
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+ </dt>
+ <dd xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="tp:docstring"/>
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ </dd>
+ </xsl:template>
+
+ <xsl:template match="tp:property">
+ <dt xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:if test="@name">
+ <code><xsl:value-of select="@name"/></code> −
+ </xsl:if>
+ <code><xsl:value-of select="@type"/></code>
+ </dt>
+ <dd xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="tp:docstring"/>
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ </dd>
+ </xsl:template>
+
+ <xsl:template match="tp:mapping">
+ <div xmlns="http://www.w3.org/1999/xhtml" class="struct">
+ <h3>
+ <a name="type-{@name}">
+ <xsl:value-of select="@name"/>
+ </a> − a{
+ <xsl:for-each select="tp:member">
+ <xsl:value-of select="@type"/>
+ <xsl:text>: </xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:if test="position() != last()"> &#x2192; </xsl:if>
+ </xsl:for-each>
+ }
+ </h3>
+ <div class="docstring">
+ <xsl:apply-templates select="tp:docstring"/>
+ <xsl:if test="string(@array-name) != ''">
+ <p>In bindings that need a separate name, arrays of
+ <xsl:value-of select="@name"/> should be called
+ <xsl:value-of select="@array-name"/>.</p>
+ </xsl:if>
+ </div>
+ <div>
+ <h4>Members</h4>
+ <dl>
+ <xsl:apply-templates select="tp:member" mode="members-in-docstring"/>
+ </dl>
+ </div>
+ </div>
+ </xsl:template>
+
+ <xsl:template match="tp:docstring" mode="in-index"/>
+
+ <xsl:template match="tp:simple-type | tp:enum | tp:flags | tp:external-type"
+ mode="in-index">
+ − <xsl:value-of select="@type"/>
+ </xsl:template>
+
+ <xsl:template match="tp:simple-type">
+
+ <xsl:if test="not(@name) or @name = ''">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: missing @name on a tp:simple-type&#10;</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <xsl:if test="not(@type) or @type = ''">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: missing @type on tp:simple-type</xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:text>&#10;</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <div xmlns="http://www.w3.org/1999/xhtml" class="simple-type">
+ <h3>
+ <a name="type-{@name}">
+ <xsl:value-of select="@name"/>
+ </a> − <xsl:value-of select="@type"/>
+ </h3>
+ <div class="docstring">
+ <xsl:apply-templates select="tp:docstring"/>
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ </div>
+ </div>
+ </xsl:template>
+
+ <xsl:template match="tp:external-type">
+
+ <xsl:if test="not(@name) or @name = ''">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: missing @name on a tp:external-type&#10;</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <xsl:if test="not(@type) or @type = ''">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: missing @type on tp:external-type</xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:text>&#10;</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <div xmlns="http://www.w3.org/1999/xhtml" class="external-type">
+ <dt>
+ <a name="type-{@name}">
+ <xsl:value-of select="@name"/>
+ </a> − <xsl:value-of select="@type"/>
+ </dt>
+ <dd>Defined by: <xsl:value-of select="@from"/></dd>
+ </div>
+ </xsl:template>
+
+ <xsl:template match="tp:struct" mode="in-index">
+ − ( <xsl:for-each select="tp:member">
+ <xsl:value-of select="@type"/>
+ <xsl:if test="position() != last()">, </xsl:if>
+ </xsl:for-each> )
+ </xsl:template>
+
+ <xsl:template match="tp:mapping" mode="in-index">
+ − a{ <xsl:for-each select="tp:member">
+ <xsl:value-of select="@type"/>
+ <xsl:if test="position() != last()"> &#x2192; </xsl:if>
+ </xsl:for-each> }
+ </xsl:template>
+
+ <xsl:template match="tp:struct">
+ <div xmlns="http://www.w3.org/1999/xhtml" class="struct">
+ <h3>
+ <a name="type-{@name}">
+ <xsl:value-of select="@name"/>
+ </a> − (
+ <xsl:for-each select="tp:member">
+ <xsl:value-of select="@type"/>
+ <xsl:text>: </xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:if test="position() != last()">, </xsl:if>
+ </xsl:for-each>
+ )
+ </h3>
+ <div class="docstring">
+ <xsl:apply-templates select="tp:docstring"/>
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ </div>
+ <xsl:choose>
+ <xsl:when test="string(@array-name) != ''">
+ <p>In bindings that need a separate name, arrays of
+ <xsl:value-of select="@name"/> should be called
+ <xsl:value-of select="@array-name"/>.</p>
+ </xsl:when>
+ <xsl:otherwise>
+ <p>Arrays of <xsl:value-of select="@name"/> don't generally
+ make sense.</p>
+ </xsl:otherwise>
+ </xsl:choose>
+ <div>
+ <h4>Members</h4>
+ <dl>
+ <xsl:apply-templates select="tp:member" mode="members-in-docstring"/>
+ </dl>
+ </div>
+ </div>
+ </xsl:template>
+
+ <xsl:template match="method">
+
+ <xsl:if test="not(parent::interface)">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: method </xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:text> does not have an interface as parent&#10;</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <xsl:if test="not(@name) or @name = ''">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: missing @name on a method of </xsl:text>
+ <xsl:value-of select="../@name"/>
+ <xsl:text>&#10;</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <xsl:for-each select="arg">
+ <xsl:if test="not(@type) or @type = ''">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: an arg of method </xsl:text>
+ <xsl:value-of select="concat(../../@name, '.', ../@name)"/>
+ <xsl:text> has no type</xsl:text>
+ </xsl:message>
+ </xsl:if>
+ <xsl:choose>
+ <xsl:when test="@direction='in'">
+ <xsl:if test="not(@name) or @name = ''">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: an 'in' arg of method </xsl:text>
+ <xsl:value-of select="concat(../../@name, '.', ../@name)"/>
+ <xsl:text> has no name</xsl:text>
+ </xsl:message>
+ </xsl:if>
+ </xsl:when>
+ <xsl:when test="@direction='out'">
+ <!-- FIXME: This is commented out until someone with a lot of time
+ on their hands goes through the spec adding names to all the "out"
+ arguments
+
+ <xsl:if test="not(@name) or @name = ''">
+ <xsl:message terminate="no">
+ <xsl:text>INFO: an 'out' arg of method </xsl:text>
+ <xsl:value-of select="concat(../../@name, '.', ../@name)"/>
+ <xsl:text> has no name</xsl:text>
+ </xsl:message>
+ </xsl:if>-->
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: an arg of method </xsl:text>
+ <xsl:value-of select="concat(../../@name, '.', ../@name)"/>
+ <xsl:text> has direction neither 'in' nor 'out'</xsl:text>
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+
+ <div xmlns="http://www.w3.org/1999/xhtml" class="method">
+ <h3 xmlns="http://www.w3.org/1999/xhtml">
+ <a name="{concat(../@name, concat('.', @name))}">
+ <xsl:value-of select="@name"/>
+ </a> (
+ <xsl:for-each xmlns="" select="arg[@direction='in']">
+ <xsl:value-of select="@type"/>: <xsl:value-of select="@name"/>
+ <xsl:if test="position() != last()">, </xsl:if>
+ </xsl:for-each>
+ ) &#x2192;
+ <xsl:choose>
+ <xsl:when test="arg[@direction='out']">
+ <xsl:for-each xmlns="" select="arg[@direction='out']">
+ <xsl:value-of select="@type"/>
+ <xsl:if test="position() != last()">, </xsl:if>
+ </xsl:for-each>
+ </xsl:when>
+ <xsl:otherwise>nothing</xsl:otherwise>
+ </xsl:choose>
+ </h3>
+ <div xmlns="http://www.w3.org/1999/xhtml" class="docstring">
+ <xsl:apply-templates select="tp:docstring" />
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ </div>
+
+ <xsl:if test="arg[@direction='in']">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <h4>Parameters</h4>
+ <dl xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="arg[@direction='in']"
+ mode="parameters-in-docstring"/>
+ </dl>
+ </div>
+ </xsl:if>
+
+ <xsl:if test="arg[@direction='out']">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <h4>Returns</h4>
+ <dl xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="arg[@direction='out']"
+ mode="returns-in-docstring"/>
+ </dl>
+ </div>
+ </xsl:if>
+
+ <xsl:if test="tp:possible-errors">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <h4>Possible errors</h4>
+ <dl xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="tp:possible-errors/tp:error"/>
+ </dl>
+ </div>
+ </xsl:if>
+
+ </div>
+ </xsl:template>
+
+ <xsl:template name="tp-type">
+ <xsl:param name="tp-type"/>
+ <xsl:param name="type"/>
+
+ <xsl:variable name="single-type">
+ <xsl:choose>
+ <xsl:when test="contains($tp-type, '[]')">
+ <xsl:value-of select="substring-before($tp-type, '[]')"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$tp-type"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:variable name="type-of-tp-type">
+ <xsl:if test="contains($tp-type, '[]')">
+ <!-- one 'a', plus one for each [ after the [], and delete all ] -->
+ <xsl:value-of select="concat('a',
+ translate(substring-after($tp-type, '[]'), '[]', 'a'))"/>
+ </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test="//tp:simple-type[@name=$single-type]">
+ <xsl:value-of select="string(//tp:simple-type[@name=$single-type]/@type)"/>
+ </xsl:when>
+ <xsl:when test="//tp:struct[@name=$single-type]">
+ <xsl:text>(</xsl:text>
+ <xsl:for-each select="//tp:struct[@name=$single-type]/tp:member">
+ <xsl:value-of select="@type"/>
+ </xsl:for-each>
+ <xsl:text>)</xsl:text>
+ </xsl:when>
+ <xsl:when test="//tp:enum[@name=$single-type]">
+ <xsl:value-of select="string(//tp:enum[@name=$single-type]/@type)"/>
+ </xsl:when>
+ <xsl:when test="//tp:flags[@name=$single-type]">
+ <xsl:value-of select="string(//tp:flags[@name=$single-type]/@type)"/>
+ </xsl:when>
+ <xsl:when test="//tp:mapping[@name=$single-type]">
+ <xsl:text>a{</xsl:text>
+ <xsl:for-each select="//tp:mapping[@name=$single-type]/tp:member">
+ <xsl:value-of select="@type"/>
+ </xsl:for-each>
+ <xsl:text>}</xsl:text>
+ </xsl:when>
+ <xsl:when test="//tp:external-type[@name=$single-type]">
+ <xsl:value-of select="string(//tp:external-type[@name=$single-type]/@type)"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: Unable to find type '</xsl:text>
+ <xsl:value-of select="$tp-type"/>
+ <xsl:text>'&#10;</xsl:text>
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:if test="string($type) != '' and
+ string($type-of-tp-type) != string($type)">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: tp:type '</xsl:text>
+ <xsl:value-of select="$tp-type"/>
+ <xsl:text>' has D-Bus type '</xsl:text>
+ <xsl:value-of select="$type-of-tp-type"/>
+ <xsl:text>' but has been used with type='</xsl:text>
+ <xsl:value-of select="$type"/>
+ <xsl:text>'&#10;</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <a href="#type-{$single-type}"><xsl:value-of select="$tp-type"/></a>
+
+ </xsl:template>
+
+ <xsl:template name="parenthesized-tp-type">
+ <xsl:if test="@tp:type">
+ <xsl:text> (</xsl:text>
+ <xsl:call-template name="tp-type">
+ <xsl:with-param name="tp-type" select="@tp:type"/>
+ <xsl:with-param name="type" select="@type"/>
+ </xsl:call-template>
+ <xsl:text>)</xsl:text>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template match="tp:member" mode="members-in-docstring">
+ <dt xmlns="http://www.w3.org/1999/xhtml">
+ <code><xsl:value-of select="@name"/></code> −
+ <code><xsl:value-of select="@type"/></code>
+ <xsl:call-template name="parenthesized-tp-type"/>
+ </dt>
+ <dd xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:choose>
+ <xsl:when test="tp:docstring">
+ <xsl:apply-templates select="tp:docstring" />
+ </xsl:when>
+ <xsl:otherwise>
+ <em>(undocumented)</em>
+ </xsl:otherwise>
+ </xsl:choose>
+ </dd>
+ </xsl:template>
+
+ <xsl:template match="arg" mode="parameters-in-docstring">
+ <dt xmlns="http://www.w3.org/1999/xhtml">
+ <code><xsl:value-of select="@name"/></code> −
+ <code><xsl:value-of select="@type"/></code>
+ <xsl:call-template name="parenthesized-tp-type"/>
+ </dt>
+ <dd xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="tp:docstring" />
+ </dd>
+ </xsl:template>
+
+ <xsl:template match="arg" mode="returns-in-docstring">
+ <dt xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:if test="@name">
+ <code><xsl:value-of select="@name"/></code> −
+ </xsl:if>
+ <code><xsl:value-of select="@type"/></code>
+ <xsl:call-template name="parenthesized-tp-type"/>
+ </dt>
+ <dd xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="tp:docstring"/>
+ </dd>
+ </xsl:template>
+
+ <xsl:template match="tp:possible-errors/tp:error">
+ <dt xmlns="http://www.w3.org/1999/xhtml">
+ <code><xsl:value-of select="@name"/></code>
+ </dt>
+ <dd xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:variable name="name" select="@name"/>
+ <xsl:choose>
+ <xsl:when test="tp:docstring">
+ <xsl:apply-templates select="tp:docstring"/>
+ </xsl:when>
+ <xsl:when test="//tp:errors/tp:error[concat(../@namespace, '.', translate(@name, ' ', ''))=$name]/tp:docstring">
+ <xsl:apply-templates select="//tp:errors/tp:error[concat(../@namespace, '.', translate(@name, ' ', ''))=$name]/tp:docstring"/> <em xmlns="http://www.w3.org/1999/xhtml">(generic description)</em>
+ </xsl:when>
+ <xsl:otherwise>
+ (Undocumented.)
+ </xsl:otherwise>
+ </xsl:choose>
+ </dd>
+ </xsl:template>
+
+ <xsl:template match="signal">
+
+ <xsl:if test="not(parent::interface)">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: signal </xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:text> does not have an interface as parent&#10;</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <xsl:if test="not(@name) or @name = ''">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: missing @name on a signal of </xsl:text>
+ <xsl:value-of select="../@name"/>
+ <xsl:text>&#10;</xsl:text>
+ </xsl:message>
+ </xsl:if>
+
+ <xsl:for-each select="arg">
+ <xsl:if test="not(@type) or @type = ''">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: an arg of signal </xsl:text>
+ <xsl:value-of select="concat(../../@name, '.', ../@name)"/>
+ <xsl:text> has no type</xsl:text>
+ </xsl:message>
+ </xsl:if>
+ <xsl:if test="not(@name) or @name = ''">
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: an arg of signal </xsl:text>
+ <xsl:value-of select="concat(../../@name, '.', ../@name)"/>
+ <xsl:text> has no name</xsl:text>
+ </xsl:message>
+ </xsl:if>
+ <xsl:choose>
+ <xsl:when test="not(@direction)"/>
+ <xsl:when test="@direction='in'">
+ <xsl:message terminate="no">
+ <xsl:text>INFO: an arg of signal </xsl:text>
+ <xsl:value-of select="concat(../../@name, '.', ../@name)"/>
+ <xsl:text> has unnecessary direction 'in'</xsl:text>
+ </xsl:message>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:message terminate="yes">
+ <xsl:text>ERR: an arg of signal </xsl:text>
+ <xsl:value-of select="concat(../../@name, '.', ../@name)"/>
+ <xsl:text> has direction other than 'in'</xsl:text>
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+
+ <div xmlns="http://www.w3.org/1999/xhtml" class="signal">
+ <h3 xmlns="http://www.w3.org/1999/xhtml">
+ <a name="{concat(../@name, concat('.', @name))}">
+ <xsl:value-of select="@name"/>
+ </a> (
+ <xsl:for-each xmlns="" select="arg">
+ <xsl:value-of select="@type"/>: <xsl:value-of select="@name"/>
+ <xsl:if test="position() != last()">, </xsl:if>
+ </xsl:for-each>
+ )</h3>
+
+ <div xmlns="http://www.w3.org/1999/xhtml" class="docstring">
+ <xsl:apply-templates select="tp:docstring"/>
+ <xsl:apply-templates select="tp:added"/>
+ <xsl:apply-templates select="tp:changed"/>
+ <xsl:apply-templates select="tp:deprecated"/>
+ </div>
+
+ <xsl:if test="arg">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <h4>Parameters</h4>
+ <dl xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:apply-templates select="arg" mode="parameters-in-docstring"/>
+ </dl>
+ </div>
+ </xsl:if>
+ </div>
+ </xsl:template>
+
+ <xsl:output method="xml" indent="no" encoding="ascii"
+ omit-xml-declaration="yes"
+ doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
+ doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" />
+
+ <xsl:template match="/tp:spec">
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>
+ <xsl:value-of select="tp:title"/>
+ <xsl:if test="tp:version">
+ <xsl:text> version </xsl:text>
+ <xsl:value-of select="tp:version"/>
+ </xsl:if>
+ </title>
+ <style type="text/css">
+
+ body {
+ font-family: sans-serif;
+ margin: 2em;
+ height: 100%;
+ font-size: 1.2em;
+ }
+ h1 {
+ padding-top: 5px;
+ padding-bottom: 5px;
+ font-size: 1.6em;
+ background: #dadae2;
+ }
+ h2 {
+ font-size: 1.3em;
+ }
+ h3 {
+ font-size: 1.2em;
+ }
+ a:link, a:visited, a:link:hover, a:visited:hover {
+ font-weight: bold;
+ }
+ .topbox {
+ padding-top: 10px;
+ padding-left: 10px;
+ border-bottom: black solid 1px;
+ padding-bottom: 10px;
+ background: #dadae2;
+ font-size: 2em;
+ font-weight: bold;
+ color: #5c5c5c;
+ }
+ .topnavbox {
+ padding-left: 10px;
+ padding-top: 5px;
+ padding-bottom: 5px;
+ background: #abacba;
+ border-bottom: black solid 1px;
+ font-size: 1.2em;
+ }
+ .topnavbox a{
+ color: black;
+ font-weight: normal;
+ }
+ .sidebar {
+ float: left;
+ /* width:9em;
+ border-right:#abacba solid 1px;
+ border-left: #abacba solid 1px;
+ height:100%; */
+ border: #abacba solid 1px;
+ padding-left: 10px;
+ margin-left: 10px;
+ padding-right: 10px;
+ margin-right: 10px;
+ color: #5d5d5d;
+ background: #dadae2;
+ }
+ .sidebar a {
+ text-decoration: none;
+ border-bottom: #e29625 dotted 1px;
+ color: #e29625;
+ font-weight: normal;
+ }
+ .sidebar h1 {
+ font-size: 1.2em;
+ color: black;
+ }
+ .sidebar ul {
+ padding-left: 25px;
+ padding-bottom: 10px;
+ border-bottom: #abacba solid 1px;
+ }
+ .sidebar li {
+ padding-top: 2px;
+ padding-bottom: 2px;
+ }
+ .sidebar h2 {
+ font-style:italic;
+ font-size: 0.81em;
+ padding-left: 5px;
+ padding-right: 5px;
+ font-weight: normal;
+ }
+ .date {
+ font-size: 0.6em;
+ float: right;
+ font-style: italic;
+ }
+ .method, .signal, .property {
+ margin-left: 1em;
+ margin-right: 4em;
+ }
+ .rationale {
+ font-style: italic;
+ border-left: 0.25em solid #808080;
+ padding-left: 0.5em;
+ }
+
+ .added {
+ color: #006600;
+ background: #ffffff;
+ }
+ .deprecated {
+ color: #ff0000;
+ background: #ffffff;
+ }
+ table, tr, td, th {
+ border: 1px solid #666;
+ }
+
+ </style>
+ </head>
+ <body>
+ <h1 class="topbox">
+ <xsl:value-of select="tp:title" />
+ </h1>
+ <xsl:if test="tp:version">
+ <h2>Version <xsl:value-of select="string(tp:version)"/></h2>
+ </xsl:if>
+ <xsl:apply-templates select="tp:copyright"/>
+ <xsl:apply-templates select="tp:license"/>
+ <xsl:apply-templates select="tp:docstring"/>
+
+ <h2>Interfaces</h2>
+ <ul>
+ <xsl:for-each select="//node/interface">
+ <li><code><a href="#{@name}"><xsl:value-of select="@name"/></a></code></li>
+ </xsl:for-each>
+ </ul>
+
+ <xsl:apply-templates select="//node"/>
+ <xsl:apply-templates select="tp:generic-types"/>
+ <xsl:apply-templates select="tp:errors"/>
+
+ <h1>Index</h1>
+ <h2>Index of interfaces</h2>
+ <ul>
+ <xsl:for-each select="//node/interface">
+ <li><code><a href="#{@name}"><xsl:value-of select="@name"/></a></code></li>
+ </xsl:for-each>
+ </ul>
+ <h2>Index of types</h2>
+ <ul>
+ <xsl:for-each select="//tp:simple-type | //tp:enum | //tp:flags | //tp:mapping | //tp:struct | //tp:external-type">
+ <xsl:sort select="@name"/>
+ <li>
+ <code>
+ <a href="#type-{@name}">
+ <xsl:value-of select="@name"/>
+ </a>
+ </code>
+ <xsl:apply-templates mode="in-index" select="."/>
+ </li>
+ </xsl:for-each>
+ </ul>
+ </body>
+ </html>
+ </xsl:template>
+
+ <xsl:template match="node">
+ <xsl:apply-templates />
+ </xsl:template>
+
+ <xsl:template match="text()">
+ <xsl:if test="normalize-space(.) != ''">
+ <xsl:message terminate="yes">
+ <xsl:text>Stray text: {{{</xsl:text>
+ <xsl:value-of select="." />
+ <xsl:text>}}}&#10;</xsl:text>
+ </xsl:message>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template match="*">
+ <xsl:message terminate="yes">
+ <xsl:text>Unrecognised element: {</xsl:text>
+ <xsl:value-of select="namespace-uri(.)" />
+ <xsl:text>}</xsl:text>
+ <xsl:value-of select="local-name(.)" />
+ <xsl:text>&#10;</xsl:text>
+ </xsl:message>
+ </xsl:template>
+</xsl:stylesheet>
+
+<!-- vim:set sw=2 sts=2 et: -->
diff --git a/tools/glib-ginterface-gen.py b/tools/glib-ginterface-gen.py
new file mode 100644
index 0000000..13f7f69
--- /dev/null
+++ b/tools/glib-ginterface-gen.py
@@ -0,0 +1,802 @@
+#!/usr/bin/python
+
+# glib-ginterface-gen.py: service-side interface generator
+#
+# Generate dbus-glib 0.x service GInterfaces from the Telepathy specification.
+# The master copy of this program is in the telepathy-glib repository -
+# please make any changes there.
+#
+# Copyright (C) 2006, 2007 Collabora Limited
+#
+# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import sys
+import os.path
+import xml.dom.minidom
+
+from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \
+ NS_TP, dbus_gutils_wincaps_to_uscore, \
+ signal_to_marshal_name, method_to_glue_marshal_name
+
+
+NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+
+class Generator(object):
+
+ def __init__(self, dom, prefix, basename, signal_marshal_prefix,
+ headers, end_headers, not_implemented_func,
+ allow_havoc):
+ self.dom = dom
+ self.__header = []
+ self.__body = []
+
+ assert prefix.endswith('_')
+ assert not signal_marshal_prefix.endswith('_')
+
+ # The main_prefix, sub_prefix thing is to get:
+ # FOO_ -> (FOO_, _)
+ # FOO_SVC_ -> (FOO_, _SVC_)
+ # but
+ # FOO_BAR/ -> (FOO_BAR_, _)
+ # FOO_BAR/SVC_ -> (FOO_BAR_, _SVC_)
+
+ if '/' in prefix:
+ main_prefix, sub_prefix = prefix.upper().split('/', 1)
+ prefix = prefix.replace('/', '_')
+ else:
+ main_prefix, sub_prefix = prefix.upper().split('_', 1)
+
+ self.MAIN_PREFIX_ = main_prefix + '_'
+ self._SUB_PREFIX_ = '_' + sub_prefix
+
+ self.Prefix_ = prefix
+ self.Prefix = prefix.replace('_', '')
+ self.prefix_ = prefix.lower()
+ self.PREFIX_ = prefix.upper()
+
+ self.basename = basename
+ self.signal_marshal_prefix = signal_marshal_prefix
+ self.headers = headers
+ self.end_headers = end_headers
+ self.not_implemented_func = not_implemented_func
+ self.allow_havoc = allow_havoc
+
+ def h(self, s):
+ self.__header.append(s)
+
+ def b(self, s):
+ self.__body.append(s)
+
+ def do_node(self, node):
+ node_name = node.getAttribute('name').replace('/', '')
+ node_name_mixed = self.node_name_mixed = node_name.replace('_', '')
+ node_name_lc = self.node_name_lc = node_name.lower()
+ node_name_uc = self.node_name_uc = node_name.upper()
+
+ interfaces = node.getElementsByTagName('interface')
+ assert len(interfaces) == 1, interfaces
+ interface = interfaces[0]
+ self.iface_name = interface.getAttribute('name')
+
+ tmp = interface.getAttribute('tp:implement-service')
+ if tmp == "no":
+ return
+
+ tmp = interface.getAttribute('tp:causes-havoc')
+ if tmp and not self.allow_havoc:
+ raise AssertionError('%s is %s' % (self.iface_name, tmp))
+
+ self.b('static const DBusGObjectInfo _%s%s_object_info;'
+ % (self.prefix_, node_name_lc))
+ self.b('')
+
+ methods = interface.getElementsByTagName('method')
+ signals = interface.getElementsByTagName('signal')
+ properties = interface.getElementsByTagName('property')
+ # Don't put properties in dbus-glib glue
+ glue_properties = []
+
+ self.b('struct _%s%sClass {' % (self.Prefix, node_name_mixed))
+ self.b(' GTypeInterface parent_class;')
+ for method in methods:
+ self.b(' %s %s;' % self.get_method_impl_names(method))
+ self.b('};')
+ self.b('')
+
+ if signals:
+ self.b('enum {')
+ for signal in signals:
+ self.b(' %s,' % self.get_signal_const_entry(signal))
+ self.b(' N_%s_SIGNALS' % node_name_uc)
+ self.b('};')
+ self.b('static guint %s_signals[N_%s_SIGNALS] = {0};'
+ % (node_name_lc, node_name_uc))
+ self.b('')
+
+ self.b('static void %s%s_base_init (gpointer klass);'
+ % (self.prefix_, node_name_lc))
+ self.b('')
+
+ self.b('GType')
+ self.b('%s%s_get_type (void)'
+ % (self.prefix_, node_name_lc))
+ self.b('{')
+ self.b(' static GType type = 0;')
+ self.b('')
+ self.b(' if (G_UNLIKELY (type == 0))')
+ self.b(' {')
+ self.b(' static const GTypeInfo info = {')
+ self.b(' sizeof (%s%sClass),' % (self.Prefix, node_name_mixed))
+ self.b(' %s%s_base_init, /* base_init */'
+ % (self.prefix_, node_name_lc))
+ self.b(' NULL, /* base_finalize */')
+ self.b(' NULL, /* class_init */')
+ self.b(' NULL, /* class_finalize */')
+ self.b(' NULL, /* class_data */')
+ self.b(' 0,')
+ self.b(' 0, /* n_preallocs */')
+ self.b(' NULL /* instance_init */')
+ self.b(' };')
+ self.b('')
+ self.b(' type = g_type_register_static (G_TYPE_INTERFACE,')
+ self.b(' "%s%s", &info, 0);' % (self.Prefix, node_name_mixed))
+ self.b(' }')
+ self.b('')
+ self.b(' return type;')
+ self.b('}')
+ self.b('')
+
+ self.h('/**')
+ self.h(' * %s%s:' % (self.Prefix, node_name_mixed))
+ self.h(' *')
+ self.h(' * Dummy typedef representing any implementation of this '
+ 'interface.')
+ self.h(' */')
+ self.h('typedef struct _%s%s %s%s;'
+ % (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed))
+ self.h('')
+ self.h('/**')
+ self.h(' * %s%sClass:' % (self.Prefix, node_name_mixed))
+ self.h(' *')
+ self.h(' * The class of %s%s.' % (self.Prefix, node_name_mixed))
+
+ if methods:
+ self.h(' *')
+ self.h(' * In a full implementation of this interface (i.e. all')
+ self.h(' * methods implemented), the interface initialization')
+ self.h(' * function used in G_IMPLEMENT_INTERFACE() would')
+ self.h(' * typically look like this:')
+ self.h(' *')
+ self.h(' * <programlisting>')
+ self.h(' * static void')
+ self.h(' * implement_%s (gpointer klass,' % self.node_name_lc)
+ self.h(' * gpointer unused G_GNUC_UNUSED)')
+ self.h(' * {')
+ # "#" is special to gtkdoc under some circumstances; it appears
+ # that escaping "##" as "#<!---->#" or "&#35;&#35;" doesn't work,
+ # but adding an extra hash symbol does. Thanks, gtkdoc :-(
+ self.h(' * #define IMPLEMENT(x) %s%s_implement_###x (\\'
+ % (self.prefix_, self.node_name_lc))
+ self.h(' * klass, my_object_###x)')
+
+ for method in methods:
+ class_member_name = method.getAttribute('tp:name-for-bindings')
+ class_member_name = class_member_name.lower()
+ self.h(' * IMPLEMENT (%s);' % class_member_name)
+
+ self.h(' * #undef IMPLEMENT')
+ self.h(' * }')
+ self.h(' * </programlisting>')
+ else:
+ self.h(' * This interface has no D-Bus methods, so an')
+ self.h(' * implementation can typically pass %NULL to')
+ self.h(' * G_IMPLEMENT_INTERFACE() as the interface')
+ self.h(' * initialization function.')
+
+ self.h(' */')
+
+ self.h('typedef struct _%s%sClass %s%sClass;'
+ % (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed))
+ self.h('')
+ self.h('GType %s%s_get_type (void);'
+ % (self.prefix_, node_name_lc))
+
+ gtype = self.current_gtype = \
+ self.MAIN_PREFIX_ + 'TYPE' + self._SUB_PREFIX_ + node_name_uc
+ classname = self.Prefix + node_name_mixed
+
+ self.h('#define %s \\\n (%s%s_get_type ())'
+ % (gtype, self.prefix_, node_name_lc))
+ self.h('#define %s%s(obj) \\\n'
+ ' (G_TYPE_CHECK_INSTANCE_CAST((obj), %s, %s))'
+ % (self.PREFIX_, node_name_uc, gtype, classname))
+ self.h('#define %sIS%s%s(obj) \\\n'
+ ' (G_TYPE_CHECK_INSTANCE_TYPE((obj), %s))'
+ % (self.MAIN_PREFIX_, self._SUB_PREFIX_, node_name_uc, gtype))
+ self.h('#define %s%s_GET_CLASS(obj) \\\n'
+ ' (G_TYPE_INSTANCE_GET_INTERFACE((obj), %s, %sClass))'
+ % (self.PREFIX_, node_name_uc, gtype, classname))
+ self.h('')
+ self.h('')
+
+ base_init_code = []
+
+ for method in methods:
+ self.do_method(method)
+
+ for signal in signals:
+ base_init_code.extend(self.do_signal(signal))
+
+ self.b('static inline void')
+ self.b('%s%s_base_init_once (gpointer klass G_GNUC_UNUSED)'
+ % (self.prefix_, node_name_lc))
+ self.b('{')
+
+ if properties:
+ self.b(' static TpDBusPropertiesMixinPropInfo properties[%d] = {'
+ % (len(properties) + 1))
+
+ for m in properties:
+ access = m.getAttribute('access')
+ assert access in ('read', 'write', 'readwrite')
+
+ if access == 'read':
+ flags = 'TP_DBUS_PROPERTIES_MIXIN_FLAG_READ'
+ elif access == 'write':
+ flags = 'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE'
+ else:
+ flags = ('TP_DBUS_PROPERTIES_MIXIN_FLAG_READ | '
+ 'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE')
+
+ self.b(' { 0, %s, "%s", 0, NULL, NULL }, /* %s */'
+ % (flags, m.getAttribute('type'), m.getAttribute('name')))
+
+ self.b(' { 0, 0, NULL, 0, NULL, NULL }')
+ self.b(' };')
+ self.b(' static TpDBusPropertiesMixinIfaceInfo interface =')
+ self.b(' { 0, properties, NULL, NULL };')
+ self.b('')
+
+
+ self.b(' dbus_g_object_type_install_info (%s%s_get_type (),'
+ % (self.prefix_, node_name_lc))
+ self.b(' &_%s%s_object_info);'
+ % (self.prefix_, node_name_lc))
+ self.b('')
+
+ if properties:
+ self.b(' interface.dbus_interface = g_quark_from_static_string '
+ '("%s");' % self.iface_name)
+
+ for i, m in enumerate(properties):
+ self.b(' properties[%d].name = g_quark_from_static_string ("%s");'
+ % (i, m.getAttribute('name')))
+ self.b(' properties[%d].type = %s;'
+ % (i, type_to_gtype(m.getAttribute('type'))[1]))
+
+ self.b(' tp_svc_interface_set_dbus_properties_info (%s, &interface);'
+ % self.current_gtype)
+
+ self.b('')
+
+ for s in base_init_code:
+ self.b(s)
+ self.b('}')
+
+ self.b('static void')
+ self.b('%s%s_base_init (gpointer klass)'
+ % (self.prefix_, node_name_lc))
+ self.b('{')
+ self.b(' static gboolean initialized = FALSE;')
+ self.b('')
+ self.b(' if (!initialized)')
+ self.b(' {')
+ self.b(' initialized = TRUE;')
+ self.b(' %s%s_base_init_once (klass);'
+ % (self.prefix_, node_name_lc))
+ self.b(' }')
+ # insert anything we need to do per implementation here
+ self.b('}')
+
+ self.h('')
+
+ self.b('static const DBusGMethodInfo _%s%s_methods[] = {'
+ % (self.prefix_, node_name_lc))
+
+ method_blob, offsets = self.get_method_glue(methods)
+
+ for method, offset in zip(methods, offsets):
+ self.do_method_glue(method, offset)
+
+ if len(methods) == 0:
+ # empty arrays are a gcc extension, so put in a dummy member
+ self.b(" { NULL, NULL, 0 }")
+
+ self.b('};')
+ self.b('')
+
+ self.b('static const DBusGObjectInfo _%s%s_object_info = {'
+ % (self.prefix_, node_name_lc))
+ self.b(' 0,') # version
+ self.b(' _%s%s_methods,' % (self.prefix_, node_name_lc))
+ self.b(' %d,' % len(methods))
+ self.b('"' + method_blob.replace('\0', '\\0') + '",')
+ self.b('"' + self.get_signal_glue(signals).replace('\0', '\\0') + '",')
+ self.b('"' +
+ self.get_property_glue(glue_properties).replace('\0', '\\0') +
+ '",')
+ self.b('};')
+ self.b('')
+
+ self.node_name_mixed = None
+ self.node_name_lc = None
+ self.node_name_uc = None
+
+ def get_method_glue(self, methods):
+ info = []
+ offsets = []
+
+ for method in methods:
+ offsets.append(len(''.join(info)))
+
+ info.append(self.iface_name + '\0')
+ info.append(method.getAttribute('name') + '\0')
+
+ info.append('A\0') # async
+
+ counter = 0
+ for arg in method.getElementsByTagName('arg'):
+ out = arg.getAttribute('direction') == 'out'
+
+ name = arg.getAttribute('name')
+ if not name:
+ assert out
+ name = 'arg%u' % counter
+ counter += 1
+
+ info.append(name + '\0')
+
+ if out:
+ info.append('O\0')
+ else:
+ info.append('I\0')
+
+ if out:
+ info.append('F\0') # not const
+ info.append('N\0') # not error or return
+ info.append(arg.getAttribute('type') + '\0')
+
+ info.append('\0')
+
+ return ''.join(info) + '\0', offsets
+
+ def do_method_glue(self, method, offset):
+ lc_name = method.getAttribute('tp:name-for-bindings')
+ if method.getAttribute('name') != lc_name.replace('_', ''):
+ raise AssertionError('Method %s tp:name-for-bindings (%s) does '
+ 'not match' % (method.getAttribute('name'), lc_name))
+ lc_name = lc_name.lower()
+
+ marshaller = method_to_glue_marshal_name(method,
+ self.signal_marshal_prefix)
+ wrapper = self.prefix_ + self.node_name_lc + '_' + lc_name
+
+ self.b(" { (GCallback) %s, %s, %d }," % (wrapper, marshaller, offset))
+
+ def get_signal_glue(self, signals):
+ info = []
+
+ for signal in signals:
+ info.append(self.iface_name)
+ info.append(signal.getAttribute('name'))
+
+ return '\0'.join(info) + '\0\0'
+
+ # the implementation can be the same
+ get_property_glue = get_signal_glue
+
+ def get_method_impl_names(self, method):
+ dbus_method_name = method.getAttribute('name')
+
+ class_member_name = method.getAttribute('tp:name-for-bindings')
+ if dbus_method_name != class_member_name.replace('_', ''):
+ raise AssertionError('Method %s tp:name-for-bindings (%s) does '
+ 'not match' % (dbus_method_name, class_member_name))
+ class_member_name = class_member_name.lower()
+
+ stub_name = (self.prefix_ + self.node_name_lc + '_' +
+ class_member_name)
+ return (stub_name + '_impl', class_member_name)
+
+ def do_method(self, method):
+ assert self.node_name_mixed is not None
+
+ in_class = []
+
+ # Examples refer to Thing.DoStuff (su) -> ii
+
+ # DoStuff
+ dbus_method_name = method.getAttribute('name')
+ # do_stuff
+ class_member_name = method.getAttribute('tp:name-for-bindings')
+ if dbus_method_name != class_member_name.replace('_', ''):
+ raise AssertionError('Method %s tp:name-for-bindings (%s) does '
+ 'not match' % (dbus_method_name, class_member_name))
+ class_member_name = class_member_name.lower()
+
+ # void tp_svc_thing_do_stuff (TpSvcThing *, const char *, guint,
+ # DBusGMethodInvocation *);
+ stub_name = (self.prefix_ + self.node_name_lc + '_' +
+ class_member_name)
+ # typedef void (*tp_svc_thing_do_stuff_impl) (TpSvcThing *,
+ # const char *, guint, DBusGMethodInvocation);
+ impl_name = stub_name + '_impl'
+ # void tp_svc_thing_return_from_do_stuff (DBusGMethodInvocation *,
+ # gint, gint);
+ ret_name = (self.prefix_ + self.node_name_lc + '_return_from_' +
+ class_member_name)
+
+ # Gather arguments
+ in_args = []
+ out_args = []
+ for i in method.getElementsByTagName('arg'):
+ name = i.getAttribute('name')
+ direction = i.getAttribute('direction') or 'in'
+ dtype = i.getAttribute('type')
+
+ assert direction in ('in', 'out')
+
+ if name:
+ name = direction + '_' + name
+ elif direction == 'in':
+ name = direction + str(len(in_args))
+ else:
+ name = direction + str(len(out_args))
+
+ ctype, gtype, marshaller, pointer = type_to_gtype(dtype)
+
+ if pointer:
+ ctype = 'const ' + ctype
+
+ struct = (ctype, name)
+
+ if direction == 'in':
+ in_args.append(struct)
+ else:
+ out_args.append(struct)
+
+ # Implementation type declaration (in header, docs in body)
+ self.b('/**')
+ self.b(' * %s:' % impl_name)
+ self.b(' * @self: The object implementing this interface')
+ for (ctype, name) in in_args:
+ self.b(' * @%s: %s (FIXME, generate documentation)'
+ % (name, ctype))
+ self.b(' * @context: Used to return values or throw an error')
+ self.b(' *')
+ self.b(' * The signature of an implementation of the D-Bus method')
+ self.b(' * %s on interface %s.' % (dbus_method_name, self.iface_name))
+ self.b(' */')
+ self.h('typedef void (*%s) (%s%s *self,'
+ % (impl_name, self.Prefix, self.node_name_mixed))
+ for (ctype, name) in in_args:
+ self.h(' %s%s,' % (ctype, name))
+ self.h(' DBusGMethodInvocation *context);')
+
+ # Class member (in class definition)
+ in_class.append(' %s %s;' % (impl_name, class_member_name))
+
+ # Stub definition (in body only - it's static)
+ self.b('static void')
+ self.b('%s (%s%s *self,'
+ % (stub_name, self.Prefix, self.node_name_mixed))
+ for (ctype, name) in in_args:
+ self.b(' %s%s,' % (ctype, name))
+ self.b(' DBusGMethodInvocation *context)')
+ self.b('{')
+ self.b(' %s impl = (%s%s_GET_CLASS (self)->%s);'
+ % (impl_name, self.PREFIX_, self.node_name_uc, class_member_name))
+ self.b('')
+ self.b(' if (impl != NULL)')
+ tmp = ['self'] + [name for (ctype, name) in in_args] + ['context']
+ self.b(' {')
+ self.b(' (impl) (%s);' % ',\n '.join(tmp))
+ self.b(' }')
+ self.b(' else')
+ self.b(' {')
+ if self.not_implemented_func:
+ self.b(' %s (context);' % self.not_implemented_func)
+ else:
+ self.b(' GError e = { DBUS_GERROR, ')
+ self.b(' DBUS_GERROR_UNKNOWN_METHOD,')
+ self.b(' "Method not implemented" };')
+ self.b('')
+ self.b(' dbus_g_method_return_error (context, &e);')
+ self.b(' }')
+ self.b('}')
+ self.b('')
+
+ # Implementation registration (in both header and body)
+ self.h('void %s%s_implement_%s (%s%sClass *klass, %s impl);'
+ % (self.prefix_, self.node_name_lc, class_member_name,
+ self.Prefix, self.node_name_mixed, impl_name))
+
+ self.b('/**')
+ self.b(' * %s%s_implement_%s:'
+ % (self.prefix_, self.node_name_lc, class_member_name))
+ self.b(' * @klass: A class whose instances implement this interface')
+ self.b(' * @impl: A callback used to implement the %s D-Bus method'
+ % dbus_method_name)
+ self.b(' *')
+ self.b(' * Register an implementation for the %s method in the vtable'
+ % dbus_method_name)
+ self.b(' * of an implementation of this interface. To be called from')
+ self.b(' * the interface init function.')
+ self.b(' */')
+ self.b('void')
+ self.b('%s%s_implement_%s (%s%sClass *klass, %s impl)'
+ % (self.prefix_, self.node_name_lc, class_member_name,
+ self.Prefix, self.node_name_mixed, impl_name))
+ self.b('{')
+ self.b(' klass->%s = impl;' % class_member_name)
+ self.b('}')
+ self.b('')
+
+ # Return convenience function (static inline, in header)
+ self.h('/**')
+ self.h(' * %s:' % ret_name)
+ self.h(' * @context: The D-Bus method invocation context')
+ for (ctype, name) in out_args:
+ self.h(' * @%s: %s (FIXME, generate documentation)'
+ % (name, ctype))
+ self.h(' *')
+ self.h(' * Return successfully by calling dbus_g_method_return().')
+ self.h(' * This inline function exists only to provide type-safety.')
+ self.h(' */')
+ tmp = (['DBusGMethodInvocation *context'] +
+ [ctype + name for (ctype, name) in out_args])
+ self.h('static inline')
+ self.h('/* this comment is to stop gtkdoc realising this is static */')
+ self.h(('void %s (' % ret_name) + (',\n '.join(tmp)) + ');')
+ self.h('static inline void')
+ self.h(('%s (' % ret_name) + (',\n '.join(tmp)) + ')')
+ self.h('{')
+ tmp = ['context'] + [name for (ctype, name) in out_args]
+ self.h(' dbus_g_method_return (' + ',\n '.join(tmp) + ');')
+ self.h('}')
+ self.h('')
+
+ return in_class
+
+ def get_signal_const_entry(self, signal):
+ assert self.node_name_uc is not None
+ return ('SIGNAL_%s_%s'
+ % (self.node_name_uc, signal.getAttribute('name')))
+
+ def do_signal(self, signal):
+ assert self.node_name_mixed is not None
+
+ in_base_init = []
+
+ # for signal: Thing::StuffHappened (s, u)
+ # we want to emit:
+ # void tp_svc_thing_emit_stuff_happened (gpointer instance,
+ # const char *arg0, guint arg1);
+
+ dbus_name = signal.getAttribute('name')
+
+ ugly_name = signal.getAttribute('tp:name-for-bindings')
+ if dbus_name != ugly_name.replace('_', ''):
+ raise AssertionError('Signal %s tp:name-for-bindings (%s) does '
+ 'not match' % (dbus_name, ugly_name))
+
+ stub_name = (self.prefix_ + self.node_name_lc + '_emit_' +
+ ugly_name.lower())
+
+ const_name = self.get_signal_const_entry(signal)
+
+ # Gather arguments
+ args = []
+ for i in signal.getElementsByTagName('arg'):
+ name = i.getAttribute('name')
+ dtype = i.getAttribute('type')
+ tp_type = i.getAttribute('tp:type')
+
+ if name:
+ name = 'arg_' + name
+ else:
+ name = 'arg' + str(len(args))
+
+ ctype, gtype, marshaller, pointer = type_to_gtype(dtype)
+
+ if pointer:
+ ctype = 'const ' + ctype
+
+ struct = (ctype, name, gtype)
+ args.append(struct)
+
+ tmp = (['gpointer instance'] +
+ [ctype + name for (ctype, name, gtype) in args])
+
+ self.h(('void %s (' % stub_name) + (',\n '.join(tmp)) + ');')
+
+ # FIXME: emit docs
+
+ self.b('/**')
+ self.b(' * %s:' % stub_name)
+ self.b(' * @instance: The object implementing this interface')
+ for (ctype, name, gtype) in args:
+ self.b(' * @%s: %s (FIXME, generate documentation)'
+ % (name, ctype))
+ self.b(' *')
+ self.b(' * Type-safe wrapper around g_signal_emit to emit the')
+ self.b(' * %s signal on interface %s.'
+ % (dbus_name, self.iface_name))
+ self.b(' */')
+
+ self.b('void')
+ self.b(('%s (' % stub_name) + (',\n '.join(tmp)) + ')')
+ self.b('{')
+ self.b(' g_assert (instance != NULL);')
+ self.b(' g_assert (G_TYPE_CHECK_INSTANCE_TYPE (instance, %s));'
+ % (self.current_gtype))
+ tmp = (['instance', '%s_signals[%s]' % (self.node_name_lc, const_name),
+ '0'] + [name for (ctype, name, gtype) in args])
+ self.b(' g_signal_emit (' + ',\n '.join(tmp) + ');')
+ self.b('}')
+ self.b('')
+
+ signal_name = dbus_gutils_wincaps_to_uscore(dbus_name).replace('_',
+ '-')
+ in_base_init.append(' /**')
+ in_base_init.append(' * %s%s::%s:'
+ % (self.Prefix, self.node_name_mixed, signal_name))
+ for (ctype, name, gtype) in args:
+ in_base_init.append(' * @%s: %s (FIXME, generate documentation)'
+ % (name, ctype))
+ in_base_init.append(' *')
+ in_base_init.append(' * The %s D-Bus signal is emitted whenever '
+ 'this GObject signal is.' % dbus_name)
+ in_base_init.append(' */')
+ in_base_init.append(' %s_signals[%s] ='
+ % (self.node_name_lc, const_name))
+ in_base_init.append(' g_signal_new ("%s",' % signal_name)
+ in_base_init.append(' G_OBJECT_CLASS_TYPE (klass),')
+ in_base_init.append(' G_SIGNAL_RUN_LAST|G_SIGNAL_DETAILED,')
+ in_base_init.append(' 0,')
+ in_base_init.append(' NULL, NULL,')
+ in_base_init.append(' %s,'
+ % signal_to_marshal_name(signal, self.signal_marshal_prefix))
+ in_base_init.append(' G_TYPE_NONE,')
+ tmp = ['%d' % len(args)] + [gtype for (ctype, name, gtype) in args]
+ in_base_init.append(' %s);' % ',\n '.join(tmp))
+ in_base_init.append('')
+
+ return in_base_init
+
+ def have_properties(self, nodes):
+ for node in nodes:
+ interface = node.getElementsByTagName('interface')[0]
+ if interface.getElementsByTagName('property'):
+ return True
+ return False
+
+ def __call__(self):
+ nodes = self.dom.getElementsByTagName('node')
+ nodes.sort(cmp_by_name)
+
+ self.h('#include <glib-object.h>')
+ self.h('#include <dbus/dbus-glib.h>')
+
+ if self.have_properties(nodes):
+ self.h('#include <telepathy-glib/dbus-properties-mixin.h>')
+
+ self.h('')
+ self.h('G_BEGIN_DECLS')
+ self.h('')
+
+ self.b('#include "%s.h"' % self.basename)
+ self.b('')
+ for header in self.headers:
+ self.b('#include %s' % header)
+ self.b('')
+
+ for node in nodes:
+ self.do_node(node)
+
+ self.h('')
+ self.h('G_END_DECLS')
+
+ self.b('')
+ for header in self.end_headers:
+ self.b('#include %s' % header)
+
+ self.h('')
+ self.b('')
+ open(self.basename + '.h', 'w').write('\n'.join(self.__header))
+ open(self.basename + '.c', 'w').write('\n'.join(self.__body))
+
+
+def cmdline_error():
+ print """\
+usage:
+ gen-ginterface [OPTIONS] xmlfile Prefix_
+options:
+ --include='<header.h>' (may be repeated)
+ --include='"header.h"' (ditto)
+ --include-end='"header.h"' (ditto)
+ Include extra headers in the generated .c file
+ --signal-marshal-prefix='prefix'
+ Use the given prefix on generated signal marshallers (default is
+ prefix.lower()).
+ --filename='BASENAME'
+ Set the basename for the output files (default is prefix.lower()
+ + 'ginterfaces')
+ --not-implemented-func='symbol'
+ Set action when methods not implemented in the interface vtable are
+ called. symbol must have signature
+ void symbol (DBusGMethodInvocation *context)
+ and return some sort of "not implemented" error via
+ dbus_g_method_return_error (context, ...)
+"""
+ sys.exit(1)
+
+
+if __name__ == '__main__':
+ from getopt import gnu_getopt
+
+ options, argv = gnu_getopt(sys.argv[1:], '',
+ ['filename=', 'signal-marshal-prefix=',
+ 'include=', 'include-end=',
+ 'allow-unstable',
+ 'not-implemented-func='])
+
+ try:
+ prefix = argv[1]
+ except IndexError:
+ cmdline_error()
+
+ basename = prefix.lower() + 'ginterfaces'
+ signal_marshal_prefix = prefix.lower().rstrip('_')
+ headers = []
+ end_headers = []
+ not_implemented_func = ''
+ allow_havoc = False
+
+ for option, value in options:
+ if option == '--filename':
+ basename = value
+ elif option == '--signal-marshal-prefix':
+ signal_marshal_prefix = value
+ elif option == '--include':
+ if value[0] not in '<"':
+ value = '"%s"' % value
+ headers.append(value)
+ elif option == '--include-end':
+ if value[0] not in '<"':
+ value = '"%s"' % value
+ end_headers.append(value)
+ elif option == '--not-implemented-func':
+ not_implemented_func = value
+ elif option == '--allow-unstable':
+ allow_havoc = True
+
+ try:
+ dom = xml.dom.minidom.parse(argv[0])
+ except IndexError:
+ cmdline_error()
+
+ Generator(dom, prefix, basename, signal_marshal_prefix, headers,
+ end_headers, not_implemented_func, allow_havoc)()
diff --git a/tools/glib-gtypes-generator.py b/tools/glib-gtypes-generator.py
new file mode 100644
index 0000000..ebc2ad4
--- /dev/null
+++ b/tools/glib-gtypes-generator.py
@@ -0,0 +1,291 @@
+#!/usr/bin/python
+
+# Generate GLib GInterfaces from the Telepathy specification.
+# The master copy of this program is in the telepathy-glib repository -
+# please make any changes there.
+#
+# Copyright (C) 2006, 2007 Collabora Limited
+#
+# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import sys
+import xml.dom.minidom
+
+from libglibcodegen import escape_as_identifier, \
+ get_docstring, \
+ NS_TP, \
+ Signature, \
+ type_to_gtype, \
+ xml_escape
+
+
+def types_to_gtypes(types):
+ return [type_to_gtype(t)[1] for t in types]
+
+
+class GTypesGenerator(object):
+ def __init__(self, dom, output, mixed_case_prefix):
+ self.dom = dom
+ self.Prefix = mixed_case_prefix
+ self.PREFIX_ = self.Prefix.upper() + '_'
+ self.prefix_ = self.Prefix.lower() + '_'
+
+ self.header = open(output + '.h', 'w')
+ self.body = open(output + '-body.h', 'w')
+
+ for f in (self.header, self.body):
+ f.write('/* Auto-generated, do not edit.\n *\n'
+ ' * This file may be distributed under the same terms\n'
+ ' * as the specification from which it was generated.\n'
+ ' */\n\n')
+
+ # keys are e.g. 'sv', values are the key escaped
+ self.need_mappings = {}
+ # keys are the contents of the struct (e.g. 'sssu'), values are the
+ # key escaped
+ self.need_structs = {}
+ # keys are the contents of the struct (e.g. 'sssu'), values are the
+ # key escaped
+ self.need_struct_arrays = {}
+
+ # keys are the contents of the array (unlike need_struct_arrays!),
+ # values are the key escaped
+ self.need_other_arrays = {}
+
+ def h(self, code):
+ self.header.write(code.encode("utf-8"))
+
+ def c(self, code):
+ self.body.write(code.encode("utf-8"))
+
+ def do_mapping_header(self, mapping):
+ members = mapping.getElementsByTagNameNS(NS_TP, 'member')
+ assert len(members) == 2
+
+ impl_sig = ''.join([elt.getAttribute('type')
+ for elt in members])
+
+ esc_impl_sig = escape_as_identifier(impl_sig)
+
+ name = (self.PREFIX_ + 'HASH_TYPE_' +
+ mapping.getAttribute('name').upper())
+ impl = self.prefix_ + 'type_dbus_hash_' + esc_impl_sig
+
+ docstring = get_docstring(mapping) or '(Undocumented)'
+
+ self.h('/**\n * %s:\n *\n' % name)
+ self.h(' * %s\n' % xml_escape(docstring))
+ self.h(' *\n')
+ self.h(' * This macro expands to a call to a function\n')
+ self.h(' * that returns the #GType of a #GHashTable\n')
+ self.h(' * appropriate for representing a D-Bus\n')
+ self.h(' * dictionary of signature\n')
+ self.h(' * <literal>a{%s}</literal>.\n' % impl_sig)
+ self.h(' *\n')
+
+ key, value = members
+
+ self.h(' * Keys (D-Bus type <literal>%s</literal>,\n'
+ % key.getAttribute('type'))
+ tp_type = key.getAttributeNS(NS_TP, 'type')
+ if tp_type:
+ self.h(' * type <literal>%s</literal>,\n' % tp_type)
+ self.h(' * named <literal>%s</literal>):\n'
+ % key.getAttribute('name'))
+ docstring = get_docstring(key) or '(Undocumented)'
+ self.h(' * %s\n' % xml_escape(docstring))
+ self.h(' *\n')
+
+ self.h(' * Values (D-Bus type <literal>%s</literal>,\n'
+ % value.getAttribute('type'))
+ tp_type = value.getAttributeNS(NS_TP, 'type')
+ if tp_type:
+ self.h(' * type <literal>%s</literal>,\n' % tp_type)
+ self.h(' * named <literal>%s</literal>):\n'
+ % value.getAttribute('name'))
+ docstring = get_docstring(value) or '(Undocumented)'
+ self.h(' * %s\n' % xml_escape(docstring))
+ self.h(' *\n')
+
+ self.h(' */\n')
+
+ self.h('#define %s (%s ())\n\n' % (name, impl))
+ self.need_mappings[impl_sig] = esc_impl_sig
+
+ array_name = mapping.getAttribute('array-name')
+ if array_name:
+ gtype_name = self.PREFIX_ + 'ARRAY_TYPE_' + array_name.upper()
+ contents_sig = 'a{' + impl_sig + '}'
+ esc_contents_sig = escape_as_identifier(contents_sig)
+ impl = self.prefix_ + 'type_dbus_array_of_' + esc_contents_sig
+ self.h('/**\n * %s:\n\n' % gtype_name)
+ self.h(' * Expands to a call to a function\n')
+ self.h(' * that returns the #GType of a #GPtrArray\n')
+ self.h(' * of #%s.\n' % name)
+ self.h(' */\n')
+ self.h('#define %s (%s ())\n\n' % (gtype_name, impl))
+ self.need_other_arrays[contents_sig] = esc_contents_sig
+
+ def do_struct_header(self, struct):
+ members = struct.getElementsByTagNameNS(NS_TP, 'member')
+ impl_sig = ''.join([elt.getAttribute('type') for elt in members])
+ esc_impl_sig = escape_as_identifier(impl_sig)
+
+ name = (self.PREFIX_ + 'STRUCT_TYPE_' +
+ struct.getAttribute('name').upper())
+ impl = self.prefix_ + 'type_dbus_struct_' + esc_impl_sig
+ docstring = struct.getElementsByTagNameNS(NS_TP, 'docstring')
+ if docstring:
+ docstring = docstring[0].toprettyxml()
+ if docstring.startswith('<tp:docstring>'):
+ docstring = docstring[14:]
+ if docstring.endswith('</tp:docstring>\n'):
+ docstring = docstring[:-16]
+ if docstring.strip() in ('<tp:docstring/>', ''):
+ docstring = '(Undocumented)'
+ else:
+ docstring = '(Undocumented)'
+ self.h('/**\n * %s:\n\n' % name)
+ self.h(' * %s\n' % xml_escape(docstring))
+ self.h(' *\n')
+ self.h(' * This macro expands to a call to a function\n')
+ self.h(' * that returns the #GType of a #GValueArray\n')
+ self.h(' * appropriate for representing a D-Bus struct\n')
+ self.h(' * with signature <literal>(%s)</literal>.\n'
+ % impl_sig)
+ self.h(' *\n')
+
+ for i, member in enumerate(members):
+ self.h(' * Member %d (D-Bus type '
+ '<literal>%s</literal>,\n'
+ % (i, member.getAttribute('type')))
+ tp_type = member.getAttributeNS(NS_TP, 'type')
+ if tp_type:
+ self.h(' * type <literal>%s</literal>,\n' % tp_type)
+ self.h(' * named <literal>%s</literal>):\n'
+ % member.getAttribute('name'))
+ docstring = get_docstring(member) or '(Undocumented)'
+ self.h(' * %s\n' % xml_escape(docstring))
+ self.h(' *\n')
+
+ self.h(' */\n')
+ self.h('#define %s (%s ())\n\n' % (name, impl))
+
+ array_name = struct.getAttribute('array-name')
+ if array_name != '':
+ array_name = (self.PREFIX_ + 'ARRAY_TYPE_' + array_name.upper())
+ impl = self.prefix_ + 'type_dbus_array_' + esc_impl_sig
+ self.h('/**\n * %s:\n\n' % array_name)
+ self.h(' * Expands to a call to a function\n')
+ self.h(' * that returns the #GType of a #GPtrArray\n')
+ self.h(' * of #%s.\n' % name)
+ self.h(' */\n')
+ self.h('#define %s (%s ())\n\n' % (array_name, impl))
+ self.need_struct_arrays[impl_sig] = esc_impl_sig
+
+ self.need_structs[impl_sig] = esc_impl_sig
+
+ def __call__(self):
+ mappings = self.dom.getElementsByTagNameNS(NS_TP, 'mapping')
+ structs = self.dom.getElementsByTagNameNS(NS_TP, 'struct')
+
+ for mapping in mappings:
+ self.do_mapping_header(mapping)
+
+ for sig in self.need_mappings:
+ self.h('GType %stype_dbus_hash_%s (void);\n\n' %
+ (self.prefix_, self.need_mappings[sig]))
+ self.c('GType\n%stype_dbus_hash_%s (void)\n{\n' %
+ (self.prefix_, self.need_mappings[sig]))
+ self.c(' static GType t = 0;\n\n')
+ self.c(' if (G_UNLIKELY (t == 0))\n')
+ # FIXME: translate sig into two GTypes
+ items = tuple(Signature(sig))
+ gtypes = types_to_gtypes(items)
+ self.c(' t = dbus_g_type_get_map ("GHashTable", '
+ '%s, %s);\n' % (gtypes[0], gtypes[1]))
+ self.c(' return t;\n')
+ self.c('}\n\n')
+
+ for struct in structs:
+ self.do_struct_header(struct)
+
+ for sig in self.need_structs:
+ self.h('GType %stype_dbus_struct_%s (void);\n\n' %
+ (self.prefix_, self.need_structs[sig]))
+ self.c('GType\n%stype_dbus_struct_%s (void)\n{\n' %
+ (self.prefix_, self.need_structs[sig]))
+ self.c(' static GType t = 0;\n\n')
+ self.c(' if (G_UNLIKELY (t == 0))\n')
+ self.c(' t = dbus_g_type_get_struct ("GValueArray",\n')
+ items = tuple(Signature(sig))
+ gtypes = types_to_gtypes(items)
+ for gtype in gtypes:
+ self.c(' %s,\n' % gtype)
+ self.c(' G_TYPE_INVALID);\n')
+ self.c(' return t;\n')
+ self.c('}\n\n')
+
+ for sig in self.need_struct_arrays:
+ self.h('GType %stype_dbus_array_%s (void);\n\n' %
+ (self.prefix_, self.need_struct_arrays[sig]))
+ self.c('GType\n%stype_dbus_array_%s (void)\n{\n' %
+ (self.prefix_, self.need_struct_arrays[sig]))
+ self.c(' static GType t = 0;\n\n')
+ self.c(' if (G_UNLIKELY (t == 0))\n')
+ self.c(' t = dbus_g_type_get_collection ("GPtrArray", '
+ '%stype_dbus_struct_%s ());\n' %
+ (self.prefix_, self.need_struct_arrays[sig]))
+ self.c(' return t;\n')
+ self.c('}\n\n')
+
+ for sig in self.need_other_arrays:
+ self.h('GType %stype_dbus_array_of_%s (void);\n\n' %
+ (self.prefix_, self.need_other_arrays[sig]))
+ self.c('GType\n%stype_dbus_array_of_%s (void)\n{\n' %
+ (self.prefix_, self.need_other_arrays[sig]))
+ self.c(' static GType t = 0;\n\n')
+ self.c(' if (G_UNLIKELY (t == 0))\n')
+
+ if sig[:2] == 'a{' and sig[-1:] == '}':
+ # array of mappings
+ self.c(' t = dbus_g_type_get_collection ('
+ '"GPtrArray", '
+ '%stype_dbus_hash_%s ());\n' %
+ (self.prefix_, escape_as_identifier(sig[2:-1])))
+ elif sig[:2] == 'a(' and sig[-1:] == ')':
+ # array of arrays of struct
+ self.c(' t = dbus_g_type_get_collection ('
+ '"GPtrArray", '
+ '%stype_dbus_array_%s ());\n' %
+ (self.prefix_, escape_as_identifier(sig[2:-1])))
+ elif sig[:1] == 'a':
+ # array of arrays of non-struct
+ self.c(' t = dbus_g_type_get_collection ('
+ '"GPtrArray", '
+ '%stype_dbus_array_of_%s ());\n' %
+ (self.prefix_, escape_as_identifier(sig[1:])))
+ else:
+ raise AssertionError("array of '%s' not supported" % sig)
+
+ self.c(' return t;\n')
+ self.c('}\n\n')
+
+if __name__ == '__main__':
+ argv = sys.argv[1:]
+
+ dom = xml.dom.minidom.parse(argv[0])
+
+ GTypesGenerator(dom, argv[1], argv[2])()
diff --git a/tools/glib-interfaces-gen.py b/tools/glib-interfaces-gen.py
new file mode 100644
index 0000000..9543968
--- /dev/null
+++ b/tools/glib-interfaces-gen.py
@@ -0,0 +1,119 @@
+#!/usr/bin/python
+
+from sys import argv, stdout, stderr
+import xml.dom.minidom
+
+from libglibcodegen import NS_TP, get_docstring, \
+ get_descendant_text, get_by_path
+
+class Generator(object):
+ def __init__(self, prefix, implfile, declfile, dom):
+ self.prefix = prefix + '_'
+ self.impls = open(implfile, 'w')
+ self.decls = open(declfile, 'w')
+ self.spec = get_by_path(dom, "spec")[0]
+
+ def h(self, code):
+ self.decls.write(code.encode('utf-8'))
+
+ def c(self, code):
+ self.impls.write(code.encode('utf-8'))
+
+ def __call__(self):
+ for f in self.h, self.c:
+ self.do_header(f)
+ self.do_body()
+
+ # Header
+ def do_header(self, f):
+ f('/* Generated from: ')
+ f(get_descendant_text(get_by_path(self.spec, 'title')))
+ version = get_by_path(self.spec, "version")
+ if version:
+ f(' version ' + get_descendant_text(version))
+ f('\n\n')
+ for copyright in get_by_path(self.spec, 'copyright'):
+ f(get_descendant_text(copyright))
+ f('\n')
+ f('\n')
+ f(get_descendant_text(get_by_path(self.spec, 'license')))
+ f(get_descendant_text(get_by_path(self.spec, 'docstring')))
+ f("""
+ */
+
+""")
+
+ # Body
+ def do_body(self):
+ for iface in self.spec.getElementsByTagName('interface'):
+ self.do_iface(iface)
+
+ def do_iface(self, iface):
+ parent_name = get_by_path(iface, '../@name')
+ self.h("""\
+/**
+ * %(IFACE_DEFINE)s:
+ *
+ * The interface name "%(name)s"
+ */
+#define %(IFACE_DEFINE)s \\
+"%(name)s"
+""" % {'IFACE_DEFINE' : (self.prefix + 'IFACE_' + \
+ parent_name).upper().replace('/', ''),
+ 'name' : iface.getAttribute('name')})
+
+ self.h("""
+/**
+ * %(IFACE_QUARK_DEFINE)s:
+ *
+ * Expands to a call to a function that returns a quark for the interface \
+name "%(name)s"
+ */
+#define %(IFACE_QUARK_DEFINE)s \\
+ (%(iface_quark_func)s ())
+
+GQuark %(iface_quark_func)s (void);
+
+""" % {'IFACE_QUARK_DEFINE' : (self.prefix + 'IFACE_QUARK_' + \
+ parent_name).upper().replace('/', ''),
+ 'iface_quark_func' : (self.prefix + 'iface_quark_' + \
+ parent_name).lower().replace('/', ''),
+ 'name' : iface.getAttribute('name')})
+
+ self.c("""\
+GQuark
+%(iface_quark_func)s (void)
+{
+ static GQuark quark = 0;
+
+ if (G_UNLIKELY (quark == 0))
+ {
+ quark = g_quark_from_static_string ("%(name)s");
+ }
+
+ return quark;
+}
+
+""" % {'iface_quark_func' : (self.prefix + 'iface_quark_' + \
+ parent_name).lower().replace('/', ''),
+ 'name' : iface.getAttribute('name')})
+
+ for prop in iface.getElementsByTagNameNS(None, 'property'):
+ self.decls.write("""
+/**
+ * %(IFACE_PREFIX)s_%(PROP_UC)s:
+ *
+ * The fully-qualified property name "%(name)s.%(prop)s"
+ */
+#define %(IFACE_PREFIX)s_%(PROP_UC)s \\
+"%(name)s.%(prop)s"
+""" % {'IFACE_PREFIX' : (self.prefix + 'PROP_' + \
+ parent_name).upper().replace('/', ''),
+ 'PROP_UC': prop.getAttributeNS(NS_TP, "name-for-bindings").upper(),
+ 'name' : iface.getAttribute('name'),
+ 'prop' : prop.getAttribute('name'),
+ })
+
+if __name__ == '__main__':
+ argv = argv[1:]
+ Generator(argv[0], argv[1], argv[2], xml.dom.minidom.parse(argv[3]))()
diff --git a/tools/glib-signals-marshal-gen.py b/tools/glib-signals-marshal-gen.py
new file mode 100644
index 0000000..0d02c13
--- /dev/null
+++ b/tools/glib-signals-marshal-gen.py
@@ -0,0 +1,55 @@
+#!/usr/bin/python
+
+import sys
+import xml.dom.minidom
+from string import ascii_letters, digits
+
+
+from libglibcodegen import signal_to_marshal_name, method_to_glue_marshal_name
+
+
+class Generator(object):
+
+ def __init__(self, dom):
+ self.dom = dom
+ self.marshallers = {}
+
+ def do_method(self, method):
+ marshaller = method_to_glue_marshal_name(method, 'PREFIX')
+
+ assert '__' in marshaller
+ rhs = marshaller.split('__', 1)[1].split('_')
+
+ self.marshallers[marshaller] = rhs
+
+ def do_signal(self, signal):
+ marshaller = signal_to_marshal_name(signal, 'PREFIX')
+
+ assert '__' in marshaller
+ rhs = marshaller.split('__', 1)[1].split('_')
+
+ self.marshallers[marshaller] = rhs
+
+ def __call__(self):
+ methods = self.dom.getElementsByTagName('method')
+
+ for method in methods:
+ self.do_method(method)
+
+ signals = self.dom.getElementsByTagName('signal')
+
+ for signal in signals:
+ self.do_signal(signal)
+
+ all = self.marshallers.keys()
+ all.sort()
+ for marshaller in all:
+ rhs = self.marshallers[marshaller]
+ if not marshaller.startswith('g_cclosure'):
+ print 'VOID:' + ','.join(rhs)
+
+if __name__ == '__main__':
+ argv = sys.argv[1:]
+ dom = xml.dom.minidom.parse(argv[0])
+
+ Generator(dom)()
diff --git a/tools/identity.xsl b/tools/identity.xsl
new file mode 100644
index 0000000..6630f84
--- /dev/null
+++ b/tools/identity.xsl
@@ -0,0 +1,7 @@
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()"/>
+ </xsl:copy>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/tools/lcov.am b/tools/lcov.am
new file mode 100644
index 0000000..7384f1b
--- /dev/null
+++ b/tools/lcov.am
@@ -0,0 +1,24 @@
+lcov-reset:
+ lcov --directory @top_srcdir@ --zerocounters
+
+lcov-report:
+ lcov --directory @top_srcdir@ --capture \
+ --output-file @top_builddir@/lcov.info.tmp
+ lcov --directory @top_srcdir@ --output-file @top_builddir@/lcov.info \
+ --remove @top_builddir@/lcov.info.tmp telepathy-glib-scan.c
+ rm @top_builddir@/lcov.info.tmp
+ $(mkdir_p) @top_builddir@/lcov.html
+ git_commit=`GIT_DIR=@top_srcdir@/.git git log -1 --pretty=format:%h 2>/dev/null`;\
+ genhtml --title "@PACKAGE_STRING@ $$git_commit" \
+ --output-directory @top_builddir@/lcov.html lcov.info
+ @echo
+ @echo 'lcov report can be found in:'
+ @echo 'file://@abs_top_builddir@/lcov.html/index.html'
+ @echo
+
+lcov-check:
+ $(MAKE) lcov-reset
+ $(MAKE) check $(LCOV_CHECK_ARGS)
+ $(MAKE) lcov-report
+
+## vim:set ft=automake:
diff --git a/tools/libglibcodegen.py b/tools/libglibcodegen.py
new file mode 100644
index 0000000..6a9d214
--- /dev/null
+++ b/tools/libglibcodegen.py
@@ -0,0 +1,172 @@
+"""Library code for GLib/D-Bus-related code generation.
+
+The master copy of this library is in the telepathy-glib repository -
+please make any changes there.
+"""
+
+# Copyright (C) 2006-2008 Collabora Limited
+#
+# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+from libtpcodegen import NS_TP, \
+ Signature, \
+ cmp_by_name, \
+ escape_as_identifier, \
+ get_by_path, \
+ get_descendant_text, \
+ get_docstring, \
+ xml_escape, \
+ get_deprecated
+
+def dbus_gutils_wincaps_to_uscore(s):
+ """Bug-for-bug compatible Python port of _dbus_gutils_wincaps_to_uscore
+ which gets sequences of capital letters wrong in the same way.
+ (e.g. in Telepathy, SendDTMF -> send_dt_mf)
+ """
+ ret = ''
+ for c in s:
+ if c >= 'A' and c <= 'Z':
+ length = len(ret)
+ if length > 0 and (length < 2 or ret[length-2] != '_'):
+ ret += '_'
+ ret += c.lower()
+ else:
+ ret += c
+ return ret
+
+
+def signal_to_marshal_type(signal):
+ """
+ return a list of strings indicating the marshalling type for this signal.
+ """
+
+ mtype=[]
+ for i in signal.getElementsByTagName("arg"):
+ name =i.getAttribute("name")
+ type = i.getAttribute("type")
+ mtype.append(type_to_gtype(type)[2])
+
+ return mtype
+
+
+_glib_marshallers = ['VOID', 'BOOLEAN', 'CHAR', 'UCHAR', 'INT',
+ 'STRING', 'UINT', 'LONG', 'ULONG', 'ENUM', 'FLAGS', 'FLOAT',
+ 'DOUBLE', 'STRING', 'PARAM', 'BOXED', 'POINTER', 'OBJECT',
+ 'UINT_POINTER']
+
+
+def signal_to_marshal_name(signal, prefix):
+
+ mtype = signal_to_marshal_type(signal)
+ if len(mtype):
+ name = '_'.join(mtype)
+ else:
+ name = 'VOID'
+
+ if name in _glib_marshallers:
+ return 'g_cclosure_marshal_VOID__' + name
+ else:
+ return prefix + '_marshal_VOID__' + name
+
+
+def method_to_glue_marshal_name(method, prefix):
+
+ mtype = []
+ for i in method.getElementsByTagName("arg"):
+ if i.getAttribute("direction") != "out":
+ type = i.getAttribute("type")
+ mtype.append(type_to_gtype(type)[2])
+
+ mtype.append('POINTER')
+
+ name = '_'.join(mtype)
+
+ if name in _glib_marshallers:
+ return 'g_cclosure_marshal_VOID__' + name
+ else:
+ return prefix + '_marshal_VOID__' + name
+
+
+def type_to_gtype(s):
+ if s == 'y': #byte
+ return ("guchar ", "G_TYPE_UCHAR","UCHAR", False)
+ elif s == 'b': #boolean
+ return ("gboolean ", "G_TYPE_BOOLEAN","BOOLEAN", False)
+ elif s == 'n': #int16
+ return ("gint ", "G_TYPE_INT","INT", False)
+ elif s == 'q': #uint16
+ return ("guint ", "G_TYPE_UINT","UINT", False)
+ elif s == 'i': #int32
+ return ("gint ", "G_TYPE_INT","INT", False)
+ elif s == 'u': #uint32
+ return ("guint ", "G_TYPE_UINT","UINT", False)
+ elif s == 'x': #int64
+ return ("gint64 ", "G_TYPE_INT64","INT64", False)
+ elif s == 't': #uint64
+ return ("guint64 ", "G_TYPE_UINT64","UINT64", False)
+ elif s == 'd': #double
+ return ("gdouble ", "G_TYPE_DOUBLE","DOUBLE", False)
+ elif s == 's': #string
+ return ("gchar *", "G_TYPE_STRING", "STRING", True)
+ elif s == 'g': #signature - FIXME
+ return ("gchar *", "DBUS_TYPE_G_SIGNATURE", "STRING", True)
+ elif s == 'o': #object path
+ return ("gchar *", "DBUS_TYPE_G_OBJECT_PATH", "BOXED", True)
+ elif s == 'v': #variant
+ return ("GValue *", "G_TYPE_VALUE", "BOXED", True)
+ elif s == 'as': #array of strings
+ return ("gchar **", "G_TYPE_STRV", "BOXED", True)
+ elif s == 'ay': #byte array
+ return ("GArray *",
+ "dbus_g_type_get_collection (\"GArray\", G_TYPE_UCHAR)", "BOXED",
+ True)
+ elif s == 'au': #uint array
+ return ("GArray *", "DBUS_TYPE_G_UINT_ARRAY", "BOXED", True)
+ elif s == 'ai': #int array
+ return ("GArray *", "DBUS_TYPE_G_INT_ARRAY", "BOXED", True)
+ elif s == 'ax': #int64 array
+ return ("GArray *", "DBUS_TYPE_G_INT64_ARRAY", "BOXED", True)
+ elif s == 'at': #uint64 array
+ return ("GArray *", "DBUS_TYPE_G_UINT64_ARRAY", "BOXED", True)
+ elif s == 'ad': #double array
+ return ("GArray *", "DBUS_TYPE_G_DOUBLE_ARRAY", "BOXED", True)
+ elif s == 'ab': #boolean array
+ return ("GArray *", "DBUS_TYPE_G_BOOLEAN_ARRAY", "BOXED", True)
+ elif s == 'ao': #object path array
+ return ("GPtrArray *",
+ 'dbus_g_type_get_collection ("GPtrArray",'
+ ' DBUS_TYPE_G_OBJECT_PATH)',
+ "BOXED", True)
+ elif s == 'a{ss}': #hash table of string to string
+ return ("GHashTable *", "DBUS_TYPE_G_STRING_STRING_HASHTABLE", "BOXED", False)
+ elif s[:2] == 'a{': #some arbitrary hash tables
+ if s[2] not in ('y', 'b', 'n', 'q', 'i', 'u', 's', 'o', 'g'):
+ raise Exception, "can't index a hashtable off non-basic type " + s
+ first = type_to_gtype(s[2])
+ second = type_to_gtype(s[3:-1])
+ return ("GHashTable *", "(dbus_g_type_get_map (\"GHashTable\", " + first[1] + ", " + second[1] + "))", "BOXED", False)
+ elif s[:2] in ('a(', 'aa'): # array of structs or arrays, recurse
+ gtype = type_to_gtype(s[1:])[1]
+ return ("GPtrArray *", "(dbus_g_type_get_collection (\"GPtrArray\", "+gtype+"))", "BOXED", True)
+ elif s[:1] == '(': #struct
+ gtype = "(dbus_g_type_get_struct (\"GValueArray\", "
+ for subsig in Signature(s[1:-1]):
+ gtype = gtype + type_to_gtype(subsig)[1] + ", "
+ gtype = gtype + "G_TYPE_INVALID))"
+ return ("GValueArray *", gtype, "BOXED", True)
+
+ # we just don't know ..
+ raise Exception, "don't know the GType for " + s
diff --git a/tools/libtpcodegen.py b/tools/libtpcodegen.py
new file mode 100644
index 0000000..837ff2f
--- /dev/null
+++ b/tools/libtpcodegen.py
@@ -0,0 +1,215 @@
+"""Library code for language-independent D-Bus-related code generation.
+
+The master copy of this library is in the telepathy-glib repository -
+please make any changes there.
+"""
+
+# Copyright (C) 2006-2008 Collabora Limited
+#
+# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+from string import ascii_letters, digits
+
+
+NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+
+_ASCII_ALNUM = ascii_letters + digits
+
+
+def cmp_by_name(node1, node2):
+ return cmp(node1.getAttributeNode("name").nodeValue,
+ node2.getAttributeNode("name").nodeValue)
+
+
+def escape_as_identifier(identifier):
+ """Escape the given string to be a valid D-Bus object path or service
+ name component, using a reversible encoding to ensure uniqueness.
+
+ The reversible encoding is as follows:
+
+ * The empty string becomes '_'
+ * Otherwise, each non-alphanumeric character is replaced by '_' plus
+ two lower-case hex digits; the same replacement is carried out on
+ the first character, if it's a digit
+ """
+ # '' -> '_'
+ if not identifier:
+ return '_'
+
+ # A bit of a fast path for strings which are already OK.
+ # We deliberately omit '_' because, for reversibility, that must also
+ # be escaped.
+ if (identifier.strip(_ASCII_ALNUM) == '' and
+ identifier[0] in ascii_letters):
+ return identifier
+
+ # The first character may not be a digit
+ if identifier[0] not in ascii_letters:
+ ret = ['_%02x' % ord(identifier[0])]
+ else:
+ ret = [identifier[0]]
+
+ # Subsequent characters may be digits or ASCII letters
+ for c in identifier[1:]:
+ if c in _ASCII_ALNUM:
+ ret.append(c)
+ else:
+ ret.append('_%02x' % ord(c))
+
+ return ''.join(ret)
+
+
+def get_by_path(element, path):
+ branches = path.split('/')
+ branch = branches[0]
+
+ # Is the current branch an attribute, if so, return the attribute value
+ if branch[0] == '@':
+ return element.getAttribute(branch[1:])
+
+ # Find matching children for the branch
+ children = []
+ if branch == '..':
+ children.append(element.parentNode)
+ else:
+ for x in element.childNodes:
+ if x.localName == branch:
+ children.append(x)
+
+ ret = []
+ # If this is not the last path element, recursively gather results from
+ # children
+ if len(branches) > 1:
+ for x in children:
+ add = get_by_path(x, '/'.join(branches[1:]))
+ if isinstance(add, list):
+ ret += add
+ else:
+ return add
+ else:
+ ret = children
+
+ return ret
+
+
+def get_docstring(element):
+ docstring = None
+ for x in element.childNodes:
+ if x.namespaceURI == NS_TP and x.localName == 'docstring':
+ docstring = x
+ if docstring is not None:
+ docstring = docstring.toxml().replace('\n', ' ').strip()
+ if docstring.startswith('<tp:docstring>'):
+ docstring = docstring[14:].lstrip()
+ if docstring.endswith('</tp:docstring>'):
+ docstring = docstring[:-15].rstrip()
+ if docstring in ('<tp:docstring/>', ''):
+ docstring = ''
+ return docstring
+
+def get_deprecated(element):
+ text = []
+ for x in element.childNodes:
+ if hasattr(x, 'data'):
+ text.append(x.data.replace('\n', ' ').strip())
+ else:
+ # This caters for tp:dbus-ref elements, but little else.
+ if x.childNodes and hasattr(x.childNodes[0], 'data'):
+ text.append(x.childNodes[0].data.replace('\n', ' ').strip())
+ return ' '.join(text)
+
+def get_descendant_text(element_or_elements):
+ if not element_or_elements:
+ return ''
+ if isinstance(element_or_elements, list):
+ return ''.join(map(get_descendant_text, element_or_elements))
+ parts = []
+ for x in element_or_elements.childNodes:
+ if x.nodeType == x.TEXT_NODE:
+ parts.append(x.nodeValue)
+ elif x.nodeType == x.ELEMENT_NODE:
+ parts.append(get_descendant_text(x))
+ else:
+ pass
+ return ''.join(parts)
+
+
+class _SignatureIter:
+ """Iterator over a D-Bus signature. Copied from dbus-python 0.71 so we
+ can run genginterface in a limited environment with only Python
+ (like Scratchbox).
+ """
+ def __init__(self, string):
+ self.remaining = string
+
+ def next(self):
+ if self.remaining == '':
+ raise StopIteration
+
+ signature = self.remaining
+ block_depth = 0
+ block_type = None
+ end = len(signature)
+
+ for marker in range(0, end):
+ cur_sig = signature[marker]
+
+ if cur_sig == 'a':
+ pass
+ elif cur_sig == '{' or cur_sig == '(':
+ if block_type == None:
+ block_type = cur_sig
+
+ if block_type == cur_sig:
+ block_depth = block_depth + 1
+
+ elif cur_sig == '}':
+ if block_type == '{':
+ block_depth = block_depth - 1
+
+ if block_depth == 0:
+ end = marker
+ break
+
+ elif cur_sig == ')':
+ if block_type == '(':
+ block_depth = block_depth - 1
+
+ if block_depth == 0:
+ end = marker
+ break
+
+ else:
+ if block_depth == 0:
+ end = marker
+ break
+
+ end = end + 1
+ self.remaining = signature[end:]
+ return Signature(signature[0:end])
+
+
+class Signature(str):
+ """A string, iteration over which is by D-Bus single complete types
+ rather than characters.
+ """
+ def __iter__(self):
+ return _SignatureIter(self)
+
+
+def xml_escape(s):
+ s = s.replace('&', '&amp;').replace("'", '&apos;').replace('"', '&quot;')
+ return s.replace('<', '&lt;').replace('>', '&gt;')
diff --git a/tools/telepathy.am b/tools/telepathy.am
new file mode 100644
index 0000000..3dab3e7
--- /dev/null
+++ b/tools/telepathy.am
@@ -0,0 +1,26 @@
+## Useful top-level Makefile.am snippets for Telepathy projects.
+
+dist-hook:
+ chmod u+w ${distdir}/ChangeLog
+ if test -d ${top_srcdir}/.git; then \
+ git log --date=iso $(CHANGELOG_RANGE) > ${distdir}/ChangeLog; \
+ fi
+
+maintainer-upload-release: _maintainer-upload-release
+
+_maintainer-upload-release-check:
+ @case @VERSION@ in \
+ (*.*.*.*) \
+ echo "@VERSION@ is not a release" >&2; \
+ exit 2; \
+ ;; \
+ esac
+ test -f @PACKAGE@-@VERSION@.tar.gz
+ test -f @PACKAGE@-@VERSION@.tar.gz.asc
+ gpg --verify @PACKAGE@-@VERSION@.tar.gz.asc
+
+_maintainer-upload-release: _maintainer-upload-release-check
+ rsync -vzP @PACKAGE@-@VERSION@.tar.gz telepathy.freedesktop.org:/srv/telepathy.freedesktop.org/www/releases/@PACKAGE@/@PACKAGE@-@VERSION@.tar.gz
+ rsync -vzP @PACKAGE@-@VERSION@.tar.gz.asc telepathy.freedesktop.org:/srv/telepathy.freedesktop.org/www/releases/@PACKAGE@/@PACKAGE@-@VERSION@.tar.gz.asc
+
+## vim:set ft=automake:
diff --git a/tools/xep.xsl b/tools/xep.xsl
new file mode 100644
index 0000000..549af85
--- /dev/null
+++ b/tools/xep.xsl
@@ -0,0 +1,921 @@
+<?xml version='1.0' encoding='UTF-8'?>
+
+<!--
+
+Copyright (c) 1999 - 2008 XMPP Standards Foundation
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+-->
+
+<!-- Authors: stpeter and temas -->
+
+<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'>
+
+ <xsl:output doctype-public='-//W3C//DTD XHTML 1.0 Transitional//EN' doctype-system='http://www.w3.org/TR/xhtml1/DTD/xhtml1-loose.dtd' method='xml'/>
+
+ <xsl:template match='/'>
+ <html>
+ <head>
+ <title>XEP-<xsl:value-of select='/xep/header/number'/>:<xsl:text> </xsl:text><xsl:value-of select='/xep/header/title' /></title>
+ <link rel='stylesheet' type='text/css' href='../xmpp.css' />
+ <link rel='shortcut icon' type='image/x-icon' href='/favicon.ico' />
+ <!-- BEGIN META TAGS FOR DUBLIN CORE -->
+ <meta>
+ <xsl:attribute name='name'><xsl:text>DC.Title</xsl:text></xsl:attribute>
+ <xsl:attribute name='content'><xsl:value-of select='/xep/header/title'/></xsl:attribute>
+ </meta>
+ <xsl:apply-templates select='/xep/header/author' mode='meta'/>
+ <meta>
+ <xsl:attribute name='name'><xsl:text>DC.Description</xsl:text></xsl:attribute>
+ <xsl:attribute name='content'><xsl:value-of select='/xep/header/abstract'/></xsl:attribute>
+ </meta>
+ <meta>
+ <xsl:attribute name='name'><xsl:text>DC.Publisher</xsl:text></xsl:attribute>
+ <xsl:attribute name='content'>XMPP Standards Foundation</xsl:attribute>
+ </meta>
+ <meta>
+ <xsl:attribute name='name'><xsl:text>DC.Contributor</xsl:text></xsl:attribute>
+ <xsl:attribute name='content'>XMPP Extensions Editor</xsl:attribute>
+ </meta>
+ <meta>
+ <xsl:attribute name='name'><xsl:text>DC.Date</xsl:text></xsl:attribute>
+ <xsl:attribute name='content'><xsl:value-of select='/xep/header/revision/date'/></xsl:attribute>
+ </meta>
+ <meta>
+ <xsl:attribute name='name'><xsl:text>DC.Type</xsl:text></xsl:attribute>
+ <xsl:attribute name='content'>XMPP Extension Protocol</xsl:attribute>
+ </meta>
+ <meta>
+ <xsl:attribute name='name'><xsl:text>DC.Format</xsl:text></xsl:attribute>
+ <xsl:attribute name='content'>XHTML</xsl:attribute>
+ </meta>
+ <meta>
+ <xsl:attribute name='name'><xsl:text>DC.Identifier</xsl:text></xsl:attribute>
+ <xsl:attribute name='content'>XEP-<xsl:value-of select='/xep/header/number'/></xsl:attribute>
+ </meta>
+ <meta>
+ <xsl:attribute name='name'><xsl:text>DC.Language</xsl:text></xsl:attribute>
+ <xsl:attribute name='content'>en</xsl:attribute>
+ </meta>
+ <meta>
+ <xsl:attribute name='name'><xsl:text>DC.Rights</xsl:text></xsl:attribute>
+ <xsl:attribute name='content'><xsl:value-of select='/xep/header/legal/copyright'/></xsl:attribute>
+ </meta>
+ <!-- END META TAGS FOR DUBLIN CORE -->
+ </head>
+ <body>
+ <!-- TITLE -->
+ <h1>XEP-<xsl:value-of select='/xep/header/number' />:<xsl:text> </xsl:text><xsl:value-of select='/xep/header/title' /></h1>
+ <!-- ABSTRACT -->
+ <p><xsl:value-of select='/xep/header/abstract'/></p>
+ <!-- NOTICE -->
+ <hr />
+ <xsl:variable name='thestatus' select='/xep/header/status'/>
+ <xsl:variable name='thetype' select='/xep/header/type'/>
+ <xsl:if test='$thestatus = "Active" and $thetype = "Historical"'>
+ <p style='color:green'>NOTICE: This Historical specification provides canonical documentation of a protocol that is in use within the Jabber/XMPP community. This document is not a standards-track specification within the XMPP Standards Foundation's standards process; however, it may be converted to standards-track in the future or may be obsoleted by a more modern protocol.</p>
+ </xsl:if>
+ <xsl:if test='$thestatus = "Active" and $thetype = "Humorous"'>
+ <p style='color:green'>NOTICE: This document is Humorous. It MAY provide amusement but SHOULD NOT be taken seriously.</p>
+ </xsl:if>
+ <xsl:if test='$thestatus = "Active" and $thetype = "Informational"'>
+ <p style='color:green'>NOTICE: This Informational specification defines a best practice or protocol profile that has been approved by the XMPP Council and/or the XSF Board of Directors. Implementations are encouraged and the best practice or protocol profile is appropriate for deployment in production systems.</p>
+ </xsl:if>
+ <xsl:if test='$thestatus = "Active" and $thetype = "Procedural"'>
+ <p style='color:green'>NOTICE: This Procedural document defines a process or activity of the XMPP Standards Foundation (XSF) that has been approved by the XMPP Council and/or the XSF Board of Directors. The XSF is currently following the process or activity defined herein and will do so until this document is deprecated or obsoleted.</p>
+ </xsl:if>
+ <xsl:if test='$thestatus = "Deferred"'>
+ <p style='color:red'>WARNING: Consideration of this document has been Deferred by the XMPP Standards Foundation. Implementation of the protocol described herein is not recommended.</p>
+ </xsl:if>
+ <xsl:if test='$thestatus = "Deprecated"'>
+ <p style='color:red'>WARNING: This document has been deprecated by the XMPP Standards Foundation. Implementation of the protocol described herein is not recommended. Developers desiring similar functionality should implement the protocol that supersedes this one (if any).</p>
+ </xsl:if>
+ <xsl:if test='$thestatus = "Draft"'>
+ <p style='color:green'>NOTICE: The protocol defined herein is a Draft Standard of the XMPP Standards Foundation. Implementations are encouraged and the protocol is appropriate for deployment in production systems, but some changes to the protocol are possible before it becomes a Final Standard.</p>
+ </xsl:if>
+ <xsl:if test='$thestatus = "Experimental" and $thetype = "Historical"'>
+ <p style='color:red'>NOTICE: This Historical document attempts to provide canonical documentation of a protocol that is in use within the Jabber/XMPP community. Publication as an XMPP Extension Protocol does not imply approval of this proposal by the XMPP Standards Foundation. This document is not a standards-track specification within the XMPP Standards Foundation's standards process; however, it may be converted to standards-track in the future or may be obsoleted by a more modern protocol.</p>
+ </xsl:if>
+ <xsl:if test='$thestatus = "Experimental" and $thetype = "Informational"'>
+ <p style='color:red'>WARNING: This Informational document is Experimental. Publication as an XMPP Extension Protocol does not imply approval of this proposal by the XMPP Standards Foundation. Implementation of the best practice or protocol profile described herein is encouraged in exploratory implementations, although production systems should not deploy implementations of this protocol until it advances to a status of Draft.</p>
+ </xsl:if>
+ <xsl:if test='$thestatus = "Experimental" and $thetype = "Procedural"'>
+ <p style='color:red'>NOTICE: This Procedural document proposes that the process or activity defined herein shall be followed by the XMPP Standards Foundation (XSF). However, this process or activity has not yet been approved by the XMPP Council and/or the XSF Board of Directors and is therefore not currently in force.</p>
+ </xsl:if>
+ <xsl:if test='$thestatus = "Experimental" and $thetype = "Standards Track"'>
+ <p style='color:red'>WARNING: This Standards-Track document is Experimental. Publication as an XMPP Extension Protocol does not imply approval of this proposal by the XMPP Standards Foundation. Implementation of the protocol described herein is encouraged in exploratory implementations, but production systems should not deploy implementations of this protocol until it advances to a status of Draft.</p>
+ </xsl:if>
+ <xsl:if test='$thestatus = "Final"'>
+ <p style='color:green'>NOTICE: The protocol defined herein is a Final Standard of the XMPP Standards Foundation and may be considered a stable technology for implementation and deployment.</p>
+ </xsl:if>
+ <xsl:if test='$thestatus = "Obsolete"'>
+ <p style='color:red'>WARNING: This document has been obsoleted by the XMPP Standards Foundation. Implementation of the protocol described herein is not recommended. Developers desiring similar functionality should implement the protocol that supersedes this one (if any).</p>
+ </xsl:if>
+ <xsl:if test='$thestatus = "Proposed"'>
+ <p style='color:red'>NOTICE: This document is currently within Last Call or under consideration by the XMPP Council for advancement to the next stage in the XSF standards process.</p>
+ </xsl:if>
+ <xsl:if test='$thestatus = "ProtoXEP"'>
+ <p style='color:red'>WARNING: This document has not yet been accepted for consideration or approved in any official manner by the XMPP Standards Foundation, and this document must not be referred to as an XMPP Extension Protocol (XEP). If this document is accepted as a XEP by the XMPP Council, it will be published at &lt;<a href="http://www.xmpp.org/extensions/">http://www.xmpp.org/extensions/</a>&gt; and announced on the &lt;standards@xmpp.org&gt; mailing list.</p>
+ </xsl:if>
+ <xsl:if test='$thestatus = "Rejected"'>
+ <p style='color:red'>WARNING: This document has been Rejected by the XMPP Council. Implementation of the protocol described herein is not recommended under any circumstances.</p>
+ </xsl:if>
+ <xsl:if test='$thestatus = "Retracted"'>
+ <p style='color:red'>WARNING: This document has been retracted by the author(s). Implementation of the protocol described herein is not recommended. Developers desiring similar functionality should implement the protocol that supersedes this one (if any).</p>
+ </xsl:if>
+ <hr />
+ <!-- XEP INFO -->
+ <h2>Document Information</h2>
+ <p class='indent'>
+ Series: <a href='http://www.xmpp.org/extensions/'>XEP</a><br />
+ Number: <xsl:value-of select='/xep/header/number'/><br />
+ Publisher: <a href='/xsf/'>XMPP Standards Foundation</a><br />
+ Status:
+ <a>
+ <xsl:attribute name='href'><xsl:text>http://www.xmpp.org/extensions/xep-0001.html#states-</xsl:text><xsl:value-of select='/xep/header/status'/></xsl:attribute>
+ <xsl:value-of select='/xep/header/status'/>
+ </a>
+ <br />
+ Type:
+ <a>
+ <xsl:attribute name='href'><xsl:text>http://www.xmpp.org/extensions/xep-0001.html#types-</xsl:text><xsl:value-of select='/xep/header/type'/></xsl:attribute>
+ <xsl:value-of select='/xep/header/type'/>
+ </a>
+ <br />
+ Version: <xsl:value-of select='/xep/header/revision[position()=1]/version'/><br />
+ Last Updated: <xsl:value-of select='/xep/header/revision[position()=1]/date'/><br />
+ <xsl:variable name='expires.count' select='count(/xep/header/expires)'/>
+ <xsl:if test='$expires.count=1'>
+ Expires: <xsl:value-of select='/xep/header/expires'/><br />
+ </xsl:if>
+ <xsl:variable name='ApprovingBody' select='/xep/header/approver'/>
+ <xsl:choose>
+ <xsl:when test='$ApprovingBody = "Board"'>
+ Approving Body: <a href='http://www.xmpp.org/xsf/board/'>XSF Board of Directors</a><br />
+ </xsl:when>
+ <xsl:otherwise>
+ Approving Body: <a href='http://www.xmpp.org/council/'>XMPP Council</a><br />
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:variable name='dependencies.count' select='count(/xep/header/dependencies/spec)'/>
+ <xsl:choose>
+ <xsl:when test='$dependencies.count &gt; 0'>
+ <xsl:text>Dependencies: </xsl:text>
+ <xsl:apply-templates select='/xep/header/dependencies/spec'>
+ <xsl:with-param name='speccount' select='$dependencies.count'/>
+ </xsl:apply-templates>
+ <br />
+ </xsl:when>
+ <xsl:otherwise>
+ Dependencies: None<br />
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:variable name='supersedes.count' select='count(/xep/header/supersedes/spec)'/>
+ <xsl:choose>
+ <xsl:when test='$supersedes.count &gt; 0'>
+ <xsl:text>Supersedes: </xsl:text>
+ <xsl:apply-templates select='/xep/header/supersedes/spec'>
+ <xsl:with-param name='speccount' select='$supersedes.count'/>
+ </xsl:apply-templates>
+ <br />
+ </xsl:when>
+ <xsl:otherwise>
+ Supersedes: None<br />
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:variable name='supersededby.count' select='count(/xep/header/supersededby/spec)'/>
+ <xsl:choose>
+ <xsl:when test='$supersededby.count &gt; 0'>
+ <xsl:text>Superseded By: </xsl:text>
+ <xsl:apply-templates select='/xep/header/supersededby/spec'>
+ <xsl:with-param name='speccount' select='$supersededby.count'/>
+ </xsl:apply-templates>
+ <br />
+ </xsl:when>
+ <xsl:otherwise>
+ Superseded By: None<br />
+ </xsl:otherwise>
+ </xsl:choose>
+ Short Name: <xsl:value-of select='/xep/header/shortname'/><br />
+ <xsl:variable name='schema.count' select='count(/xep/header/schemaloc)'/>
+ <xsl:if test='$schema.count &gt; 0'>
+ <xsl:apply-templates select='/xep/header/schemaloc'/>
+ </xsl:if>
+ <xsl:variable name='reg.count' select='count(/xep/header/registry)'/>
+ <xsl:if test='$reg.count=1'>
+ Registry:
+ <xsl:variable name='registryURL'>
+ <xsl:text>http://www.xmpp.org/registrar/</xsl:text>
+ <xsl:value-of select='/xep/header/shortname'/>
+ <xsl:text>.html</xsl:text>
+ </xsl:variable>
+ &lt;<a href='{$registryURL}'><xsl:value-of select='$registryURL'/></a>&gt;
+ <br />
+ </xsl:if>
+ <xsl:variable name='wikiURL'>
+ <xsl:text>http://wiki.jabber.org/index.php/</xsl:text>
+ <xsl:value-of select='/xep/header/title'/>
+ <xsl:text> (XEP-</xsl:text>
+ <xsl:value-of select='/xep/header/number'/>
+ <xsl:text>)</xsl:text>
+ </xsl:variable>
+ <xsl:if test='$thestatus != "ProtoXEP"'>
+ Wiki Page: &lt;<a href='{$wikiURL}'><xsl:value-of select='$wikiURL'/></a>&gt;
+ </xsl:if>
+ </p>
+ <hr />
+ <!-- AUTHOR INFO -->
+ <h2>Author Information</h2>
+ <div class='indent'>
+ <xsl:apply-templates select='/xep/header/author'/>
+ </div>
+ <hr />
+ <!-- LEGAL NOTICES -->
+ <xsl:apply-templates select='/xep/header/legal'/>
+ <hr />
+ <!-- DISCUSSION VENUE -->
+ <h2>Discussion Venue</h2>
+ <xsl:variable name='Approver' select='/xep/header/approver'/>
+ <xsl:choose>
+ <xsl:when test='$Approver = "Board"'>
+ <p class='indent'>The preferred venue for discussion of this document is the Standards discussion list: &lt;<a href="http://mail.jabber.org/mailman/listinfo/standards">http://mail.jabber.org/mailman/listinfo/standards</a>&gt;.</p>
+ <p class='indent'>Discussion by the membership of the XSF may also be appropriate (see &lt;<a href="http://mail.jabber.org/mailman/listinfo/members">http://mail.jabber.org/mailman/listinfo/members</a>&gt; for details).</p>
+ </xsl:when>
+ <xsl:otherwise>
+ <p class='indent'>The preferred venue for discussion of this document is the Standards discussion list: &lt;<a href="http://mail.jabber.org/mailman/listinfo/standards">http://mail.jabber.org/mailman/listinfo/standards</a>&gt;.</p>
+ <xsl:if test='contains(/xep/header/dependencies,"RFC")'>
+ <p class='indent'>Given that this XMPP Extension Protocol normatively references IETF technologies, discussion on the XSF-IETF list may also be appropriate (see &lt;<a href="http://mail.jabber.org/mailman/listinfo/xsf-ietf">http://mail.jabber.org/mailman/listinfo/xsf-ietf</a>&gt; for details).</p>
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+ <p class='indent'>Errata may be sent to &lt;<a href='mailto:editor@xmpp.org'>editor@xmpp.org</a>&gt;.</p>
+ <!-- XMPP NOTICE AND CONFORMANCE TERMS-->
+ <!-- (we don't put these on Procedural XEPs) -->
+ <xsl:if test='$thetype = "Standards Track" or $thetype = "Historical" or $thetype = "Informational"'>
+ <h2>Relation to XMPP</h2>
+ <p class='indent'>The Extensible Messaging and Presence Protocol (XMPP) is defined in the XMPP Core (RFC 3920) and XMPP IM (RFC 3921) specifications contributed by the XMPP Standards Foundation to the Internet Standards Process, which is managed by the Internet Engineering Task Force in accordance with RFC 2026. Any protocol defined in this document has been developed outside the Internet Standards Process and is to be understood as an extension to XMPP rather than as an evolution, development, or modification of XMPP itself.</p>
+ <h2>Conformance Terms</h2>
+ <p class='indent'>The following keywords as used in this document are to be interpreted as described in <a href='http://www.ietf.org/rfc/rfc2119.txt'>RFC 2119</a>: "MUST", "SHALL", "REQUIRED"; "MUST NOT", "SHALL NOT"; "SHOULD", "RECOMMENDED"; "SHOULD NOT", "NOT RECOMMENDED"; "MAY", "OPTIONAL".</p>
+ </xsl:if>
+ <!-- TABLE OF CONTENTS -->
+ <hr />
+ <xsl:call-template name='processTOC' />
+ <!-- XEP CONTENTS -->
+ <hr />
+ <xsl:apply-templates select='/xep/section1'/>
+ <!-- NOTES -->
+ <hr />
+ <h2><a name="notes"></a>Notes</h2>
+ <div class='indent'>
+ <xsl:apply-templates select='//note' mode='endlist'/>
+ </div>
+ <!-- REVISION HISTORY -->
+ <hr />
+ <h2><a name="revs"></a>Revision History</h2>
+ <div class='indent'>
+ <xsl:apply-templates select='/xep/header/revision'/>
+ </div>
+ <hr />
+ <p>END</p>
+ </body>
+ </html>
+ </xsl:template>
+
+ <!-- From the docbook XSL -->
+ <xsl:template name="object.id">
+ <xsl:param name="object" select="."/>
+ <xsl:choose>
+ <xsl:when test="$object/@id">
+ <xsl:value-of select="$object/@id"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="generate-id($object)"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name='processTOC'>
+ <h2>Table of Contents</h2>
+ <div class='indent'>
+ <p>
+ <xsl:apply-templates select='//section1' mode='toc'/>
+ <br /><a href="#notes">Notes</a>
+ <br /><a href="#revs">Revision History</a>
+ </p>
+ </div>
+ </xsl:template>
+
+ <xsl:template match='author' mode='meta'>
+ <meta>
+ <xsl:attribute name='name'><xsl:text>DC.Creator</xsl:text></xsl:attribute>
+ <xsl:attribute name='content'><xsl:value-of select='firstname'/><xsl:text> </xsl:text><xsl:value-of select='surname'/></xsl:attribute>
+ </meta>
+ </xsl:template>
+
+ <xsl:template match='author'>
+ <h3><xsl:value-of select='firstname'/><xsl:text> </xsl:text><xsl:value-of select='surname'/></h3>
+ <p class='indent'>
+ <xsl:variable name='org.count' select='count(org)'/>
+ <xsl:variable name='email.count' select='count(email)'/>
+ <xsl:variable name='jid.count' select='count(jid)'/>
+ <xsl:variable name='uri.count' select='count(uri)'/>
+ <xsl:variable name='authornote.count' select='count(authornote)'/>
+ <xsl:if test='$authornote.count &gt; 0'>
+ See <a href='#authornote'>Author Note</a><br />
+ </xsl:if>
+ <xsl:if test='$org.count=1'>
+ Organization: <xsl:value-of select='org'/><br />
+ </xsl:if>
+ <xsl:if test='$email.count=1'>
+ Email:
+ <a>
+ <xsl:attribute name='href'>
+ <xsl:text>mailto:</xsl:text>
+ <xsl:value-of select='email' />
+ </xsl:attribute>
+ <xsl:value-of select='email' />
+ </a>
+ <br />
+ </xsl:if>
+ <xsl:if test='$jid.count=1'>
+ JabberID:
+ <a>
+ <xsl:attribute name='href'>
+ <xsl:text>xmpp:</xsl:text>
+ <xsl:value-of select='jid' />
+ </xsl:attribute>
+ <xsl:value-of select='jid' />
+ </a>
+ <br />
+ </xsl:if>
+ <xsl:if test='$uri.count=1'>
+ URI:
+ <a>
+ <xsl:attribute name='href'>
+ <xsl:value-of select='uri' />
+ </xsl:attribute>
+ <xsl:value-of select='uri' />
+ </a>
+ <br />
+ </xsl:if>
+ </p>
+ </xsl:template>
+
+ <xsl:template match='legal'>
+ <h2>Legal Notices</h2>
+ <div class='indent'>
+ <h3>Copyright</h3>
+ <xsl:apply-templates select='/xep/header/legal/copyright'/>
+ <h3>Permissions</h3>
+ <xsl:apply-templates select='/xep/header/legal/permissions'/>
+ <h3>Disclaimer of Warranty</h3>
+ <span style='font-weight: bold'>
+ <xsl:apply-templates select='/xep/header/legal/warranty'/>
+ </span>
+ <h3>Limitation of Liability</h3>
+ <xsl:apply-templates select='/xep/header/legal/liability'/>
+ <h3>IPR Conformance</h3>
+ <xsl:apply-templates select='/xep/header/legal/conformance'/>
+ </div>
+ </xsl:template>
+
+ <xsl:template match='spec'>
+ <xsl:param name='speccount' select='""'/>
+ <xsl:variable name='specpos' select='position()'/>
+ <xsl:choose>
+ <xsl:when test='$specpos &lt; $speccount'>
+ <xsl:value-of select='.'/><xsl:text>, </xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select='.'/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match='schemaloc'>
+ <xsl:variable name='this.url' select='url'/>
+ <xsl:variable name='ns.count' select='count(ns)'/>
+ <xsl:choose>
+ <xsl:when test="$ns.count=1">
+ XML Schema for <xsl:value-of select='ns'/> namespace: &lt;<a href='{$this.url}'><xsl:value-of select='url'/></a>&gt;<br />
+ </xsl:when>
+ <xsl:otherwise>
+ Schema: &lt;<a href='{$this.url}'><xsl:value-of select='url'/></a>&gt;<br />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match='revision'>
+ <h4>Version <xsl:value-of select='version'/><xsl:text> </xsl:text>(<xsl:value-of select='date'/>)</h4>
+ <div class='indent'>
+ <xsl:apply-templates select='remark'/>
+ <xsl:text> </xsl:text>(<xsl:value-of select='initials'/>)
+ </div>
+ </xsl:template>
+
+ <xsl:template match='section1' mode='toc'>
+ <xsl:variable name='oid'>
+ <xsl:call-template name='object.id'/>
+ </xsl:variable>
+ <xsl:variable name='anch'>
+ <xsl:value-of select='@anchor'/>
+ </xsl:variable>
+ <xsl:variable name='num'>
+ <xsl:number level='multiple' count='section1'/><xsl:text>.</xsl:text>
+ </xsl:variable>
+ <xsl:variable name='sect2.count' select='count(section2)'/>
+ <br />
+ <xsl:value-of select='$num'/> <xsl:text> </xsl:text>
+ <a>
+ <xsl:attribute name='href'>
+ <xsl:text>#</xsl:text>
+ <xsl:choose>
+ <xsl:when test='$anch != ""'>
+ <xsl:value-of select='@anchor'/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>sect-</xsl:text>
+ <xsl:value-of select='$oid'/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+ <xsl:value-of select='@topic' />
+ </a>
+ <xsl:if test='$sect2.count &gt; 0'>
+ <xsl:apply-templates select='section2' mode='toc'>
+ <xsl:with-param name='prevnum' select='$num'/>
+ </xsl:apply-templates>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template match='section1'>
+ <xsl:variable name='oid'>
+ <xsl:call-template name='object.id'/>
+ </xsl:variable>
+ <xsl:variable name='anch'>
+ <xsl:value-of select='@anchor'/>
+ </xsl:variable>
+ <h2>
+ <xsl:number level='single' count='section1'/>.
+ <xsl:text> </xsl:text>
+ <a>
+ <xsl:attribute name='name'>
+ <xsl:choose>
+ <xsl:when test='$anch != ""'>
+ <xsl:value-of select='@anchor'/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>sect-</xsl:text><xsl:value-of select='$oid'/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+ <xsl:value-of select='@topic' />
+ </a>
+ </h2>
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match='section2' mode='toc'>
+ <xsl:param name='prevnum' select='""'/>
+ <xsl:variable name='oid'>
+ <xsl:call-template name='object.id'/>
+ </xsl:variable>
+ <xsl:variable name='anch'>
+ <xsl:value-of select='@anchor'/>
+ </xsl:variable>
+ <xsl:variable name='num'>
+ <xsl:value-of select='$prevnum'/><xsl:number level='multiple' count='section2'/><xsl:text>.</xsl:text>
+ </xsl:variable>
+ <xsl:variable name='sect3.count' select='count(section3)'/>
+ <br />&#160;&#160;&#160;
+ <xsl:value-of select='$num'/> <xsl:text> </xsl:text>
+ <a>
+ <xsl:attribute name='href'>
+ <xsl:text>#</xsl:text>
+ <xsl:choose>
+ <xsl:when test='$anch != ""'>
+ <xsl:value-of select='@anchor'/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>sect-</xsl:text><xsl:value-of select='$oid'/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+ <xsl:value-of select='@topic' />
+ </a>
+ <xsl:if test='$sect3.count &gt; 0'>
+ <xsl:apply-templates select='section3' mode='toc'>
+ <xsl:with-param name='prevnum' select='$num'/>
+ </xsl:apply-templates>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template match='section2'>
+ <xsl:variable name='oid'>
+ <xsl:call-template name='object.id'/>
+ </xsl:variable>
+ <xsl:variable name='anch'>
+ <xsl:value-of select='@anchor'/>
+ </xsl:variable>
+ <div class='indent'>
+ <h3>
+ <xsl:number level='single' count='section1'/>.<xsl:number level='single' count='section2'/>
+ <xsl:text> </xsl:text>
+ <a>
+ <xsl:attribute name='name'>
+ <xsl:choose>
+ <xsl:when test='$anch != ""'>
+ <xsl:value-of select='@anchor'/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>sect-</xsl:text><xsl:value-of select='$oid'/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+ <xsl:value-of select='@topic' />
+ </a>
+ </h3>
+ <xsl:apply-templates/>
+ </div>
+ </xsl:template>
+
+ <xsl:template match='section3' mode='toc'>
+ <xsl:param name='prevnum' select='""'/>
+ <xsl:variable name='oid'>
+ <xsl:call-template name='object.id'/>
+ </xsl:variable>
+ <xsl:variable name='anch'>
+ <xsl:value-of select='@anchor'/>
+ </xsl:variable>
+ <xsl:variable name='num'>
+ <xsl:value-of select='$prevnum'/><xsl:number level='multiple' count='section3'/><xsl:text>.</xsl:text>
+ </xsl:variable>
+ <xsl:variable name='sect4.count' select='count(section4)'/>
+ <br />&#160;&#160;&#160;&#160;&#160;&#160;
+ <xsl:value-of select='$num'/> <xsl:text> </xsl:text>
+ <a>
+ <xsl:attribute name='href'>
+ <xsl:text>#</xsl:text>
+ <xsl:choose>
+ <xsl:when test='$anch != ""'>
+ <xsl:value-of select='@anchor'/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>sect-</xsl:text><xsl:value-of select='$oid'/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+ <xsl:value-of select='@topic' />
+ </a>
+ <xsl:if test='$sect4.count &gt; 0'>
+ <xsl:apply-templates select='section4' mode='toc'>
+ <xsl:with-param name='prevnum' select='$num'/>
+ </xsl:apply-templates>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template match='section3'>
+ <xsl:variable name='oid'>
+ <xsl:call-template name='object.id'/>
+ </xsl:variable>
+ <xsl:variable name='anch'>
+ <xsl:value-of select='@anchor'/>
+ </xsl:variable>
+ <div class='indent'>
+ <h3>
+ <xsl:number level='single' count='section1'/>.<xsl:number level='single' count='section2'/>.<xsl:number level='single' count='section3'/>
+ <xsl:text> </xsl:text>
+ <a>
+ <xsl:attribute name='name'>
+ <xsl:choose>
+ <xsl:when test='$anch != ""'>
+ <xsl:value-of select='@anchor'/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>sect-</xsl:text><xsl:value-of select='$oid'/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+ <xsl:value-of select='@topic' />
+ </a>
+ </h3>
+ <xsl:apply-templates/>
+ </div>
+ </xsl:template>
+
+ <xsl:template match='section4' mode='toc'>
+ <xsl:param name='prevnum' select='""'/>
+ <xsl:variable name='oid'>
+ <xsl:call-template name='object.id'/>
+ </xsl:variable>
+ <xsl:variable name='anch'>
+ <xsl:value-of select='@anchor'/>
+ </xsl:variable>
+ <xsl:variable name='num'>
+ <xsl:value-of select='$prevnum'/><xsl:number level='multiple' count='section4'/><xsl:text>.</xsl:text>
+ </xsl:variable>
+ <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
+ <xsl:value-of select='$num'/> <xsl:text> </xsl:text>
+ <a>
+ <xsl:attribute name='href'>
+ <xsl:text>#</xsl:text>
+ <xsl:choose>
+ <xsl:when test='$anch != ""'>
+ <xsl:value-of select='@anchor'/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>sect-</xsl:text><xsl:value-of select='$oid'/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+ <xsl:value-of select='@topic' />
+ </a>
+ </xsl:template>
+
+ <xsl:template match='section4'>
+ <xsl:variable name='oid'>
+ <xsl:call-template name='object.id'/>
+ </xsl:variable>
+ <xsl:variable name='anch'>
+ <xsl:value-of select='@anchor'/>
+ </xsl:variable>
+ <div class='indent'>
+ <h3>
+ <xsl:number level='single' count='section1'/>.<xsl:number level='single' count='section2'/>.<xsl:number level='single' count='section3'/>.<xsl:number level='single' count='section4'/>
+ <xsl:text> </xsl:text>
+ <a>
+ <xsl:attribute name='name'>
+ <xsl:choose>
+ <xsl:when test='$anch != ""'>
+ <xsl:value-of select='@anchor'/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>sect-</xsl:text><xsl:value-of select='$oid'/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+ <xsl:value-of select='@topic' />
+ </a>
+ </h3>
+ <xsl:apply-templates/>
+ </div>
+ </xsl:template>
+
+ <xsl:template match='remark'>
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match='p'>
+ <p>
+ <xsl:variable name='class.count' select='count(@class)'/>
+ <xsl:if test='$class.count=1'>
+ <xsl:attribute name='class'><xsl:value-of select='@class'/></xsl:attribute>
+ </xsl:if>
+ <xsl:variable name='style.count' select='count(@style)'/>
+ <xsl:if test='$style.count=1'>
+ <xsl:attribute name='style'><xsl:value-of select='@style'/></xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </p>
+ </xsl:template>
+
+ <xsl:template match='br'>
+ <br />
+ </xsl:template>
+
+ <xsl:template match='ul'>
+ <ul>
+ <xsl:variable name='class.count' select='count(@class)'/>
+ <xsl:if test='$class.count=1'>
+ <xsl:attribute name='class'><xsl:value-of select='@class'/></xsl:attribute>
+ </xsl:if>
+ <xsl:variable name='style.count' select='count(@style)'/>
+ <xsl:if test='$style.count=1'>
+ <xsl:attribute name='style'><xsl:value-of select='@style'/></xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </ul>
+ </xsl:template>
+
+ <xsl:template match='ol'>
+ <ol>
+ <xsl:variable name='start.count' select='count(@start)'/>
+ <xsl:if test='$start.count=1'>
+ <xsl:attribute name='start'><xsl:value-of select='@start'/></xsl:attribute>
+ </xsl:if>
+ <xsl:variable name='class.count' select='count(@class)'/>
+ <xsl:if test='$class.count=1'>
+ <xsl:attribute name='class'><xsl:value-of select='@class'/></xsl:attribute>
+ </xsl:if>
+ <xsl:variable name='style.count' select='count(@style)'/>
+ <xsl:if test='$style.count=1'>
+ <xsl:attribute name='style'><xsl:value-of select='@style'/></xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </ol>
+ </xsl:template>
+
+ <xsl:template match='li'>
+ <li>
+ <xsl:variable name='class.count' select='count(@class)'/>
+ <xsl:if test='$class.count=1'>
+ <xsl:attribute name='class'><xsl:value-of select='@class'/></xsl:attribute>
+ </xsl:if>
+ <xsl:variable name='style.count' select='count(@style)'/>
+ <xsl:if test='$style.count=1'>
+ <xsl:attribute name='style'><xsl:value-of select='@style'/></xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </li>
+ </xsl:template>
+
+ <xsl:template match='link'>
+ <a>
+ <xsl:attribute name='href'><xsl:value-of select='@url'/></xsl:attribute>
+ <xsl:apply-templates/>
+ </a>
+ </xsl:template>
+
+ <xsl:template match='example'>
+ <p class='caption'><a><xsl:attribute name='name'><xsl:text>example-</xsl:text><xsl:number level='any' count='example'/></xsl:attribute></a>Example <xsl:number level='any' count='example'/>.<xsl:text> </xsl:text><xsl:value-of select='@caption'/></p>
+ <div class='indent'>
+ <pre><xsl:apply-templates/></pre>
+ </div>
+ </xsl:template>
+
+ <xsl:template match='code'>
+ <p class='caption'><xsl:value-of select='@caption'/></p>
+ <div class='indent'>
+ <pre><xsl:apply-templates/></pre>
+ </div>
+ </xsl:template>
+
+ <xsl:template match='img'>
+ <img>
+ <xsl:attribute name='alt'><xsl:value-of select='@alt'/></xsl:attribute>
+ <xsl:attribute name='height'><xsl:value-of select='@height'/></xsl:attribute>
+ <xsl:attribute name='src'><xsl:value-of select='@src'/></xsl:attribute>
+ <xsl:attribute name='width'><xsl:value-of select='@width'/></xsl:attribute>
+ </img>
+ </xsl:template>
+
+ <xsl:template match='table'>
+ <div class='indent'>
+ <p class='caption'><a><xsl:attribute name='name'><xsl:text>table-</xsl:text><xsl:number level='any' count='table'/></xsl:attribute></a>Table <xsl:number level='any' count='table'/>:<xsl:text> </xsl:text><xsl:value-of select='@caption'/></p>
+ <table border='1' cellpadding='3' cellspacing='0'>
+ <xsl:apply-templates/>
+ </table>
+ </div>
+ </xsl:template>
+
+ <xsl:template match='tr'>
+ <tr class='body'>
+ <xsl:apply-templates/>
+ </tr>
+ </xsl:template>
+
+ <xsl:template match='th'>
+ <th>
+ <xsl:variable name='colspan.count' select='count(@colspan)'/>
+ <xsl:variable name='rowspan.count' select='count(@rowspan)'/>
+ <xsl:if test='$colspan.count=1'>
+ <xsl:attribute name='colspan'><xsl:value-of select='@colspan'/></xsl:attribute>
+ </xsl:if>
+ <xsl:if test='$rowspan.count=1'>
+ <xsl:attribute name='rowspan'><xsl:value-of select='@rowspan'/></xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </th>
+ </xsl:template>
+
+ <xsl:template match='td'>
+ <td>
+ <xsl:variable name='align.count' select='count(@align)'/>
+ <xsl:variable name='colspan.count' select='count(@colspan)'/>
+ <xsl:variable name='rowspan.count' select='count(@rowspan)'/>
+ <xsl:if test='$align.count=1'>
+ <xsl:attribute name='align'><xsl:value-of select='@align'/></xsl:attribute>
+ </xsl:if>
+ <xsl:if test='$colspan.count=1'>
+ <xsl:attribute name='colspan'><xsl:value-of select='@colspan'/></xsl:attribute>
+ </xsl:if>
+ <xsl:if test='$rowspan.count=1'>
+ <xsl:attribute name='rowspan'><xsl:value-of select='@rowspan'/></xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </td>
+ </xsl:template>
+
+ <xsl:template match='note'>
+ <xsl:variable name='notenum'>
+ <xsl:number level='any' count='note'/>
+ </xsl:variable>
+ <xsl:variable name='oid'>
+ <xsl:call-template name='object.id'/>
+ </xsl:variable>
+ <xsl:text> [</xsl:text><a href='#nt-{$oid}'>
+ <xsl:value-of select='$notenum'/></a>
+ <xsl:text>]</xsl:text>
+ </xsl:template>
+
+ <xsl:template match='note' mode='endlist'>
+ <p>
+ <xsl:variable name='oid'>
+ <xsl:call-template name='object.id'/>
+ </xsl:variable>
+ <a name='nt-{$oid}'><xsl:value-of select='position()'/></a>
+ <xsl:text>. </xsl:text>
+ <xsl:apply-templates/>
+ </p>
+ </xsl:template>
+
+<!-- PRESENTATIONAL ELEMENTS -->
+
+ <xsl:template match='blockquote'>
+ <blockquote>
+ <xsl:apply-templates/>
+ </blockquote>
+ </xsl:template>
+
+ <xsl:template match='cite'>
+ <span class='ref'>
+ <xsl:apply-templates/>
+ </span>
+ </xsl:template>
+
+ <xsl:template match='dfn'>
+ <span class='dfn'>
+ <xsl:apply-templates/>
+ </span>
+ </xsl:template>
+
+ <xsl:template match='div'>
+ <div>
+ <xsl:variable name='class.count' select='count(@class)'/>
+ <xsl:if test='$class.count=1'>
+ <xsl:attribute name='class'><xsl:value-of select='@class'/></xsl:attribute>
+ </xsl:if>
+ <xsl:variable name='style.count' select='count(@style)'/>
+ <xsl:if test='$style.count=1'>
+ <xsl:attribute name='style'><xsl:value-of select='@style'/></xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </div>
+ </xsl:template>
+
+ <xsl:template match='em'>
+ <span class='em'>
+ <xsl:apply-templates/>
+ </span>
+ </xsl:template>
+
+ <xsl:template match='pre'>
+ <pre><xsl:apply-templates/></pre>
+ </xsl:template>
+
+ <xsl:template match='span'>
+ <span>
+ <xsl:variable name='class.count' select='count(@class)'/>
+ <xsl:if test='$class.count=1'>
+ <xsl:attribute name='class'><xsl:value-of select='@class'/></xsl:attribute>
+ </xsl:if>
+ <xsl:variable name='style.count' select='count(@style)'/>
+ <xsl:if test='$style.count=1'>
+ <xsl:attribute name='style'><xsl:value-of select='@style'/></xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </span>
+ </xsl:template>
+
+ <xsl:template match='strong'>
+ <span class='strong'>
+ <xsl:apply-templates/>
+ </span>
+ </xsl:template>
+
+ <xsl:template match='tt'>
+ <tt>
+ <xsl:apply-templates/>
+ </tt>
+ </xsl:template>
+
+<!-- END OF PRESENTATIONAL ELEMENTS -->
+
+</xsl:stylesheet>