diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index e5f3c41..dba0b28 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -1,124 +1,123 @@
# Some useful commands
add_custom_command(OUTPUT FIXME.out
COMMAND egrep
ARGS -A 5 '[F]IXME|[T]ODO|[X]XX' ${CMAKE_SOURCE_DIR}/TelepathyQt/*.[ch]*
${CMAKE_SOURCE_DIR}/TelepathyQt/*.[ch]*
> FIXME.out || true)
add_custom_target(check-local DEPENDS FIXME.out)
execute_process(COMMAND ${SH} tools/git-which-branch.sh misc | tr -d '\n' | tr -C "[:alnum:]" _
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_BRANCH_CURRENT)
if (GIT_BRANCH_CURRENT)
string(LENGTH ${GIT_BRANCH_CURRENT} HAVE_GIT_BRANCH)
if (HAVE_GIT_BRANCH)
string(REPLACE "\n" "" GIT_BRANCH_CURRENT ${GIT_BRANCH_CURRENT})
set(UPLOAD_BRANCH_TO people.freedesktop.org:public_html/telepathy-qt)
add_custom_target(upload-branch-docs rsync -rtzvPp --chmod=a+rX doc/html/ ${UPLOAD_BRANCH_TO}-${GIT_BRANCH_CURRENT}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
add_dependencies(upload-branch-docs doxygen-doc)
endif (HAVE_GIT_BRANCH)
endif (GIT_BRANCH_CURRENT)
if (PERL_FOUND)
add_custom_target(maintainer-fix-qt-links-in-docs
${PERL_EXECUTABLE} doc/html/installdox -l qt.tags@http://doc.qt.nokia.com/latest/ doc/html/*.html
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
add_dependencies(maintainer-fix-qt-links-in-docs doxygen-doc _maintainer-upload-release-check)
endif (PERL_FOUND)
add_custom_target(maintainer-upload-release-docs
rsync -rtOvzPp --chmod=Dg+s,ug+rwX,o=rX doc/html/ telepathy.freedesktop.org:/srv/telepathy.freedesktop.org/www/doc/telepathy-qt/
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
if (PERL_FOUND)
add_dependencies(maintainer-upload-release-docs maintainer-fix-qt-links-in-docs)
else (PERL_FOUND)
add_dependencies(maintainer-upload-release-docs doxygen-doc _maintainer-upload-release-check)
endif (PERL_FOUND)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/maintainer-upload-release-check.sh "
#!/bin/sh
case ${PACKAGE_VERSION} in
(*.*.*.*)
echo \"${PACKAGE_VERSION} is not a release\" >&2;
exit 2;
;;
esac
test -f ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz
if ! test -f ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz.asc; then
gpg --detach-sign -a ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz;
fi;
gpg --verify ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz.asc
")
add_custom_target(_maintainer-upload-release-check ${SH} ${CMAKE_CURRENT_BINARY_DIR}/maintainer-upload-release-check.sh)
add_custom_target(maintainer-upload-release
rsync -vzP ${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz
telepathy.freedesktop.org:/srv/telepathy.freedesktop.org/www/releases/${PACKAGE_NAME}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz
COMMAND
rsync -vzP ${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz.asc
telepathy.freedesktop.org:/srv/telepathy.freedesktop.org/www/releases/${PACKAGE_NAME}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz.asc
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
add_dependencies(maintainer-upload-release _maintainer-upload-release-check maintainer-upload-release-docs)
set(toolchain_files
c-constants-gen.py
check-misc.sh
check-whitespace.sh
git-which-branch.sh
glib-ginterface-gen.py
glib-gtypes-generator.py
glib-interfaces-gen.py
- glib-signals-marshal-gen.py
libtpcodegen.py
libglibcodegen.py
libqtcodegen.py
qt-client-gen.py
qt-constants-gen.py
qt-types-gen.py
manager-file.py
with-session-bus.sh
xincludator.py
)
string(REPLACE "." " " sh_toolchain_files ${toolchain_files})
set(TELEPATHY_SPEC_SRCDIR ${CMAKE_SOURCE_DIR}/../telepathy-spec)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/maintainer-update-from-telepathy-spec.sh "
#!/bin/sh
set -e
cd ${CMAKE_SOURCE_DIR}
for x in ${sh_toolchain_files}; do
if test -f ${TELEPATHY_SPEC_SRCDIR}/tools/$$x; then
cp ${TELEPATHY_SPEC_SRCDIR}/tools/$$x $$x;
fi;
done
")
add_custom_target(maintainer-update-from-telepathy-spec ${SH} ${CMAKE_CURRENT_BINARY_DIR}/maintainer-update-from-telepathy-spec.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
set(TELEPATHY_GLIB_SRCDIR ${CMAKE_SOURCE_DIR}/../telepathy-glib)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/maintainer-update-from-telepathy-glib.sh "
#!/bin/sh
set -e
cd ${CMAKE_SOURCE_DIR}
for x in ${sh_toolchain_files}; do
if test -f ${TELEPATHY_GLIB_SRCDIR}/tools/$$x; then
cp ${TELEPATHY_GLIB_SRCDIR}/tools/$$x $$x;
fi;
done
")
add_custom_target(maintainer-update-from-telepathy-glib ${SH} ${CMAKE_CURRENT_BINARY_DIR}/maintainer-update-from-telepathy-glib.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
diff --git a/tools/c-constants-gen.py b/tools/c-constants-gen.py
index 8969ffd..a08afee 100644
--- a/tools/c-constants-gen.py
+++ b/tools/c-constants-gen.py
@@ -1,154 +1,182 @@
#!/usr/bin/python
from sys import argv, stdout, stderr
import xml.dom.minidom
+from libtpcodegen import file_set_contents, u
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.output_base = output_base
+ self.__header = []
+ self.__docs = []
+
def __call__(self):
self.do_header()
self.do_body()
self.do_footer()
+ file_set_contents(self.output_base + '.h', u('').join(self.__header).encode('utf-8'))
+ file_set_contents(self.output_base + '-gtk-doc.h', u('').join(self.__docs).encode('utf-8'))
+
def write(self, code):
- stdout.write(code.encode('utf-8'))
+ self.__header.append(code)
+
+ def d(self, code):
+ self.__docs.append(code)
# Header
def do_header(self):
self.write('/* Generated from ')
self.write(get_descendant_text(get_by_path(self.spec, 'title')))
version = get_by_path(self.spec, "version")
if version:
self.write(', version ' + get_descendant_text(version))
self.write('\n\n')
for copyright in get_by_path(self.spec, 'copyright'):
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
extern "C" {
#endif
\n""")
# Body
def do_body(self):
for elem in self.spec.getElementsByTagNameNS(NS_TP, '*'):
if elem.localName == 'flags':
self.do_flags(elem)
elif elem.localName == 'enum':
self.do_enum(elem)
def do_flags(self, flags):
name = flags.getAttribute('plural') or flags.getAttribute('name')
value_prefix = flags.getAttribute('singular') or \
flags.getAttribute('value-prefix') or \
flags.getAttribute('name')
- self.write("""\
+ self.d("""\
/**
- *
-%s:
+ * %s:
""" % (self.prefix + name).replace('_', ''))
for flag in get_by_path(flags, 'flag'):
self.do_gtkdoc(flag, value_prefix)
- self.write(' *\n')
+ self.d(' *\n')
docstrings = get_by_path(flags, 'docstring')
if docstrings:
- self.write("""\
+ self.d("""\
*
*
""" % get_descendant_text(docstrings).replace('\n', ' '))
- self.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)
self.write("""\
} %s;
""" % (self.prefix + name).replace('_', ''))
def do_enum(self, enum):
name = enum.getAttribute('singular') or enum.getAttribute('name')
value_prefix = enum.getAttribute('singular') or \
enum.getAttribute('value-prefix') or \
enum.getAttribute('name')
name_plural = enum.getAttribute('plural') or \
enum.getAttribute('name') + 's'
- self.write("""\
+ self.d("""\
/**
- *
-%s:
+ * %s:
""" % (self.prefix + name).replace('_', ''))
vals = get_by_path(enum, 'enumvalue')
for val in vals:
self.do_gtkdoc(val, value_prefix)
- self.write(' *\n')
+ self.d(' *\n')
docstrings = get_by_path(enum, 'docstring')
if docstrings:
- self.write("""\
+ self.d("""\
*
*
""" % get_descendant_text(docstrings).replace('\n', ' '))
- self.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)
- self.write("""\
-} %(mixed-name)s;
+ self.write("} %s;\n" % (self.prefix + name).replace('_', ''))
+ self.d("""\
/**
- * NUM_%(upper-plural)s:
+ * %(upper-prefix)sNUM_%(upper-plural)s:
*
* 1 higher than the highest valid value of #%(mixed-name)s.
*/
-#define NUM_%(upper-plural)s (%(last-val)s+1)
+
+/**
+ * NUM_%(upper-prefix)s%(upper-plural)s: (skip)
+ *
+ * 1 higher than the highest valid value of #%(mixed-name)s.
+ * In new code, use %(upper-prefix)sNUM_%(upper-plural)s instead.
+ */
+""" % {'mixed-name' : (self.prefix + name).replace('_', ''),
+ 'upper-prefix' : self.prefix.upper(),
+ 'upper-plural' : name_plural.upper(),
+ 'last-val' : vals[-1].getAttribute('value')})
+
+ self.write("""\
+#define %(upper-prefix)sNUM_%(upper-plural)s (%(last-val)s+1)
+#define NUM_%(upper-prefix)s%(upper-plural)s %(upper-prefix)sNUM_%(upper-plural)s
""" % {'mixed-name' : (self.prefix + name).replace('_', ''),
- 'upper-plural' : (self.prefix + name_plural).upper(),
+ 'upper-prefix' : self.prefix.upper(),
+ 'upper-plural' : name_plural.upper(),
'last-val' : vals[-1].getAttribute('value')})
def do_val(self, val, value_prefix):
name = val.getAttribute('name')
suffix = val.getAttribute('suffix')
use_name = (self.prefix + value_prefix + '_' + \
(suffix or name)).upper()
assert not (name and suffix) or name == suffix, \
'Flag/enumvalue name %s != suffix %s' % (name, suffix)
self.write(' %s = %s,\n' % (use_name, val.getAttribute('value')))
def do_gtkdoc(self, node, value_prefix):
- self.write(' * @')
- self.write((self.prefix + value_prefix + '_' +
+ self.d(' * @')
+ self.d((self.prefix + value_prefix + '_' +
node.getAttribute('suffix')).upper())
- self.write(': \n')
+ self.d(get_descendant_text(docstring).replace('\n', ' '))
+ self.d(']]>\n')
# Footer
def do_footer(self):
self.write("""
#ifdef __cplusplus
}
#endif
""")
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/glib-ginterface-gen.py b/tools/glib-ginterface-gen.py
index 13f7f69..c0ce20d 100644
--- a/tools/glib-ginterface-gen.py
+++ b/tools/glib-ginterface-gen.py
@@ -1,802 +1,832 @@
#!/usr/bin/python
# glib-ginterface-gen.py: service-side interface generator
#
# Generate dbus-glib 0.x service GInterfaces from the Telepathy specification.
# The master copy of this program is in the telepathy-glib repository -
# please make any changes there.
#
# Copyright (C) 2006, 2007 Collabora Limited
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import sys
import os.path
import xml.dom.minidom
-from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \
- NS_TP, dbus_gutils_wincaps_to_uscore, \
- signal_to_marshal_name, method_to_glue_marshal_name
+from libtpcodegen import file_set_contents, key_by_name, u
+from libglibcodegen import Signature, type_to_gtype, \
+ NS_TP, dbus_gutils_wincaps_to_uscore
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):
self.dom = dom
self.__header = []
self.__body = []
+ self.__docs = []
assert prefix.endswith('_')
assert not signal_marshal_prefix.endswith('_')
# The main_prefix, sub_prefix thing is to get:
# FOO_ -> (FOO_, _)
# FOO_SVC_ -> (FOO_, _SVC_)
# but
# FOO_BAR/ -> (FOO_BAR_, _)
# FOO_BAR/SVC_ -> (FOO_BAR_, _SVC_)
if '/' in prefix:
main_prefix, sub_prefix = prefix.upper().split('/', 1)
prefix = prefix.replace('/', '_')
else:
main_prefix, sub_prefix = prefix.upper().split('_', 1)
self.MAIN_PREFIX_ = main_prefix + '_'
self._SUB_PREFIX_ = '_' + sub_prefix
self.Prefix_ = prefix
self.Prefix = prefix.replace('_', '')
self.prefix_ = prefix.lower()
self.PREFIX_ = prefix.upper()
self.basename = basename
self.signal_marshal_prefix = signal_marshal_prefix
self.headers = headers
self.end_headers = end_headers
self.not_implemented_func = not_implemented_func
self.allow_havoc = allow_havoc
def h(self, s):
self.__header.append(s)
def b(self, s):
self.__body.append(s)
+ def d(self, s):
+ 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('_', '')
node_name_lc = self.node_name_lc = node_name.lower()
node_name_uc = self.node_name_uc = node_name.upper()
interfaces = node.getElementsByTagName('interface')
assert len(interfaces) == 1, interfaces
interface = interfaces[0]
self.iface_name = interface.getAttribute('name')
tmp = interface.getAttribute('tp:implement-service')
if tmp == "no":
return
tmp = interface.getAttribute('tp:causes-havoc')
if tmp and not self.allow_havoc:
raise AssertionError('%s is %s' % (self.iface_name, tmp))
+ 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;')
for method in methods:
self.b(' %s %s;' % self.get_method_impl_names(method))
self.b('};')
self.b('')
if signals:
self.b('enum {')
for signal in signals:
self.b(' %s,' % self.get_signal_const_entry(signal))
self.b(' N_%s_SIGNALS' % node_name_uc)
self.b('};')
self.b('static guint %s_signals[N_%s_SIGNALS] = {0};'
% (node_name_lc, node_name_uc))
self.b('')
self.b('static void %s%s_base_init (gpointer klass);'
% (self.prefix_, node_name_lc))
self.b('')
self.b('GType')
self.b('%s%s_get_type (void)'
% (self.prefix_, node_name_lc))
self.b('{')
self.b(' static GType type = 0;')
self.b('')
self.b(' if (G_UNLIKELY (type == 0))')
self.b(' {')
self.b(' static const GTypeInfo info = {')
self.b(' sizeof (%s%sClass),' % (self.Prefix, node_name_mixed))
self.b(' %s%s_base_init, /* base_init */'
% (self.prefix_, node_name_lc))
self.b(' NULL, /* base_finalize */')
self.b(' NULL, /* class_init */')
self.b(' NULL, /* class_finalize */')
self.b(' NULL, /* class_data */')
self.b(' 0,')
self.b(' 0, /* n_preallocs */')
self.b(' NULL /* instance_init */')
self.b(' };')
self.b('')
self.b(' type = g_type_register_static (G_TYPE_INTERFACE,')
self.b(' "%s%s", &info, 0);' % (self.Prefix, node_name_mixed))
self.b(' }')
self.b('')
self.b(' return type;')
self.b('}')
self.b('')
- self.h('/**')
- self.h(' * %s%s:' % (self.Prefix, node_name_mixed))
- self.h(' *')
- self.h(' * Dummy typedef representing any implementation of this '
+ 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.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.h(' *')
- self.h(' * In a full implementation of this interface (i.e. all')
- self.h(' * methods implemented), the interface initialization')
- self.h(' * function used in G_IMPLEMENT_INTERFACE() would')
- self.h(' * typically look like this:')
- self.h(' *')
- self.h(' * ')
- self.h(' * static void')
- self.h(' * implement_%s (gpointer klass,' % self.node_name_lc)
- self.h(' * gpointer unused G_GNUC_UNUSED)')
- self.h(' * {')
- # "#" is special to gtkdoc under some circumstances; it appears
- # that escaping "##" as "##" or "##" doesn't work,
- # but adding an extra hash symbol does. Thanks, gtkdoc :-(
- self.h(' * #define IMPLEMENT(x) %s%s_implement_###x (\\'
+ 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.h(' * klass, my_object_###x)')
+ 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.h(' * IMPLEMENT (%s);' % class_member_name)
+ self.d(' * IMPLEMENT (%s);' % class_member_name)
- self.h(' * #undef IMPLEMENT')
- self.h(' * }')
- self.h(' * ')
+ self.d(' * #undef IMPLEMENT')
+ self.d(' * }')
+ self.d(' * ')
else:
- self.h(' * This interface has no D-Bus methods, so an')
- self.h(' * implementation can typically pass %NULL to')
- self.h(' * G_IMPLEMENT_INTERFACE() as the interface')
- self.h(' * initialization function.')
+ 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.h(' */')
+ self.d(' */')
+ self.d('')
self.h('typedef struct _%s%sClass %s%sClass;'
% (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed))
self.h('')
self.h('GType %s%s_get_type (void);'
% (self.prefix_, node_name_lc))
gtype = self.current_gtype = \
self.MAIN_PREFIX_ + 'TYPE' + self._SUB_PREFIX_ + node_name_uc
classname = self.Prefix + node_name_mixed
self.h('#define %s \\\n (%s%s_get_type ())'
% (gtype, self.prefix_, node_name_lc))
self.h('#define %s%s(obj) \\\n'
' (G_TYPE_CHECK_INSTANCE_CAST((obj), %s, %s))'
% (self.PREFIX_, node_name_uc, gtype, classname))
self.h('#define %sIS%s%s(obj) \\\n'
' (G_TYPE_CHECK_INSTANCE_TYPE((obj), %s))'
% (self.MAIN_PREFIX_, self._SUB_PREFIX_, node_name_uc, gtype))
self.h('#define %s%s_GET_CLASS(obj) \\\n'
' (G_TYPE_INSTANCE_GET_INTERFACE((obj), %s, %sClass))'
% (self.PREFIX_, node_name_uc, gtype, classname))
self.h('')
self.h('')
base_init_code = []
for method in methods:
self.do_method(method)
for signal in signals:
base_init_code.extend(self.do_signal(signal))
self.b('static inline void')
self.b('%s%s_base_init_once (gpointer klass G_GNUC_UNUSED)'
% (self.prefix_, node_name_lc))
self.b('{')
if properties:
self.b(' static TpDBusPropertiesMixinPropInfo properties[%d] = {'
% (len(properties) + 1))
for m in properties:
access = m.getAttribute('access')
assert access in ('read', 'write', 'readwrite')
if access == 'read':
flags = 'TP_DBUS_PROPERTIES_MIXIN_FLAG_READ'
elif access == 'write':
flags = 'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE'
else:
flags = ('TP_DBUS_PROPERTIES_MIXIN_FLAG_READ | '
'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE')
+ prop_emits_changed = get_emits_changed(m)
+
+ if prop_emits_changed is None:
+ prop_emits_changed = iface_emits_changed
+
+ if prop_emits_changed == 'true':
+ flags += ' | TP_DBUS_PROPERTIES_MIXIN_FLAG_EMITS_CHANGED'
+ elif prop_emits_changed == 'invalidates':
+ flags += ' | TP_DBUS_PROPERTIES_MIXIN_FLAG_EMITS_INVALIDATED'
+
self.b(' { 0, %s, "%s", 0, NULL, NULL }, /* %s */'
% (flags, m.getAttribute('type'), m.getAttribute('name')))
self.b(' { 0, 0, NULL, 0, NULL, NULL }')
self.b(' };')
self.b(' static TpDBusPropertiesMixinIfaceInfo interface =')
self.b(' { 0, properties, NULL, NULL };')
self.b('')
self.b(' 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')
self.b('%s%s_base_init (gpointer klass)'
% (self.prefix_, node_name_lc))
self.b('{')
self.b(' static gboolean initialized = FALSE;')
self.b('')
self.b(' if (!initialized)')
self.b(' {')
self.b(' initialized = TRUE;')
self.b(' %s%s_base_init_once (klass);'
% (self.prefix_, node_name_lc))
self.b(' }')
# insert anything we need to do per implementation here
self.b('}')
self.h('')
self.b('static const DBusGMethodInfo _%s%s_methods[] = {'
% (self.prefix_, node_name_lc))
method_blob, offsets = self.get_method_glue(methods)
for method, offset in zip(methods, offsets):
self.do_method_glue(method, offset)
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 = method_to_glue_marshal_name(method,
- self.signal_marshal_prefix)
+ 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')
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
in_class = []
# Examples refer to Thing.DoStuff (su) -> ii
# DoStuff
dbus_method_name = method.getAttribute('name')
# do_stuff
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 + '_' +
class_member_name)
# typedef void (*tp_svc_thing_do_stuff_impl) (TpSvcThing *,
# const char *, guint, DBusGMethodInvocation);
impl_name = stub_name + '_impl'
# void tp_svc_thing_return_from_do_stuff (DBusGMethodInvocation *,
# gint, gint);
ret_name = (self.prefix_ + self.node_name_lc + '_return_from_' +
class_member_name)
# Gather arguments
in_args = []
out_args = []
for i in method.getElementsByTagName('arg'):
name = i.getAttribute('name')
direction = i.getAttribute('direction') or 'in'
dtype = i.getAttribute('type')
assert direction in ('in', 'out')
if name:
name = direction + '_' + name
elif direction == 'in':
name = direction + str(len(in_args))
else:
name = direction + str(len(out_args))
ctype, gtype, marshaller, pointer = type_to_gtype(dtype)
if pointer:
ctype = 'const ' + ctype
struct = (ctype, name)
if direction == 'in':
in_args.append(struct)
else:
out_args.append(struct)
- # Implementation type declaration (in header, docs in body)
- self.b('/**')
- self.b(' * %s:' % impl_name)
- self.b(' * @self: The object implementing this interface')
+ # 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:
self.h(' %s%s,' % (ctype, name))
self.h(' DBusGMethodInvocation *context);')
# Class member (in class definition)
in_class.append(' %s %s;' % (impl_name, class_member_name))
# Stub definition (in body only - it's static)
self.b('static void')
self.b('%s (%s%s *self,'
% (stub_name, self.Prefix, self.node_name_mixed))
for (ctype, name) in in_args:
self.b(' %s%s,' % (ctype, name))
self.b(' DBusGMethodInvocation *context)')
self.b('{')
- self.b(' %s impl = (%s%s_GET_CLASS (self)->%s);'
+ 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)')
tmp = ['self'] + [name for (ctype, name) in in_args] + ['context']
self.b(' {')
self.b(' (impl) (%s);' % ',\n '.join(tmp))
self.b(' }')
self.b(' else')
self.b(' {')
if self.not_implemented_func:
self.b(' %s (context);' % self.not_implemented_func)
else:
self.b(' GError e = { DBUS_GERROR, ')
self.b(' DBUS_GERROR_UNKNOWN_METHOD,')
self.b(' "Method not implemented" };')
self.b('')
self.b(' dbus_g_method_return_error (context, &e);')
self.b(' }')
self.b('}')
self.b('')
# Implementation registration (in both header and body)
self.h('void %s%s_implement_%s (%s%sClass *klass, %s impl);'
% (self.prefix_, self.node_name_lc, class_member_name,
self.Prefix, self.node_name_mixed, impl_name))
- self.b('/**')
- self.b(' * %s%s_implement_%s:'
+ self.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')
self.h('/* this comment is to stop gtkdoc realising this is static */')
self.h(('void %s (' % ret_name) + (',\n '.join(tmp)) + ');')
self.h('static inline void')
self.h(('%s (' % ret_name) + (',\n '.join(tmp)) + ')')
self.h('{')
tmp = ['context'] + [name for (ctype, name) in out_args]
self.h(' dbus_g_method_return (' + ',\n '.join(tmp) + ');')
self.h('}')
self.h('')
return in_class
def get_signal_const_entry(self, signal):
assert self.node_name_uc is not None
return ('SIGNAL_%s_%s'
% (self.node_name_uc, signal.getAttribute('name')))
def do_signal(self, signal):
assert self.node_name_mixed is not None
in_base_init = []
# for signal: Thing::StuffHappened (s, u)
# we want to emit:
# void tp_svc_thing_emit_stuff_happened (gpointer instance,
# const char *arg0, guint arg1);
dbus_name = signal.getAttribute('name')
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_' +
ugly_name.lower())
const_name = self.get_signal_const_entry(signal)
# Gather arguments
args = []
for i in signal.getElementsByTagName('arg'):
name = i.getAttribute('name')
dtype = i.getAttribute('type')
tp_type = i.getAttribute('tp:type')
if name:
name = 'arg_' + name
else:
name = 'arg' + str(len(args))
ctype, gtype, marshaller, pointer = type_to_gtype(dtype)
if pointer:
ctype = 'const ' + ctype
struct = (ctype, name, gtype)
args.append(struct)
tmp = (['gpointer instance'] +
[ctype + name for (ctype, name, gtype) in args])
self.h(('void %s (' % stub_name) + (',\n '.join(tmp)) + ');')
# FIXME: emit docs
- self.b('/**')
- self.b(' * %s:' % stub_name)
- self.b(' * @instance: The object implementing this interface')
+ 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)) + ')')
self.b('{')
self.b(' g_assert (instance != NULL);')
self.b(' g_assert (G_TYPE_CHECK_INSTANCE_TYPE (instance, %s));'
% (self.current_gtype))
tmp = (['instance', '%s_signals[%s]' % (self.node_name_lc, const_name),
'0'] + [name for (ctype, name, gtype) in args])
self.b(' g_signal_emit (' + ',\n '.join(tmp) + ');')
self.b('}')
self.b('')
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)
in_base_init.append(' G_OBJECT_CLASS_TYPE (klass),')
in_base_init.append(' G_SIGNAL_RUN_LAST|G_SIGNAL_DETAILED,')
in_base_init.append(' 0,')
in_base_init.append(' NULL, NULL,')
- in_base_init.append(' %s,'
- % signal_to_marshal_name(signal, self.signal_marshal_prefix))
+ in_base_init.append(' g_cclosure_marshal_generic,')
in_base_init.append(' G_TYPE_NONE,')
tmp = ['%d' % len(args)] + [gtype for (ctype, name, gtype) in args]
in_base_init.append(' %s);' % ',\n '.join(tmp))
in_base_init.append('')
return in_base_init
def 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)
+ nodes.sort(key=key_by_name)
self.h('#include ')
self.h('#include ')
- if self.have_properties(nodes):
- self.h('#include ')
+ for header in self.headers:
+ self.h('#include %s' % header)
+ self.h('')
self.h('')
self.h('G_BEGIN_DECLS')
self.h('')
self.b('#include "%s.h"' % self.basename)
self.b('')
- for header in self.headers:
- self.b('#include %s' % header)
- self.b('')
for node in nodes:
self.do_node(node)
self.h('')
self.h('G_END_DECLS')
self.b('')
for header in self.end_headers:
self.b('#include %s' % header)
self.h('')
self.b('')
- open(self.basename + '.h', 'w').write('\n'.join(self.__header))
- open(self.basename + '.c', 'w').write('\n'.join(self.__body))
-
+ 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:
--include='' (may be repeated)
--include='"header.h"' (ditto)
--include-end='"header.h"' (ditto)
Include extra headers in the generated .c file
--signal-marshal-prefix='prefix'
Use the given prefix on generated signal marshallers (default is
prefix.lower()).
--filename='BASENAME'
Set the basename for the output files (default is prefix.lower()
+ 'ginterfaces')
--not-implemented-func='symbol'
Set action when methods not implemented in the interface vtable are
called. symbol must have signature
void symbol (DBusGMethodInvocation *context)
and return some sort of "not implemented" error via
dbus_g_method_return_error (context, ...)
-"""
+""")
sys.exit(1)
if __name__ == '__main__':
from getopt import gnu_getopt
options, argv = gnu_getopt(sys.argv[1:], '',
['filename=', 'signal-marshal-prefix=',
'include=', 'include-end=',
'allow-unstable',
'not-implemented-func='])
try:
prefix = argv[1]
except IndexError:
cmdline_error()
basename = prefix.lower() + 'ginterfaces'
signal_marshal_prefix = prefix.lower().rstrip('_')
headers = []
end_headers = []
not_implemented_func = ''
allow_havoc = False
for option, value in options:
if option == '--filename':
basename = value
elif option == '--signal-marshal-prefix':
signal_marshal_prefix = value
elif option == '--include':
if value[0] not in '<"':
value = '"%s"' % value
headers.append(value)
elif option == '--include-end':
if value[0] not in '<"':
value = '"%s"' % value
end_headers.append(value)
elif option == '--not-implemented-func':
not_implemented_func = value
elif option == '--allow-unstable':
allow_havoc = True
try:
dom = xml.dom.minidom.parse(argv[0])
except IndexError:
cmdline_error()
Generator(dom, prefix, basename, signal_marshal_prefix, headers,
end_headers, not_implemented_func, allow_havoc)()
diff --git a/tools/glib-gtypes-generator.py b/tools/glib-gtypes-generator.py
index ebc2ad4..1477bd3 100644
--- a/tools/glib-gtypes-generator.py
+++ b/tools/glib-gtypes-generator.py
@@ -1,291 +1,304 @@
#!/usr/bin/python
# Generate GLib GInterfaces from the Telepathy specification.
# The master copy of this program is in the telepathy-glib repository -
# please make any changes there.
#
# Copyright (C) 2006, 2007 Collabora Limited
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import sys
import xml.dom.minidom
+from libtpcodegen import file_set_contents, u
from libglibcodegen import escape_as_identifier, \
get_docstring, \
NS_TP, \
Signature, \
type_to_gtype, \
xml_escape
def types_to_gtypes(types):
return [type_to_gtype(t)[1] for t in types]
class GTypesGenerator(object):
def __init__(self, dom, output, mixed_case_prefix):
self.dom = dom
self.Prefix = mixed_case_prefix
self.PREFIX_ = self.Prefix.upper() + '_'
self.prefix_ = self.Prefix.lower() + '_'
- self.header = open(output + '.h', 'w')
- self.body = open(output + '-body.h', 'w')
+ self.header = []
+ self.body = []
+ self.docs = []
+ self.output = output
- for f in (self.header, self.body):
- f.write('/* Auto-generated, do not edit.\n *\n'
- ' * This file may be distributed under the same terms\n'
- ' * as the specification from which it was generated.\n'
- ' */\n\n')
+ for f in (self.header, self.body, self.docs):
+ f.append('/* 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 = {}
# 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"))
+ self.header.append(code)
def c(self, code):
- self.body.write(code.encode("utf-8"))
+ self.body.append(code)
+
+ def d(self, code):
+ self.docs.append(code)
def do_mapping_header(self, mapping):
members = mapping.getElementsByTagNameNS(NS_TP, 'member')
assert len(members) == 2
impl_sig = ''.join([elt.getAttribute('type')
for elt in members])
esc_impl_sig = escape_as_identifier(impl_sig)
name = (self.PREFIX_ + 'HASH_TYPE_' +
mapping.getAttribute('name').upper())
impl = self.prefix_ + 'type_dbus_hash_' + esc_impl_sig
docstring = get_docstring(mapping) or '(Undocumented)'
- self.h('/**\n * %s:\n *\n' % name)
- self.h(' * %s\n' % xml_escape(docstring))
- self.h(' *\n')
- self.h(' * This macro expands to a call to a function\n')
- self.h(' * that returns the #GType of a #GHashTable\n')
- self.h(' * appropriate for representing a D-Bus\n')
- self.h(' * dictionary of signature\n')
- self.h(' * a{%s}.\n' % impl_sig)
- self.h(' *\n')
+ self.d('/**\n * %s:\n *\n' % name.strip())
+ 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.h(' * 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.h(' * type %s,\n' % tp_type)
- self.h(' * 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.h(' * %s\n' % xml_escape(docstring))
- self.h(' *\n')
+ self.d(' * %s\n' % xml_escape(docstring))
+ self.d(' *\n')
- self.h(' * 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.h(' * type %s,\n' % tp_type)
- self.h(' * 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.h(' * %s\n' % xml_escape(docstring))
- self.h(' *\n')
+ self.d(' * %s\n' % xml_escape(docstring))
+ self.d(' *\n')
- self.h(' */\n')
+ self.d(' */\n')
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.h('/**\n * %s:\n\n' % gtype_name)
- self.h(' * Expands to a call to a function\n')
- self.h(' * that returns the #GType of a #GPtrArray\n')
- self.h(' * of #%s.\n' % name)
- self.h(' */\n')
+ 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])
esc_impl_sig = escape_as_identifier(impl_sig)
name = (self.PREFIX_ + 'STRUCT_TYPE_' +
struct.getAttribute('name').upper())
impl = self.prefix_ + 'type_dbus_struct_' + esc_impl_sig
docstring = struct.getElementsByTagNameNS(NS_TP, 'docstring')
if docstring:
docstring = docstring[0].toprettyxml()
if docstring.startswith(''):
docstring = docstring[14:]
if docstring.endswith('\n'):
docstring = docstring[:-16]
if docstring.strip() in ('', ''):
docstring = '(Undocumented)'
else:
docstring = '(Undocumented)'
- self.h('/**\n * %s:\n\n' % name)
- self.h(' * %s\n' % xml_escape(docstring))
- self.h(' *\n')
- self.h(' * This macro expands to a call to a function\n')
- self.h(' * that returns the #GType of a #GValueArray\n')
- self.h(' * appropriate for representing a D-Bus struct\n')
- self.h(' * 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.h(' *\n')
+ self.d(' *\n')
for i, member in enumerate(members):
- self.h(' * 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.h(' * type %s,\n' % tp_type)
- self.h(' * 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.h(' * %s\n' % xml_escape(docstring))
- self.h(' *\n')
+ self.d(' * %s\n' % xml_escape(docstring))
+ self.d(' *\n')
+
+ self.d(' */\n\n')
- self.h(' */\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.h('/**\n * %s:\n\n' % array_name)
- self.h(' * Expands to a call to a function\n')
- self.h(' * that returns the #GType of a #GPtrArray\n')
- self.h(' * of #%s.\n' % name)
- self.h(' */\n')
+ 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
def __call__(self):
mappings = self.dom.getElementsByTagNameNS(NS_TP, 'mapping')
structs = self.dom.getElementsByTagNameNS(NS_TP, 'struct')
for mapping in mappings:
self.do_mapping_header(mapping)
for sig in self.need_mappings:
self.h('GType %stype_dbus_hash_%s (void);\n\n' %
(self.prefix_, self.need_mappings[sig]))
self.c('GType\n%stype_dbus_hash_%s (void)\n{\n' %
(self.prefix_, self.need_mappings[sig]))
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.c(' t = dbus_g_type_get_map ("GHashTable", '
'%s, %s);\n' % (gtypes[0], gtypes[1]))
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.h('GType %stype_dbus_struct_%s (void);\n\n' %
(self.prefix_, self.need_structs[sig]))
self.c('GType\n%stype_dbus_struct_%s (void)\n{\n' %
(self.prefix_, self.need_structs[sig]))
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.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_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')
+ file_set_contents(self.output + '.h', u('').join(self.header).encode('utf-8'))
+ file_set_contents(self.output + '-body.h', u('').join(self.body).encode('utf-8'))
+ file_set_contents(self.output + '-gtk-doc.h', u('').join(self.docs).encode('utf-8'))
+
if __name__ == '__main__':
argv = sys.argv[1:]
dom = xml.dom.minidom.parse(argv[0])
GTypesGenerator(dom, argv[1], argv[2])()
diff --git a/tools/glib-interfaces-gen.py b/tools/glib-interfaces-gen.py
index 9543968..b67d7b4 100644
--- a/tools/glib-interfaces-gen.py
+++ b/tools/glib-interfaces-gen.py
@@ -1,119 +1,207 @@
#!/usr/bin/python
from sys import argv, stdout, stderr
import xml.dom.minidom
+from libtpcodegen import file_set_contents, u
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 + '_'
- self.impls = open(implfile, 'w')
- self.decls = open(declfile, 'w')
+
+ assert declfile.endswith('.h')
+ docfile = declfile[:-2] + '-gtk-doc.h'
+
+ self.implfile = implfile
+ self.declfile = declfile
+ self.docfile = docfile
+
+ self.impls = []
+ self.decls = []
+ self.docs = []
self.spec = get_by_path(dom, "spec")[0]
def h(self, code):
- self.decls.write(code.encode('utf-8'))
+ self.decls.append(code)
def c(self, code):
- self.impls.write(code.encode('utf-8'))
+ self.impls.append(code)
+
+ def d(self, code):
+ self.docs.append(code)
def __call__(self):
for f in self.h, self.c:
self.do_header(f)
self.do_body()
+ file_set_contents(self.implfile, u('').join(self.impls).encode('utf-8'))
+ file_set_contents(self.declfile, u('').join(self.decls).encode('utf-8'))
+ file_set_contents(self.docfile, u('').join(self.docs).encode('utf-8'))
+
# Header
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:
f(' version ' + get_descendant_text(version))
f('\n\n')
for copyright in get_by_path(self.spec, 'copyright'):
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("""
*/
+#include
""")
# Body
def do_body(self):
for iface in self.spec.getElementsByTagName('interface'):
self.do_iface(iface)
def do_iface(self, iface):
parent_name = get_by_path(iface, '../@name')
- self.h("""\
+ 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.h("""
+ 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 ())
GQuark %(iface_quark_func)s (void);
""" % {'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.c("""\
GQuark
%(iface_quark_func)s (void)
{
static GQuark quark = 0;
if (G_UNLIKELY (quark == 0))
{
quark = g_quark_from_static_string ("%(name)s");
}
return quark;
}
""" % {'iface_quark_func' : (self.prefix + 'iface_quark_' + \
parent_name).lower().replace('/', ''),
'name' : iface.getAttribute('name')})
for prop in iface.getElementsByTagNameNS(None, 'property'):
- self.decls.write("""
+ 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/libglibcodegen.py b/tools/libglibcodegen.py
index 6a9d214..5c76f07 100644
--- a/tools/libglibcodegen.py
+++ b/tools/libglibcodegen.py
@@ -1,172 +1,216 @@
"""Library code for GLib/D-Bus-related code generation.
The master copy of this library is in the telepathy-glib repository -
please make any changes there.
"""
# Copyright (C) 2006-2008 Collabora Limited
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from libtpcodegen import NS_TP, \
Signature, \
cmp_by_name, \
escape_as_identifier, \
get_by_path, \
get_descendant_text, \
get_docstring, \
xml_escape, \
get_deprecated
def dbus_gutils_wincaps_to_uscore(s):
"""Bug-for-bug compatible Python port of _dbus_gutils_wincaps_to_uscore
which gets sequences of capital letters wrong in the same way.
(e.g. in Telepathy, SendDTMF -> send_dt_mf)
"""
ret = ''
for c in s:
if c >= 'A' and c <= 'Z':
length = len(ret)
if length > 0 and (length < 2 or ret[length-2] != '_'):
ret += '_'
ret += c.lower()
else:
ret += c
return ret
def 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)
elif s == 'b': #boolean
return ("gboolean ", "G_TYPE_BOOLEAN","BOOLEAN", False)
elif s == 'n': #int16
return ("gint ", "G_TYPE_INT","INT", False)
elif s == 'q': #uint16
return ("guint ", "G_TYPE_UINT","UINT", False)
elif s == 'i': #int32
return ("gint ", "G_TYPE_INT","INT", False)
elif s == 'u': #uint32
return ("guint ", "G_TYPE_UINT","UINT", False)
elif s == 'x': #int64
return ("gint64 ", "G_TYPE_INT64","INT64", False)
elif s == 't': #uint64
return ("guint64 ", "G_TYPE_UINT64","UINT64", False)
elif s == 'd': #double
return ("gdouble ", "G_TYPE_DOUBLE","DOUBLE", False)
elif s == 's': #string
return ("gchar *", "G_TYPE_STRING", "STRING", True)
elif s == 'g': #signature - FIXME
return ("gchar *", "DBUS_TYPE_G_SIGNATURE", "STRING", True)
elif s == 'o': #object path
return ("gchar *", "DBUS_TYPE_G_OBJECT_PATH", "BOXED", True)
elif s == 'v': #variant
return ("GValue *", "G_TYPE_VALUE", "BOXED", True)
elif s == 'as': #array of strings
return ("gchar **", "G_TYPE_STRV", "BOXED", True)
elif s == 'ay': #byte array
return ("GArray *",
"dbus_g_type_get_collection (\"GArray\", G_TYPE_UCHAR)", "BOXED",
True)
elif s == 'au': #uint array
return ("GArray *", "DBUS_TYPE_G_UINT_ARRAY", "BOXED", True)
elif s == 'ai': #int array
return ("GArray *", "DBUS_TYPE_G_INT_ARRAY", "BOXED", True)
elif s == 'ax': #int64 array
return ("GArray *", "DBUS_TYPE_G_INT64_ARRAY", "BOXED", True)
elif s == 'at': #uint64 array
return ("GArray *", "DBUS_TYPE_G_UINT64_ARRAY", "BOXED", True)
elif s == 'ad': #double array
return ("GArray *", "DBUS_TYPE_G_DOUBLE_ARRAY", "BOXED", True)
elif s == 'ab': #boolean array
return ("GArray *", "DBUS_TYPE_G_BOOLEAN_ARRAY", "BOXED", True)
elif s == 'ao': #object path array
return ("GPtrArray *",
'dbus_g_type_get_collection ("GPtrArray",'
' DBUS_TYPE_G_OBJECT_PATH)',
"BOXED", True)
elif s == 'a{ss}': #hash table of string to string
return ("GHashTable *", "DBUS_TYPE_G_STRING_STRING_HASHTABLE", "BOXED", False)
elif s[:2] == 'a{': #some arbitrary hash tables
if s[2] not in ('y', 'b', 'n', 'q', 'i', 'u', 's', 'o', 'g'):
- raise Exception, "can't index a hashtable off non-basic type " + s
+ raise Exception("can't index a hashtable off non-basic type " + s)
first = type_to_gtype(s[2])
second = type_to_gtype(s[3:-1])
return ("GHashTable *", "(dbus_g_type_get_map (\"GHashTable\", " + first[1] + ", " + second[1] + "))", "BOXED", False)
elif s[:2] in ('a(', 'aa'): # array of structs or arrays, recurse
gtype = type_to_gtype(s[1:])[1]
return ("GPtrArray *", "(dbus_g_type_get_collection (\"GPtrArray\", "+gtype+"))", "BOXED", True)
elif s[:1] == '(': #struct
gtype = "(dbus_g_type_get_struct (\"GValueArray\", "
for subsig in Signature(s[1:-1]):
gtype = gtype + type_to_gtype(subsig)[1] + ", "
gtype = gtype + "G_TYPE_INVALID))"
return ("GValueArray *", gtype, "BOXED", True)
# we just don't know ..
- raise Exception, "don't know the GType for " + s
+ raise Exception("don't know the GType for " + s)
+
+def move_into_gvalue(gvaluep, gtype, marshaller, name):
+ if gtype == 'G_TYPE_STRING':
+ return 'g_value_take_string (%s, %s);' % (gvaluep, name)
+ elif marshaller == 'BOXED':
+ return 'g_value_take_boxed (%s, %s);' % (gvaluep, name)
+ elif gtype == 'G_TYPE_UCHAR':
+ return 'g_value_set_uchar (%s, %s);' % (gvaluep, name)
+ elif gtype == 'G_TYPE_BOOLEAN':
+ return 'g_value_set_boolean (%s, %s);' % (gvaluep, name)
+ elif gtype == 'G_TYPE_INT':
+ return 'g_value_set_int (%s, %s);' % (gvaluep, name)
+ elif gtype == 'G_TYPE_UINT':
+ return 'g_value_set_uint (%s, %s);' % (gvaluep, name)
+ elif gtype == 'G_TYPE_INT64':
+ return 'g_value_set_int (%s, %s);' % (gvaluep, name)
+ elif gtype == 'G_TYPE_UINT64':
+ return 'g_value_set_uint64 (%s, %s);' % (gvaluep, name)
+ elif gtype == 'G_TYPE_DOUBLE':
+ return 'g_value_set_double (%s, %s);' % (gvaluep, name)
+ else:
+ raise AssertionError("Don't know how to put %s in a GValue" % gtype)
+
+def copy_into_gvalue(gvaluep, gtype, marshaller, name):
+ if gtype == 'G_TYPE_STRING':
+ return 'g_value_set_string (%s, %s);' % (gvaluep, name)
+ elif marshaller == 'BOXED':
+ return 'g_value_set_boxed (%s, %s);' % (gvaluep, name)
+ elif gtype == 'G_TYPE_UCHAR':
+ return 'g_value_set_uchar (%s, %s);' % (gvaluep, name)
+ elif gtype == 'G_TYPE_BOOLEAN':
+ return 'g_value_set_boolean (%s, %s);' % (gvaluep, name)
+ elif gtype == 'G_TYPE_INT':
+ return 'g_value_set_int (%s, %s);' % (gvaluep, name)
+ elif gtype == 'G_TYPE_UINT':
+ return 'g_value_set_uint (%s, %s);' % (gvaluep, name)
+ elif gtype == 'G_TYPE_INT64':
+ return 'g_value_set_int (%s, %s);' % (gvaluep, name)
+ elif gtype == 'G_TYPE_UINT64':
+ return 'g_value_set_uint64 (%s, %s);' % (gvaluep, name)
+ elif gtype == 'G_TYPE_DOUBLE':
+ return 'g_value_set_double (%s, %s);' % (gvaluep, name)
+ else:
+ raise AssertionError("Don't know how to put %s in a GValue" % gtype)
diff --git a/tools/libqtcodegen.py b/tools/libqtcodegen.py
index 9ccb860..34d53a1 100644
--- a/tools/libqtcodegen.py
+++ b/tools/libqtcodegen.py
@@ -1,502 +1,502 @@
"""Library code for Qt D-Bus-related code generation.
The master copy of this library is in the telepathy-qt repository -
please make any changes there.
"""
# Copyright (C) 2008 Collabora Limited
# Copyright (C) 2008 Nokia Corporation
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-from sys import maxint, stderr
+from sys import maxsize, stderr
import re
from libtpcodegen import get_by_path, get_descendant_text, NS_TP, xml_escape
class Xzibit(Exception):
def __init__(self, parent, child):
self.parent = parent
self.child = child
def __str__(self):
- print """
+ print("""
Nested <%s>s are forbidden.
Parent:
%s...
Child:
%s...
""" % (self.parent.nodeName, self.parent.toxml()[:100],
- self.child.toxml()[:100])
+ self.child.toxml()[:100]))
class _QtTypeBinding:
def __init__(self, val, inarg, outarg, array_val, custom_type, array_of,
array_depth=None):
self.val = val
self.inarg = inarg
self.outarg = outarg
self.array_val = array_val
self.custom_type = custom_type
self.array_of = array_of
self.array_depth = array_depth
if array_depth is None:
self.array_depth = int(bool(array_val))
elif array_depth >= 1:
assert array_val
else:
assert not array_val
class RefTarget(object):
KIND_INTERFACE, KIND_METHOD, KIND_SIGNAL, KIND_PROPERTY = 'node', 'method', 'signal', 'property'
def __init__(self, el):
self.kind = el.localName
assert self.kind in (self.KIND_INTERFACE, self.KIND_METHOD, self.KIND_SIGNAL, self.KIND_PROPERTY)
if self.kind == self.KIND_INTERFACE:
self.dbus_text = el.getAttribute('name').lstrip('/').replace('_', '') + 'Interface'
else:
self.member_text = el.getAttribute('name')
assert el.parentNode.parentNode.localName == self.KIND_INTERFACE
host_class = el.parentNode.parentNode.getAttribute('name').lstrip('/').replace('_', '') + 'Interface'
if self.kind == self.KIND_PROPERTY:
self.member_link = 'requestProperty%s()' % (self.member_text)
self.dbus_link = '%s::%s' % (host_class, self.member_link)
else:
self.member_text = '%s()' % self.member_text
self.dbus_text = '%s::%s' % (host_class, self.member_text)
class RefRegistry(object):
def __init__(self, spec):
self.targets = {}
for node in spec.getElementsByTagName('node'):
iface, = get_by_path(node, 'interface')
iface_name = iface.getAttribute('name')
self.targets[iface_name] = RefTarget(node)
for method in iface.getElementsByTagName(RefTarget.KIND_METHOD):
self.targets[iface_name + '.' + method.getAttribute('name')] = RefTarget(method)
for signal in iface.getElementsByTagName(RefTarget.KIND_SIGNAL):
self.targets[iface_name + '.' + signal.getAttribute('name')] = RefTarget(signal)
for prop in iface.getElementsByTagName(RefTarget.KIND_PROPERTY):
self.targets[iface_name + '.' + prop.getAttribute('name')] = RefTarget(prop)
def process(self, ref):
assert ref.namespaceURI == NS_TP
def get_closest_parent(el, needle):
node = el
while node is not None and node.localName != needle:
node = node.parentNode
return node
local = get_descendant_text(ref).strip()
if ref.localName == 'member-ref':
ns = get_closest_parent(ref, 'interface').getAttribute('name')
path = ns + '.' + local.strip()
else:
if ref.hasAttribute('namespace'):
ns = ref.getAttribute('namespace').replace('ofdT', 'org.freedesktop.Telepathy')
path = ns + '.' + local.strip()
else:
path = local
target = self.targets.get(path)
if target is None:
parent = get_closest_parent(ref, 'interface') or get_closest_parent(ref, 'error')
parent_name = parent.getAttribute('name')
if (path + parent_name).find('.DRAFT') == -1 and (path + parent_name).find('.FUTURE') == -1:
- print >> stderr, 'WARNING: Failed to resolve %s to "%s" in "%s"' % (
- ref.localName, path, parent_name)
+ print(('WARNING: Failed to resolve %s to "%s" in "%s"' % (
+ ref.localName, path, parent_name)), file=stderr)
return path
if ref.localName == 'member-ref':
if target.kind == target.KIND_PROPERTY:
return '\\link %s %s \\endlink' % (target.member_link, target.member_text)
else:
return target.member_text
else:
if target.kind == target.KIND_PROPERTY:
return '\\link %s %s \\endlink' % (target.dbus_link, target.dbus_text)
else:
return target.dbus_text
def binding_from_usage(sig, tptype, custom_lists, external=False, explicit_own_ns=None):
# 'signature' : ('qt-type', 'pass-by-reference', 'array-type')
natives = {
'y' : ('uchar', False, None),
'b' : ('bool', False, 'BoolList'),
'n' : ('short', False, 'ShortList'),
'q' : ('ushort', False, 'UShortList'),
'i' : ('int', False, 'IntList'),
'u' : ('uint', False, 'UIntList'),
'x' : ('qlonglong', False, 'LongLongList'),
't' : ('qulonglong', False, 'ULongLongList'),
'd' : ('double', False, 'DoubleList'),
's' : ('QString', True, None),
'v' : ('QDBusVariant', True, None),
'o' : ('QDBusObjectPath', True, 'ObjectPathList'),
'g' : ('QDBusSignature', True, 'SignatureList'),
'as' : ('QStringList', True, "StringListList"),
'ay' : ('QByteArray', True, "ByteArrayList"),
'av' : ('QVariantList', True, "VariantListList"),
'a{sv}' : ('QVariantMap', True, None)
}
val, inarg = None, None
custom_type = False
array_of = None
- if natives.has_key(sig):
+ if sig in natives:
typename, pass_by_ref, array_name = natives[sig]
val = typename
inarg = (pass_by_ref and ('const %s&' % val)) or val
- elif sig[0] == 'a' and natives.has_key(sig[1:]) and natives[sig[1:]][2]:
+ elif sig[0] == 'a' and sig[1:] in natives and natives[sig[1:]][2]:
val = natives[sig[1:]][2]
if explicit_own_ns:
val = explicit_own_ns + '::' + val
inarg = 'const %s&' % val
array_of = natives[sig[1:]][0]
elif tptype:
tptype = tptype.replace('_', '')
custom_type = True
if external:
tptype = 'Tp::' + tptype
elif explicit_own_ns:
tptype = explicit_own_ns + '::' + tptype
if tptype.endswith('[]'):
tptype = tptype[:-2]
extra_list_nesting = 0
while tptype.endswith('[]'):
extra_list_nesting += 1
tptype = tptype[:-2]
- assert custom_lists.has_key(tptype), ('No array version of custom type %s in the spec, but array version used' % tptype)
+ assert tptype in custom_lists, ('No array version of custom type %s in the spec, but array version used' % tptype)
val = custom_lists[tptype] + 'List' * extra_list_nesting
else:
val = tptype
inarg = 'const %s&' % val
else:
assert False, 'Don\'t know how to map type (%s, %s)' % (sig, tptype)
outarg = val + '&'
return _QtTypeBinding(val, inarg, outarg, None, custom_type, array_of)
def binding_from_decl(name, array_name, array_depth=None, external=False, explicit_own_ns=''):
val = name.replace('_', '')
if external:
val = 'Tp::' + val
elif explicit_own_ns:
val = explicit_own_ns + '::' + val
inarg = 'const %s&' % val
outarg = '%s&' % val
return _QtTypeBinding(val, inarg, outarg, array_name.replace('_', ''), True, None, array_depth)
def extract_arg_or_member_info(els, custom_lists, externals, typesns, refs, docstring_indent=' * ', docstring_brackets=None, docstring_maxwidth=80):
names = []
docstrings = []
bindings = []
for el in els:
names.append(get_qt_name(el))
docstrings.append(format_docstring(el, refs, docstring_indent, docstring_brackets, docstring_maxwidth))
sig = el.getAttribute('type')
tptype = el.getAttributeNS(NS_TP, 'type')
bindings.append(binding_from_usage(sig, tptype, custom_lists, (sig, tptype) in externals, typesns))
return names, docstrings, bindings
def format_docstring(el, refs, indent=' * ', brackets=None, maxwidth=80):
docstring_el = None
for x in el.childNodes:
if x.namespaceURI == NS_TP and x.localName == 'docstring':
docstring_el = x
if not docstring_el:
return ''
lines = []
# escape backslashes, so they won't be interpreted starting doxygen commands and we can later
# insert doxygen commands we actually want
def escape_slashes(x):
if x.nodeType == x.TEXT_NODE:
x.data = x.data.replace('\\', '\\\\')
elif x.nodeType == x.ELEMENT_NODE:
for y in x.childNodes:
escape_slashes(y)
else:
return
escape_slashes(docstring_el)
doc = docstring_el.ownerDocument
for n in docstring_el.getElementsByTagNameNS(NS_TP, 'rationale'):
nested = n.getElementsByTagNameNS(NS_TP, 'rationale')
if nested:
raise Xzibit(n, nested[0])
div = doc.createElement('div')
div.setAttribute('class', 'rationale')
for rationale_body in n.childNodes:
div.appendChild(rationale_body.cloneNode(True))
n.parentNode.replaceChild(div, n)
if docstring_el.getAttribute('xmlns') == 'http://www.w3.org/1999/xhtml':
for ref in docstring_el.getElementsByTagNameNS(NS_TP, 'member-ref') + docstring_el.getElementsByTagNameNS(NS_TP, 'dbus-ref'):
nested = ref.getElementsByTagNameNS(NS_TP, 'member-ref') + ref.getElementsByTagNameNS(NS_TP, 'dbus-ref')
if nested:
raise Xzibit(n, nested[0])
text = doc.createTextNode(' \\endhtmlonly ')
text.data += refs.process(ref)
text.data += ' \\htmlonly '
ref.parentNode.replaceChild(text, ref)
splitted = ''.join([el.toxml() for el in docstring_el.childNodes]).strip(' ').strip('\n').split('\n')
- level = min([not match and maxint or match.end() - 1 for match in [re.match('^ *[^ ]', line) for line in splitted]])
- assert level != maxint
+ level = min([not match and maxsize or match.end() - 1 for match in [re.match('^ *[^ ]', line) for line in splitted]])
+ assert level != maxsize
lines = ['\\htmlonly'] + [line[level:] for line in splitted] + ['\\endhtmlonly']
else:
content = xml_escape(get_descendant_text(docstring_el).replace('\n', ' ').strip())
while content.find(' ') != -1:
content = content.replace(' ', ' ')
left = maxwidth - len(indent) - 1
line = ''
while content:
step = (content.find(' ') + 1) or len(content)
if step > left:
lines.append(line)
line = ''
left = maxwidth - len(indent) - 1
left = left - step
line = line + content[:step]
content = content[step:]
if line:
lines.append(line)
output = []
if lines:
if brackets:
output.append(brackets[0])
else:
output.append(indent)
output.append('\n')
for line in lines:
output.append(indent)
output.append(line)
output.append('\n')
if lines and brackets:
output.append(brackets[1])
output.append('\n')
return ''.join(output)
def gather_externals(spec):
externals = []
for ext in spec.getElementsByTagNameNS(NS_TP, 'external-type'):
sig = ext.getAttribute('type')
tptype = ext.getAttribute('name')
externals.append((sig, tptype))
return externals
def gather_custom_lists(spec, typesns):
custom_lists = {}
structs = [(provider, typesns) for provider in spec.getElementsByTagNameNS(NS_TP, 'struct')]
mappings = [(provider, typesns) for provider in spec.getElementsByTagNameNS(NS_TP, 'mapping')]
exts = [(provider, 'Telepathy') for provider in spec.getElementsByTagNameNS(NS_TP, 'external-type')]
for (provider, ns) in structs + mappings + exts:
tptype = provider.getAttribute('name').replace('_', '')
array_val = provider.getAttribute('array-name').replace('_', '')
array_depth = provider.getAttribute('array-depth')
if array_depth:
array_depth = int(array_depth)
else:
- array_depth = None
+ array_depth = -1
if array_val:
custom_lists[tptype] = array_val
custom_lists[ns + '::' + tptype] = ns + '::' + array_val
if array_depth >= 2:
- for i in xrange(array_depth):
+ for i in range(array_depth):
custom_lists[tptype + ('[]' * (i+1))] = (
array_val + ('List' * i))
custom_lists[ns + '::' + tptype + ('[]' * (i+1))] = (
ns + '::' + array_val + ('List' * i))
return custom_lists
def get_headerfile_cmd(realinclude, prettyinclude, indent=' * '):
prettyinclude = prettyinclude or realinclude
if realinclude:
if prettyinclude:
return indent + ('\\headerfile %s <%s>\n' % (realinclude, prettyinclude))
else:
return indent + ('\\headerfile %s <%s>\n' % (realinclude))
else:
return ''
def get_qt_name(el):
name = el.getAttribute('name')
if el.localName in ('method', 'signal', 'property'):
bname = el.getAttributeNS(NS_TP, 'name-for-bindings')
if bname:
name = bname
if not name:
return None
if name[0].isupper() and name[1].islower():
name = name[0].lower() + name[1:]
return qt_identifier_escape(name.replace('_', ''))
def qt_identifier_escape(str):
built = (str[0].isdigit() and ['_']) or []
for c in str:
if c.isalnum():
built.append(c)
else:
built.append('_')
str = ''.join(built)
# List of reserved identifiers
# Initial list from http://cs.smu.ca/~porter/csc/ref/cpp_keywords.html
# Keywords inherited from C90
reserved = ['auto',
'const',
'double',
'float',
'int',
'short',
'struct',
'unsigned',
'break',
'continue',
'else',
'for',
'long',
'signed',
'switch',
'void',
'case',
'default',
'enum',
'goto',
'register',
'sizeof',
'typedef',
'volatile',
'char',
'do',
'extern',
'if',
'return',
'static',
'union',
'while',
# C++-only keywords
'asm',
'dynamic_cast',
'namespace',
'reinterpret_cast',
'try',
'bool',
'explicit',
'new',
'static_cast',
'typeid',
'catch',
'false',
'operator',
'template',
'typename',
'class',
'friend',
'private',
'this',
'using',
'const_cast',
'inline',
'public',
'throw',
'virtual',
'delete',
'mutable',
'protected',
'true',
'wchar_t',
# Operator replacements
'and',
'bitand',
'compl',
'not_eq',
'or_eq',
'xor_eq',
'and_eq',
'bitor',
'not',
'or',
'xor',
# Predefined identifiers
'INT_MIN',
'INT_MAX',
'MAX_RAND',
'NULL',
# Qt
'SIGNAL',
'SLOT',
'signals',
'slots']
while str in reserved:
str = str + '_'
return str
diff --git a/tools/libtpcodegen.py b/tools/libtpcodegen.py
index 837ff2f..99de663 100644
--- a/tools/libtpcodegen.py
+++ b/tools/libtpcodegen.py
@@ -1,215 +1,247 @@
"""Library code for language-independent D-Bus-related code generation.
The master copy of this library is in the telepathy-glib repository -
please make any changes there.
"""
# Copyright (C) 2006-2008 Collabora Limited
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
+import os
+import sys
from string import ascii_letters, digits
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)
+ except OSError:
+ pass
+ try:
+ os.remove(filename + '.tmp')
+ except OSError:
+ pass
+
+ 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
name component, using a reversible encoding to ensure uniqueness.
The reversible encoding is as follows:
* The empty string becomes '_'
* Otherwise, each non-alphanumeric character is replaced by '_' plus
two lower-case hex digits; the same replacement is carried out on
the first character, if it's a digit
"""
# '' -> '_'
if not identifier:
return '_'
# A bit of a fast path for strings which are already OK.
# We deliberately omit '_' because, for reversibility, that must also
# be escaped.
if (identifier.strip(_ASCII_ALNUM) == '' and
identifier[0] in ascii_letters):
return identifier
# The first character may not be a digit
if identifier[0] not in ascii_letters:
ret = ['_%02x' % ord(identifier[0])]
else:
ret = [identifier[0]]
# Subsequent characters may be digits or ASCII letters
for c in identifier[1:]:
if c in _ASCII_ALNUM:
ret.append(c)
else:
ret.append('_%02x' % ord(c))
return ''.join(ret)
def get_by_path(element, path):
branches = path.split('/')
branch = branches[0]
# Is the current branch an attribute, if so, return the attribute value
if branch[0] == '@':
return element.getAttribute(branch[1:])
# Find matching children for the branch
children = []
if branch == '..':
children.append(element.parentNode)
else:
for x in element.childNodes:
if x.localName == branch:
children.append(x)
ret = []
# If this is not the last path element, recursively gather results from
# children
if len(branches) > 1:
for x in children:
add = get_by_path(x, '/'.join(branches[1:]))
if isinstance(add, list):
ret += add
else:
return add
else:
ret = children
return ret
def get_docstring(element):
docstring = None
for x in element.childNodes:
if x.namespaceURI == NS_TP and x.localName == 'docstring':
docstring = x
if docstring is not None:
docstring = docstring.toxml().replace('\n', ' ').strip()
if docstring.startswith(''):
docstring = docstring[14:].lstrip()
if docstring.endswith(''):
docstring = docstring[:-15].rstrip()
if docstring in ('', ''):
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:
return ''
if isinstance(element_or_elements, list):
return ''.join(map(get_descendant_text, element_or_elements))
parts = []
for x in element_or_elements.childNodes:
if x.nodeType == x.TEXT_NODE:
parts.append(x.nodeValue)
elif x.nodeType == x.ELEMENT_NODE:
parts.append(get_descendant_text(x))
else:
pass
return ''.join(parts)
class _SignatureIter:
"""Iterator over a D-Bus signature. Copied from dbus-python 0.71 so we
can run genginterface in a limited environment with only Python
(like Scratchbox).
"""
def __init__(self, string):
self.remaining = string
def next(self):
+ return self.__next__()
+
+ def __next__(self):
if self.remaining == '':
raise StopIteration
signature = self.remaining
block_depth = 0
block_type = None
end = len(signature)
for marker in range(0, end):
cur_sig = signature[marker]
if cur_sig == 'a':
pass
elif cur_sig == '{' or cur_sig == '(':
if block_type == None:
block_type = cur_sig
if block_type == cur_sig:
block_depth = block_depth + 1
elif cur_sig == '}':
if block_type == '{':
block_depth = block_depth - 1
if block_depth == 0:
end = marker
break
elif cur_sig == ')':
if block_type == '(':
block_depth = block_depth - 1
if block_depth == 0:
end = marker
break
else:
if block_depth == 0:
end = marker
break
end = end + 1
self.remaining = signature[end:]
return Signature(signature[0:end])
class Signature(str):
"""A string, iteration over which is by D-Bus single complete types
rather than characters.
"""
def __iter__(self):
return _SignatureIter(self)
def xml_escape(s):
s = s.replace('&', '&').replace("'", ''').replace('"', '"')
return s.replace('<', '<').replace('>', '>')
diff --git a/tools/manager-file.py b/tools/manager-file.py
index 45f6404..5e61c75 100644
--- a/tools/manager-file.py
+++ b/tools/manager-file.py
@@ -1,175 +1,188 @@
#!/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
+import os
_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
+ print('[ConnectionManager]', file=f)
+ print('BusName=org.freedesktop.Telepathy.ConnectionManager.' + manager, file=f)
+ print('ObjectPath=/org/freedesktop/Telepathy/ConnectionManager/' + manager, file=f)
# protocols
- for proto, params in protos.iteritems():
- print >> f
- print >> f, '[Protocol %s]' % proto
+ for proto, params in protos.items():
+ print(file=f)
+ print('[Protocol %s]' % proto, file=f)
defaults = {}
- for param, info in params.iteritems():
+ for param, info in params.items():
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)
+ print('param-%s=%s%s' % (param, desktop_string(dtype), flags), file=f)
- for param, default in defaults.iteritems():
- print >> f, 'default-%s=%s' % (param, default)
+ for param, default in defaults.items():
+ print('default-%s=%s' % (param, default), file=f)
def write_c_params(f, manager, proto, struct, params):
- print >> f, "static const TpCMParamSpec %s_%s_params[] = {" % (manager, proto)
+ print("static const TpCMParamSpec %s_%s_params[] = {" % (manager, proto), file=f)
- for param, info in params.iteritems():
+ for param, info in params.items():
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,
+ print((''' { %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))
+ default, struct_offset, filter, filter_data, setter_data)), file=f)
- print >> f, " { NULL }"
- print >> f, "};"
+ print(" { NULL }", file=f)
+ print("};", file=f)
if __name__ == '__main__':
environment = {}
- execfile(sys.argv[1], environment)
-
- f = open('%s/%s.manager' % (sys.argv[2], environment['MANAGER']), 'w')
+ exec(compile(open(sys.argv[1], "rb").read(), sys.argv[1], 'exec'), environment)
+
+ filename = '%s/%s.manager' % (sys.argv[2], environment['MANAGER'])
+ try:
+ os.remove(filename)
+ except OSError:
+ pass
+ f = open(filename + '.tmp', 'w')
write_manager(f, environment['MANAGER'], environment['PARAMS'])
f.close()
-
- f = open('%s/param-spec-struct.h' % sys.argv[2], 'w')
+ os.rename(filename + '.tmp', filename)
+
+ filename = '%s/param-spec-struct.h' % sys.argv[2]
+ try:
+ os.remove(filename)
+ except OSError:
+ pass
+ f = open(filename + '.tmp', 'w')
for protocol in environment['PARAMS']:
write_c_params(f, environment['MANAGER'], protocol,
environment['STRUCTS'][protocol],
environment['PARAMS'][protocol])
f.close()
+ os.rename(filename + '.tmp', filename)
diff --git a/tools/qt-client-gen.py b/tools/qt-client-gen.py
index d79ac30..b58ecd8 100644
--- a/tools/qt-client-gen.py
+++ b/tools/qt-client-gen.py
@@ -1,547 +1,548 @@
#!/usr/bin/python
#
# Copyright (C) 2008 Collabora Limited
# Copyright (C) 2008 Nokia Corporation
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from sys import argv
import xml.dom.minidom
import codecs
from getopt import gnu_getopt
+import functools
from libtpcodegen import NS_TP, get_descendant_text, get_by_path
from libqtcodegen import binding_from_usage, extract_arg_or_member_info, format_docstring, gather_externals, gather_custom_lists, get_headerfile_cmd, get_qt_name, qt_identifier_escape, RefRegistry
class Generator(object):
def __init__(self, opts):
try:
self.group = opts.get('--group', '')
self.headerfile = opts['--headerfile']
self.implfile = opts['--implfile']
self.namespace = opts['--namespace']
self.typesnamespace = opts['--typesnamespace']
self.realinclude = opts['--realinclude']
self.prettyinclude = opts.get('--prettyinclude')
self.extraincludes = opts.get('--extraincludes', None)
self.mainiface = opts.get('--mainiface', None)
self.must_define = opts.get('--must-define', None)
self.dbus_proxy = opts.get('--dbus-proxy',
'Tp::DBusProxy')
self.visibility = opts.get('--visibility', '')
ifacedom = xml.dom.minidom.parse(opts['--ifacexml'])
specdom = xml.dom.minidom.parse(opts['--specxml'])
- except KeyError, k:
+ except KeyError as k:
assert False, 'Missing required parameter %s' % k.args[0]
self.hs = []
self.bs = []
self.ifacenodes = ifacedom.getElementsByTagName('node')
self.spec, = get_by_path(specdom, "spec")
self.custom_lists = gather_custom_lists(self.spec, self.typesnamespace)
self.externals = gather_externals(self.spec)
self.refs = RefRegistry(self.spec)
def __call__(self):
# Output info header and includes
self.h("""\
/*
* This file contains D-Bus client proxy classes generated by qt-client-gen.py.
*
* This file can be distributed under the same terms as the specification from
* which it was generated.
*/
""")
if self.must_define:
self.h('\n')
self.h('#ifndef %s\n' % self.must_define)
self.h('#error %s\n' % self.must_define)
self.h('#endif\n')
self.h('\n')
if self.extraincludes:
for include in self.extraincludes.split(','):
self.h('#include %s\n' % include)
self.h("""
#include
#include
#include
#include
#include
#include
#include
#include
namespace Tp
{
class PendingVariant;
class PendingOperation;
}
""")
if self.must_define:
self.b("""#define %s\n""" % (self.must_define))
self.b("""#include "%s"
""" % self.realinclude)
# Begin namespace
for ns in self.namespace.split('::'):
self.hb("""\
namespace %s
{
""" % ns)
# Output interface proxies
def ifacenodecmp(x, y):
- xname, yname = [self.namespace + '::' + node.getAttribute('name').replace('/', '').replace('_', '') + 'Interface' for node in x, y]
+ xname, yname = [self.namespace + '::' + node.getAttribute('name').replace('/', '').replace('_', '') + 'Interface' for node in (x, y)]
if xname == self.mainiface:
return -1
elif yname == self.mainiface:
return 1
else:
- return cmp(xname, yname)
+ return (xname > yname) - (xname < yname)
- self.ifacenodes.sort(cmp=ifacenodecmp)
+ self.ifacenodes.sort(key=functools.cmp_to_key(ifacenodecmp))
for ifacenode in self.ifacenodes:
self.do_ifacenode(ifacenode)
# End namespace
self.hb(''.join(['}\n' for ns in self.namespace.split('::')]))
# Add metatype declaration - otherwise QTBUG #2151 might be triggered
for ifacenode in self.ifacenodes:
classname = ifacenode.getAttribute('name').replace('/', '').replace('_', '') + 'Interface'
self.h("Q_DECLARE_METATYPE(" + self.namespace + "::" + classname + "*)\n")
# Write output to files
- (codecs.getwriter('utf-8')(open(self.headerfile, 'w'))).write(''.join(self.hs))
- (codecs.getwriter('utf-8')(open(self.implfile, 'w'))).write(''.join(self.bs))
+ (codecs.getwriter('utf-8')(open(self.headerfile, 'wb'))).write(''.join(self.hs))
+ (codecs.getwriter('utf-8')(open(self.implfile, 'wb'))).write(''.join(self.bs))
def do_ifacenode(self, ifacenode):
# Extract info
name = ifacenode.getAttribute('name').replace('/', '').replace('_', '') + 'Interface'
iface, = get_by_path(ifacenode, 'interface')
dbusname = iface.getAttribute('name')
# Begin class, constructors
self.h("""
/**
* \\class %(name)s
%(headercmd)s\
%(groupcmd)s\
*
* Proxy class providing a 1:1 mapping of the D-Bus interface "%(dbusname)s".
*/
class %(visibility)s %(name)s : public Tp::AbstractInterface
{
Q_OBJECT
public:
/**
* Returns the name of the interface "%(dbusname)s", which this class
* represents.
*
* \\return The D-Bus interface name.
*/
static inline QLatin1String staticInterfaceName()
{
return QLatin1String("%(dbusname)s");
}
/**
* Creates a %(name)s associated with the given object on the session bus.
*
* \\param busName Name of the service the object is on.
* \\param objectPath Path to the object on the service.
* \\param parent Passed to the parent class constructor.
*/
%(name)s(
const QString& busName,
const QString& objectPath,
QObject* parent = 0
);
/**
* Creates a %(name)s associated with the given object on the given bus.
*
* \\param connection The bus via which the object can be reached.
* \\param busName Name of the service the object is on.
* \\param objectPath Path to the object on the service.
* \\param parent Passed to the parent class constructor.
*/
%(name)s(
const QDBusConnection& connection,
const QString& busName,
const QString& objectPath,
QObject* parent = 0
);
""" % {'name' : name,
'headercmd' : get_headerfile_cmd(self.realinclude, self.prettyinclude),
'groupcmd' : self.group and (' * \\ingroup %s\n' % self.group),
'dbusname' : dbusname,
'visibility': self.visibility,
})
self.b("""
%(name)s::%(name)s(const QString& busName, const QString& objectPath, QObject *parent)
: Tp::AbstractInterface(busName, objectPath, staticInterfaceName(), QDBusConnection::sessionBus(), parent)
{
}
%(name)s::%(name)s(const QDBusConnection& connection, const QString& busName, const QString& objectPath, QObject *parent)
: Tp::AbstractInterface(busName, objectPath, staticInterfaceName(), connection, parent)
{
}
""" % {'name' : name})
# Construct from DBusProxy subclass
self.h("""
/**
* Creates a %(name)s associated with the same object as the given proxy.
*
* \\param proxy The proxy to use. It will also be the QObject::parent()
* for this object.
*/
%(name)s(%(dbus_proxy)s *proxy);
""" % {'name' : name,
'dbus_proxy' : self.dbus_proxy})
self.b("""
%(name)s::%(name)s(%(dbus_proxy)s *proxy)
: Tp::AbstractInterface(proxy, staticInterfaceName())
{
}
""" % {'name' : name,
'dbus_proxy' : self.dbus_proxy})
# Main interface
mainiface = self.mainiface or 'Tp::AbstractInterface'
if mainiface != self.namespace + '::' + name:
self.h("""
/**
* Creates a %(name)s associated with the same object as the given proxy.
* Additionally, the created proxy will have the same parent as the given
* proxy.
*
* \\param mainInterface The proxy to use.
*/
explicit %(name)s(const %(mainiface)s& mainInterface);
/**
* Creates a %(name)s associated with the same object as the given proxy.
* However, a different parent object can be specified.
*
* \\param mainInterface The proxy to use.
* \\param parent Passed to the parent class constructor.
*/
%(name)s(const %(mainiface)s& mainInterface, QObject* parent);
""" % {'name' : name,
'mainiface' : mainiface})
self.b("""
%(name)s::%(name)s(const %(mainiface)s& mainInterface)
: Tp::AbstractInterface(mainInterface.service(), mainInterface.path(), staticInterfaceName(), mainInterface.connection(), mainInterface.parent())
{
}
%(name)s::%(name)s(const %(mainiface)s& mainInterface, QObject *parent)
: Tp::AbstractInterface(mainInterface.service(), mainInterface.path(), staticInterfaceName(), mainInterface.connection(), parent)
{
}
""" % {'name' : name,
'mainiface' : mainiface})
# Properties
has_props = False
for prop in get_by_path(iface, 'property'):
# Skip tp:properties
if not prop.namespaceURI:
self.do_prop(prop)
has_props = True
self.h("""
/**
* Request all of the DBus properties on the interface.
*
* \\return A pending variant map which will emit finished when the properties have
* been retrieved.
*/
Tp::PendingVariantMap *requestAllProperties() const
{
return internalRequestAllProperties();
}
""")
# Methods
methods = get_by_path(iface, 'method')
if methods:
self.h("""
public Q_SLOTS:\
""")
for method in methods:
self.do_method(method)
# Signals
signals = get_by_path(iface, 'signal')
if signals:
self.h("""
Q_SIGNALS:\
""")
for signal in signals:
self.do_signal(signal)
# invalidated handler (already a slot in the superclass)
# we can't just use disconnect(this, NULL, NULL, NULL) because
# (a) that would disconnect QObject::destroyed() and other non-D-Bus
# signals, and (b) QtDBus doesn't support that usage anyway (it needs
# specific signals in order to remove its signal match rules)
self.h("""
protected:
virtual void invalidate(Tp::DBusProxy *, const QString &, const QString &);
""")
self.b("""
void %(name)s::invalidate(Tp::DBusProxy *proxy,
const QString &error, const QString &message)
{
""" % {'name' : name})
for signal in signals:
self.do_signal_disconnect(signal)
self.b("""
Tp::AbstractInterface::invalidate(proxy, error, message);
}
""")
# Close class
self.h("""\
};
""")
def do_prop(self, prop):
name = prop.getAttribute('name')
access = prop.getAttribute('access')
gettername = name
settername = None
docstring = format_docstring(prop, self.refs, ' * ').replace('*/', '*/')
sig = prop.getAttribute('type')
tptype = prop.getAttributeNS(NS_TP, 'type')
binding = binding_from_usage(sig, tptype, self.custom_lists, (sig, tptype) in self.externals, self.typesnamespace)
if 'write' in access:
settername = 'set' + name
if 'read' in access:
self.h("""
/**
* Asynchronous getter for the remote object property \\c %(name)s of type \\c %(val)s.
*
%(docstring)s\
*
* \\return A pending variant which will emit finished when the property has been
* retrieved.
*/
inline Tp::PendingVariant *%(gettername)s() const
{
return internalRequestProperty(QLatin1String("%(name)s"));
}
""" % {'name' : name,
'docstring' : docstring,
'val' : binding.val,
'gettername' : 'requestProperty' + name})
if 'write' in access:
self.h("""
/**
* Asynchronous setter for the remote object property \\c %(name)s of type \\c %(type)s.
*
%(docstring)s\
*
* \\return A pending operation which will emit finished when the property has been
* set.
*/
inline Tp::PendingOperation *%(settername)s(%(type)s newValue)
{
return internalSetProperty(QLatin1String("%(name)s"), QVariant::fromValue(newValue));
}
""" % {'name' : name,
'docstring' : docstring,
'type' : binding.val,
'name' : name,
'settername' : 'setProperty' + name})
def do_method(self, method):
name = method.getAttribute('name')
args = get_by_path(method, 'arg')
argnames, argdocstrings, argbindings = extract_arg_or_member_info(args, self.custom_lists,
self.externals, self.typesnamespace, self.refs, ' * ')
inargs = []
outargs = []
- for i in xrange(len(args)):
+ for i in range(len(args)):
if args[i].getAttribute('direction') == 'out':
outargs.append(i)
else:
inargs.append(i)
assert argnames[i] != None, 'No argument name for input argument at index %d for method %s' % (i, name)
rettypes = ', '.join([argbindings[i].val for i in outargs])
params = ', '.join([argbindings[i].inarg + ' ' + argnames[i] for i in inargs])
if params:
params += ', int timeout = -1'
else:
params = 'int timeout = -1'
self.h("""
/**
* Begins a call to the D-Bus method \\c %s on the remote object.
%s\
*
* Note that \\a timeout is ignored as of now. It will be used once
* http://bugreports.qt.nokia.com/browse/QTBUG-11775 is fixed.
*
""" % (name, format_docstring(method, self.refs, ' * ')))
for i in inargs:
if argdocstrings[i]:
self.h("""\
*
* \\param %s
%s\
""" % (argnames[i], argdocstrings[i]))
self.h("""\
* \\param timeout The timeout in milliseconds.
""")
for i in outargs:
if argdocstrings[i]:
self.h("""\
*
* \\return
%s\
""" % argdocstrings[i])
self.h("""\
*/
inline QDBusPendingReply<%(rettypes)s> %(name)s(%(params)s)
{
if (!invalidationReason().isEmpty()) {
return QDBusPendingReply<%(rettypes)s>(QDBusMessage::createError(
invalidationReason(),
invalidationMessage()
));
}
""" % {'rettypes' : rettypes,
'name' : name,
'params' : params})
if inargs:
self.h("""
QDBusMessage callMessage = QDBusMessage::createMethodCall(this->service(), this->path(),
this->staticInterfaceName(), QLatin1String("%s"));
callMessage << %s;
return this->connection().asyncCall(callMessage, timeout);
}
""" % (name, ' << '.join(['QVariant::fromValue(%s)' % argnames[i] for i in inargs])))
else:
self.h("""
QDBusMessage callMessage = QDBusMessage::createMethodCall(this->service(), this->path(),
this->staticInterfaceName(), QLatin1String("%s"));
return this->connection().asyncCall(callMessage, timeout);
}
""" % name)
def do_signal(self, signal):
name = signal.getAttribute('name')
argnames, argdocstrings, argbindings = extract_arg_or_member_info(get_by_path(signal,
'arg'), self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ')
self.h("""
/**
* Represents the signal \\c %s on the remote object.
%s\
""" % (name, format_docstring(signal, self.refs, ' * ')))
- for i in xrange(len(argnames)):
+ for i in range(len(argnames)):
assert argnames[i] != None, 'Name missing from argument at index %d for signal %s' % (i, name)
if argdocstrings[i]:
self.h("""\
*
* \\param %s
%s\
""" % (argnames[i], argdocstrings[i]))
self.h("""\
*/
void %s(%s);
""" % (name, ', '.join(['%s %s' % (binding.inarg, name) for binding, name in zip(argbindings, argnames)])))
def do_signal_disconnect(self, signal):
name = signal.getAttribute('name')
_, _, argbindings = extract_arg_or_member_info(get_by_path(signal, 'arg'),
self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ')
self.b("""\
disconnect(this, SIGNAL(%s(%s)), NULL, NULL);
""" % (name, ', '.join([binding.inarg for binding in argbindings])))
def h(self, str):
self.hs.append(str)
def b(self, str):
self.bs.append(str)
def hb(self, str):
self.h(str)
self.b(str)
if __name__ == '__main__':
options, argv = gnu_getopt(argv[1:], '',
['group=',
'namespace=',
'typesnamespace=',
'headerfile=',
'implfile=',
'ifacexml=',
'specxml=',
'realinclude=',
'prettyinclude=',
'extraincludes=',
'mainiface=',
'must-define=',
'dbus-proxy=',
'visibility='])
Generator(dict(options))()
diff --git a/tools/qt-constants-gen.py b/tools/qt-constants-gen.py
index 48fdc43..c96949b 100644
--- a/tools/qt-constants-gen.py
+++ b/tools/qt-constants-gen.py
@@ -1,310 +1,313 @@
#!/usr/bin/python
#
# Copyright (C) 2008 Collabora Limited
# Copyright (C) 2008 Nokia Corporation
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from sys import argv, stdout, stderr
import codecs
import xml.dom.minidom
from getopt import gnu_getopt
from libtpcodegen import NS_TP, get_descendant_text, get_by_path
from libqtcodegen import format_docstring, RefRegistry
class Generator(object):
def __init__(self, opts):
try:
self.namespace = opts['--namespace']
self.must_define = opts.get('--must-define', None)
dom = xml.dom.minidom.parse(opts['--specxml'])
- except KeyError, k:
+ except KeyError as k:
assert False, 'Missing required parameter %s' % k.args[0]
self.define_prefix = None
if '--define-prefix' in opts:
self.define_prefix = opts['--define-prefix']
self.old_prefix = None
if '--str-constant-prefix' in opts:
self.old_prefix = opts['--str-constant-prefix']
self.spec = get_by_path(dom, "spec")[0]
self.out = codecs.getwriter('utf-8')(stdout)
self.refs = RefRegistry(self.spec)
def h(self, code):
- self.out.write(code)
+ if isinstance(code, str):
+ self.out.buffer.write(code.encode('utf8'))
+ else:
+ self.out.buffer.write(code)
def __call__(self):
# Header
self.h('/* Generated from ')
self.h(get_descendant_text(get_by_path(self.spec, 'title')))
version = get_by_path(self.spec, "version")
if version:
self.h(', version ' + get_descendant_text(version))
self.h("""
*/
""")
if self.must_define:
self.h("""
#ifndef %s
#error %s
#endif
""" % (self.must_define, self.must_define))
self.h("""
#include
/**
* \\addtogroup typesconstants Types and constants
*
* Enumerated, flag, structure, list and mapping types and utility constants.
*/
/**
* \\defgroup flagtypeconsts Flag type constants
* \\ingroup typesconstants
*
* Types generated from the specification representing bit flag constants and
* combinations of them (bitfields).
*/
/**
* \\defgroup enumtypeconsts Enumerated type constants
* \\ingroup typesconstants
*
* Types generated from the specification representing enumerated types ie.
* types the values of which are mutually exclusive integral constants.
*/
/**
* \\defgroup ifacestrconsts Interface string constants
* \\ingroup typesconstants
*
* D-Bus interface names of the interfaces in the specification.
*/
/**
* \\defgroup errorstrconsts Error string constants
* \\ingroup typesconstants
*
* Names of the D-Bus errors in the specification.
*/
""")
# Begin namespace
self.h("""
namespace %s
{
""" % self.namespace)
# Flags
for flags in self.spec.getElementsByTagNameNS(NS_TP, 'flags'):
self.do_flags(flags)
# Enums
for enum in self.spec.getElementsByTagNameNS(NS_TP, 'enum'):
self.do_enum(enum)
# End namespace
self.h("""\
}
""")
# Interface names
for iface in self.spec.getElementsByTagName('interface'):
if self.old_prefix:
self.h("""\
/**
* \\ingroup ifacestrconsts
*
* The interface name "%(name)s".
*/
#define %(DEFINE)s "%(name)s"
""" % {'name' : iface.getAttribute('name'),
'DEFINE' : self.old_prefix + 'INTERFACE_' + get_by_path(iface, '../@name').upper().replace('/', '')})
if self.define_prefix:
self.h("""\
/**
* \\ingroup ifacestrconsts
*
* The interface name "%(name)s" as a QLatin1String, usable in QString requiring contexts even when
* building with Q_NO_CAST_FROM_ASCII defined.
*/
#define %(DEFINE)s (QLatin1String("%(name)s"))
""" % {'name' : iface.getAttribute('name'),
'DEFINE' : self.define_prefix + 'IFACE_' + get_by_path(iface, '../@name').upper().replace('/', '')})
# Error names
for error in get_by_path(self.spec, 'errors/error'):
name = error.getAttribute('name')
fullname = get_by_path(error, '../@namespace') + '.' + name.replace(' ', '')
if self.old_prefix:
define = self.old_prefix + 'ERROR_' + name.replace(' ', '_').replace('.', '_').upper()
self.h("""\
/**
* \\ingroup errorstrconsts
*
* The error name "%(fullname)s".
%(docstring)s\
*/
#define %(DEFINE)s "%(fullname)s"
""" % {'fullname' : fullname,
'docstring': format_docstring(error, self.refs),
'DEFINE' : define})
if self.define_prefix:
define = self.define_prefix + 'ERROR_' + name.replace(' ', '_').replace('.', '_').upper()
self.h("""\
/**
* \\ingroup errorstrconsts
*
* The error name "%(fullname)s" as a QLatin1String, usable in QString requiring contexts even when
* building with Q_NO_CAST_FROM_ASCII defined.
%(docstring)s\
*/
#define %(DEFINE)s QLatin1String("%(fullname)s")
""" % {'fullname' : fullname,
'docstring': format_docstring(error, self.refs),
'DEFINE' : define})
def do_flags(self, flags):
singular = flags.getAttribute('singular') or \
flags.getAttribute('value-prefix')
using_name = False
if not singular:
using_name = True
singular = flags.getAttribute('name')
if singular.endswith('lags'):
singular = singular[:-1]
if using_name and singular.endswith('s'):
singular = singular[:-1]
singular = singular.replace('_', '')
plural = (flags.getAttribute('plural') or flags.getAttribute('name') or singular + 's').replace('_', '')
self.h("""\
/**
* \\ingroup flagtypeconsts
*
* Flag type generated from the specification.
*/
enum %(singular)s
{
""" % {'singular' : singular})
flagvalues = get_by_path(flags, 'flag')
for flag in flagvalues:
self.do_val(flag, singular, flag == flagvalues[-1])
self.h("""\
%s = 0xffffffffU
""" % ("_" + singular + "Padding"))
self.h("""\
};
/**
* \\typedef QFlags<%(singular)s> %(plural)s
* \\ingroup flagtypeconsts
*
* Type representing combinations of #%(singular)s values.
%(docstring)s\
*/
typedef QFlags<%(singular)s> %(plural)s;
Q_DECLARE_OPERATORS_FOR_FLAGS(%(plural)s)
""" % {'singular' : singular, 'plural' : plural, 'docstring' : format_docstring(flags, self.refs)})
def do_enum(self, enum):
singular = enum.getAttribute('singular') or \
enum.getAttribute('name')
value_prefix = enum.getAttribute('singular') or \
enum.getAttribute('value-prefix') or \
enum.getAttribute('name')
if singular.endswith('lags'):
singular = singular[:-1]
plural = enum.getAttribute('plural') or singular + 's'
singular = singular.replace('_', '')
value_prefix = value_prefix.replace('_', '')
vals = get_by_path(enum, 'enumvalue')
self.h("""\
/**
* \\enum %(singular)s
* \\ingroup enumtypeconsts
*
* Enumerated type generated from the specification.
%(docstring)s\
*/
enum %(singular)s
{
""" % {'singular' : singular, 'docstring' : format_docstring(enum, self.refs)})
for val in vals:
self.do_val(val, value_prefix, val == vals[-1])
self.h("""\
%s = 0xffffffffU
};
""" % ("_" + singular + "Padding"))
self.h("""\
/**
* \\ingroup enumtypeconsts
*
* 1 higher than the highest valid value of %(singular)s.
*/
const int NUM_%(upper-plural)s = (%(last-val)s+1);
""" % {'singular' : singular,
'upper-plural' : plural.upper(),
'last-val' : vals[-1].getAttribute('value')})
def do_val(self, val, prefix, last):
name = (val.getAttribute('suffix') or val.getAttribute('name')).replace('_', '')
self.h("""\
%s\
%s = %s,
""" % (format_docstring(val, self.refs, indent=' * ', brackets=(' /**', ' */')), prefix + name, val.getAttribute('value')))
if __name__ == '__main__':
options, argv = gnu_getopt(argv[1:], '',
['namespace=',
'str-constant-prefix=',
'define-prefix=',
'must-define=',
'specxml='])
Generator(dict(options))()
diff --git a/tools/qt-svc-gen.py b/tools/qt-svc-gen.py
index 58b77bb..565dd01 100644
--- a/tools/qt-svc-gen.py
+++ b/tools/qt-svc-gen.py
@@ -1,742 +1,743 @@
#!/usr/bin/python
#
# Copyright (C) 2012 Collabora Limited
# Copyright (C) 2012 Nokia Corporation
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from sys import argv
import xml.dom.minidom
import codecs
from getopt import gnu_getopt
+import functools
from libtpcodegen import NS_TP, get_descendant_text, get_by_path
from libqtcodegen import binding_from_usage, extract_arg_or_member_info, format_docstring, gather_externals, gather_custom_lists, get_headerfile_cmd, get_qt_name, qt_identifier_escape, RefRegistry
# TODO generate docstrings
def to_lower_camel_case(s):
if len(s) <= 1:
return s.lower()
i = 0
for c in s:
if c == '_':
break
i += 1
ret = s
if i == len(s):
return s.lower()
else:
ret = s[0:i].lower() + s[i:]
ret = ret.replace('_', '')
return ret
class Generator(object):
def __init__(self, opts):
try:
self.group = opts.get('--group', '')
self.headerfile = opts['--headerfile']
self.implfile = opts['--implfile']
self.namespace = opts['--namespace']
self.typesnamespace = opts['--typesnamespace']
self.realinclude = opts.get('--realinclude', None)
self.mocinclude = opts.get('--mocinclude', None)
self.prettyinclude = opts.get('--prettyinclude')
self.extraincludes = opts.get('--extraincludes', None)
self.must_define = opts.get('--must-define', None)
self.visibility = opts.get('--visibility', '')
ifacedom = xml.dom.minidom.parse(opts['--ifacexml'])
specdom = xml.dom.minidom.parse(opts['--specxml'])
- except KeyError, k:
+ except KeyError as k:
assert False, 'Missing required parameter %s' % k.args[0]
if not self.realinclude:
self.realinclude = self.headerfile
self.hs = []
self.bs = []
self.ifacenodes = ifacedom.getElementsByTagName('node')
self.spec, = get_by_path(specdom, "spec")
self.custom_lists = gather_custom_lists(self.spec, self.typesnamespace)
self.externals = gather_externals(self.spec)
self.refs = RefRegistry(self.spec)
def __call__(self):
# Output info header and includes
self.h("""\
/*
* This file contains D-Bus adaptor classes generated by qt-svc-gen.py.
*
* This file can be distributed under the same terms as the specification from
* which it was generated.
*/
""")
if self.must_define:
self.h('\n')
self.h('#ifndef %s\n' % self.must_define)
self.h('#error %s\n' % self.must_define)
self.h('#endif\n')
self.h('\n')
if self.extraincludes:
for include in self.extraincludes.split(','):
self.h('#include %s\n' % include)
self.h("""\
#include
#include
#include
#include
#include
""")
if self.must_define:
self.b("""#define %s\n""" % (self.must_define))
self.b("""#include "%s"
""" % self.realinclude)
if self.mocinclude:
self.b("""#include "%s"
""" % self.mocinclude)
self.b("""\
#include
#include
""")
# Begin namespace
for ns in self.namespace.split('::'):
self.hb("""\
namespace %s
{
""" % ns)
# Output interface proxies
def ifacenodecmp(x, y):
- xname, yname = [self.namespace + '::' + node.getAttribute('name').replace('/', '').replace('_', '') + 'Adaptor' for node in x, y]
+ xname, yname = [self.namespace + '::' + node.getAttribute('name').replace('/', '').replace('_', '') + 'Adaptor' for node in (x, y)]
- return cmp(xname, yname)
+ return (xname > yname) - (xname < yname)
- self.ifacenodes.sort(cmp=ifacenodecmp)
+ self.ifacenodes.sort(key=functools.cmp_to_key(ifacenodecmp))
for ifacenode in self.ifacenodes:
self.do_ifacenode(ifacenode)
# End namespace
self.hb(''.join(['\n}' for ns in self.namespace.split('::')]))
# Write output to files
- (codecs.getwriter('utf-8')(open(self.headerfile, 'w'))).write(''.join(self.hs))
- (codecs.getwriter('utf-8')(open(self.implfile, 'w'))).write(''.join(self.bs))
+ (codecs.getwriter('utf-8')(open(self.headerfile, 'wb'))).write(''.join(self.hs))
+ (codecs.getwriter('utf-8')(open(self.implfile, 'wb'))).write(''.join(self.bs))
def do_ifacenode(self, ifacenode):
# Extract info
name = ifacenode.getAttribute('name').replace('/', '').replace('_', '') + 'Adaptor'
iface, = get_by_path(ifacenode, 'interface')
dbusname = iface.getAttribute('name')
props = get_by_path(iface, 'property')
methods = get_by_path(iface, 'method')
signals = get_by_path(iface, 'signal')
# Begin class, constructors
self.h("""
/**
* \\class %(name)s
%(headercmd)s\
%(groupcmd)s\
*
* Adaptor class providing a 1:1 mapping of the D-Bus interface "%(dbusname)s".
*/
class %(visibility)s %(name)s : public Tp::AbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "%(dbusname)s")
Q_CLASSINFO("D-Bus Introspection", ""
" \\n"
""" % {'name': name,
'headercmd': get_headerfile_cmd(self.realinclude, self.prettyinclude),
'groupcmd': self.group and (' * \\ingroup %s\n' % self.group),
'dbusname': dbusname,
'visibility': self.visibility,
})
self.do_introspection(props, methods, signals)
self.h("""\
" \\n"
"")
""")
self.do_qprops(props)
self.h("""
public:
%(name)s(const QDBusConnection& dbusConnection, QObject* adaptee, QObject* parent);
virtual ~%(name)s();
""" % {'name': name})
self.do_mic_typedefs(methods)
self.b("""
%(name)s::%(name)s(const QDBusConnection& bus, QObject* adaptee, QObject* parent)
: Tp::AbstractAdaptor(bus, adaptee, parent)
{
""" % {'name': name})
self.do_signals_connect(signals)
self.b("""\
}
%(name)s::~%(name)s()
{
}
""" % {'name': name})
# Properties
has_props = False
if props:
self.h("""
public: // PROPERTIES
""")
for prop in props:
# Skip tp:properties
if not prop.namespaceURI:
self.do_prop(name, prop)
has_props = True
# Methods
if methods:
self.h("""
public Q_SLOTS: // METHODS
""")
for method in methods:
self.do_method(name, method)
# Signals
if signals:
self.h("""
Q_SIGNALS: // SIGNALS
""")
for signal in signals:
self.do_signal(signal)
# Close class
self.h("""\
};
""")
def do_introspection(self, props, methods, signals):
self.do_prop_introspection(props)
self.do_method_introspection(methods)
self.do_signal_introspection(signals)
def do_prop_introspection(self, props):
for prop in props:
if prop.namespaceURI:
continue
name = prop.getAttribute('name')
access = prop.getAttribute('access')
sig = prop.getAttribute('type')
tptype = prop.getAttributeNS(NS_TP, 'type')
binding = binding_from_usage(sig, tptype, self.custom_lists, (sig, tptype) in self.externals, self.typesnamespace)
if not binding.custom_type:
self.h("""\
" \\n"
""" % {'access': access,
'sig': sig,
'name': name,
})
else:
self.h("""\
" \\n"
" \\n"
" \\n"
""" % {'access': access,
'sig': sig,
'name': name,
'type': binding.val,
})
def do_method_introspection(self, methods):
for method in methods:
name = method.getAttribute('name')
args = get_by_path(method, 'arg')
argnames, argdocstrings, argbindings = extract_arg_or_member_info(args,
self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ')
if not argnames:
self.h("""\
" \\n"
""" % {'name': name})
else:
self.h("""\
" \\n"
""" % {'name': name})
outindex = 0
inindex = 0
- for i in xrange(len(argnames)):
+ for i in range(len(argnames)):
assert argnames[i] != None, 'Name missing from argument at index %d for signal %s' % (i, name)
argbinding = argbindings[i]
argname = argnames[i]
argsig = args[i].getAttribute('type')
argdirection = args[i].getAttribute('direction')
# QtDBus requires annotating a{sv}
if argsig == 'a{sv}':
argbinding.custom_type = True
if not argbinding.custom_type:
self.h("""\
" \\n"
""" % {'direction': argdirection,
'sig': argsig,
'name': argname})
else:
self.h("""\
" \\n"
" \\n"
" \\n"
""" % {'direction': argdirection,
'sig': argsig,
'name': argname,
'type': argbinding.val,
'index': 'In' + str(inindex) if argdirection == 'in' else 'Out' + str(outindex),
})
if argdirection == 'out':
outindex += 1
else:
inindex += 1
self.h("""\
" \\n"
""")
def do_signal_introspection(self, signals):
for signal in signals:
name = signal.getAttribute('name')
args = get_by_path(signal, 'arg')
argnames, argdocstrings, argbindings = extract_arg_or_member_info(args,
self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ')
if not argnames:
self.h("""\
" \\n"
""" % {'name': name})
else:
self.h("""\
" \\n"
""" % {'name': name})
- for i in xrange(len(argnames)):
+ for i in range(len(argnames)):
assert argnames[i] != None, 'Name missing from argument at index %d for signal %s' % (i, name)
argbinding = argbindings[i]
argname = argnames[i]
argsig = args[i].getAttribute('type')
if not argbinding.custom_type:
self.h("""\
" \\n"
""" % {'sig': argsig,
'name': argname})
else:
self.h("""\
" \\n"
" \\n"
" \\n"
""" % {'sig': argsig,
'name': argname,
'type': argbinding.val,
'index': i,
})
self.h("""\
" \\n"
""")
def do_mic_typedefs(self, methods):
for method in methods:
name = method.getAttribute('name')
args = get_by_path(method, 'arg')
argnames, argdocstrings, argbindings = extract_arg_or_member_info(args, self.custom_lists,
self.externals, self.typesnamespace, self.refs, ' * ')
outargs = []
- for i in xrange(len(args)):
+ for i in range(len(args)):
if args[i].getAttribute('direction') == 'out':
outargs.append(i)
if outargs:
outargtypes = ', '.join([argbindings[i].val for i in outargs])
else:
outargtypes = ''
self.h("""\
typedef Tp::MethodInvocationContextPtr< %(outargtypes)s > %(name)sContextPtr;
""" % {'name': name,
'outargtypes': outargtypes,
})
def do_qprops(self, props):
for prop in props:
# Skip tp:properties
if not prop.namespaceURI:
self.do_qprop(prop)
def do_qprop(self, prop):
name = prop.getAttribute('name')
access = prop.getAttribute('access')
gettername = name
settername = None
if 'write' in access:
settername = 'Set' + name
sig = prop.getAttribute('type')
tptype = prop.getAttributeNS(NS_TP, 'type')
binding = binding_from_usage(sig, tptype, self.custom_lists, (sig, tptype) in self.externals, self.typesnamespace)
self.h("""\
Q_PROPERTY(%(type)s %(name)s %(getter)s %(setter)s)
""" % {'type': binding.val,
'name': name,
'getter': 'READ ' + gettername if ('read' in access) else '',
'setter': 'WRITE ' + settername if ('write' in access) else '',
})
def do_prop(self, ifacename, prop):
name = prop.getAttribute('name')
adaptee_name = to_lower_camel_case(prop.getAttribute('tp:name-for-bindings'))
access = prop.getAttribute('access')
gettername = name
settername = None
if 'write' in access:
settername = 'Set' + name
docstring = format_docstring(prop, self.refs, ' * ').replace('*/', '*/')
sig = prop.getAttribute('type')
tptype = prop.getAttributeNS(NS_TP, 'type')
binding = binding_from_usage(sig, tptype, self.custom_lists, (sig, tptype) in self.externals, self.typesnamespace)
if 'read' in access:
self.h("""\
/**
* Return the value of the exported D-Bus object property \\c %(name)s of type \\c %(type)s.
*
* Adaptees should export this property as a Qt property named
* '%(adaptee_name)s' with type %(type)s.
*
%(docstring)s\
*
* \\return The value of exported property \\c %(name)s.
*/
%(type)s %(gettername)s() const;
""" % {'name': name,
'adaptee_name': adaptee_name,
'docstring': docstring,
'type': binding.val,
'gettername': gettername,
})
self.b("""
%(type)s %(ifacename)s::%(gettername)s() const
{
return qvariant_cast< %(type)s >(adaptee()->property("%(adaptee_name)s"));
}
""" % {'type': binding.val,
'ifacename': ifacename,
'gettername': gettername,
'adaptee_name': adaptee_name,
})
if 'write' in access:
self.h("""\
/**
* Set the value of the exported D-Bus object property \\c %(name)s of type \\c %(type)s.
*
* Adaptees should export this property as a writable Qt property named
* '%(adaptee_name)s' with type %(type)s.
*
%(docstring)s\
*/
void %(settername)s(const %(type)s &newValue);
""" % {'name': name,
'adaptee_name': adaptee_name,
'docstring': docstring,
'settername': settername,
'type': binding.val,
})
self.b("""
void %(ifacename)s::%(settername)s(const %(type)s &newValue)
{
adaptee()->setProperty("%(adaptee_name)s", qVariantFromValue(newValue));
}
""" % {'ifacename': ifacename,
'settername': settername,
'type': binding.val,
'adaptee_name': adaptee_name,
})
def do_method(self, ifacename, method):
name = method.getAttribute('name')
adaptee_name = to_lower_camel_case(method.getAttribute('tp:name-for-bindings'))
args = get_by_path(method, 'arg')
argnames, argdocstrings, argbindings = extract_arg_or_member_info(args, self.custom_lists,
self.externals, self.typesnamespace, self.refs, ' * ')
docstring = format_docstring(method, self.refs, ' * ').replace('*/', '*/')
inargs = []
outargs = []
- for i in xrange(len(args)):
+ for i in range(len(args)):
if args[i].getAttribute('direction') == 'out':
outargs.append(i)
else:
inargs.append(i)
assert argnames[i] != None, 'No argument name for input argument at index %d for method %s' % (i, name)
if outargs:
rettype = argbindings[outargs[0]].val
else:
rettype = 'void'
params = [argbindings[i].inarg + ' ' + argnames[i] for i in inargs]
params.append('const QDBusMessage& dbusMessage')
params += [argbindings[i].outarg + ' ' + argnames[i] for i in outargs[1:]]
params = ', '.join(params)
if outargs:
outargtypes = ', '.join([argbindings[i].val for i in outargs])
else:
outargtypes = ''
invokemethodargs = ', '.join(['Q_ARG(' + argbindings[i].val + ', ' + argnames[i] + ')' for i in inargs])
inparams = [argbindings[i].val for i in inargs]
inparams.append("%s::%s::%sContextPtr" % (self.namespace, ifacename, name))
normalized_adaptee_params = ','.join(inparams)
adaptee_params = [argbindings[i].inarg + ' ' + argnames[i] for i in inargs]
adaptee_params.append('const %(namespace)s::%(ifacename)s::%(name)sContextPtr &context' %
{'namespace': self.namespace,
'ifacename': ifacename,
'name': name})
adaptee_params = ', '.join(adaptee_params)
self.h("""\
/**
* Begins a call to the exported D-Bus method \\c %(name)s on this object.
*
* Adaptees should export this method as a Qt slot with the following signature:
* void %(adaptee_name)s(%(adaptee_params)s);
*
* Implementations should call MethodInvocationContext::setFinished (or setFinishedWithError
* accordingly) on the received \\a context object once the method has finished processing.
*
%(docstring)s\
*
""" % {'name': name,
'adaptee_name': adaptee_name,
'adaptee_params': adaptee_params,
'rettype': rettype,
'docstring': docstring
})
for i in inargs:
if argdocstrings[i]:
self.h("""\
* \\param %s
%s\
""" % (argnames[i], argdocstrings[i]))
for i in outargs[1:]:
if argdocstrings[i]:
self.h("""\
* \\param %s Output parameter
%s\
""" % (argnames[i], argdocstrings[i]))
if outargs:
self.h("""\
* \\return
%s\
""" % argdocstrings[outargs[0]])
self.h("""\
*/
%(rettype)s %(name)s(%(params)s);
""" % {'rettype': rettype,
'name': name,
'params': params
})
self.b("""
%(rettype)s %(ifacename)s::%(name)s(%(params)s)
{
- if (!adaptee()->metaObject()->indexOfMethod("%(adaptee_name)s(%(normalized_adaptee_params)s)") == -1) {
+ if (adaptee()->metaObject()->indexOfMethod("%(adaptee_name)s(%(normalized_adaptee_params)s)") < 0) {
dbusConnection().send(dbusMessage.createErrorReply(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")));
""" % {'rettype': rettype,
'ifacename': ifacename,
'name': name,
'adaptee_name': adaptee_name,
'normalized_adaptee_params': normalized_adaptee_params,
'params': params,
})
if rettype != 'void':
self.b("""\
return %(rettype)s();
""" % {'rettype': rettype})
else:
self.b("""\
return;
""")
self.b("""\
}
%(name)sContextPtr ctx = %(name)sContextPtr(
new Tp::MethodInvocationContext< %(outargtypes)s >(dbusConnection(), dbusMessage));
""" % {'name': name,
'outargtypes': outargtypes,
})
if invokemethodargs:
self.b("""\
QMetaObject::invokeMethod(adaptee(), "%(adaptee_name)s",
%(invokemethodargs)s,
Q_ARG(%(namespace)s::%(ifacename)s::%(name)sContextPtr, ctx));
""" % {'namespace': self.namespace,
'ifacename': ifacename,
'name': name,
'adaptee_name': adaptee_name,
'invokemethodargs': invokemethodargs,
})
else:
self.b("""\
QMetaObject::invokeMethod(adaptee(), "%(lname)s",
Q_ARG(%(namespace)s::%(ifacename)s::%(name)sContextPtr, ctx));
""" % {'namespace': self.namespace,
'ifacename': ifacename,
'name': name,
'lname': (name[0].lower() + name[1:]),
})
if rettype != 'void':
self.b("""\
return %(rettype)s();
""" % {'rettype': rettype})
self.b("}\n")
def do_signal(self, signal):
name = signal.getAttribute('name')
adaptee_name = to_lower_camel_case(signal.getAttribute('tp:name-for-bindings'))
argnames, argdocstrings, argbindings = extract_arg_or_member_info(get_by_path(signal,
'arg'), self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ')
params = ', '.join(['%s %s' % (binding.inarg, param_name) for binding, param_name in zip(argbindings, argnames)])
- for i in xrange(len(argnames)):
+ for i in range(len(argnames)):
assert argnames[i] != None, 'Name missing from argument at index %d for signal %s' % (i, name)
self.h("""\
/**
* Represents the exported D-Bus signal \\c %(name)s on this object.
*
* Adaptees should export this signal as a Qt signal with the following signature:
* void %(adaptee_name)s(%(params)s);
*
* The adaptee signal will be automatically relayed as a D-Bus signal once emitted.
*
""" % {'name': name,
'adaptee_name': adaptee_name,
'params': params
})
- for i in xrange(len(argnames)):
+ for i in range(len(argnames)):
assert argnames[i] != None, 'Name missing from argument at index %d for signal %s' % (i, name)
if argdocstrings[i]:
self.h("""\
* \\param %s
%s\
""" % (argnames[i], argdocstrings[i]))
self.h("""\
*/
void %(name)s(%(params)s);
""" % {'name': name,
'params': params
})
def do_signals_connect(self, signals):
for signal in signals:
name = signal.getAttribute('name')
adaptee_name = to_lower_camel_case(signal.getAttribute('tp:name-for-bindings'))
_, _, argbindings = extract_arg_or_member_info(get_by_path(signal, 'arg'),
self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ')
self.b("""\
connect(adaptee, SIGNAL(%(adaptee_name)s(%(params)s)), SIGNAL(%(name)s(%(params)s)));
""" % {'name': name,
'adaptee_name': adaptee_name,
'params': ', '.join([binding.inarg for binding in argbindings])
})
def h(self, str):
self.hs.append(str)
def b(self, str):
self.bs.append(str)
def hb(self, str):
self.h(str)
self.b(str)
if __name__ == '__main__':
options, argv = gnu_getopt(argv[1:], '',
['group=',
'headerfile=',
'implfile=',
'namespace=',
'typesnamespace=',
'realinclude=',
'mocinclude=',
'prettyinclude=',
'extraincludes=',
'must-define=',
'visibility=',
'ifacexml=',
'specxml='])
Generator(dict(options))()
diff --git a/tools/qt-types-gen.py b/tools/qt-types-gen.py
index 119cf9c..1ade9da 100644
--- a/tools/qt-types-gen.py
+++ b/tools/qt-types-gen.py
@@ -1,557 +1,591 @@
#!/usr/bin/python
#
# Copyright (C) 2008 Collabora Limited
# Copyright (C) 2008 Nokia Corporation
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import sys
import xml.dom.minidom
from getopt import gnu_getopt
from libtpcodegen import NS_TP, get_descendant_text, get_by_path
from libqtcodegen import binding_from_usage, binding_from_decl, extract_arg_or_member_info, format_docstring, gather_externals, gather_custom_lists, get_qt_name, get_headerfile_cmd, RefRegistry
class BrokenSpecException(Exception):
pass
class MissingTypes(BrokenSpecException):
def __init__(self, types):
super(MissingTypes, self).__init__(self)
self.types = types
def __str__(self):
typelist = ''.join([' %s' % t for t in self.types])
return "The following types were used, but not provided by the spec " \
"or by declarations in all.xml:\n%s" % typelist
class UnresolvedDependency(BrokenSpecException):
def __init__(self, child, parent):
super(UnresolvedDependency, self).__init__(self)
self.child = child
self.parent = parent
def __str__(self):
return 'Type %s has unresolved dependency on %s' % (
self.child, self.parent)
class EmptyStruct(BrokenSpecException):
def __init__(self, struct_name):
super(EmptyStruct, self).__init__(self)
self.struct_name = struct_name
def __str__(self):
return 'tp:struct %s should have some members' % self.struct_name
class MalformedMapping(BrokenSpecException):
def __init__(self, mapping_name, members):
super(MalformedMapping, self).__init__(self)
self.mapping_name = mapping_name
self.members = members
def __str__(self):
return 'tp:mapping %s should have 2 members, not %u' % (
self.mapping_name, self.members)
class WTF(BrokenSpecException):
def __init__(self, element_name):
super(BrokenSpecException, self).__init__(self)
self.element_name = element_name
def __str__(self):
return 'What the hell is a tp:%s?' % self.element_name
class DepInfo:
def __init__(self, el, externals, custom_lists):
self.el = el
name = get_by_path(el, '@name')
array_name = get_by_path(el, '@array-name')
array_depth = get_by_path(el, '@array-depth')
if array_depth:
array_depth = int(array_depth)
else:
array_depth = None
self.binding = binding_from_decl(name, array_name, array_depth)
self.deps = []
for member in get_by_path(el, 'member'):
sig = member.getAttribute('type')
tptype = member.getAttributeNS(NS_TP, 'type')
if (sig, tptype) in externals:
continue
if tptype.endswith('[]'):
tptype = tptype[:-2]
binding = binding_from_usage(sig, tptype, custom_lists)
if binding.custom_type:
self.deps.append(binding.val)
self.revdeps = []
class Generator(object):
def __init__(self, opts):
try:
self.namespace = opts['--namespace']
self.declfile = opts['--declfile']
self.implfile = opts['--implfile']
self.realinclude = opts['--realinclude']
self.prettyinclude = opts.get('--prettyinclude', self.realinclude)
self.extraincludes = opts.get('--extraincludes', None)
self.must_define = opts.get('--must-define', None)
self.visibility = opts.get('--visibility', '')
dom = xml.dom.minidom.parse(opts['--specxml'])
- except KeyError, k:
+ except KeyError as k:
assert False, 'Missing required parameter %s' % k.args[0]
self.decls = []
self.impls = []
self.spec = get_by_path(dom, "spec")[0]
self.externals = gather_externals(self.spec)
self.custom_lists = gather_custom_lists(self.spec, self.namespace)
self.required_custom = []
self.required_arrays = []
self.to_declare = []
self.depinfos = {}
self.refs = RefRegistry(self.spec)
def __call__(self):
# Emit comment header
self.both('/* Generated from ')
self.both(get_descendant_text(get_by_path(self.spec, 'title')))
version = get_by_path(self.spec, "version")
if version:
self.both(', version ' + get_descendant_text(version))
self.both(' */\n')
# Gather info on available and required types
self.gather_required()
if self.must_define:
self.decl('\n')
self.decl('#ifndef %s\n' % self.must_define)
self.decl('#error %s\n' % self.must_define)
self.decl('#endif')
self.decl('\n')
if self.extraincludes:
for include in self.extraincludes.split(','):
self.decl('#include %s\n' % include)
self.decl("""
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/**
* \\addtogroup typesconstants Types and constants
*
* Enumerated, flag, structure, list and mapping types and utility constants.
*/
/**
* \\defgroup struct Structure types
* \\ingroup typesconstants
*
* Structure types generated from the specification.
*/
/**
* \\defgroup list List types
* \\ingroup typesconstants
*
* List types generated from the specification.
*/
/**
* \\defgroup mapping Mapping types
* \\ingroup typesconstants
*
* Mapping types generated from the specification.
*/
""")
if self.must_define:
self.impl("""
#define %s""" % self.must_define)
self.impl("""
#include "%s"
""" % self.realinclude)
self.both("""
namespace %s
{
""" % self.namespace)
# Emit type definitions for types provided in the spec
self.provide_all()
# Emit type registration function
self.decl("""
} // namespace %s
""" % self.namespace)
self.impl("""\
TP_QT_NO_EXPORT void _registerTypes()
{
static bool registered = false;
if (registered)
return;
registered = true;
""")
# Emit Qt metatype declarations
self.to_declare.sort()
for metatype in self.to_declare:
self.decl('Q_DECLARE_METATYPE(%s)\n' % metatype)
self.impl(' qDBusRegisterMetaType<%s>();\n' % ((metatype.endswith('>') and metatype + ' ') or metatype))
self.impl("""\
}
} // namespace %s
""" % self.namespace)
# Write output to files
- open(self.declfile, 'w').write(''.join(self.decls).encode("utf-8"))
- open(self.implfile, 'w').write(''.join(self.impls).encode("utf-8"))
+ open(self.declfile, 'wb').write(''.join(self.decls).encode("utf-8"))
+ open(self.implfile, 'wb').write(''.join(self.impls).encode("utf-8"))
def decl(self, str):
self.decls.append(str)
def impl(self, str):
self.impls.append(str)
def both(self, str):
self.decl(str)
self.impl(str)
def gather_required(self):
members = self.spec.getElementsByTagNameNS(NS_TP, 'member')
args = self.spec.getElementsByTagName('arg')
props = self.spec.getElementsByTagName('property')
tp_props = self.spec.getElementsByTagNameNS(NS_TP, 'property')
for requirer in members + args + props + tp_props:
sig = requirer.getAttribute('type')
tptype = requirer.getAttributeNS(NS_TP, 'type')
external = (sig, tptype) in self.externals
binding = binding_from_usage(sig, tptype, self.custom_lists, external)
if binding.custom_type and binding.val not in self.required_custom:
self.required_custom.append(binding.val)
if not binding.custom_type and binding.array_of and (binding.val, binding.array_of) not in self.required_arrays:
self.required_arrays.append((binding.val, binding.array_of))
def provide_all(self):
self.required_arrays.sort()
for (val, array_of) in self.required_arrays:
real = 'QList<%s>' % array_of
self.decl("""\
/**
* \\struct %s
* \\ingroup list
%s\
*
* Generic list type with %s elements. Convertible with
* %s, but needed to have a discrete type in the Qt type system.
*/
""" % (val, get_headerfile_cmd(self.realinclude, self.prettyinclude), array_of, real))
self.decl(self.faketype(val, real))
self.to_declare.append(self.namespace + '::' + val)
+ self.both('%s QDBusArgument& operator<<(QDBusArgument& arg, const %s &list)' %
+ (self.visibility, val))
+ self.decl(';\n')
+ self.impl("""
+{
+ int id = qMetaTypeId<%s>();
+ arg.beginArray(id);
+ for (int i = 0; i < list.count(); ++i) {
+ arg << list.at(i);
+ }
+ arg.endArray();
+ return arg;
+}
+
+""" % (array_of))
+
+ self.both('%s const QDBusArgument& operator>>(const QDBusArgument& arg, %s &list)' %
+ (self.visibility, val))
+ self.decl(';\n\n')
+ self.impl("""
+{
+ arg.beginArray();
+ list.clear();
+ while (!arg.atEnd()) {
+ %s item;
+ arg >> item;
+ list.append(item);
+ }
+ arg.endArray();
+ return arg;
+}
+
+""" % (array_of))
+
structs = self.spec.getElementsByTagNameNS(NS_TP, 'struct')
mappings = self.spec.getElementsByTagNameNS(NS_TP, 'mapping')
exts = self.spec.getElementsByTagNameNS(NS_TP, 'external-type')
for deptype in structs + mappings:
info = DepInfo(deptype, self.externals, self.custom_lists)
self.depinfos[info.binding.val] = info
leaves = []
next_leaves = []
- for val, depinfo in self.depinfos.iteritems():
+ for val, depinfo in self.depinfos.items():
leaf = True
for dep in depinfo.deps:
- if not self.depinfos.has_key(dep):
+ if dep not in self.depinfos:
raise UnresolvedDependency(val, dep)
leaf = False
self.depinfos[dep].revdeps.append(val)
if leaf:
next_leaves.append(val)
while leaves or next_leaves:
if not leaves:
leaves = next_leaves
leaves.sort()
next_leaves = []
val = leaves.pop(0)
depinfo = self.depinfos[val]
self.output_by_depinfo(depinfo)
for revdep in depinfo.revdeps:
revdepinfo = self.depinfos[revdep]
revdepinfo.deps.remove(val)
if not revdepinfo.deps:
next_leaves.append(revdep)
del self.depinfos[val]
for provider in structs + mappings + exts:
name = get_by_path(provider, '@name')
array_name = get_by_path(provider, '@array-name')
array_depth = get_by_path(provider, '@array-depth')
if array_depth:
array_depth = int(array_depth)
else:
array_depth = None
sig = provider.getAttribute('type')
tptype = provider.getAttribute('name')
external = (sig, tptype) in self.externals
binding = binding_from_decl(name, array_name, array_depth, external)
self.provide(binding.val)
if binding.array_val:
self.provide(binding.array_val)
d = binding.array_depth
while d > 1:
d -= 1
self.provide(binding.array_val + ('List' * d))
if self.required_custom:
raise MissingTypes(self.required_custom)
def provide(self, type):
if type in self.required_custom:
self.required_custom.remove(type)
def output_by_depinfo(self, depinfo):
names, docstrings, bindings = extract_arg_or_member_info(get_by_path(depinfo.el, 'member'), self.custom_lists, self.externals, None, self.refs, ' * ', (' /**', ' */'))
members = len(names)
if depinfo.el.localName == 'struct':
if members == 0:
raise EmptyStruct(depinfo.binding.val)
self.decl("""\
/**
* \\struct %(name)s
* \\ingroup struct
%(headercmd)s\
*
* Structure type generated from the specification.
%(docstring)s\
*/
struct %(visibility)s %(name)s
{
""" % {
'name' : depinfo.binding.val,
'headercmd': get_headerfile_cmd(self.realinclude, self.prettyinclude),
'docstring' : format_docstring(depinfo.el, self.refs),
'visibility': self.visibility,
})
- for i in xrange(members):
+ for i in range(members):
self.decl("""\
%s\
%s %s;
""" % (docstrings[i], bindings[i].val, names[i]))
self.decl("""\
};
""")
self.both('%s bool operator==(%s v1, %s v2)' %
(self.visibility,
depinfo.binding.inarg,
depinfo.binding.inarg))
self.decl(';\n')
self.impl("""
{""")
if (bindings[0].val != 'QDBusVariant'):
self.impl("""
return ((v1.%s == v2.%s)""" % (names[0], names[0]))
else:
self.impl("""
return ((v1.%s.variant() == v2.%s.variant())""" % (names[0], names[0]))
- for i in xrange(1, members):
+ for i in range(1, members):
if (bindings[i].val != 'QDBusVariant'):
self.impl("""
&& (v1.%s == v2.%s)""" % (names[i], names[i]))
else:
self.impl("""
&& (v1.%s.variant() == v2.%s.variant())""" % (names[i], names[i]))
self.impl("""
);
}
""")
self.decl('inline bool operator!=(%s v1, %s v2)' %
(depinfo.binding.inarg, depinfo.binding.inarg))
self.decl("""
{
return !operator==(v1, v2);
}
""")
self.both('%s QDBusArgument& operator<<(QDBusArgument& arg, %s val)' %
(self.visibility, depinfo.binding.inarg))
self.decl(';\n')
self.impl("""
{
arg.beginStructure();
arg << %s;
arg.endStructure();
return arg;
}
""" % ' << '.join(['val.' + name for name in names]))
self.both('%s const QDBusArgument& operator>>(const QDBusArgument& arg, %s val)' %
(self.visibility, depinfo.binding.outarg))
self.decl(';\n\n')
self.impl("""
{
arg.beginStructure();
arg >> %s;
arg.endStructure();
return arg;
}
""" % ' >> '.join(['val.' + name for name in names]))
elif depinfo.el.localName == 'mapping':
if members != 2:
raise MalformedMapping(depinfo.binding.val, members)
realtype = 'QMap<%s, %s>' % (bindings[0].val, (bindings[1].val.endswith('>') and bindings[1].val + ' ') or bindings[1].val)
self.decl("""\
/**
* \\struct %s
* \\ingroup mapping
%s\
*
* Mapping type generated from the specification. Convertible with
* %s, but needed to have a discrete type in the Qt type system.
%s\
*/
""" % (depinfo.binding.val, get_headerfile_cmd(self.realinclude, self.prettyinclude), realtype, format_docstring(depinfo.el, self.refs)))
self.decl(self.faketype(depinfo.binding.val, realtype))
else:
raise WTF(depinfo.el.localName)
self.to_declare.append(self.namespace + '::' + depinfo.binding.val)
if depinfo.binding.array_val:
self.to_declare.append('%s::%s' % (self.namespace, depinfo.binding.array_val))
self.decl("""\
/**
* \\ingroup list
%s\
*
* Array of %s values.
*/
typedef %s %s;
""" % (get_headerfile_cmd(self.realinclude, self.prettyinclude), depinfo.binding.val, 'QList<%s>' % depinfo.binding.val, depinfo.binding.array_val))
i = depinfo.binding.array_depth
while i > 1:
i -= 1
self.to_declare.append('%s::%s%s' % (self.namespace, depinfo.binding.array_val, ('List' * i)))
list_of = depinfo.binding.array_val + ('List' * (i-1))
self.decl("""\
/**
* \\ingroup list
%s\
*
* Array of %s values.
*/
typedef QList<%s> %sList;
""" % (get_headerfile_cmd(self.realinclude, self.prettyinclude), list_of, list_of, list_of))
def faketype(self, fake, real):
return """\
struct %(visibility)s %(fake)s : public %(real)s
{
- inline %(fake)s() : %(real)s() {}
- inline %(fake)s(const %(real)s& a) : %(real)s(a) {}
+ %(fake)s() : %(real)s() {}
+ %(fake)s(const %(real)s& a) : %(real)s(a) {}
- inline %(fake)s& operator=(const %(real)s& a)
+ %(fake)s& operator=(const %(real)s& a)
{
*(static_cast<%(real)s*>(this)) = a;
return *this;
}
};
""" % {'fake' : fake, 'real' : real, 'visibility': self.visibility}
if __name__ == '__main__':
options, argv = gnu_getopt(sys.argv[1:], '',
['declfile=',
'implfile=',
'realinclude=',
'prettyinclude=',
'extraincludes=',
'must-define=',
'namespace=',
'specxml=',
'visibility=',
])
try:
Generator(dict(options))()
except BrokenSpecException as e:
- print >> sys.stderr, 'Your spec is broken, dear developer! %s' % e
+ print('Your spec is broken, dear developer! %s' % e, file=sys.stderr)
sys.exit(42)
diff --git a/tools/xincludator.py b/tools/xincludator.py
index 63e106a..5f852bf 100644
--- a/tools/xincludator.py
+++ b/tools/xincludator.py
@@ -1,39 +1,47 @@
#!/usr/bin/python
+import sys
from sys import argv, stdout, stderr
import codecs, locale
import os
import xml.dom.minidom
-stdout = codecs.getwriter('utf-8')(stdout)
+if sys.version_info[0] < 3:
+ 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):
+ for i in range(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')
+
+ if sys.version_info[0] >= 3:
+ xml = dom.toxml('utf-8')
+ stdout.buffer.write(xml)
+ stdout.buffer.write(b'\n')
+ else:
+ xml = dom.toxml()
+ stdout.write(xml)
+ stdout.write('\n')