File indexing completed on 2024-05-05 17:01:41

0001 #!/usr/bin/python
0002 #
0003 # Copyright (C) 2008 Collabora Limited <http://www.collabora.co.uk>
0004 # Copyright (C) 2008 Nokia Corporation
0005 #
0006 # This library is free software; you can redistribute it and/or
0007 # modify it under the terms of the GNU Lesser General Public
0008 # License as published by the Free Software Foundation; either
0009 # version 2.1 of the License, or (at your option) any later version.
0010 #
0011 # This library is distributed in the hope that it will be useful,
0012 # but WITHOUT ANY WARRANTY; without even the implied warranty of
0013 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014 # Lesser General Public License for more details.
0015 #
0016 # You should have received a copy of the GNU Lesser General Public
0017 # License along with this library; if not, write to the Free Software
0018 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
0019 
0020 from sys import argv, stdout, stderr
0021 import codecs
0022 import xml.dom.minidom
0023 from getopt import gnu_getopt
0024 
0025 from libtpcodegen import NS_TP, get_descendant_text, get_by_path
0026 from libqtcodegen import format_docstring, RefRegistry
0027 
0028 class Generator(object):
0029     def __init__(self, opts):
0030         try:
0031             self.namespace = opts['--namespace']
0032             self.must_define = opts.get('--must-define', None)
0033             dom = xml.dom.minidom.parse(opts['--specxml'])
0034         except KeyError, k:
0035             assert False, 'Missing required parameter %s' % k.args[0]
0036 
0037         self.define_prefix = None
0038         if '--define-prefix' in opts:
0039             self.define_prefix = opts['--define-prefix']
0040 
0041         self.old_prefix = None
0042         if '--str-constant-prefix' in opts:
0043             self.old_prefix = opts['--str-constant-prefix']
0044 
0045         self.spec = get_by_path(dom, "spec")[0]
0046         self.out = codecs.getwriter('utf-8')(stdout)
0047         self.refs = RefRegistry(self.spec)
0048 
0049     def h(self, code):
0050         self.out.write(code)
0051 
0052     def __call__(self):
0053         # Header
0054         self.h('/* Generated from ')
0055         self.h(get_descendant_text(get_by_path(self.spec, 'title')))
0056         version = get_by_path(self.spec, "version")
0057 
0058         if version:
0059             self.h(', version ' + get_descendant_text(version))
0060 
0061         self.h("""
0062  */
0063  """)
0064 
0065         if self.must_define:
0066             self.h("""
0067 #ifndef %s
0068 #error %s
0069 #endif
0070 """ % (self.must_define, self.must_define))
0071 
0072         self.h("""
0073 #include <QFlags>
0074 
0075 /**
0076  * \\addtogroup typesconstants Types and constants
0077  *
0078  * Enumerated, flag, structure, list and mapping types and utility constants.
0079  */
0080 
0081 /**
0082  * \\defgroup flagtypeconsts Flag type constants
0083  * \\ingroup typesconstants
0084  *
0085  * Types generated from the specification representing bit flag constants and
0086  * combinations of them (bitfields).
0087  */
0088 
0089 /**
0090  * \\defgroup enumtypeconsts Enumerated type constants
0091  * \\ingroup typesconstants
0092  *
0093  * Types generated from the specification representing enumerated types ie.
0094  * types the values of which are mutually exclusive integral constants.
0095  */
0096 
0097 /**
0098  * \\defgroup ifacestrconsts Interface string constants
0099  * \\ingroup typesconstants
0100  *
0101  * D-Bus interface names of the interfaces in the specification.
0102  */
0103 
0104 /**
0105  * \\defgroup errorstrconsts Error string constants
0106  * \\ingroup typesconstants
0107  *
0108  * Names of the D-Bus errors in the specification.
0109  */
0110 """)
0111 
0112         # Begin namespace
0113         self.h("""
0114 namespace %s
0115 {
0116 """ % self.namespace)
0117 
0118         # Flags
0119         for flags in self.spec.getElementsByTagNameNS(NS_TP, 'flags'):
0120             self.do_flags(flags)
0121 
0122         # Enums
0123         for enum in self.spec.getElementsByTagNameNS(NS_TP, 'enum'):
0124             self.do_enum(enum)
0125 
0126         # End namespace
0127         self.h("""\
0128 }
0129 
0130 """)
0131 
0132         # Interface names
0133         for iface in self.spec.getElementsByTagName('interface'):
0134             if self.old_prefix:
0135                 self.h("""\
0136 /**
0137  * \\ingroup ifacestrconsts
0138  *
0139  * The interface name "%(name)s".
0140  */
0141 #define %(DEFINE)s "%(name)s"
0142 
0143 """ % {'name' : iface.getAttribute('name'),
0144        'DEFINE' : self.old_prefix + 'INTERFACE_' + get_by_path(iface, '../@name').upper().replace('/', '')})
0145 
0146             if self.define_prefix:
0147                 self.h("""\
0148 /**
0149  * \\ingroup ifacestrconsts
0150  *
0151  * The interface name "%(name)s" as a QLatin1String, usable in QString requiring contexts even when
0152  * building with Q_NO_CAST_FROM_ASCII defined.
0153  */
0154 #define %(DEFINE)s (QLatin1String("%(name)s"))
0155 
0156 """ % {'name' : iface.getAttribute('name'),
0157        'DEFINE' : self.define_prefix + 'IFACE_' + get_by_path(iface, '../@name').upper().replace('/', '')})
0158 
0159         # Error names
0160         for error in get_by_path(self.spec, 'errors/error'):
0161             name = error.getAttribute('name')
0162             fullname = get_by_path(error, '../@namespace') + '.' + name.replace(' ', '')
0163 
0164             if self.old_prefix:
0165                 define = self.old_prefix + 'ERROR_' + name.replace(' ', '_').replace('.', '_').upper()
0166                 self.h("""\
0167 /**
0168  * \\ingroup errorstrconsts
0169  *
0170  * The error name "%(fullname)s".
0171 %(docstring)s\
0172  */
0173 #define %(DEFINE)s "%(fullname)s"
0174 
0175 """ % {'fullname' : fullname,
0176        'docstring': format_docstring(error, self.refs),
0177        'DEFINE' : define})
0178 
0179             if self.define_prefix:
0180                 define = self.define_prefix + 'ERROR_' + name.replace(' ', '_').replace('.', '_').upper()
0181                 self.h("""\
0182 /**
0183  * \\ingroup errorstrconsts
0184  *
0185  * The error name "%(fullname)s" as a QLatin1String, usable in QString requiring contexts even when
0186  * building with Q_NO_CAST_FROM_ASCII defined.
0187 %(docstring)s\
0188  */
0189 #define %(DEFINE)s QLatin1String("%(fullname)s")
0190 
0191 """ % {'fullname' : fullname,
0192        'docstring': format_docstring(error, self.refs),
0193        'DEFINE' : define})
0194 
0195     def do_flags(self, flags):
0196         singular = flags.getAttribute('singular') or \
0197                    flags.getAttribute('value-prefix')
0198 
0199         using_name = False
0200         if not singular:
0201             using_name = True
0202             singular = flags.getAttribute('name')
0203 
0204         if singular.endswith('lags'):
0205             singular = singular[:-1]
0206 
0207         if using_name and singular.endswith('s'):
0208             singular = singular[:-1]
0209 
0210         singular = singular.replace('_', '')
0211         plural = (flags.getAttribute('plural') or flags.getAttribute('name') or singular + 's').replace('_', '')
0212         self.h("""\
0213 /**
0214  * \\ingroup flagtypeconsts
0215  *
0216  * Flag type generated from the specification.
0217  */
0218 enum %(singular)s
0219 {
0220 """ % {'singular' : singular})
0221 
0222         flagvalues = get_by_path(flags, 'flag')
0223 
0224         for flag in flagvalues:
0225             self.do_val(flag, singular, flag == flagvalues[-1])
0226 
0227         self.h("""\
0228     %s = 0xffffffffU
0229 """ % ("_" + singular + "Padding"))
0230 
0231         self.h("""\
0232 };
0233 
0234 /**
0235  * \\typedef QFlags<%(singular)s> %(plural)s
0236  * \\ingroup flagtypeconsts
0237  *
0238  * Type representing combinations of #%(singular)s values.
0239 %(docstring)s\
0240  */
0241 typedef QFlags<%(singular)s> %(plural)s;
0242 Q_DECLARE_OPERATORS_FOR_FLAGS(%(plural)s)
0243 
0244 """ % {'singular' : singular, 'plural' : plural, 'docstring' : format_docstring(flags, self.refs)})
0245 
0246     def do_enum(self, enum):
0247         singular = enum.getAttribute('singular') or \
0248                    enum.getAttribute('name')
0249         value_prefix = enum.getAttribute('singular') or \
0250                        enum.getAttribute('value-prefix') or \
0251                        enum.getAttribute('name')
0252 
0253         if singular.endswith('lags'):
0254             singular = singular[:-1]
0255 
0256         plural = enum.getAttribute('plural') or singular + 's'
0257         singular = singular.replace('_', '')
0258         value_prefix = value_prefix.replace('_', '')
0259         vals = get_by_path(enum, 'enumvalue')
0260 
0261         self.h("""\
0262 /**
0263  * \\enum %(singular)s
0264  * \\ingroup enumtypeconsts
0265  *
0266  * Enumerated type generated from the specification.
0267 %(docstring)s\
0268  */
0269 enum %(singular)s
0270 {
0271 """ % {'singular' : singular, 'docstring' : format_docstring(enum, self.refs)})
0272 
0273         for val in vals:
0274             self.do_val(val, value_prefix, val == vals[-1])
0275 
0276         self.h("""\
0277     %s = 0xffffffffU
0278 };
0279 
0280 """ % ("_" + singular + "Padding"))
0281 
0282         self.h("""\
0283 /**
0284  * \\ingroup enumtypeconsts
0285  *
0286  * 1 higher than the highest valid value of %(singular)s.
0287  */
0288 const int NUM_%(upper-plural)s = (%(last-val)s+1);
0289 
0290 """ % {'singular' : singular,
0291        'upper-plural' : plural.upper(),
0292        'last-val' : vals[-1].getAttribute('value')})
0293 
0294     def do_val(self, val, prefix, last):
0295         name = (val.getAttribute('suffix') or val.getAttribute('name')).replace('_', '')
0296         self.h("""\
0297 %s\
0298     %s = %s,
0299 
0300 """ % (format_docstring(val, self.refs, indent='     * ', brackets=('    /**', '     */')), prefix + name, val.getAttribute('value')))
0301 
0302 if __name__ == '__main__':
0303     options, argv = gnu_getopt(argv[1:], '',
0304             ['namespace=',
0305              'str-constant-prefix=',
0306              'define-prefix=',
0307              'must-define=',
0308              'specxml='])
0309 
0310     Generator(dict(options))()