File indexing completed on 2024-04-28 08:54:37

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 libtpcodegen import file_set_contents, u
0027 from libglibcodegen import escape_as_identifier, \
0028                            get_docstring, \
0029                            NS_TP, \
0030                            Signature, \
0031                            type_to_gtype, \
0032                            xml_escape
0033 
0034 
0035 def types_to_gtypes(types):
0036     return [type_to_gtype(t)[1] for t in types]
0037 
0038 
0039 class GTypesGenerator(object):
0040     def __init__(self, dom, output, mixed_case_prefix):
0041         self.dom = dom
0042         self.Prefix = mixed_case_prefix
0043         self.PREFIX_ = self.Prefix.upper() + '_'
0044         self.prefix_ = self.Prefix.lower() + '_'
0045 
0046         self.header = []
0047         self.body = []
0048         self.docs = []
0049         self.output = output
0050 
0051         for f in (self.header, self.body, self.docs):
0052             f.append('/* Auto-generated, do not edit.\n *\n'
0053                      ' * This file may be distributed under the same terms\n'
0054                      ' * as the specification from which it was generated.\n'
0055                      ' */\n\n')
0056 
0057         # keys are e.g. 'sv', values are the key escaped
0058         self.need_mappings = {}
0059         # keys are the contents of the struct (e.g. 'sssu'), values are the
0060         # key escaped
0061         self.need_structs = {}
0062         # keys are the contents of the struct (e.g. 'sssu'), values are the
0063         # key escaped
0064         self.need_struct_arrays = {}
0065 
0066         # keys are the contents of the array (unlike need_struct_arrays!),
0067         # values are the key escaped
0068         self.need_other_arrays = {}
0069 
0070     def h(self, code):
0071         self.header.append(code)
0072 
0073     def c(self, code):
0074         self.body.append(code)
0075 
0076     def d(self, code):
0077         self.docs.append(code)
0078 
0079     def do_mapping_header(self, mapping):
0080         members = mapping.getElementsByTagNameNS(NS_TP, 'member')
0081         assert len(members) == 2
0082 
0083         impl_sig = ''.join([elt.getAttribute('type')
0084                             for elt in members])
0085 
0086         esc_impl_sig = escape_as_identifier(impl_sig)
0087 
0088         name = (self.PREFIX_ + 'HASH_TYPE_' +
0089                 mapping.getAttribute('name').upper())
0090         impl = self.prefix_ + 'type_dbus_hash_' + esc_impl_sig
0091 
0092         docstring = get_docstring(mapping) or '(Undocumented)'
0093 
0094         self.d('/**\n * %s:\n *\n' % name.strip())
0095         self.d(' * %s\n' % xml_escape(docstring))
0096         self.d(' *\n')
0097         self.d(' * This macro expands to a call to a function\n')
0098         self.d(' * that returns the #GType of a #GHashTable\n')
0099         self.d(' * appropriate for representing a D-Bus\n')
0100         self.d(' * dictionary of signature\n')
0101         self.d(' * <literal>a{%s}</literal>.\n' % impl_sig)
0102         self.d(' *\n')
0103 
0104         key, value = members
0105 
0106         self.d(' * Keys (D-Bus type <literal>%s</literal>,\n'
0107                           % key.getAttribute('type'))
0108         tp_type = key.getAttributeNS(NS_TP, 'type')
0109         if tp_type:
0110             self.d(' * type <literal>%s</literal>,\n' % tp_type)
0111         self.d(' * named <literal>%s</literal>):\n'
0112                           % key.getAttribute('name'))
0113         docstring = get_docstring(key) or '(Undocumented)'
0114         self.d(' * %s\n' % xml_escape(docstring))
0115         self.d(' *\n')
0116 
0117         self.d(' * Values (D-Bus type <literal>%s</literal>,\n'
0118                           % value.getAttribute('type'))
0119         tp_type = value.getAttributeNS(NS_TP, 'type')
0120         if tp_type:
0121             self.d(' * type <literal>%s</literal>,\n' % tp_type)
0122         self.d(' * named <literal>%s</literal>):\n'
0123                           % value.getAttribute('name'))
0124         docstring = get_docstring(value) or '(Undocumented)'
0125         self.d(' * %s\n' % xml_escape(docstring))
0126         self.d(' *\n')
0127 
0128         self.d(' */\n')
0129 
0130         self.h('#define %s (%s ())\n\n' % (name, impl))
0131         self.need_mappings[impl_sig] = esc_impl_sig
0132 
0133         array_name = mapping.getAttribute('array-name')
0134         if array_name:
0135             gtype_name = self.PREFIX_ + 'ARRAY_TYPE_' + array_name.upper()
0136             contents_sig = 'a{' + impl_sig + '}'
0137             esc_contents_sig = escape_as_identifier(contents_sig)
0138             impl = self.prefix_ + 'type_dbus_array_of_' + esc_contents_sig
0139             self.d('/**\n * %s:\n\n' % gtype_name)
0140             self.d(' * Expands to a call to a function\n')
0141             self.d(' * that returns the #GType of a #GPtrArray\n')
0142             self.d(' * of #%s.\n' % name)
0143             self.d(' */\n\n')
0144 
0145             self.h('#define %s (%s ())\n\n' % (gtype_name, impl))
0146             self.need_other_arrays[contents_sig] = esc_contents_sig
0147 
0148     def do_struct_header(self, struct):
0149         members = struct.getElementsByTagNameNS(NS_TP, 'member')
0150         impl_sig = ''.join([elt.getAttribute('type') for elt in members])
0151         esc_impl_sig = escape_as_identifier(impl_sig)
0152 
0153         name = (self.PREFIX_ + 'STRUCT_TYPE_' +
0154                 struct.getAttribute('name').upper())
0155         impl = self.prefix_ + 'type_dbus_struct_' + esc_impl_sig
0156         docstring = struct.getElementsByTagNameNS(NS_TP, 'docstring')
0157         if docstring:
0158             docstring = docstring[0].toprettyxml()
0159             if docstring.startswith('<tp:docstring>'):
0160                 docstring = docstring[14:]
0161             if docstring.endswith('</tp:docstring>\n'):
0162                 docstring = docstring[:-16]
0163             if docstring.strip() in ('<tp:docstring/>', ''):
0164                 docstring = '(Undocumented)'
0165         else:
0166             docstring = '(Undocumented)'
0167         self.d('/**\n * %s:\n\n' % name)
0168         self.d(' * %s\n' % xml_escape(docstring))
0169         self.d(' *\n')
0170         self.d(' * This macro expands to a call to a function\n')
0171         self.d(' * that returns the #GType of a #GValueArray\n')
0172         self.d(' * appropriate for representing a D-Bus struct\n')
0173         self.d(' * with signature <literal>(%s)</literal>.\n'
0174                           % impl_sig)
0175         self.d(' *\n')
0176 
0177         for i, member in enumerate(members):
0178             self.d(' * Member %d (D-Bus type '
0179                               '<literal>%s</literal>,\n'
0180                               % (i, member.getAttribute('type')))
0181             tp_type = member.getAttributeNS(NS_TP, 'type')
0182             if tp_type:
0183                 self.d(' * type <literal>%s</literal>,\n' % tp_type)
0184             self.d(' * named <literal>%s</literal>):\n'
0185                               % member.getAttribute('name'))
0186             docstring = get_docstring(member) or '(Undocumented)'
0187             self.d(' * %s\n' % xml_escape(docstring))
0188             self.d(' *\n')
0189 
0190         self.d(' */\n\n')
0191 
0192         self.h('#define %s (%s ())\n\n' % (name, impl))
0193 
0194         array_name = struct.getAttribute('array-name')
0195         if array_name != '':
0196             array_name = (self.PREFIX_ + 'ARRAY_TYPE_' + array_name.upper())
0197             impl = self.prefix_ + 'type_dbus_array_' + esc_impl_sig
0198             self.d('/**\n * %s:\n\n' % array_name)
0199             self.d(' * Expands to a call to a function\n')
0200             self.d(' * that returns the #GType of a #GPtrArray\n')
0201             self.d(' * of #%s.\n' % name)
0202             self.d(' */\n\n')
0203 
0204             self.h('#define %s (%s ())\n\n' % (array_name, impl))
0205             self.need_struct_arrays[impl_sig] = esc_impl_sig
0206 
0207         self.need_structs[impl_sig] = esc_impl_sig
0208 
0209     def __call__(self):
0210         mappings = self.dom.getElementsByTagNameNS(NS_TP, 'mapping')
0211         structs = self.dom.getElementsByTagNameNS(NS_TP, 'struct')
0212 
0213         for mapping in mappings:
0214             self.do_mapping_header(mapping)
0215 
0216         for sig in self.need_mappings:
0217             self.h('GType %stype_dbus_hash_%s (void);\n\n' %
0218                               (self.prefix_, self.need_mappings[sig]))
0219             self.c('GType\n%stype_dbus_hash_%s (void)\n{\n' %
0220                               (self.prefix_, self.need_mappings[sig]))
0221             self.c('  static GType t = 0;\n\n')
0222             self.c('  if (G_UNLIKELY (t == 0))\n')
0223             # FIXME: translate sig into two GTypes
0224             items = tuple(Signature(sig))
0225             gtypes = types_to_gtypes(items)
0226             self.c('    t = dbus_g_type_get_map ("GHashTable", '
0227                             '%s, %s);\n' % (gtypes[0], gtypes[1]))
0228             self.c('  return t;\n')
0229             self.c('}\n\n')
0230 
0231         for struct in structs:
0232             self.do_struct_header(struct)
0233 
0234         for sig in self.need_structs:
0235             self.h('GType %stype_dbus_struct_%s (void);\n\n' %
0236                               (self.prefix_, self.need_structs[sig]))
0237             self.c('GType\n%stype_dbus_struct_%s (void)\n{\n' %
0238                               (self.prefix_, self.need_structs[sig]))
0239             self.c('  static GType t = 0;\n\n')
0240             self.c('  if (G_UNLIKELY (t == 0))\n')
0241             self.c('    t = dbus_g_type_get_struct ("GValueArray",\n')
0242             items = tuple(Signature(sig))
0243             gtypes = types_to_gtypes(items)
0244             for gtype in gtypes:
0245                 self.c('        %s,\n' % gtype)
0246             self.c('        G_TYPE_INVALID);\n')
0247             self.c('  return t;\n')
0248             self.c('}\n\n')
0249 
0250         for sig in self.need_struct_arrays:
0251             self.h('GType %stype_dbus_array_%s (void);\n\n' %
0252                               (self.prefix_, self.need_struct_arrays[sig]))
0253             self.c('GType\n%stype_dbus_array_%s (void)\n{\n' %
0254                               (self.prefix_, self.need_struct_arrays[sig]))
0255             self.c('  static GType t = 0;\n\n')
0256             self.c('  if (G_UNLIKELY (t == 0))\n')
0257             self.c('    t = dbus_g_type_get_collection ("GPtrArray", '
0258                             '%stype_dbus_struct_%s ());\n' %
0259                             (self.prefix_, self.need_struct_arrays[sig]))
0260             self.c('  return t;\n')
0261             self.c('}\n\n')
0262 
0263         for sig in self.need_other_arrays:
0264             self.h('GType %stype_dbus_array_of_%s (void);\n\n' %
0265                               (self.prefix_, self.need_other_arrays[sig]))
0266             self.c('GType\n%stype_dbus_array_of_%s (void)\n{\n' %
0267                               (self.prefix_, self.need_other_arrays[sig]))
0268             self.c('  static GType t = 0;\n\n')
0269             self.c('  if (G_UNLIKELY (t == 0))\n')
0270 
0271             if sig[:2] == 'a{' and sig[-1:] == '}':
0272                 # array of mappings
0273                 self.c('    t = dbus_g_type_get_collection ('
0274                             '"GPtrArray", '
0275                             '%stype_dbus_hash_%s ());\n' %
0276                             (self.prefix_, escape_as_identifier(sig[2:-1])))
0277             elif sig[:2] == 'a(' and sig[-1:] == ')':
0278                 # array of arrays of struct
0279                 self.c('    t = dbus_g_type_get_collection ('
0280                             '"GPtrArray", '
0281                             '%stype_dbus_array_%s ());\n' %
0282                             (self.prefix_, escape_as_identifier(sig[2:-1])))
0283             elif sig[:1] == 'a':
0284                 # array of arrays of non-struct
0285                 self.c('    t = dbus_g_type_get_collection ('
0286                             '"GPtrArray", '
0287                             '%stype_dbus_array_of_%s ());\n' %
0288                             (self.prefix_, escape_as_identifier(sig[1:])))
0289             else:
0290                 raise AssertionError("array of '%s' not supported" % sig)
0291 
0292             self.c('  return t;\n')
0293             self.c('}\n\n')
0294 
0295         file_set_contents(self.output + '.h', u('').join(self.header).encode('utf-8'))
0296         file_set_contents(self.output + '-body.h', u('').join(self.body).encode('utf-8'))
0297         file_set_contents(self.output + '-gtk-doc.h', u('').join(self.docs).encode('utf-8'))
0298 
0299 if __name__ == '__main__':
0300     argv = sys.argv[1:]
0301 
0302     dom = xml.dom.minidom.parse(argv[0])
0303 
0304     GTypesGenerator(dom, argv[1], argv[2])()