[Telepathy-commits] [telepathy-gabble/master] Update libglibcodegen.py from telepathy-glib; add libtpcodegen (new dependency) and glib-gtypes-generator.py

Simon McVittie simon.mcvittie at collabora.co.uk
Tue Aug 19 10:53:08 PDT 2008


20080609124532-53eee-dc3c7a9e80b283f3710ec33984369af99f7a4a27.gz
---
 tools/Makefile.am              |   11 ++
 tools/glib-gtypes-generator.py |  230 ++++++++++++++++++++++++++++++++++++++++
 tools/libglibcodegen.py        |  171 ++----------------------------
 tools/libtpcodegen.py          |  194 +++++++++++++++++++++++++++++++++
 4 files changed, 445 insertions(+), 161 deletions(-)
 create mode 100644 tools/glib-gtypes-generator.py
 create mode 100644 tools/libtpcodegen.py

diff --git a/tools/Makefile.am b/tools/Makefile.am
index fb1b130..b79f466 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -7,11 +7,22 @@ EXTRA_DIST = \
     check-whitespace.sh \
     doc-generator.xsl \
     glib-ginterface-gen.py \
+    glib-gtypes-generator.py \
     glib-signals-marshal-gen.py \
     identity.xsl \
     libglibcodegen.py \
+    libtpcodegen.py \
     xep.xsl
 
+libglibcodegen.py: libtpcodegen.py
+	test -e $@
+	touch $@
+
+glib-ginterface-gen.py glib-gtypes-generator.py glib-signals-marshal-gen.py: \
+		libglibcodegen.py
+	test -e $@
+	touch $@
+
 maintainer-update-from-xmpp.org:
 	set -e; \
 	uri=svn://svn.xmpp.org:7938/xmpp/trunk/extensions/xep.xsl; \
diff --git a/tools/glib-gtypes-generator.py b/tools/glib-gtypes-generator.py
new file mode 100644
index 0000000..fcb46e8
--- /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/libglibcodegen.py b/tools/libglibcodegen.py
index d465b74..6a725c0 100644
--- a/tools/libglibcodegen.py
+++ b/tools/libglibcodegen.py
@@ -4,7 +4,7 @@ The master copy of this library is in the telepathy-glib repository -
 please make any changes there.
 """
 
-# Copyright (C) 2006, 2007 Collabora Limited
+# 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
@@ -21,44 +21,15 @@ please make any changes there.
 # 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)
-
+from libtpcodegen import NS_TP, \
+                         Signature, \
+                         camelcase_to_lower, \
+                         camelcase_to_upper, \
+                         cmp_by_name, \
+                         escape_as_identifier, \
+                         get_descendant_text, \
+                         get_docstring, \
+                         xml_escape
 
 def dbus_gutils_wincaps_to_uscore(s):
     """Bug-for-bug compatible Python port of _dbus_gutils_wincaps_to_uscore
@@ -77,60 +48,6 @@ def dbus_gutils_wincaps_to_uscore(s):
     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.
@@ -183,69 +100,6 @@ def method_to_glue_marshal_name(method, prefix):
         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)
@@ -313,8 +167,3 @@ def type_to_gtype(s):
 
     # we just don't know ..
     raise Exception, "don't know the GType for " + s
-
-
-def xml_escape(s):
-    s = s.replace('&', '&amp;').replace("'", '&apos;').replace('"', '&quot;')
-    return s.replace('<', '&lt;').replace('>', '&gt;')
diff --git a/tools/libtpcodegen.py b/tools/libtpcodegen.py
new file mode 100644
index 0000000..e7527c8
--- /dev/null
+++ b/tools/libtpcodegen.py
@@ -0,0 +1,194 @@
+"""Library code for language-independent D-Bus-related code generation.
+
+The master copy of this library is in the telepathy-glib repository -
+please make any changes there.
+"""
+
+# Copyright (C) 2006-2008 Collabora Limited
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+from string import ascii_letters, digits
+
+
+NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+
+_ASCII_ALNUM = ascii_letters + digits
+
+
+def 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 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 get_descendant_text(element):
+    parts = []
+    for x in element.childNodes:
+        if x.nodeType == x.TEXT_NODE:
+            parts.append(x.nodeValue)
+        elif x.nodeType == x.ELEMENT_NODE:
+            parts.append(get_descendant_text(x))
+        else:
+            pass
+    return ''.join(parts)
+
+
+class _SignatureIter:
+    """Iterator over a D-Bus signature. Copied from dbus-python 0.71 so we
+    can run genginterface in a limited environment with only Python
+    (like Scratchbox).
+    """
+    def __init__(self, string):
+        self.remaining = string
+
+    def next(self):
+        if self.remaining == '':
+            raise StopIteration
+
+        signature = self.remaining
+        block_depth = 0
+        block_type = None
+        end = len(signature)
+
+        for marker in range(0, end):
+            cur_sig = signature[marker]
+
+            if cur_sig == 'a':
+                pass
+            elif cur_sig == '{' or cur_sig == '(':
+                if block_type == None:
+                    block_type = cur_sig
+
+                if block_type == cur_sig:
+                    block_depth = block_depth + 1
+
+            elif cur_sig == '}':
+                if block_type == '{':
+                    block_depth = block_depth - 1
+
+                if block_depth == 0:
+                    end = marker
+                    break
+
+            elif cur_sig == ')':
+                if block_type == '(':
+                    block_depth = block_depth - 1
+
+                if block_depth == 0:
+                    end = marker
+                    break
+
+            else:
+                if block_depth == 0:
+                    end = marker
+                    break
+
+        end = end + 1
+        self.remaining = signature[end:]
+        return Signature(signature[0:end])
+
+
+class Signature(str):
+    """A string, iteration over which is by D-Bus single complete types
+    rather than characters.
+    """
+    def __iter__(self):
+        return _SignatureIter(self)
+
+
+def xml_escape(s):
+    s = s.replace('&', '&amp;').replace("'", '&apos;').replace('"', '&quot;')
+    return s.replace('<', '&lt;').replace('>', '&gt;')
-- 
1.5.6.3




More information about the Telepathy-commits mailing list