diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2008-04-21 16:48:35 +0000 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2008-04-21 16:48:35 +0000 |
commit | 82fd790681fff991ac0a151e71288550c1cd8a94 (patch) | |
tree | dfa2d51751555d2349f0820f3533867226932d0f /tools | |
parent | 840dc089b307ec92829ec1168d4e49358910c6be (diff) | |
download | telepathy-salut-82fd790681fff991ac0a151e71288550c1cd8a94.tar.gz |
Move extensions/tools to tools (consistent with Gabble, telepathy-glib, etc.)
20080421164835-53eee-424948eb2510e98e743a9c2ba68b8985ed9f84de.gz
Diffstat (limited to 'tools')
-rw-r--r-- | tools/.git-darcs-dir | 0 | ||||
-rw-r--r-- | tools/Makefile.am | 42 | ||||
-rw-r--r-- | tools/c-constants-generator.xsl | 299 | ||||
-rw-r--r-- | tools/c-interfaces-generator.xsl | 84 | ||||
-rw-r--r-- | tools/doc-generator.xsl | 758 | ||||
-rw-r--r-- | tools/genginterface.py | 712 | ||||
-rw-r--r-- | tools/glib-client-marshaller-gen.py | 59 | ||||
-rw-r--r-- | tools/glib-errors-enum-body.xsl | 72 | ||||
-rw-r--r-- | tools/glib-errors-enum-header.xsl | 73 | ||||
-rw-r--r-- | tools/glib-ginterface-gen.py | 711 | ||||
-rw-r--r-- | tools/glib-gtypes-generator.py | 230 | ||||
-rw-r--r-- | tools/glib-interfaces-body-generator.xsl | 47 | ||||
-rw-r--r-- | tools/glib-interfaces-generator.xsl | 55 | ||||
-rw-r--r-- | tools/glib-signals-marshal-gen.py | 55 | ||||
-rw-r--r-- | tools/identity.xsl | 7 | ||||
-rw-r--r-- | tools/libglibcodegen.py | 320 | ||||
-rw-r--r-- | tools/ls-interfaces.xsl | 35 | ||||
-rw-r--r-- | tools/make-all-async.xsl | 43 | ||||
-rw-r--r-- | tools/spec-to-introspect.xsl | 51 | ||||
-rw-r--r-- | tools/update-spec-gen-am.sh | 75 |
20 files changed, 3728 insertions, 0 deletions
diff --git a/tools/.git-darcs-dir b/tools/.git-darcs-dir new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/tools/.git-darcs-dir diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 00000000..ac5ad2ec --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,42 @@ +EXTRA_DIST = \ + c-constants-generator.xsl \ + c-interfaces-generator.xsl \ + doc-generator.xsl \ + genginterface.py \ + glib-client-marshaller-gen.py \ + glib-errors-enum-body.xsl \ + glib-errors-enum-header.xsl \ + glib-interfaces-generator.xsl \ + glib-interfaces-body-generator.xsl \ + glib-ginterface-gen.py \ + glib-gtypes-generator.py \ + glib-signals-marshal-gen.py \ + identity.xsl \ + libglibcodegen.py \ + ls-interfaces.xsl \ + make-all-async.xsl \ + spec-to-introspect.xsl \ + update-spec-gen-am.sh + +glib-client-marshaller-gen.py: libglibcodegen.py + touch $@ +glib-ginterface-gen.py: libglibcodegen.py + touch $@ +glib-gtypes-generator.py: libglibcodegen.py + touch $@ +glib-signals-marshal-gen.py: libglibcodegen.py + touch $@ + +glib-interfaces-generator.xsl: c-interfaces-generator.xsl + touch $@ +glib-interfaces-body-generator.xsl: c-interfaces-generator.xsl + touch $@ + +TELEPATHY_GLIB_SRCDIR = $(top_srcdir)/../telepathy-glib +maintainer-update-from-telepathy-glib: + set -e && cd $(srcdir) && \ + for x in $(EXTRA_DIST); do \ + if test -f $(TELEPATHY_GLIB_SRCDIR)/tools/$$x; then \ + cp $(TELEPATHY_GLIB_SRCDIR)/tools/$$x $$x; \ + fi; \ + done diff --git a/tools/c-constants-generator.xsl b/tools/c-constants-generator.xsl new file mode 100644 index 00000000..18b2e495 --- /dev/null +++ b/tools/c-constants-generator.xsl @@ -0,0 +1,299 @@ +<!-- Stylesheet to extract C enumerations from the Telepathy spec. +The master copy of this stylesheet is in telepathy-glib - 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 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:text>/** </xsl:text> + <xsl:text> * </xsl:text> + <xsl:value-of select="translate(concat($mixed-case-prefix, $name), '_', '')"/> + <xsl:text>: </xsl:text> + <xsl:apply-templates mode="flag-or-enumvalue-gtkdoc"> + <xsl:with-param name="value-prefix" select="$value-prefix"/> + </xsl:apply-templates> + <xsl:text> * </xsl:text> + <xsl:if test="tp:docstring"> + <xsl:text> * <![CDATA[</xsl:text> + <xsl:value-of select="translate(string (tp:docstring), ' ', ' ')"/> + <xsl:text>]]> </xsl:text> + <xsl:text> * </xsl:text> + </xsl:if> + <xsl:text> * Bitfield/set of flags generated from the Telepathy specification. </xsl:text> + <xsl:text> */ </xsl:text> + <xsl:text>typedef enum { </xsl:text> + <xsl:apply-templates> + <xsl:with-param name="value-prefix" select="$value-prefix"/> + </xsl:apply-templates> + <xsl:text>} </xsl:text> + <xsl:value-of select="translate(concat($mixed-case-prefix, $name), '_', '')"/> + <xsl:text>; </xsl:text> + <xsl:text> </xsl:text> + </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:text>/** </xsl:text> + <xsl:text> * </xsl:text> + <xsl:value-of select="translate(concat($mixed-case-prefix, $name), '_', '')"/> + <xsl:text>: </xsl:text> + <xsl:apply-templates mode="flag-or-enumvalue-gtkdoc"> + <xsl:with-param name="value-prefix" select="$value-prefix"/> + </xsl:apply-templates> + <xsl:text> * </xsl:text> + <xsl:if test="tp:docstring"> + <xsl:text> * <![CDATA[</xsl:text> + <xsl:value-of select="translate(string (tp:docstring), ' ', ' ')"/> + <xsl:text>]]> </xsl:text> + <xsl:text> * </xsl:text> + </xsl:if> + <xsl:text> * Bitfield/set of flags generated from the Telepathy specification. </xsl:text> + <xsl:text> */ </xsl:text> + <xsl:text>typedef enum { </xsl:text> + <xsl:apply-templates> + <xsl:with-param name="value-prefix" select="$value-prefix"/> + </xsl:apply-templates> + <xsl:text>} </xsl:text> + <xsl:value-of select="translate(concat($mixed-case-prefix, $name), '_', '')"/> + <xsl:text>; </xsl:text> + <xsl:text> </xsl:text> + <xsl:text>/** </xsl:text> + <xsl:text> * NUM_</xsl:text> + <xsl:value-of select="translate(concat($upper-case-prefix, $name-plural), $lower, $upper)"/> + <xsl:text>: </xsl:text> + <xsl:text> * </xsl:text> + <xsl:text> * 1 higher than the highest valid value of #</xsl:text> + <xsl:value-of select="translate(concat($mixed-case-prefix, $name), '_', '')"/> + <xsl:text>. </xsl:text> + <xsl:text> */ </xsl:text> + <xsl:text>#define NUM_</xsl:text> + <xsl:value-of select="translate(concat($upper-case-prefix, $name-plural), $lower, $upper)"/> + <xsl:text> (</xsl:text> + <xsl:value-of select="tp:enumvalue[position() = last()]/@value"/> + <xsl:text>+1) </xsl:text> + <xsl:text> </xsl:text> + </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"> + <xsl:text>Flag name </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> != suffix </xsl:text> + <xsl:value-of select="@suffix"/> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:if> + <xsl:text> </xsl:text> + <xsl:value-of select="$name"/> + <xsl:text> = </xsl:text> + <xsl:value-of select="@value"/> + <xsl:text>, </xsl:text> + </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"> + <xsl:text>Enumvalue name </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> != suffix </xsl:text> + <xsl:value-of select="@suffix"/> + <xsl:text> </xsl:text> + </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"> + <xsl:text>Enum values must be in ascending numeric order, but </xsl:text> + <xsl:value-of select="$name"/> + <xsl:text> is less than the previous value</xsl:text> + </xsl:message> + </xsl:if> + + <xsl:text> </xsl:text> + <xsl:value-of select="$name"/> + <xsl:text> = </xsl:text> + <xsl:value-of select="@value"/> + <xsl:text>, </xsl:text> + </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: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> </xsl:text> + <xsl:text> */ </xsl:text> + <xsl:text> </xsl:text> + <xsl:text>#ifdef __cplusplus </xsl:text> + <xsl:text>extern "C" { </xsl:text> + <xsl:text>#endif </xsl:text> + <xsl:text> </xsl:text> + <xsl:apply-templates/> + <xsl:text> </xsl:text> + <xsl:text>#ifdef __cplusplus </xsl:text> + <xsl:text>} </xsl:text> + <xsl:text>#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 00000000..f965a705 --- /dev/null +++ b/tools/c-interfaces-generator.xsl @@ -0,0 +1,84 @@ +<!-- Stylesheet to extract C enumerations from the Telepathy spec. +The master copy of this stylesheet is in telepathy-glib - 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 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/> + </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 00000000..a820e46d --- /dev/null +++ b/tools/doc-generator.xsl @@ -0,0 +1,758 @@ +<!-- 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:template match="html:*" mode="html"> + <xsl:copy> + <xsl:apply-templates mode="html"/> + </xsl:copy> + </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 select="text() | html:* | tp:rationale" mode="html"/> + </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: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="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: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"> + <h3> + <a name="type-{@name}"> + <xsl:value-of select="@name"/> + </a> + </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"> + <a name="type-{@name}"> + <xsl:value-of select="@name"/> + </a> + </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="property"> + <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:text>access: </xsl:text> + <code><xsl:value-of select="@access"/></code> + </xsl:otherwise> + </xsl:choose> + </dt> + <dd xmlns="http://www.w3.org/1999/xhtml"> + <xsl:apply-templates select="tp:docstring"/> + </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"/> + </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()"> → </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"> + <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"/> + </div> + </div> + </xsl:template> + + <xsl:template match="tp:external-type"> + <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()"> → </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"/> + </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"> + <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> + ) → + <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 name="parenthesized-tp-type"> + <xsl:if test="@tp:type"> + <xsl:variable name="tp-type" select="@tp: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:choose> + <xsl:when test="//tp:simple-type[@name=$tp-type]" /> + <xsl:when test="//tp:simple-type[concat(@name, '[]')=$tp-type]" /> + <xsl:when test="//tp:struct[concat(@name, '[]')=$tp-type][string(@array-name) != '']" /> + <xsl:when test="//tp:mapping[concat(@name, '[]')=$tp-type][string(@array-name) != '']" /> + <xsl:when test="//tp:struct[@name=$tp-type]" /> + <xsl:when test="//tp:enum[@name=$tp-type]" /> + <xsl:when test="//tp:enum[concat(@name, '[]')=$tp-type]" /> + <xsl:when test="//tp:flags[@name=$tp-type]" /> + <xsl:when test="//tp:flags[concat(@name, '[]')=$tp-type]" /> + <xsl:when test="//tp:mapping[@name=$tp-type]" /> + <xsl:when test="//tp:external-type[concat(@name, '[]')=$tp-type]" /> + <xsl:when test="//tp:external-type[@name=$tp-type]" /> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:text>ERR: Unable to find type '</xsl:text> + <xsl:value-of select="$tp-type"/> + <xsl:text>' </xsl:text> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + (<a href="#type-{$single-type}"><xsl:value-of select="$tp-type"/></a>) + </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"> + <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"/> + </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; + } + + </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: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:stylesheet> + +<!-- vim:set sw=2 sts=2 et: --> diff --git a/tools/genginterface.py b/tools/genginterface.py new file mode 100644 index 00000000..c0ae7b9e --- /dev/null +++ b/tools/genginterface.py @@ -0,0 +1,712 @@ +#!/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 ("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", "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[:2] == 'aa': #array of arrays, 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 (" GObjectClass 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/glib-client-marshaller-gen.py b/tools/glib-client-marshaller-gen.py new file mode 100644 index 00000000..54447255 --- /dev/null +++ b/tools/glib-client-marshaller-gen.py @@ -0,0 +1,59 @@ +#!/usr/bin/python + +import sys +import xml.dom.minidom +from string import ascii_letters, digits + + +from libglibcodegen import signal_to_marshal_name + + +NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" + +class Generator(object): + + def __init__(self, dom, prefix): + self.dom = dom + self.marshallers = {} + self.prefix = prefix + + def do_signal(self, signal): + marshaller = signal_to_marshal_name(signal, self.prefix) + + assert '__' in marshaller + rhs = marshaller.split('__', 1)[1].split('_') + + self.marshallers[marshaller] = rhs + + def __call__(self): + signals = self.dom.getElementsByTagName('signal') + + for signal in signals: + self.do_signal(signal) + + print 'void' + print '%s_register_dbus_glib_marshallers (void)' % self.prefix + print '{' + + all = self.marshallers.keys() + all.sort() + for marshaller in all: + rhs = self.marshallers[marshaller] + + print ' dbus_g_object_register_marshaller (%s,' % marshaller + print ' G_TYPE_NONE, /* return */' + for type in rhs: + print ' G_TYPE_%s,' % type.replace('VOID', 'NONE') + print ' G_TYPE_INVALID);' + + print '}' + + +def types_to_gtypes(types): + return [type_to_gtype(t)[1] for t in types] + +if __name__ == '__main__': + argv = sys.argv[1:] + dom = xml.dom.minidom.parse(argv[0]) + + Generator(dom, argv[1])() diff --git a/tools/glib-errors-enum-body.xsl b/tools/glib-errors-enum-body.xsl new file mode 100644 index 00000000..17054b76 --- /dev/null +++ b/tools/glib-errors-enum-body.xsl @@ -0,0 +1,72 @@ +<!-- Stylesheet to extract GLib error enumerations from the Telepathy spec. +The master copy of this stylesheet is in telepathy-glib - 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 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:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/> + <xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'"/> + + <xsl:template match="tp:error" mode="values"> + <!-- CHANNEL_BANNED --> + <xsl:variable name="name" select="translate(@name, concat($lower, '. '), + concat($upper, '__'))"/> + <!-- Channel.Banned --> + <xsl:variable name="nick" select="translate(@name, ' ', '')"/> + /* <xsl:value-of select="concat(../@namespace, '.', $name)"/> + <xsl:value-of select="tp:docstring"/> */ + { TP_ERROR_<xsl:value-of select="$name"/>, "TP_ERROR_<xsl:value-of select="$name"/>", "<xsl:value-of select="$nick"/>" }, +</xsl:template> + + <xsl:template match="text()"/> + + <xsl:template match="//tp:errors">/* Generated from the Telepathy spec + +<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"/> +*/ + +#include <_gen/telepathy-errors.h> + +GType +tp_error_get_type (void) +{ + static GType etype = 0; + if (G_UNLIKELY (etype == 0)) + { + static const GEnumValue values[] = { +<xsl:apply-templates select="tp:error" mode="values"/> }; + + etype = g_enum_register_static ("TpError", values); + } + return etype; +} + +</xsl:template> + +</xsl:stylesheet> + +<!-- vim:set sw=2 sts=2 et noai noci: --> diff --git a/tools/glib-errors-enum-header.xsl b/tools/glib-errors-enum-header.xsl new file mode 100644 index 00000000..5275041c --- /dev/null +++ b/tools/glib-errors-enum-header.xsl @@ -0,0 +1,73 @@ +<!-- Stylesheet to extract GLib error enumerations from the Telepathy spec. +The master copy of this stylesheet is in telepathy-glib - 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 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:template match="tp:error" mode="gtkdoc"> + * @TP_ERROR_<xsl:value-of select="translate(@name, 'abcdefghijklmnopqrstuvwxyz .', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ__')"/>: <xsl:value-of select="concat(../@namespace, '.', translate(@name, ' ', ''))"/>: + * <xsl:value-of select="translate(tp:docstring, ' ', '')"/> + </xsl:template> + + <xsl:template match="tp:error" mode="enum"> +<xsl:text> TP_ERROR_</xsl:text><xsl:value-of select="translate(@name, 'abcdefghijklmnopqrstuvwxyz .', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ__')"/>, +</xsl:template> + + <xsl:template match="text()"/> + + <xsl:template match="//tp:errors">/* Generated from the Telepathy spec + +<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"/> +*/ + +#include <glib-object.h> + +G_BEGIN_DECLS + +GType tp_error_get_type (void); + +/** + * TP_TYPE_ERROR: + * + * The GType of the Telepathy error enumeration. + */ +#define TP_TYPE_ERROR (tp_error_get_type()) + +/** + * TpError:<xsl:apply-templates select="tp:error" mode="gtkdoc"/> + * + * Enumerated type representing the Telepathy D-Bus errors. + */ +typedef enum { +<xsl:apply-templates select="tp:error" mode="enum"/>} TpError; + +G_END_DECLS +</xsl:template> + +</xsl:stylesheet> + +<!-- vim:set sw=2 sts=2 et noai noci: --> diff --git a/tools/glib-ginterface-gen.py b/tools/glib-ginterface-gen.py new file mode 100644 index 00000000..36f3242b --- /dev/null +++ b/tools/glib-ginterface-gen.py @@ -0,0 +1,711 @@ +#!/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, \ + camelcase_to_lower, 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.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)) + 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('{') + 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(' 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(' 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('}') + + 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) + + 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 = camelcase_to_lower(method.getAttribute('name')) + + 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 = camelcase_to_lower(dbus_method_name) + 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 = camelcase_to_lower(dbus_method_name) + # 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') + stub_name = (self.prefix_ + self.node_name_lc + '_emit_' + + camelcase_to_lower(dbus_name)) + 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('') + + in_base_init.append(' %s_signals[%s] =' + % (self.node_name_lc, const_name)) + in_base_init.append(' g_signal_new ("%s",' + % (dbus_gutils_wincaps_to_uscore(dbus_name).replace('_', '-'))) + 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 __call__(self): + self.h('#include <glib-object.h>') + self.h('#include <dbus/dbus-glib.h>') + self.h('#include <telepathy-glib/dbus-properties-mixin.h>') + self.h('') + self.h('G_BEGIN_DECLS') + self.h('') + + self.b('#include "%s.h"' % basename) + self.b('') + for header in self.headers: + self.b('#include %s' % header) + self.b('') + + nodes = self.dom.getElementsByTagName('node') + nodes.sort(cmp_by_name) + + 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(basename + '.h', 'w').write('\n'.join(self.__header)) + open(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 00000000..fcb46e84 --- /dev/null +++ b/tools/glib-gtypes-generator.py @@ -0,0 +1,230 @@ +#!/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') + + self.need_mappings = {} + self.need_structs = {} + self.need_arrays = {} + + 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.header.write('/**\n * %s:\n *\n' % name) + self.header.write(' * %s\n' % xml_escape(docstring)) + self.header.write(' *\n') + self.header.write(' * This macro expands to a call to a function\n') + self.header.write(' * that returns the #GType of a #GHashTable\n') + self.header.write(' * appropriate for representing a D-Bus\n') + self.header.write(' * dictionary of signature\n') + self.header.write(' * <literal>a{%s}</literal>.\n' % impl_sig) + self.header.write(' *\n') + + key, value = members + + self.header.write(' * Keys (D-Bus type <literal>%s</literal>,\n' + % key.getAttribute('type')) + tp_type = key.getAttributeNS(NS_TP, 'type') + if tp_type: + self.header.write(' * type <literal>%s</literal>,\n' % tp_type) + self.header.write(' * named <literal>%s</literal>):\n' + % key.getAttribute('name')) + docstring = get_docstring(key) or '(Undocumented)' + self.header.write(' * %s\n' % xml_escape(docstring)) + self.header.write(' *\n') + + self.header.write(' * Values (D-Bus type <literal>%s</literal>,\n' + % value.getAttribute('type')) + tp_type = value.getAttributeNS(NS_TP, 'type') + if tp_type: + self.header.write(' * type <literal>%s</literal>,\n' % tp_type) + self.header.write(' * named <literal>%s</literal>):\n' + % value.getAttribute('name')) + docstring = get_docstring(value) or '(Undocumented)' + self.header.write(' * %s\n' % xml_escape(docstring)) + self.header.write(' *\n') + + self.header.write(' */\n') + + self.header.write('#define %s (%s ())\n\n' % (name, impl)) + self.need_mappings[impl_sig] = esc_impl_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.header.write('/**\n * %s:\n\n' % name) + self.header.write(' * %s\n' % xml_escape(docstring)) + self.header.write(' *\n') + self.header.write(' * This macro expands to a call to a function\n') + self.header.write(' * that returns the #GType of a #GValueArray\n') + self.header.write(' * appropriate for representing a D-Bus struct\n') + self.header.write(' * with signature <literal>(%s)</literal>.\n' + % impl_sig) + self.header.write(' *\n') + + for i, member in enumerate(members): + self.header.write(' * Member %d (D-Bus type ' + '<literal>%s</literal>,\n' + % (i, member.getAttribute('type'))) + tp_type = member.getAttributeNS(NS_TP, 'type') + if tp_type: + self.header.write(' * type <literal>%s</literal>,\n' % tp_type) + self.header.write(' * named <literal>%s</literal>):\n' + % member.getAttribute('name')) + docstring = get_docstring(member) or '(Undocumented)' + self.header.write(' * %s\n' % xml_escape(docstring)) + self.header.write(' *\n') + + self.header.write(' */\n') + self.header.write('#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.header.write('/**\n * %s:\n\n' % array_name) + self.header.write(' * Expands to a call to a function\n') + self.header.write(' * that returns the #GType of a #GPtrArray\n') + self.header.write(' * of #%s.\n' % name) + self.header.write(' */\n') + self.header.write('#define %s (%s ())\n\n' % (array_name, impl)) + self.need_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.header.write('GType %stype_dbus_hash_%s (void);\n\n' % + (self.prefix_, self.need_mappings[sig])) + self.body.write('GType\n%stype_dbus_hash_%s (void)\n{\n' % + (self.prefix_, self.need_mappings[sig])) + self.body.write(' static GType t = 0;\n\n') + self.body.write(' if (G_UNLIKELY (t == 0))\n') + # FIXME: translate sig into two GTypes + items = tuple(Signature(sig)) + gtypes = types_to_gtypes(items) + self.body.write(' t = dbus_g_type_get_map ("GHashTable", ' + '%s, %s);\n' % (gtypes[0], gtypes[1])) + self.body.write(' return t;\n') + self.body.write('}\n\n') + + for struct in structs: + self.do_struct_header(struct) + + for sig in self.need_structs: + self.header.write('GType %stype_dbus_struct_%s (void);\n\n' % + (self.prefix_, self.need_structs[sig])) + self.body.write('GType\n%stype_dbus_struct_%s (void)\n{\n' % + (self.prefix_, self.need_structs[sig])) + self.body.write(' static GType t = 0;\n\n') + self.body.write(' if (G_UNLIKELY (t == 0))\n') + self.body.write(' t = dbus_g_type_get_struct ("GValueArray",\n') + items = tuple(Signature(sig)) + gtypes = types_to_gtypes(items) + for gtype in gtypes: + self.body.write(' %s,\n' % gtype) + self.body.write(' G_TYPE_INVALID);\n') + self.body.write(' return t;\n') + self.body.write('}\n\n') + + for sig in self.need_arrays: + self.header.write('GType %stype_dbus_array_%s (void);\n\n' % + (self.prefix_, self.need_structs[sig])) + self.body.write('GType\n%stype_dbus_array_%s (void)\n{\n' % + (self.prefix_, self.need_structs[sig])) + self.body.write(' static GType t = 0;\n\n') + self.body.write(' if (G_UNLIKELY (t == 0))\n') + self.body.write(' t = dbus_g_type_get_collection ("GPtrArray", ' + '%stype_dbus_struct_%s ());\n' % + (self.prefix_, self.need_structs[sig])) + self.body.write(' return t;\n') + self.body.write('}\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-body-generator.xsl b/tools/glib-interfaces-body-generator.xsl new file mode 100644 index 00000000..caff8917 --- /dev/null +++ b/tools/glib-interfaces-body-generator.xsl @@ -0,0 +1,47 @@ +<!-- Stylesheet to extract C interface names from the Telepathy spec. +The master copy of this stylesheet is in telepathy-glib - 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 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:import href="c-interfaces-generator.xsl"/> + + <xsl:template match="interface"> + <xsl:text>GQuark </xsl:text> + <xsl:value-of select="$prefix"/> + <xsl:text>_iface_quark_</xsl:text> + <xsl:value-of select="translate(../@name, concat($upper, '/'), $lower)"/> + <xsl:text> (void) { </xsl:text> + <xsl:text> static GQuark quark = 0; </xsl:text> + <xsl:text> if (G_UNLIKELY (quark == 0)) </xsl:text> + <xsl:text> { </xsl:text> + <xsl:text> quark = g_quark_from_static_string ("</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>"); </xsl:text> + <xsl:text> } </xsl:text> + <xsl:text> return quark; </xsl:text> + <xsl:text>} </xsl:text> + </xsl:template> + +</xsl:stylesheet> + +<!-- vim:set sw=2 sts=2 et noai noci: --> diff --git a/tools/glib-interfaces-generator.xsl b/tools/glib-interfaces-generator.xsl new file mode 100644 index 00000000..e703c407 --- /dev/null +++ b/tools/glib-interfaces-generator.xsl @@ -0,0 +1,55 @@ +<!-- Stylesheet to extract C interface names from the Telepathy spec. +The master copy of this stylesheet is in telepathy-glib - 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 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:import href="c-interfaces-generator.xsl"/> + + <xsl:template match="interface"> + <xsl:apply-imports/> + + <xsl:text>/** * </xsl:text> + <xsl:value-of select="$PREFIX"/> + <xsl:text>_IFACE_QUARK_</xsl:text> + <xsl:value-of select="translate(../@name, concat($lower, '/'), $upper)"/> + <xsl:text>: * * Expands to a call to a function that </xsl:text> + <xsl:text>returns a quark for the interface name "</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>" */ #define </xsl:text> + <xsl:value-of select="$PREFIX"/> + <xsl:text>_IFACE_QUARK_</xsl:text> + <xsl:value-of select="translate(../@name, concat($lower, '/'), $upper)"/> + <xsl:text> \ (</xsl:text> + <xsl:value-of select="$prefix"/> + <xsl:text>_iface_quark_</xsl:text> + <xsl:value-of select="translate(../@name, concat($upper, '/'), $lower)"/> + <xsl:text> ()) GQuark </xsl:text> + <xsl:value-of select="$prefix"/> + <xsl:text>_iface_quark_</xsl:text> + <xsl:value-of select="translate(../@name, concat($upper, '/'), $lower)"/> + <xsl:text> (void); </xsl:text> + </xsl:template> + +</xsl:stylesheet> + +<!-- vim:set sw=2 sts=2 et noai noci: --> diff --git a/tools/glib-signals-marshal-gen.py b/tools/glib-signals-marshal-gen.py new file mode 100644 index 00000000..0d02c134 --- /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 00000000..6630f84d --- /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/libglibcodegen.py b/tools/libglibcodegen.py new file mode 100644 index 00000000..d465b740 --- /dev/null +++ b/tools/libglibcodegen.py @@ -0,0 +1,320 @@ +"""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, 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 + + +from string import ascii_letters, digits + + +NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" + +_ASCII_ALNUM = ascii_letters + digits + + +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() + + +def cmp_by_name(node1, node2): + return cmp(node1.getAttributeNode("name").nodeValue, + node2.getAttributeNode("name").nodeValue) + + +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 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_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 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 + + +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 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_TYPE_G_OBJECT_ARRAY", "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 + + +def xml_escape(s): + s = s.replace('&', '&').replace("'", ''').replace('"', '"') + return s.replace('<', '<').replace('>', '>') diff --git a/tools/ls-interfaces.xsl b/tools/ls-interfaces.xsl new file mode 100644 index 00000000..22c4ff5e --- /dev/null +++ b/tools/ls-interfaces.xsl @@ -0,0 +1,35 @@ +<!-- +Extract a space-separated list of interface classnames from the Telepathy spec. +The master copy of this stylesheet is in the Telepathy spec 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 +--> + +<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 00000000..634ee3ca --- /dev/null +++ b/tools/make-all-async.xsl @@ -0,0 +1,43 @@ +<!-- Alter a D-Bus introspection XML file to add the DBus.GLib.Async annotation +to all methods. +The master copy of this stylesheet 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 +--> +<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 00000000..980604ac --- /dev/null +++ b/tools/spec-to-introspect.xsl @@ -0,0 +1,51 @@ +<!-- Remove Telepathy extensions from a D-Bus interface, trying to leave only +DTD-compliant introspection XML. The output still needs to be subjected to the +following sed filter: +sed -e 's@xmlns:tp="http://telepathy\.freedesktop\.org/wiki/DbusSpec.extensions-v0"@@g' + +The master copy of this stylesheet is in the Telepathy spec 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 +--> + +<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 00000000..35fc16c0 --- /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="tools" +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 \\\\\\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" |