diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2008-06-09 12:45:32 +0000 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2008-06-09 12:45:32 +0000 |
commit | f7aea199419923d99b87980ccac31731805985a4 (patch) | |
tree | a52534e12c7dddee5b1f34fd3af14f3e3e4062a3 /tools | |
parent | c168c97a76f932276715dd301f36ccf6127e87e7 (diff) |
Update libglibcodegen.py from telepathy-glib; add libtpcodegen (new dependency) and glib-gtypes-generator.py
Diffstat (limited to 'tools')
-rw-r--r-- | tools/Makefile.am | 11 | ||||
-rw-r--r-- | tools/glib-gtypes-generator.py | 230 | ||||
-rw-r--r-- | tools/libglibcodegen.py | 171 | ||||
-rw-r--r-- | tools/libtpcodegen.py | 194 |
4 files changed, 445 insertions, 161 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am index fb1b130b6..b79f466fc 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 000000000..fcb46e841 --- /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 d465b7406..6a725c052 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('&', '&').replace("'", ''').replace('"', '"') - return s.replace('<', '<').replace('>', '>') diff --git a/tools/libtpcodegen.py b/tools/libtpcodegen.py new file mode 100644 index 000000000..e7527c8a9 --- /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('&', '&').replace("'", ''').replace('"', '"') + return s.replace('<', '<').replace('>', '>') |