From 621bbbb8631f4b149d0478a3423687e4e973b04f Mon Sep 17 00:00:00 2001 From: Emilio Pozuelo Monfort Date: Tue, 1 Feb 2011 13:47:58 +0000 Subject: Update tools from telepathy-glib --- tools/Makefile.am | 14 +- tools/c-constants-gen.py | 84 +++++--- tools/check-coding-style.mk | 4 +- tools/git-which-branch.sh | 25 +++ tools/glib-client-gen.py | 283 +++++++++++++++---------- tools/glib-errors-check-gen.py | 58 ++++++ tools/glib-errors-enum-body-gen.py | 62 ------ tools/glib-errors-enum-header-gen.py | 75 ------- tools/glib-errors-str-gen.py | 82 ++++++++ tools/glib-ginterface-gen.py | 293 +++++++++++++++++--------- tools/glib-gtypes-generator.py | 214 ++++++++++++------- tools/glib-interfaces-gen.py | 138 +++++++++++-- tools/gobject-foo.py | 23 ++- tools/identity.xsl | 7 - tools/libglibcodegen.py | 5 +- tools/libtpcodegen.py | 36 +--- tools/make-release-mail.py | 76 +++++++ tools/manager-file.py | 175 ++++++++++++++++ tools/shave.mk | 1 + tools/telepathy-glib.supp | 390 +++++++++++++++++++++++++++++++++++ tools/test-wrapper.sh | 30 +++ tools/valgrind.mk | 13 ++ tools/with-session-bus.sh | 10 +- tools/xincludator.py | 39 ++++ 24 files changed, 1618 insertions(+), 519 deletions(-) create mode 100644 tools/git-which-branch.sh create mode 100644 tools/glib-errors-check-gen.py delete mode 100644 tools/glib-errors-enum-body-gen.py delete mode 100644 tools/glib-errors-enum-header-gen.py create mode 100644 tools/glib-errors-str-gen.py delete mode 100644 tools/identity.xsl create mode 100644 tools/make-release-mail.py create mode 100644 tools/manager-file.py create mode 100644 tools/shave.mk create mode 100644 tools/telepathy-glib.supp create mode 100755 tools/test-wrapper.sh create mode 100644 tools/valgrind.mk create mode 100644 tools/xincludator.py (limited to 'tools') diff --git a/tools/Makefile.am b/tools/Makefile.am index c9ac350e..96cc60f5 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -14,23 +14,29 @@ EXTRA_DIST = \ check-whitespace.sh \ doc-generator.xsl \ flymake.mk \ + git-which-branch.sh \ glib-client-gen.py \ glib-client-marshaller-gen.py \ - glib-errors-enum-body-gen.py \ - glib-errors-enum-header-gen.py \ + glib-errors-check-gen.py \ + glib-errors-str-gen.py \ glib-ginterface-gen.py \ glib-gtypes-generator.py \ glib-interfaces-gen.py \ glib-signals-marshal-gen.py \ gobject-foo.py \ - identity.xsl \ lcov.am \ libtpcodegen.py \ libglibcodegen.py \ + make-release-mail.py \ make-version-script.py \ + manager-file.py \ + shave.mk \ telepathy.am \ + telepathy-glib.supp \ telepathy-glib-env.in \ - with-session-bus.sh + test-wrapper.sh \ + with-session-bus.sh \ + xincludator.py CLEANFILES = libtpcodegen.pyc libtpcodegen.pyo libglibcodegen.pyc libglibcodegen.pyo $(noinst_SCRIPTS) diff --git a/tools/c-constants-gen.py b/tools/c-constants-gen.py index f338257a..188ab82a 100644 --- a/tools/c-constants-gen.py +++ b/tools/c-constants-gen.py @@ -3,34 +3,43 @@ from sys import argv, stdout, stderr import xml.dom.minidom -from libglibcodegen import NS_TP, camelcase_to_upper, get_docstring, \ +from libglibcodegen import NS_TP, get_docstring, \ get_descendant_text, get_by_path class Generator(object): - def __init__(self, prefix, dom): + def __init__(self, prefix, dom, output_base): self.prefix = prefix + '_' self.spec = get_by_path(dom, "spec")[0] + self.__header = open(output_base + '.h', 'w') + self.__docs = open(output_base + '-gtk-doc.h', 'w') + def __call__(self): self.do_header() self.do_body() self.do_footer() + def write(self, code): + self.__header.write(code.encode('utf-8')) + + def d(self, code): + self.__docs.write(code.encode('utf-8')) + # Header def do_header(self): - stdout.write('/* Generated from ') - stdout.write(get_descendant_text(get_by_path(self.spec, 'title'))) + self.write('/* Generated from ') + self.write(get_descendant_text(get_by_path(self.spec, 'title'))) version = get_by_path(self.spec, "version") if version: - stdout.write(', version ' + get_descendant_text(version)) - stdout.write('\n\n') + self.write(', version ' + get_descendant_text(version)) + self.write('\n\n') for copyright in get_by_path(self.spec, 'copyright'): - stdout.write(get_descendant_text(copyright)) - stdout.write('\n') - stdout.write(get_descendant_text(get_by_path(self.spec, 'license'))) - stdout.write('\n') - stdout.write(get_descendant_text(get_by_path(self.spec, 'docstring'))) - stdout.write(""" + self.write(get_descendant_text(copyright)) + self.write('\n') + self.write(get_descendant_text(get_by_path(self.spec, 'license'))) + self.write('\n') + self.write(get_descendant_text(get_by_path(self.spec, 'docstring'))) + self.write(""" */ #ifdef __cplusplus @@ -51,28 +60,30 @@ extern "C" { value_prefix = flags.getAttribute('singular') or \ flags.getAttribute('value-prefix') or \ flags.getAttribute('name') - stdout.write("""\ + self.d("""\ /** * %s: """ % (self.prefix + name).replace('_', '')) for flag in get_by_path(flags, 'flag'): self.do_gtkdoc(flag, value_prefix) - stdout.write(' *\n') + self.d(' *\n') docstrings = get_by_path(flags, 'docstring') if docstrings: - stdout.write("""\ + self.d("""\ * * """ % get_descendant_text(docstrings).replace('\n', ' ')) - stdout.write("""\ + self.d("""\ * Bitfield/set of flags generated from the Telepathy specification. */ -typedef enum { """) + + self.write("typedef enum /*< flags >*/ {\n") + for flag in get_by_path(flags, 'flag'): self.do_val(flag, value_prefix) - stdout.write("""\ + self.write("""\ } %s; """ % (self.prefix + name).replace('_', '')) @@ -84,7 +95,7 @@ typedef enum { enum.getAttribute('name') name_plural = enum.getAttribute('plural') or \ enum.getAttribute('name') + 's' - stdout.write("""\ + self.d("""\ /** * %s: @@ -92,28 +103,35 @@ typedef enum { vals = get_by_path(enum, 'enumvalue') for val in vals: self.do_gtkdoc(val, value_prefix) - stdout.write(' *\n') + self.d(' *\n') docstrings = get_by_path(enum, 'docstring') if docstrings: - stdout.write("""\ + self.d("""\ * * """ % get_descendant_text(docstrings).replace('\n', ' ')) - stdout.write("""\ + self.d("""\ * Bitfield/set of flags generated from the Telepathy specification. */ -typedef enum { """) + + self.write("typedef enum {\n") + for val in vals: self.do_val(val, value_prefix) - stdout.write("""\ -} %(mixed-name)s; + self.write("} %s;\n" % (self.prefix + name).replace('_', '')) + self.d("""\ /** * NUM_%(upper-plural)s: * * 1 higher than the highest valid value of #%(mixed-name)s. */ +""" % {'mixed-name' : (self.prefix + name).replace('_', ''), + 'upper-plural' : (self.prefix + name_plural).upper(), + 'last-val' : vals[-1].getAttribute('value')}) + + self.write("""\ #define NUM_%(upper-plural)s (%(last-val)s+1) """ % {'mixed-name' : (self.prefix + name).replace('_', ''), @@ -127,20 +145,20 @@ typedef enum { (suffix or name)).upper() assert not (name and suffix) or name == suffix, \ 'Flag/enumvalue name %s != suffix %s' % (name, suffix) - stdout.write(' %s = %s,\n' % (use_name, val.getAttribute('value'))) + self.write(' %s = %s,\n' % (use_name, val.getAttribute('value'))) def do_gtkdoc(self, node, value_prefix): - stdout.write(' * @') - stdout.write((self.prefix + value_prefix + '_' + + self.d(' * @') + self.d((self.prefix + value_prefix + '_' + node.getAttribute('suffix')).upper()) - stdout.write(': \n') + self.d(get_descendant_text(docstring).replace('\n', ' ')) + self.d(']]>\n') # Footer def do_footer(self): - stdout.write(""" + self.write(""" #ifdef __cplusplus } #endif @@ -148,4 +166,4 @@ typedef enum { if __name__ == '__main__': argv = argv[1:] - Generator(argv[0], xml.dom.minidom.parse(argv[1]))() + Generator(argv[0], xml.dom.minidom.parse(argv[1]), argv[2])() diff --git a/tools/check-coding-style.mk b/tools/check-coding-style.mk index 3fc92fc8..1c0a60f6 100644 --- a/tools/check-coding-style.mk +++ b/tools/check-coding-style.mk @@ -3,12 +3,12 @@ check-coding-style: if test -n "$(check_misc_sources)"; then \ tools_dir=$(top_srcdir)/tools \ sh $(top_srcdir)/tools/check-misc.sh \ - $(check_misc_sources) || fail=1; \ + $(addprefix $(srcdir)/,$(check_misc_sources)) || fail=1; \ fi; \ if test -n "$(check_c_sources)"; then \ tools_dir=$(top_srcdir)/tools \ sh $(top_srcdir)/tools/check-c-style.sh \ - $(check_c_sources) || fail=1; \ + $(addprefix $(srcdir)/,$(check_c_sources)) || fail=1; \ fi;\ if test yes = "$(ENABLE_CODING_STYLE_CHECKS)"; then \ exit "$$fail";\ diff --git a/tools/git-which-branch.sh b/tools/git-which-branch.sh new file mode 100644 index 00000000..b96b5d5e --- /dev/null +++ b/tools/git-which-branch.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# git-which-branch.sh - output the name of the current git branch +# +# The canonical location of this program is the telepathy-spec tools/ +# directory, please synchronize any changes with that copy. +# +# Copyright (C) 2008 Collabora Ltd. +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. + +default="$1" +if { ref="`git symbolic-ref HEAD 2>/dev/null`"; }; then + echo ${ref#refs/heads/} + exit 0 +fi + +if test -n "$default"; then + echo "$default" >/dev/null + exit 0 +fi + +echo "no git branch found" >&2 +exit 1 diff --git a/tools/glib-client-gen.py b/tools/glib-client-gen.py index 701fcafe..6b0bdeba 100644 --- a/tools/glib-client-gen.py +++ b/tools/glib-client-gen.py @@ -28,7 +28,7 @@ import xml.dom.minidom from getopt import gnu_getopt from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \ - camelcase_to_lower, get_docstring, xml_escape + get_docstring, xml_escape, get_deprecated NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" @@ -39,6 +39,7 @@ class Generator(object): self.dom = dom self.__header = [] self.__body = [] + self.__docs = [] self.prefix_lc = prefix.lower() self.prefix_uc = prefix.upper() @@ -55,6 +56,11 @@ class Generator(object): % opts.get('--subclass', 'TpProxy')) if self.proxy_arg == 'void *': self.proxy_arg = 'gpointer ' + self.generate_reentrant = ('--generate-reentrant' in opts or + '--deprecate-reentrant' in opts) + self.deprecate_reentrant = opts.get('--deprecate-reentrant', None) + self.deprecation_attribute = opts.get('--deprecation-attribute', + 'G_GNUC_DEPRECATED') def h(self, s): if isinstance(s, unicode): @@ -66,6 +72,11 @@ class Generator(object): s = s.encode('utf-8') self.__body.append(s) + def d(self, s): + if isinstance(s, unicode): + s = s.encode('utf-8') + self.__docs.append(s) + def get_iface_quark(self): assert self.iface_dbus is not None assert self.iface_uc is not None @@ -78,7 +89,11 @@ class Generator(object): iface_lc = iface.lower() member = signal.getAttribute('name') - member_lc = camelcase_to_lower(member) + member_lc = signal.getAttribute('tp:name-for-bindings') + if member != member_lc.replace('_', ''): + raise AssertionError('Signal %s tp:name-for-bindings (%s) does ' + 'not match' % (member, member_lc)) + member_lc = member_lc.lower() member_uc = member_lc.upper() arg_count = 0 @@ -114,25 +129,27 @@ class Generator(object): # guint arg_handle, gboolean arg_suppress_handler, # gpointer user_data, GObject *weak_object); - self.b('/**') - self.b(' * %s:' % callback_name) - self.b(' * @proxy: The proxy on which %s_%s_connect_to_%s ()' + self.d('/**') + self.d(' * %s:' % callback_name) + self.d(' * @proxy: The proxy on which %s_%s_connect_to_%s ()' % (self.prefix_lc, iface_lc, member_lc)) - self.b(' * was called') + self.d(' * was called') for arg in args: name, info, tp_type, elt = arg ctype, gtype, marshaller, pointer = info - self.b(' * @%s: %s' % (name, + self.d(' * @%s: %s' % (name, xml_escape(get_docstring(elt) or '(Undocumented)'))) - self.b(' * @user_data: User-supplied data') - self.b(' * @weak_object: User-supplied weakly referenced object') - self.b(' *') - self.b(' * Represents the signature of a callback for the signal %s.' + self.d(' * @user_data: User-supplied data') + self.d(' * @weak_object: User-supplied weakly referenced object') + self.d(' *') + self.d(' * Represents the signature of a callback for the signal %s.' % member) - self.b(' */') + self.d(' */') + self.d('') + self.h('typedef void (*%s) (%sproxy,' % (callback_name, self.proxy_cls)) @@ -281,31 +298,33 @@ class Generator(object): # emitted the 'invalidated' signal, or because the weakly referenced # object has gone away. - self.b('/**') - self.b(' * %s_%s_connect_to_%s:' + self.d('/**') + self.d(' * %s_%s_connect_to_%s:' % (self.prefix_lc, iface_lc, member_lc)) - self.b(' * @proxy: %s' % self.proxy_doc) - self.b(' * @callback: Callback to be called when the signal is') - self.b(' * received') - self.b(' * @user_data: User-supplied data for the callback') - self.b(' * @destroy: Destructor for the user-supplied data, which') - self.b(' * will be called when this signal is disconnected, or') - self.b(' * before this function returns %NULL') - self.b(' * @weak_object: A #GObject which will be weakly referenced; ') - self.b(' * if it is destroyed, this callback will automatically be') - self.b(' * disconnected') - self.b(' * @error: If not %NULL, used to raise an error if %NULL is') - self.b(' * returned') - self.b(' *') - self.b(' * Connect a handler to the signal %s.' % member) - self.b(' *') - self.b(' * %s' % xml_escape(get_docstring(signal) or '(Undocumented)')) - self.b(' *') - self.b(' * Returns: a #TpProxySignalConnection containing all of the') - self.b(' * above, which can be used to disconnect the signal; or') - self.b(' * %NULL if the proxy does not have the desired interface') - self.b(' * or has become invalid.') - self.b(' */') + self.d(' * @proxy: %s' % self.proxy_doc) + self.d(' * @callback: Callback to be called when the signal is') + self.d(' * received') + self.d(' * @user_data: User-supplied data for the callback') + self.d(' * @destroy: Destructor for the user-supplied data, which') + self.d(' * will be called when this signal is disconnected, or') + self.d(' * before this function returns %NULL') + self.d(' * @weak_object: A #GObject which will be weakly referenced; ') + self.d(' * if it is destroyed, this callback will automatically be') + self.d(' * disconnected') + self.d(' * @error: If not %NULL, used to raise an error if %NULL is') + self.d(' * returned') + self.d(' *') + self.d(' * Connect a handler to the signal %s.' % member) + self.d(' *') + self.d(' * %s' % xml_escape(get_docstring(signal) or '(Undocumented)')) + self.d(' *') + self.d(' * Returns: a #TpProxySignalConnection containing all of the') + self.d(' * above, which can be used to disconnect the signal; or') + self.d(' * %NULL if the proxy does not have the desired interface') + self.d(' * or has become invalid.') + self.d(' */') + self.d('') + self.h('TpProxySignalConnection *%s_%s_connect_to_%s (%sproxy,' % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg)) self.h(' %s callback,' % callback_name) @@ -313,6 +332,7 @@ class Generator(object): self.h(' GDestroyNotify destroy,') self.h(' GObject *weak_object,') self.h(' GError **error);') + self.h('') self.b('TpProxySignalConnection *') self.b('%s_%s_connect_to_%s (%sproxy,' @@ -352,13 +372,15 @@ class Generator(object): self.b('}') self.b('') - self.h('') - def do_method(self, iface, method): iface_lc = iface.lower() member = method.getAttribute('name') - member_lc = camelcase_to_lower(member) + member_lc = method.getAttribute('tp:name-for-bindings') + if member != member_lc.replace('_', ''): + raise AssertionError('Method %s tp:name-for-bindings (%s) does ' + 'not match' % (member, member_lc)) + member_lc = member_lc.lower() member_uc = member_lc.upper() in_count = 0 @@ -401,27 +423,35 @@ class Generator(object): # gpointer user_data, # GObject *weak_object); - self.b('/**') - self.b(' * %s_%s_callback_for_%s:' + self.d('/**') + self.d(' * %s_%s_callback_for_%s:' % (self.prefix_lc, iface_lc, member_lc)) - self.b(' * @proxy: the proxy on which the call was made') + self.d(' * @proxy: the proxy on which the call was made') for arg in out_args: name, info, tp_type, elt = arg ctype, gtype, marshaller, pointer = info - self.b(' * @%s: Used to return an \'out\' argument if @error is ' + self.d(' * @%s: Used to return an \'out\' argument if @error is ' '%%NULL: %s' % (name, xml_escape(get_docstring(elt) or '(Undocumented)'))) - self.b(' * @error: %NULL on success, or an error on failure') - self.b(' * @user_data: user-supplied data') - self.b(' * @weak_object: user-supplied object') - self.b(' *') - self.b(' * Signature of the callback called when a %s method call' + self.d(' * @error: %NULL on success, or an error on failure') + self.d(' * @user_data: user-supplied data') + self.d(' * @weak_object: user-supplied object') + self.d(' *') + self.d(' * Signature of the callback called when a %s method call' % member) - self.b(' * succeeds or fails.') - self.b(' */') + self.d(' * succeeds or fails.') + + deprecated = method.getElementsByTagName('tp:deprecated') + if deprecated: + d = deprecated[0] + self.d(' *') + self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d))) + + self.d(' */') + self.d('') callback_name = '%s_%s_callback_for_%s' % (self.prefix_lc, iface_lc, member_lc) @@ -646,42 +676,51 @@ class Generator(object): % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg)) self.h(' gint timeout_ms,') - self.b('/**') - self.b(' * %s_%s_call_%s:' + self.d('/**') + self.d(' * %s_%s_call_%s:' % (self.prefix_lc, iface_lc, member_lc)) - self.b(' * @proxy: the #TpProxy') - self.b(' * @timeout_ms: the timeout in milliseconds, or -1 to use the') - self.b(' * default') + self.d(' * @proxy: the #TpProxy') + self.d(' * @timeout_ms: the timeout in milliseconds, or -1 to use the') + self.d(' * default') for arg in in_args: name, info, tp_type, elt = arg ctype, gtype, marshaller, pointer = info - self.b(' * @%s: Used to pass an \'in\' argument: %s' + self.d(' * @%s: Used to pass an \'in\' argument: %s' % (name, xml_escape(get_docstring(elt) or '(Undocumented)'))) - self.b(' * @callback: called when the method call succeeds or fails;') - self.b(' * may be %NULL to make a "fire and forget" call with no ') - self.b(' * reply tracking') - self.b(' * @user_data: user-supplied data passed to the callback;') - self.b(' * must be %NULL if @callback is %NULL') - self.b(' * @destroy: called with the user_data as argument, after the') - self.b(' * call has succeeded, failed or been cancelled;') - self.b(' * must be %NULL if @callback is %NULL') - self.b(' * @weak_object: If not %NULL, a #GObject which will be ') - self.b(' * weakly referenced; if it is destroyed, this call ') - self.b(' * will automatically be cancelled. Must be %NULL if ') - self.b(' * @callback is %NULL') - self.b(' *') - self.b(' * Start a %s method call.' % member) - self.b(' *') - self.b(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)')) - self.b(' *') - self.b(' * Returns: a #TpProxyPendingCall representing the call in') - self.b(' * progress. It is borrowed from the object, and will become') - self.b(' * invalid when the callback is called, the call is') - self.b(' * cancelled or the #TpProxy becomes invalid.') - self.b(' */') + self.d(' * @callback: called when the method call succeeds or fails;') + self.d(' * may be %NULL to make a "fire and forget" call with no ') + self.d(' * reply tracking') + self.d(' * @user_data: user-supplied data passed to the callback;') + self.d(' * must be %NULL if @callback is %NULL') + self.d(' * @destroy: called with the user_data as argument, after the') + self.d(' * call has succeeded, failed or been cancelled;') + self.d(' * must be %NULL if @callback is %NULL') + self.d(' * @weak_object: If not %NULL, a #GObject which will be ') + self.d(' * weakly referenced; if it is destroyed, this call ') + self.d(' * will automatically be cancelled. Must be %NULL if ') + self.d(' * @callback is %NULL') + self.d(' *') + self.d(' * Start a %s method call.' % member) + self.d(' *') + self.d(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)')) + self.d(' *') + self.d(' * Returns: a #TpProxyPendingCall representing the call in') + self.d(' * progress. It is borrowed from the object, and will become') + self.d(' * invalid when the callback is called, the call is') + self.d(' * cancelled or the #TpProxy becomes invalid.') + + deprecated = method.getElementsByTagName('tp:deprecated') + if deprecated: + d = deprecated[0] + self.d(' *') + self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d))) + + self.d(' */') + self.d('') + self.b('TpProxyPendingCall *\n%s_%s_call_%s (%sproxy,' % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg)) self.b(' gint timeout_ms,') @@ -793,6 +832,17 @@ class Generator(object): self.b('}') self.b('') + if self.generate_reentrant: + self.do_method_reentrant(method, iface_lc, member, member_lc, + in_args, out_args, collect_callback) + + # leave a gap for the end of the method + self.d('') + self.b('') + self.h('') + + def do_method_reentrant(self, method, iface_lc, member, member_lc, in_args, + out_args, collect_callback): # Reentrant blocking calls # Example: # gboolean tp_cli_properties_interface_run_get_properties @@ -877,48 +927,60 @@ class Generator(object): self.b('}') self.b('') + if self.deprecate_reentrant: + self.h('#ifndef %s' % self.deprecate_reentrant) + self.h('gboolean %s_%s_run_%s (%sproxy,' % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg)) self.h(' gint timeout_ms,') - self.b('/**') - self.b(' * %s_%s_run_%s:' % (self.prefix_lc, iface_lc, member_lc)) - self.b(' * @proxy: %s' % self.proxy_doc) - self.b(' * @timeout_ms: Timeout in milliseconds, or -1 for default') + self.d('/**') + self.d(' * %s_%s_run_%s:' % (self.prefix_lc, iface_lc, member_lc)) + self.d(' * @proxy: %s' % self.proxy_doc) + self.d(' * @timeout_ms: Timeout in milliseconds, or -1 for default') for arg in in_args: name, info, tp_type, elt = arg ctype, gtype, marshaller, pointer = info - self.b(' * @%s: Used to pass an \'in\' argument: %s' + self.d(' * @%s: Used to pass an \'in\' argument: %s' % (name, xml_escape(get_docstring(elt) or '(Undocumented)'))) for arg in out_args: name, info, tp_type, elt = arg ctype, gtype, marshaller, pointer = info - self.b(' * @%s: Used to return an \'out\' argument if %%TRUE is ' + self.d(' * @%s: Used to return an \'out\' argument if %%TRUE is ' 'returned: %s' % (name, xml_escape(get_docstring(elt) or '(Undocumented)'))) - self.b(' * @error: If not %NULL, used to return errors if %FALSE ') - self.b(' * is returned') - self.b(' * @loop: If not %NULL, set before re-entering ') - self.b(' * the main loop, to point to a #GMainLoop ') - self.b(' * which can be used to cancel this call with ') - self.b(' * g_main_loop_quit(), causing a return of ') - self.b(' * %FALSE with @error set to %TP_DBUS_ERROR_CANCELLED') - self.b(' *') - self.b(' * Call the method %s and run the main loop' % member) - self.b(' * until it returns. Before calling this method, you must') - self.b(' * add a reference to any borrowed objects you need to keep,') - self.b(' * and generally ensure that everything is in a consistent') - self.b(' * state.') - self.b(' *') - self.b(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)')) - self.b(' *') - self.b(' * Returns: TRUE on success, FALSE and sets @error on error') - self.b(' */') + self.d(' * @error: If not %NULL, used to return errors if %FALSE ') + self.d(' * is returned') + self.d(' * @loop: If not %NULL, set before re-entering ') + self.d(' * the main loop, to point to a #GMainLoop ') + self.d(' * which can be used to cancel this call with ') + self.d(' * g_main_loop_quit(), causing a return of ') + self.d(' * %FALSE with @error set to %TP_DBUS_ERROR_CANCELLED') + self.d(' *') + self.d(' * Call the method %s and run the main loop' % member) + self.d(' * until it returns. Before calling this method, you must') + self.d(' * add a reference to any borrowed objects you need to keep,') + self.d(' * and generally ensure that everything is in a consistent') + self.d(' * state.') + self.d(' *') + self.d(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)')) + self.d(' *') + self.d(' * Returns: TRUE on success, FALSE and sets @error on error') + + deprecated = method.getElementsByTagName('tp:deprecated') + if deprecated: + d = deprecated[0] + self.d(' *') + self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d))) + + self.d(' */') + self.d('') + self.b('gboolean\n%s_%s_run_%s (%sproxy,' % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg)) self.b(' gint timeout_ms,') @@ -940,7 +1002,13 @@ class Generator(object): self.b(' %s*%s,' % (ctype, name)) self.h(' GError **error,') - self.h(' GMainLoop **loop);') + + if self.deprecate_reentrant: + self.h(' GMainLoop **loop) %s;' % self.deprecation_attribute) + self.h('#endif /* not %s */' % self.deprecate_reentrant) + else: + self.h(' GMainLoop **loop);') + self.h('') self.b(' GError **error,') @@ -1012,10 +1080,6 @@ class Generator(object): self.b('}') self.b('') - # leave a gap for the end of the method - self.b('') - self.h('') - def do_signal_add(self, signal): marshaller_items = [] gtypes = [] @@ -1136,6 +1200,7 @@ class Generator(object): open(self.basename + '.h', 'w').write('\n'.join(self.__header)) open(self.basename + '-body.h', 'w').write('\n'.join(self.__body)) + open(self.basename + '-gtk-doc.h', 'w').write('\n'.join(self.__docs)) def types_to_gtypes(types): @@ -1145,7 +1210,9 @@ def types_to_gtypes(types): if __name__ == '__main__': options, argv = gnu_getopt(sys.argv[1:], '', ['group=', 'subclass=', 'subclass-assert=', - 'iface-quark-prefix=', 'tp-proxy-api=']) + 'iface-quark-prefix=', 'tp-proxy-api=', + 'generate-reentrant', 'deprecate-reentrant=', + 'deprecation-attribute=']) opts = {} diff --git a/tools/glib-errors-check-gen.py b/tools/glib-errors-check-gen.py new file mode 100644 index 00000000..553fc9ca --- /dev/null +++ b/tools/glib-errors-check-gen.py @@ -0,0 +1,58 @@ +#!/usr/bin/python + +import sys +import xml.dom.minidom + +from libglibcodegen import NS_TP, get_docstring, get_descendant_text + +class Generator(object): + def __init__(self, dom): + self.dom = dom + self.errors = self.dom.getElementsByTagNameNS(NS_TP, 'errors')[0] + + def __call__(self): + + print '{' + print ' GEnumClass *klass;' + print ' GEnumValue *value_by_name;' + print ' GEnumValue *value_by_nick;' + print '' + print ' g_type_init ();' + print ' klass = g_type_class_ref (TP_TYPE_ERROR);' + + for error in self.errors.getElementsByTagNameNS(NS_TP, 'error'): + ns = error.parentNode.getAttribute('namespace') + nick = error.getAttribute('name').replace(' ', '') + enum = ('TP_ERROR_' + + error.getAttribute('name').replace(' ', '_').replace('.', '_').upper()) + s = ('TP_ERROR_STR_' + + error.getAttribute('name').replace(' ', '_').replace('.', '_').upper()) + + print '' + print ' /* %s.%s */' % (ns, nick) + print (' value_by_name = g_enum_get_value_by_name (klass, "%s");' + % enum) + print (' value_by_nick = g_enum_get_value_by_nick (klass, "%s");' + % nick) + print (' g_assert (value_by_name != NULL);') + print (' g_assert (value_by_nick != NULL);') + print (' g_assert_cmpint (value_by_name->value, ==, %s);' + % enum) + print (' g_assert_cmpint (value_by_nick->value, ==, %s);' + % enum) + print (' g_assert_cmpstr (value_by_name->value_name, ==, "%s");' + % enum) + print (' g_assert_cmpstr (value_by_nick->value_name, ==, "%s");' + % enum) + print (' g_assert_cmpstr (value_by_name->value_nick, ==, "%s");' + % nick) + print (' g_assert_cmpstr (value_by_nick->value_nick, ==, "%s");' + % nick) + print (' g_assert_cmpstr (%s, ==, TP_ERROR_PREFIX ".%s");' + % (s, nick)) + + print '}' + +if __name__ == '__main__': + argv = sys.argv[1:] + Generator(xml.dom.minidom.parse(argv[0]))() diff --git a/tools/glib-errors-enum-body-gen.py b/tools/glib-errors-enum-body-gen.py deleted file mode 100644 index 44863ee4..00000000 --- a/tools/glib-errors-enum-body-gen.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/python - -import sys -import xml.dom.minidom - -from libglibcodegen import NS_TP, camelcase_to_upper, get_docstring, \ - get_descendant_text - -class Generator(object): - def __init__(self, dom): - self.dom = dom - self.errors = self.dom.getElementsByTagNameNS(NS_TP, 'errors')[0] - - def do_header(self): - print '/* Generated from the Telepathy spec\n' - copyrights = self.errors.getElementsByTagNameNS(NS_TP, 'copyright') - for copyright in copyrights: - print get_descendant_text(copyright) - license = self.errors.getElementsByTagNameNS(NS_TP, 'license')[0] - print '\n' + get_descendant_text(license) + '\n*/' - - def do_enum_values(self): - for error in self.errors.getElementsByTagNameNS(NS_TP, 'error'): - print '' - nick = error.getAttribute('name').replace(' ', '') - name = camelcase_to_upper(nick.replace('.', '')) - ns = error.parentNode.getAttribute('namespace') - enum = 'TP_ERROR_' + name - print ' /* ' + ns + '.' + name - print ' ' + get_docstring(error) - print ' */' - print ' { %s, "%s", "%s" },' % (enum, enum, nick) - - - def do_get_type(self): - print """ -#include <_gen/telepathy-errors.h> - -GType -tp_error_get_type (void) -{ - static GType etype = 0; - if (G_UNLIKELY (etype == 0)) - { - static const GEnumValue values[] = {""" - self.do_enum_values() - print """\ - }; - - etype = g_enum_register_static ("TpError", values); - } - return etype; -} -""" - - def __call__(self): - self.do_header() - self.do_get_type() - -if __name__ == '__main__': - argv = sys.argv[1:] - Generator(xml.dom.minidom.parse(argv[0]))() diff --git a/tools/glib-errors-enum-header-gen.py b/tools/glib-errors-enum-header-gen.py deleted file mode 100644 index 64939b41..00000000 --- a/tools/glib-errors-enum-header-gen.py +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/python - -import sys -import xml.dom.minidom - -from libglibcodegen import NS_TP, camelcase_to_upper, get_docstring, \ - get_descendant_text - -class Generator(object): - def __init__(self, dom): - self.dom = dom - self.errors = self.dom.getElementsByTagNameNS(NS_TP, 'errors')[0] - - def do_header(self): - print '/* Generated from the Telepathy spec\n' - copyrights = self.errors.getElementsByTagNameNS(NS_TP, 'copyright') - for copyright in copyrights: - print get_descendant_text(copyright) - license = self.errors.getElementsByTagNameNS(NS_TP, 'license')[0] - print '\n' + get_descendant_text(license) + '\n*/' - - def do_gtkdoc(self): - for error in self.errors.getElementsByTagNameNS(NS_TP, 'error'): - ns = error.parentNode.getAttribute('namespace') - nick = error.getAttribute('name').replace(' ', '') - enum = 'TP_ERROR_' + camelcase_to_upper(nick.replace('.', '')) - print ' * @' + enum + ': ' + ns + '.' + nick + ':' - print ' * ' + get_docstring(error) + ' ' - - def do_enumnames(self): - for error in self.errors.getElementsByTagNameNS(NS_TP, 'error'): - nick = error.getAttribute('name').replace(' ', '') - enum = 'TP_ERROR_' + camelcase_to_upper(nick.replace('.', '')) - print ' ' + enum + ',' - - def do_get_type(self): - print """ -#include - -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()) -""" - - def do_enum(self): - print """\ -/** - * TpError:""" - self.do_gtkdoc() - print """\ - * - * Enumerated type representing the Telepathy D-Bus errors. - */ -typedef enum {""" - self.do_enumnames() - print """\ -} TpError; - -G_END_DECLS""" - - def __call__(self): - self.do_header() - self.do_get_type() - self.do_enum() - -if __name__ == '__main__': - argv = sys.argv[1:] - Generator(xml.dom.minidom.parse(argv[0]))() diff --git a/tools/glib-errors-str-gen.py b/tools/glib-errors-str-gen.py new file mode 100644 index 00000000..a948a7ca --- /dev/null +++ b/tools/glib-errors-str-gen.py @@ -0,0 +1,82 @@ +#!/usr/bin/python + +import sys +import xml.dom.minidom + +from libglibcodegen import NS_TP, get_docstring, xml_escape + +class Generator(object): + def __init__(self, dom, basename): + self.dom = dom + self.errors = self.dom.getElementsByTagNameNS(NS_TP, 'errors')[0] + self.basename = basename + + self.__header = [] + self.__body = [] + self.__docs = [] + + def h(self, s): + if isinstance(s, unicode): + s = s.encode('utf-8') + self.__header.append(s) + + def b(self, s): + if isinstance(s, unicode): + s = s.encode('utf-8') + self.__body.append(s) + + def d(self, s): + if isinstance(s, unicode): + s = s.encode('utf-8') + self.__docs.append(s) + + def __call__(self): + errors = self.errors.getElementsByTagNameNS(NS_TP, 'error') + + self.b('#include ') + self.b('') + self.b('const gchar *') + self.b('tp_error_get_dbus_name (TpError error)') + self.b('{') + self.b(' switch (error)') + self.b(' {') + + for error in errors: + ns = error.parentNode.getAttribute('namespace') + nick = error.getAttribute('name').replace(' ', '') + uc_nick = error.getAttribute('name').replace(' ', '_').replace('.', '_').upper() + name = 'TP_ERROR_STR_' + uc_nick + error_name = '%s.%s' % (ns, nick) + + self.d('/**') + self.d(' * %s:' % name) + self.d(' *') + self.d(' * The D-Bus error name %s' % error_name) + self.d(' *') + self.d(' * %s' % xml_escape(get_docstring(error))) + self.d(' */') + self.d('') + + self.h('#define %s "%s"' % (name, error_name)) + + self.b(' case TP_ERROR_%s:' % uc_nick) + self.b(' return %s;' % name) + + self.b(' default:') + self.b(' g_return_val_if_reached (NULL);') + self.b(' }') + self.b('}') + + # make both files end with a newline + self.h('') + self.b('') + + open(self.basename + '.h', 'w').write('\n'.join(self.__header)) + open(self.basename + '.c', 'w').write('\n'.join(self.__body)) + open(self.basename + '-gtk-doc.h', 'w').write('\n'.join(self.__docs)) + +if __name__ == '__main__': + argv = sys.argv[1:] + basename = argv[0] + + Generator(xml.dom.minidom.parse(argv[1]), basename)() diff --git a/tools/glib-ginterface-gen.py b/tools/glib-ginterface-gen.py index 9eb7af5c..9dfdcc75 100644 --- a/tools/glib-ginterface-gen.py +++ b/tools/glib-ginterface-gen.py @@ -27,7 +27,7 @@ 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, \ + NS_TP, dbus_gutils_wincaps_to_uscore, \ signal_to_marshal_name, method_to_glue_marshal_name @@ -41,6 +41,7 @@ class Generator(object): self.dom = dom self.__header = [] self.__body = [] + self.__docs = [] assert prefix.endswith('_') assert not signal_marshal_prefix.endswith('_') @@ -66,6 +67,7 @@ class Generator(object): self.prefix_ = prefix.lower() self.PREFIX_ = prefix.upper() + self.basename = basename self.signal_marshal_prefix = signal_marshal_prefix self.headers = headers self.end_headers = end_headers @@ -73,11 +75,20 @@ class Generator(object): self.allow_havoc = allow_havoc def h(self, s): + if isinstance(s, unicode): + s = s.encode('utf-8') self.__header.append(s) def b(self, s): + if isinstance(s, unicode): + s = s.encode('utf-8') self.__body.append(s) + def d(self, s): + if isinstance(s, unicode): + s = s.encode('utf-8') + self.__docs.append(s) + def do_node(self, node): node_name = node.getAttribute('name').replace('/', '') node_name_mixed = self.node_name_mixed = node_name.replace('_', '') @@ -157,20 +168,55 @@ class Generator(object): 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 ' + self.d('/**') + self.d(' * %s%s:' % (self.Prefix, node_name_mixed)) + self.d(' *') + self.d(' * Dummy typedef representing any implementation of this ' 'interface.') - self.h(' */') + self.d(' */') + 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.d('/**') + self.d(' * %s%sClass:' % (self.Prefix, node_name_mixed)) + self.d(' *') + self.d(' * The class of %s%s.' % (self.Prefix, node_name_mixed)) + + if methods: + self.d(' *') + self.d(' * In a full implementation of this interface (i.e. all') + self.d(' * methods implemented), the interface initialization') + self.d(' * function used in G_IMPLEMENT_INTERFACE() would') + self.d(' * typically look like this:') + self.d(' *') + self.d(' * ') + self.d(' * static void') + self.d(' * implement_%s (gpointer klass,' % self.node_name_lc) + self.d(' * gpointer unused G_GNUC_UNUSED)') + self.d(' * {') + self.d(' * #define IMPLEMENT(x) %s%s_implement_##x (\\' + % (self.prefix_, self.node_name_lc)) + self.d(' * klass, my_object_##x)') + + for method in methods: + class_member_name = method.getAttribute('tp:name-for-bindings') + class_member_name = class_member_name.lower() + self.d(' * IMPLEMENT (%s);' % class_member_name) + + self.d(' * #undef IMPLEMENT') + self.d(' * }') + self.d(' * ') + else: + self.d(' * This interface has no D-Bus methods, so an') + self.d(' * implementation can typically pass %NULL to') + self.d(' * G_IMPLEMENT_INTERFACE() as the interface') + self.d(' * initialization function.') + + self.d(' */') + self.d('') + self.h('typedef struct _%s%sClass %s%sClass;' % (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed)) self.h('') @@ -207,48 +253,56 @@ class Generator(object): 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 properties: + self.b(' static TpDBusPropertiesMixinPropInfo properties[%d] = {' + % (len(properties) + 1)) - 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') + for m in properties: + access = m.getAttribute('access') + assert access in ('read', 'write', 'readwrite') - self.b(' { 0, %s, "%s", 0, NULL, NULL }, /* %s */' - % (flags, m.getAttribute('type'), m.getAttribute('name'))) + 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, 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) + self.b(' { 0, %s, "%s", 0, NULL, NULL }, /* %s */' + % (flags, m.getAttribute('type'), m.getAttribute('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(' { 0, 0, NULL, 0, NULL, NULL }') + self.b(' };') + self.b(' static TpDBusPropertiesMixinIfaceInfo interface =') + self.b(' { 0, properties, NULL, NULL };') + self.b('') - 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('') + + if properties: + self.b(' interface.dbus_interface = g_quark_from_static_string ' + '("%s");' % self.iface_name) + + for i, m in enumerate(properties): + self.b(' properties[%d].name = g_quark_from_static_string ("%s");' + % (i, m.getAttribute('name'))) + self.b(' properties[%d].type = %s;' + % (i, type_to_gtype(m.getAttribute('type'))[1])) + + self.b(' tp_svc_interface_set_dbus_properties_info (%s, &interface);' + % self.current_gtype) + + self.b('') + + for s in base_init_code: + self.b(s) self.b('}') self.b('static void') @@ -276,6 +330,10 @@ class Generator(object): for method, offset in zip(methods, offsets): self.do_method_glue(method, offset) + if len(methods) == 0: + # empty arrays are a gcc extension, so put in a dummy member + self.b(" { NULL, NULL, 0 }") + self.b('};') self.b('') @@ -335,7 +393,11 @@ class Generator(object): return ''.join(info) + '\0', offsets def do_method_glue(self, method, offset): - lc_name = camelcase_to_lower(method.getAttribute('name')) + lc_name = method.getAttribute('tp:name-for-bindings') + if method.getAttribute('name') != lc_name.replace('_', ''): + raise AssertionError('Method %s tp:name-for-bindings (%s) does ' + 'not match' % (method.getAttribute('name'), lc_name)) + lc_name = lc_name.lower() marshaller = method_to_glue_marshal_name(method, self.signal_marshal_prefix) @@ -357,10 +419,16 @@ class Generator(object): def get_method_impl_names(self, method): dbus_method_name = method.getAttribute('name') - class_member_name = camelcase_to_lower(dbus_method_name) + + class_member_name = method.getAttribute('tp:name-for-bindings') + if dbus_method_name != class_member_name.replace('_', ''): + raise AssertionError('Method %s tp:name-for-bindings (%s) does ' + 'not match' % (dbus_method_name, class_member_name)) + class_member_name = class_member_name.lower() + stub_name = (self.prefix_ + self.node_name_lc + '_' + class_member_name) - return (stub_name + '_impl', class_member_name) + return (stub_name + '_impl', class_member_name + '_cb') def do_method(self, method): assert self.node_name_mixed is not None @@ -372,7 +440,12 @@ class Generator(object): # DoStuff dbus_method_name = method.getAttribute('name') # do_stuff - class_member_name = camelcase_to_lower(dbus_method_name) + class_member_name = method.getAttribute('tp:name-for-bindings') + if dbus_method_name != class_member_name.replace('_', ''): + raise AssertionError('Method %s tp:name-for-bindings (%s) does ' + 'not match' % (dbus_method_name, class_member_name)) + class_member_name = class_member_name.lower() + # void tp_svc_thing_do_stuff (TpSvcThing *, const char *, guint, # DBusGMethodInvocation *); stub_name = (self.prefix_ + self.node_name_lc + '_' + @@ -414,18 +487,19 @@ class Generator(object): 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') + # Implementation type declaration (in header, docs separated) + self.d('/**') + self.d(' * %s:' % impl_name) + self.d(' * @self: The object implementing this interface') for (ctype, name) in in_args: - self.b(' * @%s: %s (FIXME, generate documentation)' + self.d(' * @%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.d(' * @context: Used to return values or throw an error') + self.d(' *') + self.d(' * The signature of an implementation of the D-Bus method') + self.d(' * %s on interface %s.' % (dbus_method_name, self.iface_name)) + self.d(' */') + self.h('typedef void (*%s) (%s%s *self,' % (impl_name, self.Prefix, self.node_name_mixed)) for (ctype, name) in in_args: @@ -443,7 +517,7 @@ class Generator(object): self.b(' %s%s,' % (ctype, name)) self.b(' DBusGMethodInvocation *context)') self.b('{') - self.b(' %s impl = (%s%s_GET_CLASS (self)->%s);' + self.b(' %s impl = (%s%s_GET_CLASS (self)->%s_cb);' % (impl_name, self.PREFIX_, self.node_name_uc, class_member_name)) self.b('') self.b(' if (impl != NULL)') @@ -470,38 +544,41 @@ class Generator(object): % (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.d('/**') + self.d(' * %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' + self.d(' * @klass: A class whose instances implement this interface') + self.d(' * @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' + self.d(' *') + self.d(' * 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.d(' * of an implementation of this interface. To be called from') + self.d(' * the interface init function.') + self.d(' */') + 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(' klass->%s_cb = 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') + self.d('/**') + self.d(' * %s:' % ret_name) + self.d(' * @context: The D-Bus method invocation context') for (ctype, name) in out_args: - self.h(' * @%s: %s (FIXME, generate documentation)' + self.d(' * @%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(' */') + self.d(' *') + self.d(' * Return successfully by calling dbus_g_method_return().') + self.d(' * This inline function exists only to provide type-safety.') + self.d(' */') + self.d('') + tmp = (['DBusGMethodInvocation *context'] + [ctype + name for (ctype, name) in out_args]) self.h('static inline') @@ -533,8 +610,15 @@ class Generator(object): # const char *arg0, guint arg1); dbus_name = signal.getAttribute('name') + + ugly_name = signal.getAttribute('tp:name-for-bindings') + if dbus_name != ugly_name.replace('_', ''): + raise AssertionError('Signal %s tp:name-for-bindings (%s) does ' + 'not match' % (dbus_name, ugly_name)) + stub_name = (self.prefix_ + self.node_name_lc + '_emit_' + - camelcase_to_lower(dbus_name)) + ugly_name.lower()) + const_name = self.get_signal_const_entry(signal) # Gather arguments @@ -564,17 +648,17 @@ class Generator(object): # FIXME: emit docs - self.b('/**') - self.b(' * %s:' % stub_name) - self.b(' * @instance: The object implementing this interface') + self.d('/**') + self.d(' * %s:' % stub_name) + self.d(' * @instance: The object implementing this interface') for (ctype, name, gtype) in args: - self.b(' * @%s: %s (FIXME, generate documentation)' + self.d(' * @%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.' + self.d(' *') + self.d(' * Type-safe wrapper around g_signal_emit to emit the') + self.d(' * %s signal on interface %s.' % (dbus_name, self.iface_name)) - self.b(' */') + self.d(' */') self.b('void') self.b(('%s (' % stub_name) + (',\n '.join(tmp)) + ')') @@ -590,16 +674,20 @@ class Generator(object): signal_name = dbus_gutils_wincaps_to_uscore(dbus_name).replace('_', '-') - in_base_init.append(' /**') - in_base_init.append(' * %s%s::%s:' + + self.d('/**') + self.d(' * %s%s::%s:' % (self.Prefix, self.node_name_mixed, signal_name)) + self.d(' * @self: an object') for (ctype, name, gtype) in args: - in_base_init.append(' * @%s: %s (FIXME, generate documentation)' + self.d(' * @%s: %s (FIXME, generate documentation)' % (name, ctype)) - in_base_init.append(' *') - in_base_init.append(' * The %s D-Bus signal is emitted whenever ' + self.d(' *') + self.d(' * The %s D-Bus signal is emitted whenever ' 'this GObject signal is.' % dbus_name) - in_base_init.append(' */') + self.d(' */') + self.d('') + in_base_init.append(' %s_signals[%s] =' % (self.node_name_lc, const_name)) in_base_init.append(' g_signal_new ("%s",' % signal_name) @@ -616,23 +704,33 @@ class Generator(object): return in_base_init + def have_properties(self, nodes): + for node in nodes: + interface = node.getElementsByTagName('interface')[0] + if interface.getElementsByTagName('property'): + return True + return False + def __call__(self): + nodes = self.dom.getElementsByTagName('node') + nodes.sort(cmp_by_name) + self.h('#include ') self.h('#include ') - self.h('#include ') + + if self.have_properties(nodes): + self.h('#include ') + self.h('') self.h('G_BEGIN_DECLS') self.h('') - self.b('#include "%s.h"' % basename) + self.b('#include "%s.h"' % self.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) @@ -645,8 +743,9 @@ class Generator(object): self.h('') self.b('') - open(basename + '.h', 'w').write('\n'.join(self.__header)) - open(basename + '.c', 'w').write('\n'.join(self.__body)) + open(self.basename + '.h', 'w').write('\n'.join(self.__header)) + open(self.basename + '.c', 'w').write('\n'.join(self.__body)) + open(self.basename + '-gtk-doc.h', 'w').write('\n'.join(self.__docs)) def cmdline_error(): diff --git a/tools/glib-gtypes-generator.py b/tools/glib-gtypes-generator.py index fcb46e84..a49c36e7 100644 --- a/tools/glib-gtypes-generator.py +++ b/tools/glib-gtypes-generator.py @@ -44,16 +44,35 @@ class GTypesGenerator(object): self.header = open(output + '.h', 'w') self.body = open(output + '-body.h', 'w') + self.docs = open(output + '-gtk-doc.h', 'w') - for f in (self.header, self.body): + for f in (self.header, self.body, self.docs): f.write('/* Auto-generated, do not edit.\n *\n' ' * This file may be distributed under the same terms\n' ' * as the specification from which it was generated.\n' ' */\n\n') + # keys are e.g. 'sv', values are the key escaped self.need_mappings = {} + # keys are the contents of the struct (e.g. 'sssu'), values are the + # key escaped self.need_structs = {} - self.need_arrays = {} + # keys are the contents of the struct (e.g. 'sssu'), values are the + # key escaped + self.need_struct_arrays = {} + + # keys are the contents of the array (unlike need_struct_arrays!), + # values are the key escaped + self.need_other_arrays = {} + + def h(self, code): + self.header.write(code.encode("utf-8")) + + def c(self, code): + self.body.write(code.encode("utf-8")) + + def d(self, code): + self.docs.write(code.encode('utf-8')) def do_mapping_header(self, mapping): members = mapping.getElementsByTagNameNS(NS_TP, 'member') @@ -70,45 +89,60 @@ class GTypesGenerator(object): 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(' * a{%s}.\n' % impl_sig) - self.header.write(' *\n') + self.d('/**\n * %s:\n *\n' % name) + self.d(' * %s\n' % xml_escape(docstring)) + self.d(' *\n') + self.d(' * This macro expands to a call to a function\n') + self.d(' * that returns the #GType of a #GHashTable\n') + self.d(' * appropriate for representing a D-Bus\n') + self.d(' * dictionary of signature\n') + self.d(' * a{%s}.\n' % impl_sig) + self.d(' *\n') key, value = members - self.header.write(' * Keys (D-Bus type %s,\n' + self.d(' * Keys (D-Bus type %s,\n' % key.getAttribute('type')) tp_type = key.getAttributeNS(NS_TP, 'type') if tp_type: - self.header.write(' * type %s,\n' % tp_type) - self.header.write(' * named %s):\n' + self.d(' * type %s,\n' % tp_type) + self.d(' * named %s):\n' % key.getAttribute('name')) docstring = get_docstring(key) or '(Undocumented)' - self.header.write(' * %s\n' % xml_escape(docstring)) - self.header.write(' *\n') + self.d(' * %s\n' % xml_escape(docstring)) + self.d(' *\n') - self.header.write(' * Values (D-Bus type %s,\n' + self.d(' * Values (D-Bus type %s,\n' % value.getAttribute('type')) tp_type = value.getAttributeNS(NS_TP, 'type') if tp_type: - self.header.write(' * type %s,\n' % tp_type) - self.header.write(' * named %s):\n' + self.d(' * type %s,\n' % tp_type) + self.d(' * named %s):\n' % value.getAttribute('name')) docstring = get_docstring(value) or '(Undocumented)' - self.header.write(' * %s\n' % xml_escape(docstring)) - self.header.write(' *\n') + self.d(' * %s\n' % xml_escape(docstring)) + self.d(' *\n') - self.header.write(' */\n') + self.d(' */\n') - self.header.write('#define %s (%s ())\n\n' % (name, impl)) + self.h('#define %s (%s ())\n\n' % (name, impl)) self.need_mappings[impl_sig] = esc_impl_sig + array_name = mapping.getAttribute('array-name') + if array_name: + gtype_name = self.PREFIX_ + 'ARRAY_TYPE_' + array_name.upper() + contents_sig = 'a{' + impl_sig + '}' + esc_contents_sig = escape_as_identifier(contents_sig) + impl = self.prefix_ + 'type_dbus_array_of_' + esc_contents_sig + self.d('/**\n * %s:\n\n' % gtype_name) + self.d(' * Expands to a call to a function\n') + self.d(' * that returns the #GType of a #GPtrArray\n') + self.d(' * of #%s.\n' % name) + self.d(' */\n\n') + + self.h('#define %s (%s ())\n\n' % (gtype_name, impl)) + self.need_other_arrays[contents_sig] = esc_contents_sig + def do_struct_header(self, struct): members = struct.getElementsByTagNameNS(NS_TP, 'member') impl_sig = ''.join([elt.getAttribute('type') for elt in members]) @@ -128,43 +162,45 @@ class GTypesGenerator(object): 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 (%s).\n' + self.d('/**\n * %s:\n\n' % name) + self.d(' * %s\n' % xml_escape(docstring)) + self.d(' *\n') + self.d(' * This macro expands to a call to a function\n') + self.d(' * that returns the #GType of a #GValueArray\n') + self.d(' * appropriate for representing a D-Bus struct\n') + self.d(' * with signature (%s).\n' % impl_sig) - self.header.write(' *\n') + self.d(' *\n') for i, member in enumerate(members): - self.header.write(' * Member %d (D-Bus type ' + self.d(' * Member %d (D-Bus type ' '%s,\n' % (i, member.getAttribute('type'))) tp_type = member.getAttributeNS(NS_TP, 'type') if tp_type: - self.header.write(' * type %s,\n' % tp_type) - self.header.write(' * named %s):\n' + self.d(' * type %s,\n' % tp_type) + self.d(' * named %s):\n' % member.getAttribute('name')) docstring = get_docstring(member) or '(Undocumented)' - self.header.write(' * %s\n' % xml_escape(docstring)) - self.header.write(' *\n') + self.d(' * %s\n' % xml_escape(docstring)) + self.d(' *\n') - self.header.write(' */\n') - self.header.write('#define %s (%s ())\n\n' % (name, impl)) + self.d(' */\n\n') + + self.h('#define %s (%s ())\n\n' % (name, impl)) array_name = struct.getAttribute('array-name') if array_name != '': array_name = (self.PREFIX_ + 'ARRAY_TYPE_' + array_name.upper()) impl = self.prefix_ + 'type_dbus_array_' + esc_impl_sig - self.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.d('/**\n * %s:\n\n' % array_name) + self.d(' * Expands to a call to a function\n') + self.d(' * that returns the #GType of a #GPtrArray\n') + self.d(' * of #%s.\n' % name) + self.d(' */\n\n') + + self.h('#define %s (%s ())\n\n' % (array_name, impl)) + self.need_struct_arrays[impl_sig] = esc_impl_sig self.need_structs[impl_sig] = esc_impl_sig @@ -176,51 +212,83 @@ class GTypesGenerator(object): self.do_mapping_header(mapping) for sig in self.need_mappings: - self.header.write('GType %stype_dbus_hash_%s (void);\n\n' % + self.h('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.c('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') + self.c(' static GType t = 0;\n\n') + self.c(' if (G_UNLIKELY (t == 0))\n') # FIXME: translate sig into two GTypes items = tuple(Signature(sig)) gtypes = types_to_gtypes(items) - self.body.write(' t = dbus_g_type_get_map ("GHashTable", ' + self.c(' 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') + self.c(' return t;\n') + self.c('}\n\n') for struct in structs: self.do_struct_header(struct) for sig in self.need_structs: - self.header.write('GType %stype_dbus_struct_%s (void);\n\n' % + self.h('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.c('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') + self.c(' static GType t = 0;\n\n') + self.c(' if (G_UNLIKELY (t == 0))\n') + self.c(' t = dbus_g_type_get_struct ("GValueArray",\n') items = tuple(Signature(sig)) gtypes = types_to_gtypes(items) for gtype in gtypes: - self.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", ' + self.c(' %s,\n' % gtype) + self.c(' G_TYPE_INVALID);\n') + self.c(' return t;\n') + self.c('}\n\n') + + for sig in self.need_struct_arrays: + self.h('GType %stype_dbus_array_%s (void);\n\n' % + (self.prefix_, self.need_struct_arrays[sig])) + self.c('GType\n%stype_dbus_array_%s (void)\n{\n' % + (self.prefix_, self.need_struct_arrays[sig])) + self.c(' static GType t = 0;\n\n') + self.c(' if (G_UNLIKELY (t == 0))\n') + self.c(' t = dbus_g_type_get_collection ("GPtrArray", ' '%stype_dbus_struct_%s ());\n' % - (self.prefix_, self.need_structs[sig])) - self.body.write(' return t;\n') - self.body.write('}\n\n') + (self.prefix_, self.need_struct_arrays[sig])) + self.c(' return t;\n') + self.c('}\n\n') + + for sig in self.need_other_arrays: + self.h('GType %stype_dbus_array_of_%s (void);\n\n' % + (self.prefix_, self.need_other_arrays[sig])) + self.c('GType\n%stype_dbus_array_of_%s (void)\n{\n' % + (self.prefix_, self.need_other_arrays[sig])) + self.c(' static GType t = 0;\n\n') + self.c(' if (G_UNLIKELY (t == 0))\n') + + if sig[:2] == 'a{' and sig[-1:] == '}': + # array of mappings + self.c(' t = dbus_g_type_get_collection (' + '"GPtrArray", ' + '%stype_dbus_hash_%s ());\n' % + (self.prefix_, escape_as_identifier(sig[2:-1]))) + elif sig[:2] == 'a(' and sig[-1:] == ')': + # array of arrays of struct + self.c(' t = dbus_g_type_get_collection (' + '"GPtrArray", ' + '%stype_dbus_array_%s ());\n' % + (self.prefix_, escape_as_identifier(sig[2:-1]))) + elif sig[:1] == 'a': + # array of arrays of non-struct + self.c(' t = dbus_g_type_get_collection (' + '"GPtrArray", ' + '%stype_dbus_array_of_%s ());\n' % + (self.prefix_, escape_as_identifier(sig[1:]))) + else: + raise AssertionError("array of '%s' not supported" % sig) + + self.c(' return t;\n') + self.c('}\n\n') if __name__ == '__main__': argv = sys.argv[1:] diff --git a/tools/glib-interfaces-gen.py b/tools/glib-interfaces-gen.py index 741626ce..69c721be 100644 --- a/tools/glib-interfaces-gen.py +++ b/tools/glib-interfaces-gen.py @@ -3,36 +3,50 @@ from sys import argv, stdout, stderr import xml.dom.minidom -from libglibcodegen import NS_TP, camelcase_to_upper, get_docstring, \ +from libglibcodegen import NS_TP, get_docstring, \ get_descendant_text, get_by_path class Generator(object): def __init__(self, prefix, implfile, declfile, dom): self.prefix = prefix + '_' + + assert declfile.endswith('.h') + docfile = declfile[:-2] + '-gtk-doc.h' + self.impls = open(implfile, 'w') self.decls = open(declfile, 'w') + self.docs = open(docfile, 'w') self.spec = get_by_path(dom, "spec")[0] + def h(self, code): + self.decls.write(code.encode('utf-8')) + + def c(self, code): + self.impls.write(code.encode('utf-8')) + + def d(self, code): + self.docs.write(code.encode('utf-8')) + def __call__(self): - for file in self.decls, self.impls: - self.do_header(file) + for f in self.h, self.c: + self.do_header(f) self.do_body() # Header - def do_header(self, file): - file.write('/* Generated from: ') - file.write(get_descendant_text(get_by_path(self.spec, 'title'))) + def do_header(self, f): + f('/* Generated from: ') + f(get_descendant_text(get_by_path(self.spec, 'title'))) version = get_by_path(self.spec, "version") if version: - file.write(' version ' + get_descendant_text(version)) - file.write('\n\n') + f(' version ' + get_descendant_text(version)) + f('\n\n') for copyright in get_by_path(self.spec, 'copyright'): - stdout.write(get_descendant_text(copyright)) - stdout.write('\n') - file.write('\n') - file.write(get_descendant_text(get_by_path(self.spec, 'license'))) - file.write(get_descendant_text(get_by_path(self.spec, 'docstring'))) - file.write(""" + f(get_descendant_text(copyright)) + f('\n') + f('\n') + f(get_descendant_text(get_by_path(self.spec, 'license'))) + f(get_descendant_text(get_by_path(self.spec, 'docstring'))) + f(""" */ """) @@ -44,25 +58,37 @@ class Generator(object): def do_iface(self, iface): parent_name = get_by_path(iface, '../@name') - self.decls.write("""\ + self.d("""\ /** * %(IFACE_DEFINE)s: - * + * * The interface name "%(name)s" */ +""" % {'IFACE_DEFINE' : (self.prefix + 'IFACE_' + \ + parent_name).upper().replace('/', ''), + 'name' : iface.getAttribute('name')}) + + self.h(""" #define %(IFACE_DEFINE)s \\ "%(name)s" """ % {'IFACE_DEFINE' : (self.prefix + 'IFACE_' + \ parent_name).upper().replace('/', ''), 'name' : iface.getAttribute('name')}) - self.decls.write(""" + self.d(""" /** * %(IFACE_QUARK_DEFINE)s: - * + * * Expands to a call to a function that returns a quark for the interface \ name "%(name)s" */ +""" % {'IFACE_QUARK_DEFINE' : (self.prefix + 'IFACE_QUARK_' + \ + parent_name).upper().replace('/', ''), + 'iface_quark_func' : (self.prefix + 'iface_quark_' + \ + parent_name).lower().replace('/', ''), + 'name' : iface.getAttribute('name')}) + + self.h(""" #define %(IFACE_QUARK_DEFINE)s \\ (%(iface_quark_func)s ()) @@ -74,7 +100,7 @@ GQuark %(iface_quark_func)s (void); parent_name).lower().replace('/', ''), 'name' : iface.getAttribute('name')}) - self.impls.write("""\ + self.c("""\ GQuark %(iface_quark_func)s (void) { @@ -92,6 +118,80 @@ GQuark parent_name).lower().replace('/', ''), 'name' : iface.getAttribute('name')}) + for prop in iface.getElementsByTagNameNS(None, 'property'): + self.d(""" +/** + * %(IFACE_PREFIX)s_%(PROP_UC)s: + * + * The fully-qualified property name "%(name)s.%(prop)s" + */ +""" % {'IFACE_PREFIX' : (self.prefix + 'PROP_' + \ + parent_name).upper().replace('/', ''), + 'PROP_UC': prop.getAttributeNS(NS_TP, "name-for-bindings").upper(), + 'name' : iface.getAttribute('name'), + 'prop' : prop.getAttribute('name'), + }) + + self.h(""" +#define %(IFACE_PREFIX)s_%(PROP_UC)s \\ +"%(name)s.%(prop)s" +""" % {'IFACE_PREFIX' : (self.prefix + 'PROP_' + \ + parent_name).upper().replace('/', ''), + 'PROP_UC': prop.getAttributeNS(NS_TP, "name-for-bindings").upper(), + 'name' : iface.getAttribute('name'), + 'prop' : prop.getAttribute('name'), + }) + + + for prop in iface.getElementsByTagNameNS(NS_TP, 'contact-attribute'): + self.d(""" +/** + * %(TOKEN_PREFIX)s_%(TOKEN_UC)s: + * + * The fully-qualified contact attribute token name "%(name)s/%(prop)s" + */ +""" % {'TOKEN_PREFIX' : (self.prefix + 'TOKEN_' + \ + parent_name).upper().replace('/', ''), + 'TOKEN_UC': prop.getAttributeNS(None, "name").upper().replace("-", "_").replace(".", "_"), + 'name' : iface.getAttribute('name'), + 'prop' : prop.getAttribute('name'), + }) + + self.h(""" +#define %(TOKEN_PREFIX)s_%(TOKEN_UC)s \\ +"%(name)s/%(prop)s" +""" % {'TOKEN_PREFIX' : (self.prefix + 'TOKEN_' + \ + parent_name).upper().replace('/', ''), + 'TOKEN_UC': prop.getAttributeNS(None, "name").upper().replace("-", "_").replace(".", "_"), + 'name' : iface.getAttribute('name'), + 'prop' : prop.getAttribute('name'), + }) + + for prop in iface.getElementsByTagNameNS(NS_TP, 'hct'): + if (prop.getAttribute('is-family') != "yes"): + self.d(""" +/** + * %(TOKEN_PREFIX)s_%(TOKEN_UC)s: + * + * The fully-qualified capability token name "%(name)s/%(prop)s" + */ +""" % {'TOKEN_PREFIX' : (self.prefix + 'TOKEN_' + \ + parent_name).upper().replace('/', ''), + 'TOKEN_UC': prop.getAttributeNS(None, "name").upper().replace("-", "_").replace(".", "_"), + 'name' : iface.getAttribute('name'), + 'prop' : prop.getAttribute('name'), + }) + + self.h(""" +#define %(TOKEN_PREFIX)s_%(TOKEN_UC)s \\ +"%(name)s/%(prop)s" +""" % {'TOKEN_PREFIX' : (self.prefix + 'TOKEN_' + \ + parent_name).upper().replace('/', ''), + 'TOKEN_UC': prop.getAttributeNS(None, "name").upper().replace("-", "_").replace(".", "_"), + 'name' : iface.getAttribute('name'), + 'prop' : prop.getAttribute('name'), + }) + if __name__ == '__main__': argv = argv[1:] Generator(argv[0], argv[1], argv[2], xml.dom.minidom.parse(argv[3]))() diff --git a/tools/gobject-foo.py b/tools/gobject-foo.py index 5921cab8..002a290b 100644 --- a/tools/gobject-foo.py +++ b/tools/gobject-foo.py @@ -5,7 +5,7 @@ # The master copy of this program is in the telepathy-glib repository - # please make any changes there. # -# Copyright (C) 2007 Collabora Ltd. +# Copyright (C) 2007-2010 Collabora Ltd. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -33,8 +33,13 @@ def gobject_header(head, tail, as_interface=False): gtype = head.upper() + '_TYPE_' + tail.upper() o("typedef struct _%s %s;" % (MixedCase, MixedCase)) - o("typedef struct _%sClass %sClass;" % (MixedCase, MixedCase)) - o("typedef struct _%sPrivate %sPrivate;" % (MixedCase, MixedCase)) + + if as_interface: + o("typedef struct _%sInterface %sInterface;" % (MixedCase, MixedCase)) + else: + o("typedef struct _%sClass %sClass;" % (MixedCase, MixedCase)) + o("typedef struct _%sPrivate %sPrivate;" % (MixedCase, MixedCase)) + o("") o("GType %s_get_type (void);" % lower_case) o("") @@ -54,13 +59,17 @@ def gobject_header(head, tail, as_interface=False): o("#define %s_IS_%s(obj) \\" % (head.upper(), tail.upper())) o(" (G_TYPE_CHECK_INSTANCE_TYPE ((obj), %s))" % gtype) - if not as_interface: + if as_interface: + o("#define %s_GET_IFACE(obj) \\" % UPPER_CASE) + o(" (G_TYPE_INSTANCE_GET_INTERFACE ((obj), %s, \\" % gtype) + o(" %sInterface))" % MixedCase) + else: o("#define %s_IS_%s_CLASS(klass) \\" % (head.upper(), tail.upper())) o(" (G_TYPE_CHECK_CLASS_TYPE ((klass), %s))" % gtype) - o("#define %s_GET_CLASS(obj) \\" % UPPER_CASE) - o(" (G_TYPE_INSTANCE_GET_CLASS ((obj), %s, \\" % gtype) - o(" %sClass))" % MixedCase) + o("#define %s_GET_CLASS(obj) \\" % UPPER_CASE) + o(" (G_TYPE_INSTANCE_GET_CLASS ((obj), %s, \\" % gtype) + o(" %sClass))" % MixedCase) return out diff --git a/tools/identity.xsl b/tools/identity.xsl deleted file mode 100644 index 6630f84d..00000000 --- a/tools/identity.xsl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/tools/libglibcodegen.py b/tools/libglibcodegen.py index 129c179e..6a9d2148 100644 --- a/tools/libglibcodegen.py +++ b/tools/libglibcodegen.py @@ -23,14 +23,13 @@ please make any changes there. from libtpcodegen import NS_TP, \ Signature, \ - camelcase_to_lower, \ - camelcase_to_upper, \ cmp_by_name, \ escape_as_identifier, \ get_by_path, \ get_descendant_text, \ get_docstring, \ - xml_escape + xml_escape, \ + get_deprecated def dbus_gutils_wincaps_to_uscore(s): """Bug-for-bug compatible Python port of _dbus_gutils_wincaps_to_uscore diff --git a/tools/libtpcodegen.py b/tools/libtpcodegen.py index 6391f1a4..837ff2f7 100644 --- a/tools/libtpcodegen.py +++ b/tools/libtpcodegen.py @@ -29,32 +29,6 @@ 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) @@ -146,6 +120,16 @@ def get_docstring(element): docstring = '' return docstring +def get_deprecated(element): + text = [] + for x in element.childNodes: + if hasattr(x, 'data'): + text.append(x.data.replace('\n', ' ').strip()) + else: + # This caters for tp:dbus-ref elements, but little else. + if x.childNodes and hasattr(x.childNodes[0], 'data'): + text.append(x.childNodes[0].data.replace('\n', ' ').strip()) + return ' '.join(text) def get_descendant_text(element_or_elements): if not element_or_elements: diff --git a/tools/make-release-mail.py b/tools/make-release-mail.py new file mode 100644 index 00000000..2bd7c2bc --- /dev/null +++ b/tools/make-release-mail.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : +# +# Hello. This is make-release-mail.py from the Telepathy project. It's +# designed to turn an item from a NEWS file into a mail suitable for sending +# to . I hope that you enjoy your stay. + +import sys + +def extract_description(package, version, news_path): + release_name = [] + details = [] + + with open(news_path) as f: + lines = (line for line in f.readlines()) + for line in lines: + # Find the 'telepathy-foo 0.1.2' header + if line.startswith("%s %s" % (package, version)): + break + + # Skip the ====== line, and the first blank line + lines.next() + lines.next() + + got_release_name = False + + for line in lines: + line = line.rstrip() + # If we hit the next version header, we're done + if line.startswith(package): + break + # Else, if we hit a blank line and we're still reading the release + # name, we're done with the release name. + elif not got_release_name and line == '': + got_release_name = True + # Otherwise, append this to the relevant list + elif not got_release_name: + release_name.append(line) + else: + details.append(line) + + assert got_release_name, (release_name, details) + + # We rstrip details because it picks up a trailing blank line + return ('\n'.join(release_name), '\n'.join(details).rstrip()) + +BASE_URL = 'http://telepathy.freedesktop.org/releases' + +def main(package, version, news_path): + release_name, details = extract_description(package, version, news_path) + + print """ +%(release_name)s + +tarball: %(base_url)s/%(package)s/%(package)s-%(version)s.tar.gz +signature: %(base_url)s/%(package)s/%(package)s-%(version)s.tar.gz.asc + +%(details)s""".strip().rstrip() % { + 'base_url': BASE_URL, + 'package': package, + 'version': version, + 'release_name': release_name, + 'details': details, + } + +if __name__ == '__main__': + try: + package, version, news_path = sys.argv[1:] + + main(package, version, news_path) + except ValueError, e: + sys.stderr.write( + 'Usage: %s package-name package.version.number path/to/NEWS\n' % + sys.argv[0]) + sys.stderr.flush() + sys.exit(1) diff --git a/tools/manager-file.py b/tools/manager-file.py new file mode 100644 index 00000000..45f64040 --- /dev/null +++ b/tools/manager-file.py @@ -0,0 +1,175 @@ +#!/usr/bin/python + +# manager-file.py: generate .manager files and TpCMParamSpec arrays from the +# same data (should be suitable for all connection managers that don't have +# plugins) +# +# The master copy of this program is in the telepathy-glib repository - +# please make any changes there. +# +# Copyright (c) Collabora Ltd. +# +# 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 re +import sys + +_NOT_C_STR = re.compile(r'[^A-Za-z0-9_-]') + +def c_string(x): + # whitelist-based brute force and ignorance - escape nearly all punctuation + return '"' + _NOT_C_STR.sub(lambda c: r'\x%02x' % ord(c), x) + '"' + +def desktop_string(x): + return x.replace(' ', r'\s').replace('\n', r'\n').replace('\r', r'\r').replace('\t', r'\t') + +supported = list('sbuiqn') + +fdefaultencoders = { + 's': desktop_string, + 'b': (lambda b: b and '1' or '0'), + 'u': (lambda n: '%u' % n), + 'i': (lambda n: '%d' % n), + 'q': (lambda n: '%u' % n), + 'n': (lambda n: '%d' % n), + } +for x in supported: assert x in fdefaultencoders + +gtypes = { + 's': 'G_TYPE_STRING', + 'b': 'G_TYPE_BOOLEAN', + 'u': 'G_TYPE_UINT', + 'i': 'G_TYPE_INT', + 'q': 'G_TYPE_UINT', + 'n': 'G_TYPE_INT', +} +for x in supported: assert x in gtypes + +gdefaultencoders = { + 's': c_string, + 'b': (lambda b: b and 'GINT_TO_POINTER (TRUE)' or 'GINT_TO_POINTER (FALSE)'), + 'u': (lambda n: 'GUINT_TO_POINTER (%u)' % n), + 'i': (lambda n: 'GINT_TO_POINTER (%d)' % n), + 'q': (lambda n: 'GUINT_TO_POINTER (%u)' % n), + 'n': (lambda n: 'GINT_TO_POINTER (%d)' % n), + } +for x in supported: assert x in gdefaultencoders + +gdefaultdefaults = { + 's': 'NULL', + 'b': 'GINT_TO_POINTER (FALSE)', + 'u': 'GUINT_TO_POINTER (0)', + 'i': 'GINT_TO_POINTER (0)', + 'q': 'GUINT_TO_POINTER (0)', + 'n': 'GINT_TO_POINTER (0)', + } +for x in supported: assert x in gdefaultdefaults + +gflags = { + 'has-default': 'TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT', + 'register': 'TP_CONN_MGR_PARAM_FLAG_REGISTER', + 'required': 'TP_CONN_MGR_PARAM_FLAG_REQUIRED', + 'secret': 'TP_CONN_MGR_PARAM_FLAG_SECRET', + 'dbus-property': 'TP_CONN_MGR_PARAM_FLAG_DBUS_PROPERTY', +} + +def write_manager(f, manager, protos): + # pointless backwards compat section + print >> f, '[ConnectionManager]' + print >> f, 'BusName=org.freedesktop.Telepathy.ConnectionManager.' + manager + print >> f, 'ObjectPath=/org/freedesktop/Telepathy/ConnectionManager/' + manager + + # protocols + for proto, params in protos.iteritems(): + print >> f + print >> f, '[Protocol %s]' % proto + + defaults = {} + + for param, info in params.iteritems(): + dtype = info['dtype'] + flags = info.get('flags', '').split() + struct_field = info.get('struct_field', param.replace('-', '_')) + filter = info.get('filter', 'NULL') + filter_data = info.get('filter_data', 'NULL') + setter_data = 'NULL' + + if 'default' in info: + default = fdefaultencoders[dtype](info['default']) + defaults[param] = default + + if flags: + flags = ' ' + ' '.join(flags) + else: + flags = '' + + print >> f, 'param-%s=%s%s' % (param, desktop_string(dtype), flags) + + for param, default in defaults.iteritems(): + print >> f, 'default-%s=%s' % (param, default) + +def write_c_params(f, manager, proto, struct, params): + print >> f, "static const TpCMParamSpec %s_%s_params[] = {" % (manager, proto) + + for param, info in params.iteritems(): + dtype = info['dtype'] + flags = info.get('flags', '').split() + struct_field = info.get('struct_field', param.replace('-', '_')) + filter = info.get('filter', 'NULL') + filter_data = info.get('filter_data', 'NULL') + setter_data = 'NULL' + + if 'default' in info: + default = gdefaultencoders[dtype](info['default']) + else: + default = gdefaultdefaults[dtype] + + if flags: + flags = ' | '.join([gflags[flag] for flag in flags]) + else: + flags = '0' + + if struct is None or struct_field is None: + struct_offset = '0' + else: + struct_offset = 'G_STRUCT_OFFSET (%s, %s)' % (struct, struct_field) + + print >> f, (''' { %s, %s, %s, + %s, + %s, /* default */ + %s, /* struct offset */ + %s, /* filter */ + %s, /* filter data */ + %s /* setter data */ },''' % + (c_string(param), c_string(dtype), gtypes[dtype], flags, + default, struct_offset, filter, filter_data, setter_data)) + + print >> f, " { NULL }" + print >> f, "};" + +if __name__ == '__main__': + environment = {} + execfile(sys.argv[1], environment) + + f = open('%s/%s.manager' % (sys.argv[2], environment['MANAGER']), 'w') + write_manager(f, environment['MANAGER'], environment['PARAMS']) + f.close() + + f = open('%s/param-spec-struct.h' % sys.argv[2], 'w') + for protocol in environment['PARAMS']: + write_c_params(f, environment['MANAGER'], protocol, + environment['STRUCTS'][protocol], + environment['PARAMS'][protocol]) + f.close() diff --git a/tools/shave.mk b/tools/shave.mk new file mode 100644 index 00000000..53cb3bf5 --- /dev/null +++ b/tools/shave.mk @@ -0,0 +1 @@ +QUIET_GEN = $(Q:@=@echo ' GEN '$@;) diff --git a/tools/telepathy-glib.supp b/tools/telepathy-glib.supp new file mode 100644 index 00000000..28bd5a06 --- /dev/null +++ b/tools/telepathy-glib.supp @@ -0,0 +1,390 @@ +# Valgrind error suppression file + +# ============================= libc ================================== + +{ + ld.so initialization + selinux + Memcheck:Leak + ... + fun:_dl_init + obj:/lib/ld-*.so +} + +{ + dlopen initialization, triggered by handle-leak-debug code + Memcheck:Leak + ... + fun:__libc_dlopen_mode + fun:init + fun:backtrace + fun:handle_leak_debug_bt + fun:dynamic_ensure_handle + fun:tp_handle_ensure +} + +# default.supp has these for 2.10, but they're too specific +{ + Debian libc6 (2.10.x, 2.11.x) stripped dynamic linker + Memcheck:Cond + fun:index + fun:expand_dynamic_string_token + fun:_dl_map_object + fun:map_doit + fun:_dl_catch_error + fun:do_preload + fun:dl_main + fun:_dl_sysdep_start + fun:_dl_start + obj:/lib/ld-*.so +} +{ + Debian libc6 (2.9.x - 2.11.x) stripped dynamic linker + Memcheck:Cond + fun:_dl_relocate_object + fun:dl_main + fun:_dl_sysdep_start + fun:_dl_start + obj:/lib/ld-*.so +} + +{ + ld.so initialization on glibc 2.9 + Memcheck:Cond + fun:strlen + fun:_dl_init_paths + fun:dl_main + fun:_dl_sysdep_start + fun:_dl_start + obj:/lib/ld-2.9.so +} + +# ======================= libselinux on Debian amd64 ===================== + +{ + I have no idea what SELinux is doing but it's not my problem + Memcheck:Cond + ... + obj:/lib/libselinux.so.1 + obj:/lib/libselinux.so.1 + obj:/lib/libselinux.so.1 +} + +{ + I have no idea what SELinux is doing but it's not my problem + Memcheck:Value8 + ... + obj:/lib/libselinux.so.1 + obj:/lib/libselinux.so.1 + obj:/lib/libselinux.so.1 +} + +{ + I have no idea what SELinux is doing but it's not my problem + Memcheck:Leak + ... + obj:/lib/libselinux.so.1 + obj:/lib/libselinux.so.1 + obj:/lib/libselinux.so.1 +} + +# ============================= GLib ================================== + +{ + g_set_prgname copies its argument + Memcheck:Leak + ... + fun:g_set_prgname +} + +{ + one g_get_charset per child^Wprocess + Memcheck:Leak + ... + fun:g_get_charset +} + +{ + one g_get_home_dir per process + Memcheck:Leak + ... + fun:g_get_home_dir +} + +{ + GQuarks can't be freed + Memcheck:Leak + ... + fun:g_quark_from_static_string +} + +{ + GQuarks can't be freed + Memcheck:Leak + ... + fun:g_quark_from_string +} + +{ + interned strings can't be freed + Memcheck:Leak + ... + fun:g_intern_string +} + +{ + interned strings can't be freed + Memcheck:Leak + ... + fun:g_intern_static_string +} + +{ + shared global default g_main_context + Memcheck:Leak + ... + fun:g_main_context_new + fun:g_main_context_default +} + +{ + GTest initialization + Memcheck:Leak + ... + fun:g_test_init + fun:main +} + +{ + GTest admin + Memcheck:Leak + ... + fun:g_test_add_vtable +} + +{ + GTest pseudorandomness + Memcheck:Leak + ... + fun:g_rand_new_with_seed_array + fun:test_run_seed + ... + fun:g_test_run +} + +{ + GSLice initialization + Memcheck:Leak + ... + fun:g_malloc0 + fun:g_slice_init_nomessage + fun:g_slice_alloc +} + +# ============================= GObject =============================== + +{ + g_type_init + Memcheck:Leak + ... + fun:g_type_init +} + +{ + g_type_init_with_debug_flags + Memcheck:Leak + ... + fun:g_type_init_with_debug_flags +} + +{ + g_type_register_static + Memcheck:Leak + ... + fun:g_type_register_static +} + +{ + g_type_add_interface_static + Memcheck:Leak + ... + fun:g_type_add_interface_static +} + +{ + initialization of interfaces + Memcheck:Leak + ... + fun:type_iface_vtable_base_init_Wm + fun:g_type_class_ref +} + +# ============================= GIO =================================== + +{ + GIO init + Memcheck:Leak + ... + fun:g_inet_address_class_intern_init +} + +{ + g_simple_async_result class + Memcheck:Leak + ... + fun:g_type_class_ref + ... + fun:g_simple_async_result_new +} + +# ============================= dbus-glib ============================= + +{ + registering marshallers is permanent + Memcheck:Leak + ... + fun:dbus_g_object_register_marshaller_array + fun:dbus_g_object_register_marshaller +} + +{ + dbus-glib specialized GTypes are permanent + Memcheck:Leak + ... + fun:dbus_g_type_specialized_init +} + +{ + libdbus shared connection + Memcheck:Leak + ... + fun:dbus_g_bus_get +} + +{ + dbus-gobject registrations aren't freed unless we fall off the bus + Memcheck:Leak + ... + fun:g_slist_append + fun:dbus_g_connection_register_g_object +} + +{ + DBusGProxy slots aren't freed unless we fall off the bus + Memcheck:Leak + ... + fun:dbus_connection_allocate_data_slot + ... + fun:dbus_g_proxy_constructor +} + +{ + error registrations are for life, not just for Christmas + Memcheck:Leak + ... + fun:dbus_g_error_domain_register +} + +{ + DBusGProxy class init + Memcheck:Leak + ... + fun:dbus_g_proxy_class_init +} + +# ============================= telepathy-glib ======================== + +{ + tp_dbus_daemon_constructor @daemons once per DBusConnection + Memcheck:Leak + ... + fun:g_slice_alloc + fun:tp_dbus_daemon_constructor +} + +{ + tp_proxy_subclass_add_error_mapping refs the enum + Memcheck:Leak + ... + fun:g_type_class_ref + fun:tp_proxy_subclass_add_error_mapping +} + +{ + tp_proxy_or_subclass_hook_on_interface_add never frees its list + Memcheck:Leak + ... + fun:tp_proxy_or_subclass_hook_on_interface_add +} + +{ + tp_dbus_daemon_constructor filter not freed til we fall off the bus + Memcheck:Leak + ... + fun:dbus_connection_add_filter + fun:tp_dbus_daemon_constructor +} + +{ + tp_g_socket_address_from_variant reffing GNIO types + Memcheck:Leak + ... + fun:g_type_class_ref + ... + fun:tp_g_socket_address_from_variant +} + +{ + creating classes for DBusGProxy + Memcheck:Leak + ... + fun:g_type_class_ref + ... + fun:g_object_new + ... + fun:tp_proxy_borrow_interface_by_id +} + +{ + creating classes for tp_dbus_daemon_new + Memcheck:Leak + ... + fun:g_type_class_ref + ... + fun:g_object_new + ... + fun:tp_dbus_daemon_new +} + +{ + creating classes for TpCHannel + Memcheck:Leak + ... + fun:g_type_class_ref + ... + fun:g_object_new + ... + fun:tp_channel_new +} + +{ + creating a boxed type to use in TpCapabilities + Memcheck:Leak + ... + fun:g_type_class_ref + ... + fun:g_param_spec_boxed + fun:tp_capabilities_class_intern_init +} + +# ============================= questionable ========================== + +{ + creating classes for instances (this is a pretty big hammer) + Memcheck:Leak + ... + fun:g_type_class_ref + ... + fun:g_type_create_instance + ... + fun:g_param_spec_string +} diff --git a/tools/test-wrapper.sh b/tools/test-wrapper.sh new file mode 100755 index 00000000..94900674 --- /dev/null +++ b/tools/test-wrapper.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# Make tests shut up. On success, if stdout is a tty, we only output messages +# about skipped tests; on failure, or if stdout is a file or pipe, we output +# the lot. +# +# Usage: test-wrapper.sh PROGRAM [ARGS...] + +set -e + +if test -t 1 && test "z$CHECK_VERBOSE" = z; then + : # continue with the output-suppressed code path, below +else + "$@" || e=$? + exit $e +fi + +e=0 +"$@" > capture-$$.log 2>&1 || e=$? +if test z$e = z0; then + grep -i skipped capture-$$.log || true + rm -f capture-$$.log +else + cat capture-$$.log + exit $e +fi + +# Copyright © 2010 Collabora Ltd. +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. There is no warranty. diff --git a/tools/valgrind.mk b/tools/valgrind.mk new file mode 100644 index 00000000..25a3488c --- /dev/null +++ b/tools/valgrind.mk @@ -0,0 +1,13 @@ +VALGRIND = valgrind --tool=memcheck \ + --verbose \ + --leak-check=full \ + --leak-resolution=high \ + --suppressions=$(top_srcdir)/tools/telepathy-glib.supp \ + --child-silent-after-fork=yes \ + --num-callers=20 \ + --gen-suppressions=all + +# other potentially interesting options: +# --show-reachable=yes reachable objects (many!) +# --read-var-info=yes better diagnostics from DWARF3 info +# --track-origins=yes better diagnostics for uninit values (slow) diff --git a/tools/with-session-bus.sh b/tools/with-session-bus.sh index 063bd7e1..cfedb5b9 100644 --- a/tools/with-session-bus.sh +++ b/tools/with-session-bus.sh @@ -59,7 +59,9 @@ cleanup () { pid=`head -n1 $me-$$.pid` if test -n "$pid" ; then - echo "Killing temporary bus daemon: $pid" >&2 + if [ -n "$VERBOSE_TESTS" ]; then + echo "Killing temporary bus daemon: $pid" >&2 + fi kill -INT "$pid" fi rm -f $me-$$.address @@ -69,8 +71,10 @@ cleanup () trap cleanup INT HUP TERM dbus-daemon $dbus_daemon_args -{ echo -n "Temporary bus daemon is "; cat $me-$$.address; } >&2 -{ echo -n "Temporary bus daemon PID is "; head -n1 $me-$$.pid; } >&2 +if [ -n "$VERBOSE_TESTS" ]; then + { echo -n "Temporary bus daemon is "; cat $me-$$.address; } >&2 + { echo -n "Temporary bus daemon PID is "; head -n1 $me-$$.pid; } >&2 +fi e=0 DBUS_SESSION_BUS_ADDRESS="`cat $me-$$.address`" diff --git a/tools/xincludator.py b/tools/xincludator.py new file mode 100644 index 00000000..63e106ac --- /dev/null +++ b/tools/xincludator.py @@ -0,0 +1,39 @@ +#!/usr/bin/python + +from sys import argv, stdout, stderr +import codecs, locale +import os +import xml.dom.minidom + +stdout = codecs.getwriter('utf-8')(stdout) + +NS_XI = 'http://www.w3.org/2001/XInclude' + +def xincludate(dom, base, dropns = []): + remove_attrs = [] + for i in xrange(dom.documentElement.attributes.length): + attr = dom.documentElement.attributes.item(i) + if attr.prefix == 'xmlns': + if attr.localName in dropns: + remove_attrs.append(attr) + else: + dropns.append(attr.localName) + for attr in remove_attrs: + dom.documentElement.removeAttributeNode(attr) + for include in dom.getElementsByTagNameNS(NS_XI, 'include'): + href = include.getAttribute('href') + # FIXME: assumes Unixy paths + filename = os.path.join(os.path.dirname(base), href) + subdom = xml.dom.minidom.parse(filename) + xincludate(subdom, filename, dropns) + if './' in href: + subdom.documentElement.setAttribute('xml:base', href) + include.parentNode.replaceChild(subdom.documentElement, include) + +if __name__ == '__main__': + argv = argv[1:] + dom = xml.dom.minidom.parse(argv[0]) + xincludate(dom, argv[0]) + xml = dom.toxml() + stdout.write(xml) + stdout.write('\n') -- cgit v1.2.1