#!/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 = []
self.body = []
self.docs = []
self.output = output
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.append(code)
def c(self, code):
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.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.d(' * Keys (D-Bus type %s,\n'
% key.getAttribute('type'))
tp_type = key.getAttributeNS(NS_TP, 'type')
if tp_type:
self.d(' * type %s,\n' % tp_type)
self.d(' * named %s):\n'
% key.getAttribute('name'))
docstring = get_docstring(key) or '(Undocumented)'
self.d(' * %s\n' % xml_escape(docstring))
self.d(' *\n')
self.d(' * Values (D-Bus type %s,\n'
% value.getAttribute('type'))
tp_type = value.getAttributeNS(NS_TP, 'type')
if tp_type:
self.d(' * type %s,\n' % tp_type)
self.d(' * named %s):\n'
% value.getAttribute('name'))
docstring = get_docstring(value) or '(Undocumented)'
self.d(' * %s\n' % xml_escape(docstring))
self.d(' *\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.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.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.d(' *\n')
for i, member in enumerate(members):
self.d(' * Member %d (D-Bus type '
'%s,\n'
% (i, member.getAttribute('type')))
tp_type = member.getAttributeNS(NS_TP, 'type')
if tp_type:
self.d(' * type %s,\n' % tp_type)
self.d(' * named %s):\n'
% member.getAttribute('name'))
docstring = get_docstring(member) or '(Undocumented)'
self.d(' * %s\n' % xml_escape(docstring))
self.d(' *\n')
self.d(' */\n\n')
self.h('#define %s (%s ())\n\n' % (name, impl))
array_name = struct.getAttribute('array-name')
if array_name != '':
array_name = (self.PREFIX_ + 'ARRAY_TYPE_' + array_name.upper())
impl = self.prefix_ + 'type_dbus_array_' + esc_impl_sig
self.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])()