File indexing completed on 2024-04-28 16:13:13

0001 #!/usr/bin/python
0002 
0003 # Generate GLib GInterfaces from the Telepathy specification.
0004 # The master copy of this program is in the telepathy-glib repository -
0005 # please make any changes there.
0006 #
0007 # Copyright (C) 2006, 2007 Collabora Limited
0008 #
0009 # This library is free software; you can redistribute it and/or
0010 # modify it under the terms of the GNU Lesser General Public
0011 # License as published by the Free Software Foundation; either
0012 # version 2.1 of the License, or (at your option) any later version.
0013 #
0014 # This library is distributed in the hope that it will be useful,
0015 # but WITHOUT ANY WARRANTY; without even the implied warranty of
0016 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0017 # Lesser General Public License for more details.
0018 #
0019 # You should have received a copy of the GNU Lesser General Public
0020 # License along with this library; if not, write to the Free Software
0021 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
0022 
0023 import sys
0024 import xml.dom.minidom
0025 
0026 from libglibcodegen import escape_as_identifier, \
0027                            get_docstring, \
0028                            NS_TP, \
0029                            Signature, \
0030                            type_to_gtype, \
0031                            xml_escape
0032 
0033 
0034 def types_to_gtypes(types):
0035     return [type_to_gtype(t)[1] for t in types]
0036 
0037 
0038 class GTypesGenerator(object):
0039     def __init__(self, dom, output, mixed_case_prefix):
0040         self.dom = dom
0041         self.Prefix = mixed_case_prefix
0042         self.PREFIX_ = self.Prefix.upper() + '_'
0043         self.prefix_ = self.Prefix.lower() + '_'
0044 
0045         self.header = open(output + '.h', 'w')
0046         self.body = open(output + '-body.h', 'w')
0047 
0048         for f in (self.header, self.body):
0049             f.write('/* Auto-generated, do not edit.\n *\n'
0050                     ' * This file may be distributed under the same terms\n'
0051                     ' * as the specification from which it was generated.\n'
0052                     ' */\n\n')
0053 
0054         # keys are e.g. 'sv', values are the key escaped
0055         self.need_mappings = {}
0056         # keys are the contents of the struct (e.g. 'sssu'), values are the
0057         # key escaped
0058         self.need_structs = {}
0059         # keys are the contents of the struct (e.g. 'sssu'), values are the
0060         # key escaped
0061         self.need_struct_arrays = {}
0062 
0063         # keys are the contents of the array (unlike need_struct_arrays!),
0064         # values are the key escaped
0065         self.need_other_arrays = {}
0066 
0067     def h(self, code):
0068         self.header.write(code.encode("utf-8"))
0069 
0070     def c(self, code):
0071         self.body.write(code.encode("utf-8"))
0072 
0073     def do_mapping_header(self, mapping):
0074         members = mapping.getElementsByTagNameNS(NS_TP, 'member')
0075         assert len(members) == 2
0076 
0077         impl_sig = ''.join([elt.getAttribute('type')
0078                             for elt in members])
0079 
0080         esc_impl_sig = escape_as_identifier(impl_sig)
0081 
0082         name = (self.PREFIX_ + 'HASH_TYPE_' +
0083                 mapping.getAttribute('name').upper())
0084         impl = self.prefix_ + 'type_dbus_hash_' + esc_impl_sig
0085 
0086         docstring = get_docstring(mapping) or '(Undocumented)'
0087 
0088         self.h('/**\n * %s:\n *\n' % name)
0089         self.h(' * %s\n' % xml_escape(docstring))
0090         self.h(' *\n')
0091         self.h(' * This macro expands to a call to a function\n')
0092         self.h(' * that returns the #GType of a #GHashTable\n')
0093         self.h(' * appropriate for representing a D-Bus\n')
0094         self.h(' * dictionary of signature\n')
0095         self.h(' * <literal>a{%s}</literal>.\n' % impl_sig)
0096         self.h(' *\n')
0097 
0098         key, value = members
0099 
0100         self.h(' * Keys (D-Bus type <literal>%s</literal>,\n'
0101                           % key.getAttribute('type'))
0102         tp_type = key.getAttributeNS(NS_TP, 'type')
0103         if tp_type:
0104             self.h(' * type <literal>%s</literal>,\n' % tp_type)
0105         self.h(' * named <literal>%s</literal>):\n'
0106                           % key.getAttribute('name'))
0107         docstring = get_docstring(key) or '(Undocumented)'
0108         self.h(' * %s\n' % xml_escape(docstring))
0109         self.h(' *\n')
0110 
0111         self.h(' * Values (D-Bus type <literal>%s</literal>,\n'
0112                           % value.getAttribute('type'))
0113         tp_type = value.getAttributeNS(NS_TP, 'type')
0114         if tp_type:
0115             self.h(' * type <literal>%s</literal>,\n' % tp_type)
0116         self.h(' * named <literal>%s</literal>):\n'
0117                           % value.getAttribute('name'))
0118         docstring = get_docstring(value) or '(Undocumented)'
0119         self.h(' * %s\n' % xml_escape(docstring))
0120         self.h(' *\n')
0121 
0122         self.h(' */\n')
0123 
0124         self.h('#define %s (%s ())\n\n' % (name, impl))
0125         self.need_mappings[impl_sig] = esc_impl_sig
0126 
0127         array_name = mapping.getAttribute('array-name')
0128         if array_name:
0129             gtype_name = self.PREFIX_ + 'ARRAY_TYPE_' + array_name.upper()
0130             contents_sig = 'a{' + impl_sig + '}'
0131             esc_contents_sig = escape_as_identifier(contents_sig)
0132             impl = self.prefix_ + 'type_dbus_array_of_' + esc_contents_sig
0133             self.h('/**\n * %s:\n\n' % gtype_name)
0134             self.h(' * Expands to a call to a function\n')
0135             self.h(' * that returns the #GType of a #GPtrArray\n')
0136             self.h(' * of #%s.\n' % name)
0137             self.h(' */\n')
0138             self.h('#define %s (%s ())\n\n' % (gtype_name, impl))
0139             self.need_other_arrays[contents_sig] = esc_contents_sig
0140 
0141     def do_struct_header(self, struct):
0142         members = struct.getElementsByTagNameNS(NS_TP, 'member')
0143         impl_sig = ''.join([elt.getAttribute('type') for elt in members])
0144         esc_impl_sig = escape_as_identifier(impl_sig)
0145 
0146         name = (self.PREFIX_ + 'STRUCT_TYPE_' +
0147                 struct.getAttribute('name').upper())
0148         impl = self.prefix_ + 'type_dbus_struct_' + esc_impl_sig
0149         docstring = struct.getElementsByTagNameNS(NS_TP, 'docstring')
0150         if docstring:
0151             docstring = docstring[0].toprettyxml()
0152             if docstring.startswith('<tp:docstring>'):
0153                 docstring = docstring[14:]
0154             if docstring.endswith('</tp:docstring>\n'):
0155                 docstring = docstring[:-16]
0156             if docstring.strip() in ('<tp:docstring/>', ''):
0157                 docstring = '(Undocumented)'
0158         else:
0159             docstring = '(Undocumented)'
0160         self.h('/**\n * %s:\n\n' % name)
0161         self.h(' * %s\n' % xml_escape(docstring))
0162         self.h(' *\n')
0163         self.h(' * This macro expands to a call to a function\n')
0164         self.h(' * that returns the #GType of a #GValueArray\n')
0165         self.h(' * appropriate for representing a D-Bus struct\n')
0166         self.h(' * with signature <literal>(%s)</literal>.\n'
0167                           % impl_sig)
0168         self.h(' *\n')
0169 
0170         for i, member in enumerate(members):
0171             self.h(' * Member %d (D-Bus type '
0172                               '<literal>%s</literal>,\n'
0173                               % (i, member.getAttribute('type')))
0174             tp_type = member.getAttributeNS(NS_TP, 'type')
0175             if tp_type:
0176                 self.h(' * type <literal>%s</literal>,\n' % tp_type)
0177             self.h(' * named <literal>%s</literal>):\n'
0178                               % member.getAttribute('name'))
0179             docstring = get_docstring(member) or '(Undocumented)'
0180             self.h(' * %s\n' % xml_escape(docstring))
0181             self.h(' *\n')
0182 
0183         self.h(' */\n')
0184         self.h('#define %s (%s ())\n\n' % (name, impl))
0185 
0186         array_name = struct.getAttribute('array-name')
0187         if array_name != '':
0188             array_name = (self.PREFIX_ + 'ARRAY_TYPE_' + array_name.upper())
0189             impl = self.prefix_ + 'type_dbus_array_' + esc_impl_sig
0190             self.h('/**\n * %s:\n\n' % array_name)
0191             self.h(' * Expands to a call to a function\n')
0192             self.h(' * that returns the #GType of a #GPtrArray\n')
0193             self.h(' * of #%s.\n' % name)
0194             self.h(' */\n')
0195             self.h('#define %s (%s ())\n\n' % (array_name, impl))
0196             self.need_struct_arrays[impl_sig] = esc_impl_sig
0197 
0198         self.need_structs[impl_sig] = esc_impl_sig
0199 
0200     def __call__(self):
0201         mappings = self.dom.getElementsByTagNameNS(NS_TP, 'mapping')
0202         structs = self.dom.getElementsByTagNameNS(NS_TP, 'struct')
0203 
0204         for mapping in mappings:
0205             self.do_mapping_header(mapping)
0206 
0207         for sig in self.need_mappings:
0208             self.h('GType %stype_dbus_hash_%s (void);\n\n' %
0209                               (self.prefix_, self.need_mappings[sig]))
0210             self.c('GType\n%stype_dbus_hash_%s (void)\n{\n' %
0211                               (self.prefix_, self.need_mappings[sig]))
0212             self.c('  static GType t = 0;\n\n')
0213             self.c('  if (G_UNLIKELY (t == 0))\n')
0214             # FIXME: translate sig into two GTypes
0215             items = tuple(Signature(sig))
0216             gtypes = types_to_gtypes(items)
0217             self.c('    t = dbus_g_type_get_map ("GHashTable", '
0218                             '%s, %s);\n' % (gtypes[0], gtypes[1]))
0219             self.c('  return t;\n')
0220             self.c('}\n\n')
0221 
0222         for struct in structs:
0223             self.do_struct_header(struct)
0224 
0225         for sig in self.need_structs:
0226             self.h('GType %stype_dbus_struct_%s (void);\n\n' %
0227                               (self.prefix_, self.need_structs[sig]))
0228             self.c('GType\n%stype_dbus_struct_%s (void)\n{\n' %
0229                               (self.prefix_, self.need_structs[sig]))
0230             self.c('  static GType t = 0;\n\n')
0231             self.c('  if (G_UNLIKELY (t == 0))\n')
0232             self.c('    t = dbus_g_type_get_struct ("GValueArray",\n')
0233             items = tuple(Signature(sig))
0234             gtypes = types_to_gtypes(items)
0235             for gtype in gtypes:
0236                 self.c('        %s,\n' % gtype)
0237             self.c('        G_TYPE_INVALID);\n')
0238             self.c('  return t;\n')
0239             self.c('}\n\n')
0240 
0241         for sig in self.need_struct_arrays:
0242             self.h('GType %stype_dbus_array_%s (void);\n\n' %
0243                               (self.prefix_, self.need_struct_arrays[sig]))
0244             self.c('GType\n%stype_dbus_array_%s (void)\n{\n' %
0245                               (self.prefix_, self.need_struct_arrays[sig]))
0246             self.c('  static GType t = 0;\n\n')
0247             self.c('  if (G_UNLIKELY (t == 0))\n')
0248             self.c('    t = dbus_g_type_get_collection ("GPtrArray", '
0249                             '%stype_dbus_struct_%s ());\n' %
0250                             (self.prefix_, self.need_struct_arrays[sig]))
0251             self.c('  return t;\n')
0252             self.c('}\n\n')
0253 
0254         for sig in self.need_other_arrays:
0255             self.h('GType %stype_dbus_array_of_%s (void);\n\n' %
0256                               (self.prefix_, self.need_other_arrays[sig]))
0257             self.c('GType\n%stype_dbus_array_of_%s (void)\n{\n' %
0258                               (self.prefix_, self.need_other_arrays[sig]))
0259             self.c('  static GType t = 0;\n\n')
0260             self.c('  if (G_UNLIKELY (t == 0))\n')
0261 
0262             if sig[:2] == 'a{' and sig[-1:] == '}':
0263                 # array of mappings
0264                 self.c('    t = dbus_g_type_get_collection ('
0265                             '"GPtrArray", '
0266                             '%stype_dbus_hash_%s ());\n' %
0267                             (self.prefix_, escape_as_identifier(sig[2:-1])))
0268             elif sig[:2] == 'a(' and sig[-1:] == ')':
0269                 # array of arrays of struct
0270                 self.c('    t = dbus_g_type_get_collection ('
0271                             '"GPtrArray", '
0272                             '%stype_dbus_array_%s ());\n' %
0273                             (self.prefix_, escape_as_identifier(sig[2:-1])))
0274             elif sig[:1] == 'a':
0275                 # array of arrays of non-struct
0276                 self.c('    t = dbus_g_type_get_collection ('
0277                             '"GPtrArray", '
0278                             '%stype_dbus_array_of_%s ());\n' %
0279                             (self.prefix_, escape_as_identifier(sig[1:])))
0280             else:
0281                 raise AssertionError("array of '%s' not supported" % sig)
0282 
0283             self.c('  return t;\n')
0284             self.c('}\n\n')
0285 
0286 if __name__ == '__main__':
0287     argv = sys.argv[1:]
0288 
0289     dom = xml.dom.minidom.parse(argv[0])
0290 
0291     GTypesGenerator(dom, argv[1], argv[2])()