diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2007-11-23 14:01:39 +0000 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2007-11-23 14:01:39 +0000 |
commit | 031607bd26b6cd7b042ff26eaa0b97d3cf387164 (patch) | |
tree | e3ad9651a748df059719e38f810169ffc7b18d94 /tools | |
parent | c81f69f6db3db739f2c17ad9c0075e19de3c6f62 (diff) |
Move tools directory to top level. Stop using spec-gen.am
Diffstat (limited to 'tools')
-rw-r--r-- | tools/.git-darcs-dir | 0 | ||||
-rw-r--r-- | tools/Makefile.am | 9 | ||||
-rw-r--r-- | tools/c-constants-generator.xsl | 255 | ||||
-rw-r--r-- | tools/c-interfaces-generator.xsl | 82 | ||||
-rw-r--r-- | tools/doc-generator.xsl | 427 | ||||
-rw-r--r-- | tools/genginterface.py | 709 | ||||
-rw-r--r-- | tools/ls-interfaces.xsl | 33 | ||||
-rw-r--r-- | tools/make-all-async.xsl | 22 | ||||
-rw-r--r-- | tools/spec-to-introspect.xsl | 26 | ||||
-rw-r--r-- | tools/update-spec-gen-am.sh | 75 |
10 files changed, 1638 insertions, 0 deletions
diff --git a/tools/.git-darcs-dir b/tools/.git-darcs-dir new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tools/.git-darcs-dir diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 0000000..c27fe04 --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,9 @@ +EXTRA_DIST = \ + c-constants-generator.xsl \ + c-interfaces-generator.xsl \ + doc-generator.xsl \ + genginterface.py \ + ls-interfaces.xsl \ + make-all-async.xsl \ + spec-to-introspect.xsl \ + update-spec-gen-am.sh diff --git a/tools/c-constants-generator.xsl b/tools/c-constants-generator.xsl new file mode 100644 index 0000000..c249240 --- /dev/null +++ b/tools/c-constants-generator.xsl @@ -0,0 +1,255 @@ +<!-- Stylesheet to extract C enumerations from the Telepathy spec. + +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 +Library 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 Street, 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" + exclude-result-prefixes="tp"> + + <xsl:output method="text" indent="no" encoding="ascii"/> + + <xsl:param name="mixed-case-prefix" select="''"/> + + <xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/> + <xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'"/> + + <xsl:variable name="upper-case-prefix" select="concat(translate($mixed-case-prefix, $lower, $upper), '_')"/> + <xsl:variable name="lower-case-prefix" select="concat(translate($mixed-case-prefix, $upper, $lower), '_')"/> + + + <xsl:template match="tp:flags"> + <xsl:variable name="name"> + <xsl:choose> + <xsl:when test="@plural"> + <xsl:value-of select="@plural"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@name"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="value-prefix"> + <xsl:choose> + <xsl:when test="@singular"> + <xsl:value-of select="@singular"/> + </xsl:when> + <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:value-of select="translate(concat($mixed-case-prefix, $name), '_', '')"/>: +<xsl:apply-templates mode="flag-or-enumvalue-gtkdoc"> + <xsl:with-param name="value-prefix" select="$value-prefix"/> +</xsl:apply-templates> * +<xsl:if test="tp:docstring"> + * <![CDATA[<xsl:value-of select="translate(string (tp:docstring), ' ', ' ')"/>]]> + * +</xsl:if> * Bitfield/set of flags generated from the Telepathy specification. + */ +typedef enum { +<xsl:apply-templates> + <xsl:with-param name="value-prefix" select="$value-prefix"/> +</xsl:apply-templates>} <xsl:value-of select="translate(concat($mixed-case-prefix, $name), '_', '')"/>; + +</xsl:template> + + <xsl:template match="text()" mode="flag-or-enumvalue-gtkdoc"/> + + <xsl:template match="tp:enumvalue" mode="flag-or-enumvalue-gtkdoc"> + <xsl:param name="value-prefix"/> + <xsl:text> * @</xsl:text> + <xsl:value-of select="translate(concat($upper-case-prefix, $value-prefix, '_', @suffix), $lower, $upper)"/> + <xsl:text>: <![CDATA[</xsl:text> + <xsl:value-of select="translate(string(tp:docstring), ' ', ' ')"/> + <xsl:text>]]> </xsl:text> + </xsl:template> + + <xsl:template match="tp:flag" mode="flag-or-enumvalue-gtkdoc"> + <xsl:param name="value-prefix"/> + <xsl:text> * @</xsl:text> + <xsl:value-of select="translate(concat($upper-case-prefix, $value-prefix, '_', @suffix), $lower, $upper)"/> + <xsl:text>: <![CDATA[</xsl:text> + <xsl:value-of select="translate(string(tp:docstring), ' ', ' ')"/> + <xsl:text>]]> </xsl:text> + </xsl:template> + + <xsl:template match="tp:enum"> + <xsl:variable name="name"> + <xsl:choose> + <xsl:when test="@singular"> + <xsl:value-of select="@singular"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@name"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="value-prefix"> + <xsl:choose> + <xsl:when test="@singular"> + <xsl:value-of select="@singular"/> + </xsl:when> + <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:variable name="name-plural"> + <xsl:choose> + <xsl:when test="@plural"> + <xsl:value-of select="@plural"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@name"/><xsl:text>s</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> +/** + * <xsl:value-of select="translate(concat($mixed-case-prefix, $name), '_', '')"/>: +<xsl:apply-templates mode="flag-or-enumvalue-gtkdoc"> + <xsl:with-param name="value-prefix" select="$value-prefix"/> +</xsl:apply-templates> * +<xsl:if test="tp:docstring"> + * <![CDATA[[<xsl:value-of select="translate(string (tp:docstring), ' ', ' ')"/>]]> + * +</xsl:if> * Enumeration generated from the Telepathy specification. + */ +typedef enum { +<xsl:apply-templates> + <xsl:with-param name="value-prefix" select="$value-prefix"/> +</xsl:apply-templates>} <xsl:value-of select="translate(concat($mixed-case-prefix, $name), '_', '')"/>; + +/** + * NUM_<xsl:value-of select="translate(concat($upper-case-prefix, $name-plural), $lower, $upper)"/>: + * + * 1 higher than the highest valid value of #<xsl:value-of select="translate(concat($mixed-case-prefix, $name), '_', '')"/>. + */ +#define NUM_<xsl:value-of select="translate(concat($upper-case-prefix, $name-plural), $lower, $upper)"/> (<xsl:value-of select="tp:enumvalue[position() = last()]/@value"/>+1) + +</xsl:template> + + <xsl:template match="tp:flags/tp:flag"> + <xsl:param name="value-prefix"/> + <xsl:variable name="suffix"> + <xsl:choose> + <xsl:when test="@suffix"> + <xsl:value-of select="@suffix"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@name"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="name" select="translate(concat($upper-case-prefix, $value-prefix, '_', $suffix), $lower, $upper)"/> + + <xsl:if test="@name and @suffix and @name != @suffix"> + <xsl:message terminate="yes">Flag name <xsl:value-of select="@name"/> != suffix <xsl:value-of select="@suffix"/> +</xsl:message> + </xsl:if> + <xsl:text> </xsl:text><xsl:value-of select="$name"/> = <xsl:value-of select="@value"/>, +</xsl:template> + + <xsl:template match="tp:enum/tp:enumvalue"> + <xsl:param name="value-prefix"/> + <xsl:variable name="suffix"> + <xsl:choose> + <xsl:when test="@suffix"> + <xsl:value-of select="@suffix"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@name"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="name" select="translate(concat($upper-case-prefix, $value-prefix, '_', $suffix), $lower, $upper)"/> + + <xsl:if test="@name and @suffix and @name != @suffix"> + <xsl:message terminate="yes">Flag name <xsl:value-of select="@name"/> != suffix <xsl:value-of select="@suffix"/> +</xsl:message> + </xsl:if> + + <xsl:if test="preceding-sibling::tp:enumvalue and number(preceding-sibling::tp:enumvalue[1]/@value) > number(@value)"> + <xsl:message terminate="yes">Enum values must be in ascending numeric order, +but <xsl:value-of select="$name"/> is less than the previous value +</xsl:message> + </xsl:if> + + <xsl:text> </xsl:text><xsl:value-of select="$name"/> = <xsl:value-of select="@value"/>, +</xsl:template> + + <xsl:template match="tp:flag"> + <xsl:message terminate="yes">tp:flag found outside tp:flags +</xsl:message> + </xsl:template> + + <xsl:template match="tp:enumvalue"> + <xsl:message terminate="yes">tp:enumvalue found outside tp:enum +</xsl:message> + </xsl:template> + + <xsl:template match="text()"/> + + <xsl:template match="/tp:spec"> + <xsl:if test="$mixed-case-prefix = ''"> + <xsl:message terminate="yes"> + <xsl:text>mixed-case-prefix param must be set </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:text>/* Generated from </xsl:text> + <xsl:value-of select="tp:title"/> + <xsl:if test="tp:version"> + <xsl:text>, version </xsl:text> + <xsl:value-of select="tp:version"/> + </xsl:if> + <xsl:text> </xsl:text> + <xsl:for-each select="tp:copyright"> + <xsl:value-of select="."/> + <xsl:text> </xsl:text> + </xsl:for-each> + <xsl:value-of select="tp:license"/> + <xsl:text> </xsl:text> + <xsl:value-of select="tp:docstring"/> + <xsl:text> */ + +#ifdef __cplusplus +extern "C" { +#endif + +</xsl:text> + <xsl:apply-templates select="node"/> + <xsl:text> + +#ifdef __cplusplus +} +#endif + +</xsl:text> + </xsl:template> + +</xsl:stylesheet> + +<!-- vim:set sw=2 sts=2 et noai noci: --> diff --git a/tools/c-interfaces-generator.xsl b/tools/c-interfaces-generator.xsl new file mode 100644 index 0000000..8cd2a59 --- /dev/null +++ b/tools/c-interfaces-generator.xsl @@ -0,0 +1,82 @@ +<!-- Stylesheet to extract C enumerations from the Telepathy spec. + +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 +Library 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 Street, 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" + exclude-result-prefixes="tp"> + + <xsl:param name="mixed-case-prefix" select="''"/> + + <xsl:variable name="PREFIX" + select="translate($mixed-case-prefix, $lower, $upper)"/> + <xsl:variable name="Prefix" select="$mixed-case-prefix"/> + <xsl:variable name="prefix" + select="translate($mixed-case-prefix, $upper, $lower)"/> + + <xsl:output method="text" indent="no" encoding="ascii"/> + + <xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/> + <xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'"/> + + <xsl:template match="interface"> + <xsl:text>/** * </xsl:text> + <xsl:value-of select="$PREFIX"/> + <xsl:text>_IFACE_</xsl:text> + <xsl:value-of select="translate(../@name, concat($lower, '/'), $upper)"/> + <xsl:text>: * * The interface name "</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>" */ #define </xsl:text> + <xsl:value-of select="$PREFIX"/> + <xsl:text>_IFACE_</xsl:text> + <xsl:value-of select="translate(../@name, concat($lower, '/'), $upper)"/> + <xsl:text> \ "</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>" </xsl:text> + </xsl:template> + + <xsl:template match="text()"/> + + <xsl:template match="/tp:spec"> + <xsl:if test="$mixed-case-prefix = ''"> + <xsl:message terminate="yes"> + <xsl:text>mixed-case-prefix param must be set </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:text>/* Generated from: </xsl:text> + <xsl:value-of select="tp:title"/> + <xsl:if test="tp:version"> + <xsl:text> version </xsl:text> + <xsl:value-of select="tp:version"/> + </xsl:if> + <xsl:text> </xsl:text> + <xsl:for-each select="tp:copyright"> + <xsl:value-of select="."/> + <xsl:text> </xsl:text> + </xsl:for-each> + <xsl:text> </xsl:text> + <xsl:value-of select="tp:license"/> + <xsl:value-of select="tp:docstring"/> + <xsl:text> */ </xsl:text> + <xsl:apply-templates select="node"/> + </xsl:template> + +</xsl:stylesheet> + +<!-- vim:set sw=2 sts=2 et noai noci: --> diff --git a/tools/doc-generator.xsl b/tools/doc-generator.xsl new file mode 100644 index 0000000..3b76d13 --- /dev/null +++ b/tools/doc-generator.xsl @@ -0,0 +1,427 @@ +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" + exclude-result-prefixes="tp"> + <!--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:template match="*" mode="identity"> + <xsl:copy> + <xsl:apply-templates mode="identity"/> + </xsl:copy> + </xsl:template> + + <xsl:template match="tp:docstring"> + <xsl:apply-templates select="node()" mode="identity"/> + </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: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:template> + + <xsl:template match="/tp:spec/tp:copyright"> + <div xmlns="http://www.w3.org/1999/xhtml"> + <xsl:apply-templates/> + </div> + </xsl:template> + <xsl:template match="/tp:spec/tp:license"> + <div xmlns="http://www.w3.org/1999/xhtml" class="license"> + <xsl:apply-templates mode="identity"/> + </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: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: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">Properties:</h2> + <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 properties.</p> + </xsl:otherwise> + </xsl:choose> + + <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:template> + + <xsl:template match="tp:flags"> + <h3 xmlns="http://www.w3.org/1999/xhtml"><xsl:value-of select="@name"/></h3> + <xsl:apply-templates select="tp:docstring" /> + <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" /></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"> + <h3 xmlns="http://www.w3.org/1999/xhtml"><xsl:value-of select="@name"/></h3> + <xsl:apply-templates select="tp:docstring" /> + <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" /></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: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"/> + </dd> + </xsl:template> + + <xsl:template match="method"> + <div xmlns="http://www.w3.org/1999/xhtml" class="method"> + <h3 xmlns="http://www.w3.org/1999/xhtml"><xsl:value-of select="@name"/> ( + <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> + ) → + <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" /> + </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 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> + </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> + </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"> + <div xmlns="http://www.w3.org/1999/xhtml" class="signal"> + <h3 xmlns="http://www.w3.org/1999/xhtml"><xsl:value-of select="@name"/> ( + <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"/> + </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 { + margin-left: 1em; + margin-right: 4em; + } + .signal { + margin-left: 1em; + margin-right: 4em; + } + + </style> + </head> + <body> + <h1 class="topbox"> + <xsl:value-of select="tp:title" /> + </h1> + <xsl:if test="tp:version"> + <h2>Version <xsl:apply-templates select="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:errors"/> + </body> + </html> + </xsl:template> + +</xsl:stylesheet> + +<!-- vim:set sw=2 sts=2 et: --> diff --git a/tools/genginterface.py b/tools/genginterface.py new file mode 100644 index 0000000..9fbbb04 --- /dev/null +++ b/tools/genginterface.py @@ -0,0 +1,709 @@ +#!/usr/bin/python + +import sys +import os.path +import xml.dom.minidom + +def cmdline_error(): + print """\ +usage: + gen-ginterface [OPTIONS] xmlfile classname +options: + --include='<header.h>' (may be repeated) + --include='"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 + derived from class name). If this is given, classname-signals-marshal.h + is not automatically included. + --filename='BASENAME' + Set the basename for the output files (default is derived from class + name) + --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) + +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 camelcase_to_lower(s): + out =""; + out += s[0].lower() + last_upper=False + if s[0].isupper(): + last_upper=True + for i in range(1,len(s)): + if s[i].isupper(): + if last_upper: + if (i+1) < len(s) and s[i+1].islower(): + out += "_" + s[i].lower() + else: + out += s[i].lower() + else: + out += "_" + s[i].lower() + last_upper=True + else: + out += s[i] + last_upper=False + return out + +def camelcase_to_upper(s): + return camelcase_to_lower(s).upper() + +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): + def __iter__(self): + return SignatureIter(self) + + +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 ("gint ", "G_TYPE_INT64","INT64", False) + elif s == 't': #uint32 + return ("guint ", "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", "STRING", 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[:2] == 'a(': #array of structs, recurse + gtype = type_to_gtype(s[1:])[1] + return ("GPtrArray *", "(dbus_g_type_get_collection (\"GPtrArray\", "+gtype+"))", "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[: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 + + +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 + +def signal_to_marshal_name(signal, prefix): + glib_marshallers = ['VOID', 'BOOLEAN', 'CHAR', 'UCHAR', 'INT', + 'STRING', 'UINT', 'LONG', 'ULONG', 'ENUM', 'FLAGS', 'FLOAT', + 'DOUBLE', 'STRING', 'PARAM', 'BOXED', 'POINTER', 'OBJECT', + 'UINT_POINTER'] + + 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 signal_to_gtype_list(signal): + gtype=[] + for i in signal.getElementsByTagName("arg"): + name =i.getAttribute("name") + type = i.getAttribute("type") + gtype.append(type_to_gtype(type)[1]) + + return gtype + + +def print_license(stream, filename, description, dom): + stream.write( +"""/* + * %s - %s + * +""" % (filename, description)) + + for c in dom.getElementsByTagName('tp:copyright'): + # assume all child nodes are text + stream.write(' * %s\n' % ''.join([n.data for n in c.childNodes + if n.nodeType in (n.TEXT_NODE, + n.CDATA_SECTION_NODE)])) + + stream.write("""\ + * + * This file may be distributed under the same terms as the specification + * from which it is generated. + */ + +""") + +def print_header_begin(stream, prefix): + guardname = '__'+prefix.upper()+'_H__' + stream.write ("#ifndef "+guardname+"\n") + stream.write ("#define "+guardname+"\n\n") + + stream.write ("#include <glib-object.h>\n#include <dbus/dbus-glib.h>\n\n") + stream.write ("G_BEGIN_DECLS\n\n") + +def print_header_end(stream, prefix): + guardname = '__'+prefix.upper()+'_H__' + stream.write ("\nG_END_DECLS\n\n") + stream.write ("#endif /* #ifndef "+guardname+"*/\n") + +def print_class_declaration(stream, prefix, classname, methods): + stream.write ("""\ +/** + * %(classname)s: + * + * Dummy typedef representing any implementation of this interface. + */ +typedef struct _%(classname)s %(classname)s; + +/** + * %(classname)sClass: + * + * The class of %(classname)s. + */ +typedef struct _%(classname)sClass %(classname)sClass; + +""" % locals()) + + stream.write( +""" +GType %(prefix)s_get_type (void); + +""" % {'prefix':prefix,'uprefix':prefix.upper()}) + + macro_prefix = prefix.upper().split('_',1) + gtype = '_TYPE_'.join(macro_prefix) + + stream.write( +"""/* TYPE MACROS */ +#define %(type)s \\ + (%(prefix)s_get_type ()) +#define %(main)s_%(sub)s(obj) \\ + (G_TYPE_CHECK_INSTANCE_CAST((obj), %(type)s, %(name)s)) +#define %(main)s_IS_%(sub)s(obj) \\ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), %(type)s)) +#define %(main)s_%(sub)s_GET_CLASS(obj) \\ + (G_TYPE_INSTANCE_GET_INTERFACE ((obj), %(type)s, %(name)sClass)) + +""" % {"main":macro_prefix[0], "sub":macro_prefix[1], "type":gtype, "name":classname, "prefix":prefix}) + + +def signal_emit_stub(signal): + # for signal: org.freedesktop.Telepathy.Thing::StuffHappened (s, u) + # emit: void tp_svc_thing_emit_stuff_happened (gpointer instance, + # const char *arg, guint arg2) + dbus_name = signal.getAttributeNode("name").nodeValue + c_emitter_name = prefix + '_emit_' + camelcase_to_lower(dbus_name) + c_signal_const_name = 'SIGNAL_' + dbus_name + + macro_prefix = prefix.upper().split('_',1) + + decl = 'void ' + c_emitter_name + ' (gpointer instance' + args = '' + argdoc = '' + + for i in signal.getElementsByTagName("arg"): + name = i.getAttribute("name") + type = i.getAttribute("type") + info = type_to_gtype(type) + gtype = info[0] + if gtype[3]: + gtype = 'const ' + gtype + decl += ',\n ' + gtype + ' ' + name + args += ', ' + name + argdoc += ' * @' + name + ': FIXME: document args in genginterface\n' + decl += ')' + + doc = ("""\ +/** + * %s: + * @instance: An object implementing this interface +%s * + * Emit the %s D-Bus signal from @instance with the given arguments. + */ +""" % (c_emitter_name, argdoc, dbus_name)) + + header = decl + ';\n\n' + body = doc + decl + ('\n{\n' + ' g_assert (%s_IS_%s (instance));\n' + ' g_signal_emit (instance, signals[%s], 0%s);\n' + '}\n\n' + % (macro_prefix[0], macro_prefix[1], c_signal_const_name, + args)) + + return header, body + + +def print_class_definition(stream, prefix, classname, methods): + stream.write ("struct _%sClass {\n" % classname) + stream.write (" GTypeInterface parent_class;\n") + + for method in methods: + dbus_method_name = method.getAttributeNode("name").nodeValue + lc_method_name = camelcase_to_lower(dbus_method_name) + c_impl_name = prefix + '_' + lc_method_name + '_impl' + stream.write(' %s %s;\n' % (c_impl_name, lc_method_name)) + + stream.write ("};\n\n") + + +def cmp_by_name(node1, node2): + return cmp(node1.getAttributeNode("name").nodeValue, + node2.getAttributeNode("name").nodeValue) + + +def do_method(method): + # DoStuff (s -> u) + dbus_method_name = method.getAttributeNode("name").nodeValue + lc_method_name = camelcase_to_lower(dbus_method_name) + # void tp_svc_thing_do_stuff (TpSvcThing *, const char *, + # DBusGMethodInvocation *); + c_method_name = prefix + '_' + lc_method_name + # typedef void (*tp_svc_thing_do_stuff_impl) (TpSvcThing *, const char *, + # DBusGMethodInvocation *); + c_impl_name = prefix + '_' + lc_method_name + '_impl' + # void tp_svc_thing_return_from_do_stuff (DBusGMethodInvocation *, guint); + ret_method_name = prefix + '_return_from_' + lc_method_name + + ret_count=0 + + header = '' + body = '' + + c_decl = "static void\n" + method_decl = "typedef void (*" + c_impl_name + ') (' + ret_decl = 'void\n' + ret_body = '{\n dbus_g_method_return (dbus_context' + arg_doc = '' + ret_arg_doc = '' + + tmp = c_method_name+' (' + pad = ' ' * len(tmp) + c_decl += tmp+classname+' *self' + + method_pad = ' ' * len(method_decl) + method_decl += classname + ' *self' + args = 'self' + + tmp = ret_method_name+' (' + ret_pad = ' ' * len(tmp) + ret_decl += tmp+'DBusGMethodInvocation *dbus_context' + + for i in method.getElementsByTagName("arg"): + name =i.getAttribute("name") + direction = i.getAttribute("direction") + type = i.getAttribute("type") + + if not name and direction == "out": + if ret_count==0: + name = "ret" + else: + name = "ret"+str(ret_count) + ret_count += 1 + + gtype = type_to_gtype(type)[0] + if type_to_gtype(type)[3]: + gtype="const "+gtype + if direction != "out": + c_decl +=",\n"+pad+gtype+name + method_decl +=",\n"+method_pad+gtype+name + args += ', '+name + arg_doc += (' * @' + name + + ': FIXME: document args in genginterface\n') + else: + ret_decl += ",\n"+ret_pad+gtype+name + ret_body += ', '+name + ret_arg_doc += (' * @' + name + + ': FIXME: document args in genginterface\n') + + c_decl += ",\n"+pad+"DBusGMethodInvocation *context)" + method_decl += ",\n"+method_pad+"DBusGMethodInvocation *context);\n" + args += ', context' + + ret_doc = ("""\ +/** + * %s: + * @dbus_context: The D-Bus method invocation context +%s * + * Return successfully by calling dbus_g_method_return (@dbus_context, + * ...). This inline function is just a type-safe wrapper for + * dbus_g_method_return. + */ +""" % (ret_method_name, ret_arg_doc)) + + interface = method.parentNode.getAttribute("name"); + ret_decl += ')\n' + ret_body += ');\n}\n' + header += (ret_doc + 'static inline\n/**/\n' + ret_decl + ';\n' + + 'static inline ' + ret_decl + ret_body) + body += ( +""" +/** + * %(c_impl_name)s + * @self: The object implementing this interface +%(arg_doc)s * @context: The D-Bus invocation context to use to return values + * or throw an error. + * + * Signature of an implementation of D-Bus method %(dbus_method_name)s + * on interface %(interface)s + */ +""" % locals()) + + body += c_decl+"\n{\n" + body += " %s impl = (%s_GET_CLASS (self)->%s);\n" % ( + c_impl_name, prefix.upper(), lc_method_name) + body += " if (impl)\n" + body += " (impl) (%s);\n" % args + body += " else\n" + if not_implemented_func: + body += " %s (context);\n" % not_implemented_func + else: + # this seems as appropriate an error as any + body += """\ + { + GError e = { DBUS_GERROR, DBUS_GERROR_UNKNOWN_METHOD, + "Method not implemented" }; + + dbus_g_method_return_error (context, &e); + } +""" + body += "}\n\n" + + dg_method_name = prefix + '_' + dbus_gutils_wincaps_to_uscore(dbus_method_name) + if dg_method_name != c_method_name: + body += ("""\ +#define %(dg_method_name)s %(c_method_name)s + +""" % {'dg_method_name': dg_method_name, 'c_method_name': c_method_name }) + + method_decl += 'void %s_implement_%s (%sClass *klass, %s impl);\n\n' \ + % (prefix, lc_method_name, classname, c_impl_name) + + body += ("""\ +/** + * %s_implement_%s: + * @klass: A class whose instances implement this interface + * @impl: A callback used to implement the %s method + * + * Register an implementation for the %s method in the vtable of an + * implementation of this interface. To be called from the interface + * init function. + */ +""" % (prefix, lc_method_name, dbus_method_name, dbus_method_name)) + body += 'void\n%s_implement_%s (%sClass *klass, %s impl)\n{\n'\ + % (prefix, lc_method_name, classname, c_impl_name) + body += ' klass->%s = impl;\n' % lc_method_name + body += '}\n\n' + + return (method_decl, header, body) + +if __name__ == '__main__': + from getopt import gnu_getopt + + options, argv = gnu_getopt(sys.argv[1:], '', + ['filename=', 'signal-marshal-prefix=', + 'include=', + 'not-implemented-func=']) + + try: + classname = argv[1] + except IndexError: + cmdline_error() + + prefix = camelcase_to_lower(classname) + + basename = prefix.replace('_', '-') + signal_marshal_prefix = prefix + headers = [] + not_implemented_func = '' + + 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 == '--not-implemented-func': + not_implemented_func = value + + outname_header = basename + ".h" + outname_body = basename + ".c" + outname_signal_marshal = basename + "-signals-marshal.list" + + header=open(outname_header,'w') + body=open(outname_body, 'w') + + signal_marshal=open(outname_signal_marshal, 'w') + + try: + dom = xml.dom.minidom.parse(argv[0]) + except IndexError: + cmdline_error() + + signals = dom.getElementsByTagName("signal") + signals.sort(cmp_by_name) + methods = dom.getElementsByTagName("method") + methods.sort(cmp_by_name) + + print_license(header, outname_header, "Header for " + classname, dom) + print_license(body, outname_body, "Source for " + classname, dom) + print_header_begin(header,prefix) + + print_class_declaration(header, prefix, classname, methods) + + # include my own header first, to ensure self-contained + body.write( +"""#include "%s" + +""" % outname_header) + + # required headers + body.write( +"""#include <stdio.h> +#include <stdlib.h> + +""") + + for h in headers: + body.write('#include %s\n' % h) + body.write('\n') + + if signal_marshal_prefix == prefix: + body.write('#include "%s-signals-marshal.h"\n' % basename) + # else assume the signal marshallers are declared in one of the headers + + body.write('const DBusGObjectInfo dbus_glib_%s_object_info;\n' + % prefix) + + print_class_definition(body, prefix, classname, methods) + + if signals: + body.write('enum {\n') + for signal in signals: + dbus_name = signal.getAttributeNode("name").nodeValue + body.write(' SIGNAL_%s,\n' % (dbus_name)) + body.write(' N_SIGNALS\n};\nstatic guint signals[N_SIGNALS] = {0};\n\n') + + gtypename = '_TYPE_'.join(prefix.upper().split('_',1)) + + body.write( +""" +static void +%(prefix)s_base_init (gpointer klass) +{ + static gboolean initialized = FALSE; + + if (!initialized) + { + initialized = TRUE; +""" % {'classname':classname, 'gtypename':gtypename, 'prefix':prefix, 'uprefix':prefix.upper()}) + + header.write("\n") + + marshallers = {} + for signal in signals: + dbus_name = signal.getAttributeNode("name").nodeValue + gtypelist = signal_to_gtype_list(signal) + marshal_name = signal_to_marshal_name(signal, signal_marshal_prefix) + + body.write( +""" + signals[SIGNAL_%s] = + g_signal_new ("%s", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + %s, + G_TYPE_NONE, %s); +""" % (dbus_name, + (dbus_gutils_wincaps_to_uscore(dbus_name)).replace('_','-'), + marshal_name, + ', '.join([str(len(gtypelist))] + gtypelist))) + + if not marshal_name.startswith('g_cclosure_marshal_VOID__'): + mtype = signal_to_marshal_type(signal) + assert(len(mtype)) + marshallers[','.join(mtype)] = True + + for marshaller in marshallers: + signal_marshal.write("VOID:"+marshaller+"\n") + + body.write( +""" + dbus_g_object_type_install_info (%(prefix)s_get_type (), &dbus_glib_%(prefix)s_object_info); + } +} + +GType +%(prefix)s_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo info = { + sizeof (%(classname)sClass), + %(prefix)s_base_init, /* base_init */ + NULL, /* base_finalize */ + NULL, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, /* n_preallocs */ + NULL /* instance_init */ + }; + + type = g_type_register_static (G_TYPE_INTERFACE, "%(classname)s", &info, 0); + } + + return type; +} + +""" % {'classname':classname,'prefix':prefix, 'uprefix':prefix.upper()}) + + for method in methods: + m, h, b = do_method(method) + header.write(m + '\n') + header.write(h) + body.write(b) + + for signal in signals: + h, b = signal_emit_stub(signal) + header.write(h) + body.write(b) + + header.write('\n') + + body.write("""\ +#include "%s-glue.h" + +""" % (basename)) + + print_header_end(header,prefix) + header.close() + body.close() diff --git a/tools/ls-interfaces.xsl b/tools/ls-interfaces.xsl new file mode 100644 index 0000000..7b970ce --- /dev/null +++ b/tools/ls-interfaces.xsl @@ -0,0 +1,33 @@ +<!-- +Extract a space-separated list of interface classnames from the Telepathy spec. + +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 +Library General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +--> + +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + + <xsl:output method="text" indent="no" encoding="ascii"/> + + <xsl:template match="text()"/> + + <xsl:template match="node"> + <xsl:value-of select="concat(' ', translate(@name, '/', ''), ' ')"/> + </xsl:template> + +</xsl:stylesheet> + +<!-- vim:set sw=2 sts=2 et noai noci: --> diff --git a/tools/make-all-async.xsl b/tools/make-all-async.xsl new file mode 100644 index 0000000..1dec391 --- /dev/null +++ b/tools/make-all-async.xsl @@ -0,0 +1,22 @@ +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + + <xsl:output method="xml" indent="yes" encoding="ascii"/> + + <xsl:template match="method"> + <xsl:copy> + <xsl:apply-templates select="@*|node()"/> + <xsl:if test="not(annotation[name='org.freedesktop.DBus.GLib.Async'])"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + </xsl:if> + </xsl:copy> + </xsl:template> + + <xsl:template match="@*|node()"> + <xsl:copy> + <xsl:apply-templates select="@*|node()"/> + </xsl:copy> + </xsl:template> + +</xsl:stylesheet> + +<!-- vim:set sw=2 sts=2 et: --> diff --git a/tools/spec-to-introspect.xsl b/tools/spec-to-introspect.xsl new file mode 100644 index 0000000..1eefd3d --- /dev/null +++ b/tools/spec-to-introspect.xsl @@ -0,0 +1,26 @@ +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" + exclude-result-prefixes="tp"> + + <xsl:template match="*"> + <xsl:copy> + <xsl:for-each select="@*"> + <xsl:if test="not(starts-with(name(), 'tp:'))"> + <xsl:copy/> + </xsl:if> + </xsl:for-each> + <xsl:apply-templates/> + </xsl:copy> + </xsl:template> + + <xsl:template match="tp:*"/> + <xsl:template match="text()"/> + + <xsl:output method="xml" indent="yes" encoding="UTF-8" + omit-xml-declaration="no" + doctype-system="http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" + doctype-public="-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" /> + +</xsl:stylesheet> + +<!-- vim:set sw=2 sts=2 et: --> diff --git a/tools/update-spec-gen-am.sh b/tools/update-spec-gen-am.sh new file mode 100644 index 0000000..b484846 --- /dev/null +++ b/tools/update-spec-gen-am.sh @@ -0,0 +1,75 @@ +#!/bin/sh + +mk_specdir="extensions" +mk_toolsdir="extensions/tools" + +test -n "$XSLTPROC" || XSLTPROC=xsltproc +test -n "$TOP_SRCDIR" || TOP_SRCDIR=../.. + +toolsdir="${TOP_SRCDIR}/${mk_toolsdir}" +specdir="${TOP_SRCDIR}/${mk_specdir}" + +outfile="$1" +gendir="$2" +whitelist="$3" + +SPEC_INTERFACES="`$XSLTPROC --nonet --novalid --xinclude $toolsdir/ls-interfaces.xsl $specdir/all.xml`" + +install -d ./`dirname "$outfile"` +exec > "$outfile.tmp" + +echo "# Rules to re-generate this file" +printf "$outfile: \$(top_srcdir)/$mk_specdir/all.xml $whitelist \\\\\\n" +printf "\\t\\t\$(top_srcdir)/$mk_specdir/all.xml \\\\\\n" +printf "\\t\\t\$(SPEC_INTERFACE_XMLS) \\\\\\n" +printf "\\t\\t\$(top_srcdir)/$mk_toolsdir/ls-interfaces.xsl \\\\\\n" +printf "\\t\\t\$(top_builddir)/$mk_toolsdir/update-spec-gen-am.sh\\n" +printf "\\tXSLTPROC=xsltproc TOP_SRCDIR=\$(top_srcdir) \$(SHELL) \$(top_builddir)/$mk_toolsdir/update-spec-gen-am.sh $outfile $gendir $whitelist\\n" +echo + +for class in INTERFACES INTERFACE_XMLS GENERATED_CS GENERATED_HS \ + GENERATED_LISTS GLUE_HS +do + if test -z "$whitelist" + then + echo "SPEC_$class =" + else + echo "STABLE_SPEC_$class =" + echo "UNSTABLE_SPEC_$class =" + fi +done + +for iface in $SPEC_INTERFACES +do + if test -z "$whitelist" + then + # just output the combined variables directly + stability= + elif grep "^$iface\$" "$whitelist" >/dev/null + then + stability=STABLE_ + else + stability=UNSTABLE_ + fi + echo "${stability}SPEC_INTERFACES += $iface" + echo "${stability}SPEC_INTERFACE_XMLS += \$(top_srcdir)/$mk_specdir/$iface.xml" + if test -n "$gendir" + then + echo "${stability}SPEC_GENERATED_CS += $gendir/svc-$iface.c" + echo "${stability}SPEC_GENERATED_HS += $gendir/svc-$iface.h" + echo "${stability}SPEC_GLUE_HS += $gendir/svc-$iface-glue.h" + echo "${stability}SPEC_GENERATED_LISTS +="\ + "$gendir/svc-$iface-signals-marshal.list" + fi +done + +if test -n "$whitelist" +then + for class in INTERFACES INTERFACE_XMLS GENERATED_CS GENERATED_HS \ + GENERATED_LISTS GLUE_HS + do + echo "SPEC_$class = \$(STABLE_SPEC_$class) \$(UNSTABLE_SPEC_$class)" + done +fi + +mv "$outfile.tmp" "$outfile" |