diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2014-03-24 18:22:43 +0000 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2014-03-24 20:19:06 +0000 |
commit | 3df71eb11fbe8a6195564f179186a70b5ee60d6d (patch) | |
tree | b858fd7e03d8a3d6f1347d5651cc313077ffd18f | |
parent | 530e30cd657ee8c0bdae253ea93532bd7de87a0e (diff) |
codegen: sync from telepathy-glib, gdbus3 branch
-rw-r--r-- | tools/glib-ginterface-gen.py | 385 | ||||
-rw-r--r-- | tools/libglibcodegen.py | 282 | ||||
-rw-r--r-- | tools/libtpcodegen.py | 32 |
3 files changed, 454 insertions, 245 deletions
diff --git a/tools/glib-ginterface-gen.py b/tools/glib-ginterface-gen.py index 8fea5df..d5a786f 100644 --- a/tools/glib-ginterface-gen.py +++ b/tools/glib-ginterface-gen.py @@ -26,28 +26,19 @@ import sys import os.path import xml.dom.minidom -from libtpcodegen import file_set_contents -from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \ - NS_TP, dbus_gutils_wincaps_to_uscore +from libtpcodegen import file_set_contents, key_by_name, u, get_emits_changed +from libglibcodegen import (Signature, type_to_gtype, + NS_TP, dbus_gutils_wincaps_to_uscore, value_getter, + GDBusInterfaceInfo) NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" -def get_emits_changed(node): - try: - return [ - annotation.getAttribute('value') - for annotation in node.getElementsByTagName('annotation') - if annotation.getAttribute('name') == 'org.freedesktop.DBus.Property.EmitsChangedSignal' - ][0] - except IndexError: - return None - class Generator(object): def __init__(self, dom, prefix, basename, signal_marshal_prefix, headers, end_headers, not_implemented_func, - allow_havoc): + allow_havoc, allow_single_include): self.dom = dom self.__header = [] self.__body = [] @@ -83,20 +74,15 @@ class Generator(object): self.end_headers = end_headers self.not_implemented_func = not_implemented_func self.allow_havoc = allow_havoc + self.allow_single_include = allow_single_include 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): @@ -120,15 +106,9 @@ class Generator(object): iface_emits_changed = get_emits_changed(interface) - self.b('static const DBusGObjectInfo _%s%s_object_info;' - % (self.prefix_, node_name_lc)) - self.b('') - methods = interface.getElementsByTagName('method') signals = interface.getElementsByTagName('signal') properties = interface.getElementsByTagName('property') - # Don't put properties in dbus-glib glue - glue_properties = [] self.b('struct _%s%sClass {' % (self.Prefix, node_name_mixed)) self.b(' GTypeInterface parent_class;') @@ -251,16 +231,75 @@ class Generator(object): ' (G_TYPE_INSTANCE_GET_INTERFACE((obj), %s, %sClass))' % (self.PREFIX_, node_name_uc, gtype, classname)) self.h('') - self.h('') base_init_code = [] + method_call_code = [] for method in methods: - self.do_method(method) + self.do_method(method, method_call_code) + + signal_table = [ + 'static const gchar * const _gsignals_%s[] = {' % + self.node_name_lc + ] for signal in signals: - base_init_code.extend(self.do_signal(signal)) + # we rely on this being in the same order as the interface info + self.do_signal(signal, in_base_init=base_init_code, + in_signal_table=signal_table) + + signal_table.append(' NULL') + signal_table.append('};') + signal_table.append('') + for line in signal_table: + self.b(line) + # e.g. _interface_info_connection_interface_contact_info1 + for line in GDBusInterfaceInfo(node_name, interface, + '_interface_info_%s' % node_name_lc).to_lines(linkage='static'): + self.b(line) + + self.b('') + self.b('static void') + self.b('_method_call_%s (GDBusConnection *connection,' % node_name_lc) + self.b(' const gchar *sender,') + self.b(' const gchar *object_path,') + self.b(' const gchar *interface_name,') + self.b(' const gchar *method_name,') + self.b(' GVariant *parameters,') + self.b(' GDBusMethodInvocation *invocation,') + self.b(' gpointer user_data)') + self.b('{') + + for line in method_call_code: + self.b(line) + + # Deliberately not using self.not_implemented_func here so that callers + # can distinguish between "you called Protocol.NormalizeContact() but + # that isn't implemented here" and "you called Protocol.Badger() + # which isn't even in the spec" if required. + self.b(' g_dbus_method_invocation_return_error (invocation,') + self.b(' G_DBUS_ERROR,') + self.b(' G_DBUS_ERROR_UNKNOWN_METHOD,') + self.b(' "Method not implemented");') + self.b('}') + self.b('') + self.b('static const GDBusInterfaceVTable _vtable_%s = {' % + node_name_lc) + self.b(' _method_call_%s,' % node_name_lc) + self.b(' NULL, /* get property */') + self.b(' NULL /* set property */') + self.b('};') + self.b('') + self.b('static const TpSvcInterfaceInfo _tp_interface_info_%s = {' % + node_name_lc) + self.b(' -1,') + self.b(' (GDBusInterfaceInfo *) &_interface_info_%s,' % node_name_lc) + self.b(' (GDBusInterfaceVTable *) &_vtable_%s,' % node_name_lc) + self.b(' (gchar **) _gsignals_%s' % node_name_lc) + self.b(' /* _future is implicitly zero-filled */') + self.b('};') + self.b('') self.b('static inline void') self.b('%s%s_base_init_once (gpointer klass G_GNUC_UNUSED)' % (self.prefix_, node_name_lc)) @@ -301,13 +340,6 @@ class Generator(object): self.b(' { 0, properties, NULL, NULL };') self.b('') - - 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) @@ -323,6 +355,10 @@ class Generator(object): self.b('') + self.b(' tp_svc_interface_set_dbus_interface_info (%s,' + % (self.current_gtype)) + self.b(' &_tp_interface_info_%s);' % node_name_lc) + for s in base_init_code: self.b(s) self.b('}') @@ -344,100 +380,10 @@ class Generator(object): self.h('') - self.b('static const DBusGMethodInfo _%s%s_methods[] = {' - % (self.prefix_, node_name_lc)) - - method_blob, offsets = self.get_method_glue(methods) - - for method, offset in zip(methods, offsets): - self.do_method_glue(method, offset) - - 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('') - - self.b('static const DBusGObjectInfo _%s%s_object_info = {' - % (self.prefix_, node_name_lc)) - self.b(' 0,') # version - self.b(' _%s%s_methods,' % (self.prefix_, node_name_lc)) - self.b(' %d,' % len(methods)) - self.b('"' + method_blob.replace('\0', '\\0') + '",') - self.b('"' + self.get_signal_glue(signals).replace('\0', '\\0') + '",') - self.b('"' + - self.get_property_glue(glue_properties).replace('\0', '\\0') + - '",') - self.b('};') - self.b('') - self.node_name_mixed = None self.node_name_lc = None self.node_name_uc = None - def get_method_glue(self, methods): - info = [] - offsets = [] - - for method in methods: - offsets.append(len(''.join(info))) - - info.append(self.iface_name + '\0') - info.append(method.getAttribute('name') + '\0') - - info.append('A\0') # async - - counter = 0 - for arg in method.getElementsByTagName('arg'): - out = arg.getAttribute('direction') == 'out' - - name = arg.getAttribute('name') - if not name: - assert out - name = 'arg%u' % counter - counter += 1 - - info.append(name + '\0') - - if out: - info.append('O\0') - else: - info.append('I\0') - - if out: - info.append('F\0') # not const - info.append('N\0') # not error or return - info.append(arg.getAttribute('type') + '\0') - - info.append('\0') - - return ''.join(info) + '\0', offsets - - def do_method_glue(self, method, offset): - lc_name = 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 = 'g_cclosure_marshal_generic' - wrapper = self.prefix_ + self.node_name_lc + '_' + lc_name - - self.b(" { (GCallback) %s, %s, %d }," % (wrapper, marshaller, offset)) - - def get_signal_glue(self, signals): - info = [] - - for signal in signals: - info.append(self.iface_name) - info.append(signal.getAttribute('name')) - - return '\0'.join(info) + '\0\0' - - # the implementation can be the same - get_property_glue = get_signal_glue - def get_method_impl_names(self, method): dbus_method_name = method.getAttribute('name') @@ -451,11 +397,9 @@ class Generator(object): class_member_name) return (stub_name + '_impl', class_member_name + '_cb') - def do_method(self, method): + def do_method(self, method, method_call_code): assert self.node_name_mixed is not None - in_class = [] - # Examples refer to Thing.DoStuff (su) -> ii # DoStuff @@ -467,20 +411,20 @@ class Generator(object): '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 *); + # tp_svc_thing_do_stuff (signature of GDBusInterfaceMethodCallFunc) stub_name = (self.prefix_ + self.node_name_lc + '_' + class_member_name) # typedef void (*tp_svc_thing_do_stuff_impl) (TpSvcThing *, - # const char *, guint, DBusGMethodInvocation); + # const char *, guint, GDBusMethodInvocation); impl_name = stub_name + '_impl' - # void tp_svc_thing_return_from_do_stuff (DBusGMethodInvocation *, + # void tp_svc_thing_return_from_do_stuff (GDBusMethodInvocation *, # gint, gint); ret_name = (self.prefix_ + self.node_name_lc + '_return_from_' + class_member_name) # Gather arguments in_args = [] + in_arg_value_getters = [] out_args = [] for i in method.getElementsByTagName('arg'): name = i.getAttribute('name') @@ -504,9 +448,22 @@ class Generator(object): struct = (ctype, name) if direction == 'in': - in_args.append(struct) + in_args.append((ctype, name)) + in_arg_value_getters.append(value_getter(gtype, marshaller)) else: - out_args.append(struct) + out_args.append((gtype, ctype, name)) + + # bits of _method_call_myiface + method_call_code.extend([ + ' if (g_strcmp0 (method_name, "%s") == 0)' % dbus_method_name, + ' {', + ' %s (connection, sender, object_path, interface_name, ' % + stub_name, + ' method_name, parameters, invocation, user_data);', + ' return;', + ' }', + '' + ]) # Implementation type declaration (in header, docs separated) self.d('/**') @@ -515,7 +472,7 @@ class Generator(object): for (ctype, name) in in_args: self.d(' * @%s: %s (FIXME, generate documentation)' % (name, ctype)) - self.d(' * @context: Used to return values or throw an error') + self.d(' * @invocation: 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)) @@ -525,37 +482,59 @@ class Generator(object): % (impl_name, self.Prefix, self.node_name_mixed)) for (ctype, name) in in_args: self.h(' %s%s,' % (ctype, name)) - self.h(' DBusGMethodInvocation *context);') - - # Class member (in class definition) - in_class.append(' %s %s;' % (impl_name, class_member_name)) + self.h(' GDBusMethodInvocation *invocation);') # Stub definition (in body only - it's static) self.b('static void') - self.b('%s (%s%s *self,' - % (stub_name, self.Prefix, self.node_name_mixed)) - for (ctype, name) in in_args: - self.b(' %s%s,' % (ctype, name)) - self.b(' DBusGMethodInvocation *context)') + self.b('%s (GDBusConnection *connection,' % stub_name) + self.b(' const gchar *sender,') + self.b(' const gchar *object_path,') + self.b(' const gchar *interface_name,') + self.b(' const gchar *method_name,') + self.b(' GVariant *parameters,') + self.b(' GDBusMethodInvocation *invocation,') + self.b(' gpointer user_data)') self.b('{') - self.b(' %s impl = (%s%s_GET_CLASS (self)->%s_cb);' - % (impl_name, self.PREFIX_, self.node_name_uc, class_member_name)) + self.b(' %s%s *self = %s%s (user_data);' + % (self.Prefix, self.node_name_mixed, self.PREFIX_, + self.node_name_uc)) + self.b(' %s%sClass *cls = %s%s_GET_CLASS (self);' + % (self.Prefix, self.node_name_mixed, self.PREFIX_, + self.node_name_uc)) + self.b(' %s impl = cls->%s_cb;' % (impl_name, class_member_name)) self.b('') self.b(' if (impl != NULL)') - tmp = ['self'] + [name for (ctype, name) in in_args] + ['context'] + tmp = ['self'] + [name for (ctype, name) in in_args] + ['invocation'] self.b(' {') - self.b(' (impl) (%s);' % ',\n '.join(tmp)) + + if in_args: + self.b(' GValue args_val = G_VALUE_INIT;') + self.b(' GValueArray *va;') + self.b('') + self.b(' dbus_g_value_parse_g_variant (parameters, &args_val);') + self.b(' va = g_value_get_boxed (&args_val);') + self.b('') + + self.b(' (impl) (self,') + + for i, getter in enumerate(in_arg_value_getters): + self.b(' %s (va->values + %d),' % (getter, i)) + + self.b(' invocation);') + + if in_args: + self.b(' g_value_unset (&args_val);') + self.b(' }') self.b(' else') self.b(' {') if self.not_implemented_func: - self.b(' %s (context);' % self.not_implemented_func) + self.b(' %s (invocation);' % self.not_implemented_func) else: - self.b(' GError e = { DBUS_GERROR, ') - self.b(' DBUS_GERROR_UNKNOWN_METHOD,') - self.b(' "Method not implemented" };') - self.b('') - self.b(' dbus_g_method_return_error (context, &e);') + self.b(' g_dbus_method_invocation_return_error (invocation,') + self.b(' G_DBUS_ERROR,') + self.b(' G_DBUS_ERROR_UNKNOWN_METHOD,') + self.b(' "Method not implemented");') self.b(' }') self.b('}') self.b('') @@ -587,44 +566,59 @@ class Generator(object): self.b('}') self.b('') - # Return convenience function (static inline, in header) + # Return convenience function self.d('/**') self.d(' * %s:' % ret_name) - self.d(' * @context: The D-Bus method invocation context') - for (ctype, name) in out_args: + self.d(' * @invocation: The D-Bus method invocation context') + for (gtype, ctype, name) in out_args: self.d(' * @%s: %s (FIXME, generate documentation)' % (name, ctype)) 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(' * Return successfully by calling g_dbus_method_invocation_return_value().') self.d(' */') self.d('') - tmp = (['DBusGMethodInvocation *context'] + - [ctype + name for (ctype, name) in out_args]) - self.h('static inline') - self.h('/* this comment is to stop gtkdoc realising this is static */') + tmp = (['GDBusMethodInvocation *invocation'] + + [ctype + name for (gtype, ctype, name) in out_args]) self.h(('void %s (' % ret_name) + (',\n '.join(tmp)) + ');') - self.h('static inline void') - self.h(('%s (' % ret_name) + (',\n '.join(tmp)) + ')') - self.h('{') - tmp = ['context'] + [name for (ctype, name) in out_args] - self.h(' dbus_g_method_return (' + ',\n '.join(tmp) + ');') - self.h('}') - self.h('') - return in_class + self.b('void') + self.b(('%s (' % ret_name) + (',\n '.join(tmp)) + ')') + self.b('{') + self.b(' GValueArray *tmp = tp_value_array_build (%d,' % len(out_args)) + + for (gtype, ctype, name) in out_args: + self.b(' %s, %s,' % (gtype, name)) + + self.b(' G_TYPE_INVALID);') + self.b(' GValue args_val = G_VALUE_INIT;') + self.b('') + + self.b(' g_value_init (&args_val, ' + 'dbus_g_type_get_struct ("GValueArray",') + + for (gtype, ctype, name) in out_args: + self.b(' %s,' % gtype) + + self.b(' G_TYPE_INVALID));') + + self.b(' g_value_take_boxed (&args_val, tmp);') + + self.b(' g_dbus_method_invocation_return_value (invocation,') + self.b(' /* consume floating ref */') + self.b(' dbus_g_value_build_g_variant (&args_val));') + self.b(' g_value_unset (&args_val);') + self.b('}') + self.b('') def get_signal_const_entry(self, signal): assert self.node_name_uc is not None return ('SIGNAL_%s_%s' % (self.node_name_uc, signal.getAttribute('name'))) - def do_signal(self, signal): + def do_signal(self, signal, in_base_init, in_signal_table): assert self.node_name_mixed is not None - in_base_init = [] - # for signal: Thing::StuffHappened (s, u) # we want to emit: # void tp_svc_thing_emit_stuff_happened (gpointer instance, @@ -722,7 +716,7 @@ class Generator(object): in_base_init.append(' %s);' % ',\n '.join(tmp)) in_base_init.append('') - return in_base_init + in_signal_table.append(' "%s",' % signal_name) def have_properties(self, nodes): for node in nodes: @@ -733,20 +727,28 @@ class Generator(object): def __call__(self): nodes = self.dom.getElementsByTagName('node') - nodes.sort(cmp_by_name) + nodes.sort(key=key_by_name) self.h('#include <glib-object.h>') + self.h('#include <gio/gio.h>') self.h('#include <dbus/dbus-glib.h>') - if self.have_properties(nodes): - self.h('#include <telepathy-glib/telepathy-glib.h>') - self.h('') self.h('G_BEGIN_DECLS') self.h('') self.b('#include "%s.h"' % self.basename) self.b('') + + if self.allow_single_include: + self.b('#include <telepathy-glib/core-svc-interface.h>') + self.b('#include <telepathy-glib/dbus.h>') + self.b('#include <telepathy-glib/dbus-properties-mixin.h>') + self.b('#include <telepathy-glib/util.h>') + else: + self.b('#include <telepathy-glib/telepathy-glib.h>') + self.b('') + for header in self.headers: self.b('#include %s' % header) self.b('') @@ -763,12 +765,12 @@ class Generator(object): self.h('') self.b('') - file_set_contents(self.basename + '.h', '\n'.join(self.__header)) - file_set_contents(self.basename + '.c', '\n'.join(self.__body)) - file_set_contents(self.basename + '-gtk-doc.h', '\n'.join(self.__docs)) + file_set_contents(self.basename + '.h', u('\n').join(self.__header).encode('utf-8')) + file_set_contents(self.basename + '.c', u('\n').join(self.__body).encode('utf-8')) + file_set_contents(self.basename + '-gtk-doc.h', u('\n').join(self.__docs).encode('utf-8')) def cmdline_error(): - print """\ + print("""\ usage: gen-ginterface [OPTIONS] xmlfile Prefix_ options: @@ -785,10 +787,10 @@ options: --not-implemented-func='symbol' Set action when methods not implemented in the interface vtable are called. symbol must have signature - void symbol (DBusGMethodInvocation *context) + void symbol (GDBusMethodInvocation *invocation) and return some sort of "not implemented" error via - dbus_g_method_return_error (context, ...) -""" + e.g. g_dbus_method_invocation_return_error +""") sys.exit(1) @@ -799,7 +801,8 @@ if __name__ == '__main__': ['filename=', 'signal-marshal-prefix=', 'include=', 'include-end=', 'allow-unstable', - 'not-implemented-func=']) + 'not-implemented-func=', + "allow-single-include"]) try: prefix = argv[1] @@ -812,6 +815,7 @@ if __name__ == '__main__': end_headers = [] not_implemented_func = '' allow_havoc = False + allow_single_include = False for option, value in options: if option == '--filename': @@ -830,6 +834,8 @@ if __name__ == '__main__': not_implemented_func = value elif option == '--allow-unstable': allow_havoc = True + elif option == '--allow-single-include': + allow_single_include = True try: dom = xml.dom.minidom.parse(argv[0]) @@ -837,4 +843,5 @@ if __name__ == '__main__': cmdline_error() Generator(dom, prefix, basename, signal_marshal_prefix, headers, - end_headers, not_implemented_func, allow_havoc)() + end_headers, not_implemented_func, allow_havoc, + allow_single_include)() diff --git a/tools/libglibcodegen.py b/tools/libglibcodegen.py index 6a9d214..5cd0058 100644 --- a/tools/libglibcodegen.py +++ b/tools/libglibcodegen.py @@ -47,59 +47,6 @@ def dbus_gutils_wincaps_to_uscore(s): ret += c return ret - -def signal_to_marshal_type(signal): - """ - return a list of strings indicating the marshalling type for this signal. - """ - - mtype=[] - for i in signal.getElementsByTagName("arg"): - name =i.getAttribute("name") - type = i.getAttribute("type") - mtype.append(type_to_gtype(type)[2]) - - return mtype - - -_glib_marshallers = ['VOID', 'BOOLEAN', 'CHAR', 'UCHAR', 'INT', - 'STRING', 'UINT', 'LONG', 'ULONG', 'ENUM', 'FLAGS', 'FLOAT', - 'DOUBLE', 'STRING', 'PARAM', 'BOXED', 'POINTER', 'OBJECT', - 'UINT_POINTER'] - - -def signal_to_marshal_name(signal, prefix): - - mtype = signal_to_marshal_type(signal) - if len(mtype): - name = '_'.join(mtype) - else: - name = 'VOID' - - if name in _glib_marshallers: - return 'g_cclosure_marshal_VOID__' + name - else: - return prefix + '_marshal_VOID__' + name - - -def method_to_glue_marshal_name(method, prefix): - - mtype = [] - for i in method.getElementsByTagName("arg"): - if i.getAttribute("direction") != "out": - type = i.getAttribute("type") - mtype.append(type_to_gtype(type)[2]) - - mtype.append('POINTER') - - name = '_'.join(mtype) - - if name in _glib_marshallers: - return 'g_cclosure_marshal_VOID__' + name - else: - return prefix + '_marshal_VOID__' + name - - def type_to_gtype(s): if s == 'y': #byte return ("guchar ", "G_TYPE_UCHAR","UCHAR", False) @@ -154,7 +101,7 @@ def type_to_gtype(s): return ("GHashTable *", "DBUS_TYPE_G_STRING_STRING_HASHTABLE", "BOXED", False) elif s[:2] == 'a{': #some arbitrary hash tables if s[2] not in ('y', 'b', 'n', 'q', 'i', 'u', 's', 'o', 'g'): - raise Exception, "can't index a hashtable off non-basic type " + s + raise Exception("can't index a hashtable off non-basic type " + s) first = type_to_gtype(s[2]) second = type_to_gtype(s[3:-1]) return ("GHashTable *", "(dbus_g_type_get_map (\"GHashTable\", " + first[1] + ", " + second[1] + "))", "BOXED", False) @@ -169,4 +116,229 @@ def type_to_gtype(s): return ("GValueArray *", gtype, "BOXED", True) # we just don't know .. - raise Exception, "don't know the GType for " + s + raise Exception("don't know the GType for " + s) + +def value_getter(gtype, marshaller): + if marshaller == 'BOXED': + return 'g_value_get_boxed' + elif gtype == 'G_TYPE_STRING': + return 'g_value_get_string' + elif gtype == 'G_TYPE_UCHAR': + return 'g_value_get_uchar' + elif gtype == 'G_TYPE_BOOLEAN': + return 'g_value_get_boolean' + elif gtype == 'G_TYPE_UINT': + return 'g_value_get_uint' + elif gtype == 'G_TYPE_INT': + return 'g_value_get_int' + elif gtype == 'G_TYPE_UINT64': + return 'g_value_get_uint64' + elif gtype == 'G_TYPE_INT64': + return 'g_value_get_int64' + elif gtype == 'G_TYPE_DOUBLE': + return 'g_value_get_double' + else: + raise AssertionError("Don't know how to get %s from a GValue" % marshaller) + +class GDBusInterfaceInfo(object): + def __init__(self, ugly_name, iface_element, c_name): + self.ugly_name = ugly_name + self.mixed_name = ugly_name.replace('_', '') + self.lc_name = ugly_name.lower() + self.uc_name = ugly_name.upper() + self.c_name = c_name + self.iface_element = iface_element + + self.method_elements = iface_element.getElementsByTagName('method') + self.signal_elements = iface_element.getElementsByTagName('signal') + self.property_elements = iface_element.getElementsByTagName('property') + + def do_methods(self): + method_args = [ + ] + method_in_arg_pointers = [ + ] + method_out_arg_pointers = [ + ] + methods = [ + ] + method_pointers = [ + 'static const GDBusMethodInfo *const method_pointers_%s[] = {' + % self.c_name, + ] + + for meth in self.method_elements: + lc_name = meth.getAttribute('tp:name-for-bindings') + if meth.getAttribute('name') != lc_name.replace('_', ''): + raise AssertionError('Method %s tp:name-for-bindings (%s) ' + 'does not match' % + (meth.getAttribute('name'), lc_name)) + lc_name = lc_name.lower() + + c_name = 'method_%s_%s' % (self.c_name, lc_name) + + method_in_arg_pointers.append('static const GDBusArgInfo *const ' + 'method_in_arg_pointers_%s_%s[] = {' % + (self.c_name, lc_name)) + method_out_arg_pointers.append('static const GDBusArgInfo *const ' + 'method_out_arg_pointers_%s_%s[] = {' + % (self.c_name, lc_name)) + + for i, arg in enumerate(meth.getElementsByTagName('arg')): + name = arg.getAttribute('name') + if not name: + name = 'arg%d' % i + + method_args.append('static const GDBusArgInfo ' + 'method_arg_%s_%s_%d = {' % (self.c_name, lc_name, i)) + method_args.append(' -1, /* refcount */') + method_args.append(' "%s",' % name) + method_args.append(' "%s",' % arg.getAttribute('type')) + method_args.append(' NULL /* annotations */') + method_args.append('};') + + if arg.getAttribute('direction') == 'out': + method_out_arg_pointers.append(' &method_arg_%s_%s_%d,' % + (self.c_name, lc_name, i)) + else: + method_in_arg_pointers.append(' &method_arg_%s_%s_%d,' % + (self.c_name, lc_name, i)) + + method_in_arg_pointers.append(' NULL') + method_in_arg_pointers.append('};') + method_out_arg_pointers.append(' NULL') + method_out_arg_pointers.append('};') + + methods.append('static const GDBusMethodInfo %s = {' % c_name) + methods.append(' -1, /* refcount */') + methods.append(' "%s",' % meth.getAttribute("name")) + methods.append(' (GDBusArgInfo **) method_in_arg_pointers_%s_%s,' + % (self.c_name, lc_name)) + methods.append(' (GDBusArgInfo **) method_out_arg_pointers_%s_%s,' + % (self.c_name, lc_name)) + methods.append(' NULL /* annotations */') + methods.append('};') + + method_pointers.append(' &%s,' % c_name) + + method_pointers.append(' NULL') + method_pointers.append('};') + + return (method_args + method_in_arg_pointers + + method_out_arg_pointers + methods + method_pointers) + + def do_signals(self): + signal_args = [ + ] + signal_arg_pointers = [ + ] + signals = [ + ] + signal_pointers = [ + 'static const GDBusSignalInfo *const signal_pointers_%s[] = {' + % self.c_name, + ] + + for sig in self.signal_elements: + lc_name = sig.getAttribute('tp:name-for-bindings') + if sig.getAttribute('name') != lc_name.replace('_', ''): + raise AssertionError('Signal %s tp:name-for-bindings (%s) ' + 'does not match' % + (sig.getAttribute('name'), lc_name)) + lc_name = lc_name.lower() + + c_name = 'signal_%s_%s' % (self.c_name, lc_name) + + signal_arg_pointers.append('static const GDBusArgInfo *const ' + 'signal_arg_pointers_%s_%s[] = {' % (self.c_name, lc_name)) + + for i, arg in enumerate(sig.getElementsByTagName('arg')): + name = arg.getAttribute('name') + if not name: + name = 'arg%d' % i + + signal_args.append('static const GDBusArgInfo ' + 'signal_arg_%s_%s_%d = {' % (self.c_name, lc_name, i)) + signal_args.append(' -1, /* refcount */') + signal_args.append(' "%s",' % name) + signal_args.append(' "%s",' % arg.getAttribute('type')) + signal_args.append(' NULL /* annotations */') + signal_args.append('};') + + signal_arg_pointers.append(' &signal_arg_%s_%s_%d,' % + (self.c_name, lc_name, i)) + + signal_arg_pointers.append(' NULL') + signal_arg_pointers.append('};') + + signals.append('static const GDBusSignalInfo %s = {' % c_name) + signals.append(' -1, /* refcount */') + signals.append(' "%s",' % sig.getAttribute("name")) + signals.append(' (GDBusArgInfo **) signal_arg_pointers_%s_%s,' + % (self.c_name, lc_name)) + signals.append(' NULL /* annotations */') + signals.append('};') + + signal_pointers.append(' &%s,' % c_name) + + signal_pointers.append(' NULL') + signal_pointers.append('};') + + return signal_args + signal_arg_pointers + signals + signal_pointers + + def do_properties(self): + properties = [ + ] + property_pointers = [ + 'static const GDBusPropertyInfo *const property_pointers_%s[] = {' + % self.c_name, + ] + + for prop in self.property_elements: + access = prop.getAttribute('access') + flags = { + 'read': 'G_DBUS_PROPERTY_INFO_FLAGS_READABLE', + 'write': 'G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE', + 'readwrite': + 'G_DBUS_PROPERTY_INFO_FLAGS_READABLE | ' + 'G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE', + }[access] + + lc_name = prop.getAttribute('tp:name-for-bindings') + if prop.getAttribute('name') != lc_name.replace('_', ''): + raise AssertionError('Property %s tp:name-for-bindings (%s) ' + 'does not match' % + (prop.getAttribute('name'), lc_name)) + lc_name = lc_name.lower() + + c_name = 'property_%s_%s' % (self.c_name, lc_name) + + properties.append('static const GDBusPropertyInfo %s = {' % c_name) + properties.append(' -1, /* refcount */') + properties.append(' "%s",' % prop.getAttribute("name")) + properties.append(' "%s",' % prop.getAttribute("type")) + properties.append(' %s,' % flags) + # FIXME: add annotations? + properties.append(' NULL /* annotations */') + properties.append('};') + + property_pointers.append(' &%s,' % c_name) + + property_pointers.append(' NULL') + property_pointers.append('};') + + return properties + property_pointers + + def to_lines(self, linkage='static'): + return (self.do_methods() + + self.do_signals() + + self.do_properties() + [ + '%s const GDBusInterfaceInfo %s = {' % (linkage, self.c_name), + ' -1, /* refcount */', + ' "%s",' % self.iface_element.getAttribute('name'), + ' (GDBusMethodInfo **) method_pointers_%s,' % self.c_name, + ' (GDBusSignalInfo **) signal_pointers_%s,' % self.c_name, + ' (GDBusPropertyInfo **) property_pointers_%s,' % self.c_name, + ' NULL /* annotations */', + '};' + ]) diff --git a/tools/libtpcodegen.py b/tools/libtpcodegen.py index 7e9eb9a..021a82b 100644 --- a/tools/libtpcodegen.py +++ b/tools/libtpcodegen.py @@ -21,6 +21,7 @@ please make any changes there. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import os +import sys from string import ascii_letters, digits @@ -28,6 +29,20 @@ NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" _ASCII_ALNUM = ascii_letters + digits +if sys.version_info[0] >= 3: + def u(s): + """Return s, which must be a str literal with no non-ASCII characters. + This is like a more restricted form of the Python 2 u'' syntax. + """ + return s.encode('ascii').decode('ascii') +else: + def u(s): + """Return a Unicode version of s, which must be a str literal + (a bytestring) in which each byte is an ASCII character. + This is like a more restricted form of the u'' syntax. + """ + return s.decode('ascii') + def file_set_contents(filename, contents): try: os.remove(filename) @@ -38,13 +53,15 @@ def file_set_contents(filename, contents): except OSError: pass - open(filename + '.tmp', 'w').write(contents) + open(filename + '.tmp', 'wb').write(contents) os.rename(filename + '.tmp', filename) def cmp_by_name(node1, node2): return cmp(node1.getAttributeNode("name").nodeValue, node2.getAttributeNode("name").nodeValue) +def key_by_name(node): + return node.getAttributeNode("name").nodeValue def escape_as_identifier(identifier): """Escape the given string to be a valid D-Bus object path or service @@ -168,6 +185,9 @@ class _SignatureIter: self.remaining = string def next(self): + return self.__next__() + + def __next__(self): if self.remaining == '': raise StopIteration @@ -225,3 +245,13 @@ class Signature(str): def xml_escape(s): s = s.replace('&', '&').replace("'", ''').replace('"', '"') return s.replace('<', '<').replace('>', '>') + +def get_emits_changed(node): + try: + return [ + annotation.getAttribute('value') + for annotation in node.getElementsByTagName('annotation') + if annotation.getAttribute('name') == 'org.freedesktop.DBus.Property.EmitsChangedSignal' + ][0] + except IndexError: + return None |