File indexing completed on 2024-04-21 05:01:51

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 as 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         if isinstance(code, str):
0051             self.out.buffer.write(code.encode('utf8'))
0052         else:
0053             self.out.buffer.write(code)
0054 
0055     def __call__(self):
0056         # Header
0057         self.h('/* Generated from ')
0058         self.h(get_descendant_text(get_by_path(self.spec, 'title')))
0059         version = get_by_path(self.spec, "version")
0060 
0061         if version:
0062             self.h(', version ' + get_descendant_text(version))
0063 
0064         self.h("""
0065  */
0066  """)
0067 
0068         if self.must_define:
0069             self.h("""
0070 #ifndef %s
0071 #error %s
0072 #endif
0073 """ % (self.must_define, self.must_define))
0074 
0075         self.h("""
0076 #include <QFlags>
0077 
0078 /**
0079  * \\addtogroup typesconstants Types and constants
0080  *
0081  * Enumerated, flag, structure, list and mapping types and utility constants.
0082  */
0083 
0084 /**
0085  * \\defgroup flagtypeconsts Flag type constants
0086  * \\ingroup typesconstants
0087  *
0088  * Types generated from the specification representing bit flag constants and
0089  * combinations of them (bitfields).
0090  */
0091 
0092 /**
0093  * \\defgroup enumtypeconsts Enumerated type constants
0094  * \\ingroup typesconstants
0095  *
0096  * Types generated from the specification representing enumerated types ie.
0097  * types the values of which are mutually exclusive integral constants.
0098  */
0099 
0100 /**
0101  * \\defgroup ifacestrconsts Interface string constants
0102  * \\ingroup typesconstants
0103  *
0104  * D-Bus interface names of the interfaces in the specification.
0105  */
0106 
0107 /**
0108  * \\defgroup errorstrconsts Error string constants
0109  * \\ingroup typesconstants
0110  *
0111  * Names of the D-Bus errors in the specification.
0112  */
0113 """)
0114 
0115         # Begin namespace
0116         self.h("""
0117 namespace %s
0118 {
0119 """ % self.namespace)
0120 
0121         # Flags
0122         for flags in self.spec.getElementsByTagNameNS(NS_TP, 'flags'):
0123             self.do_flags(flags)
0124 
0125         # Enums
0126         for enum in self.spec.getElementsByTagNameNS(NS_TP, 'enum'):
0127             self.do_enum(enum)
0128 
0129         # End namespace
0130         self.h("""\
0131 }
0132 
0133 """)
0134 
0135         # Interface names
0136         for iface in self.spec.getElementsByTagName('interface'):
0137             if self.old_prefix:
0138                 self.h("""\
0139 /**
0140  * \\ingroup ifacestrconsts
0141  *
0142  * The interface name "%(name)s".
0143  */
0144 #define %(DEFINE)s "%(name)s"
0145 
0146 """ % {'name' : iface.getAttribute('name'),
0147        'DEFINE' : self.old_prefix + 'INTERFACE_' + get_by_path(iface, '../@name').upper().replace('/', '')})
0148 
0149             if self.define_prefix:
0150                 self.h("""\
0151 /**
0152  * \\ingroup ifacestrconsts
0153  *
0154  * The interface name "%(name)s" as a QLatin1String, usable in QString requiring contexts even when
0155  * building with Q_NO_CAST_FROM_ASCII defined.
0156  */
0157 #define %(DEFINE)s (QLatin1String("%(name)s"))
0158 
0159 """ % {'name' : iface.getAttribute('name'),
0160        'DEFINE' : self.define_prefix + 'IFACE_' + get_by_path(iface, '../@name').upper().replace('/', '')})
0161 
0162         # Error names
0163         for error in get_by_path(self.spec, 'errors/error'):
0164             name = error.getAttribute('name')
0165             fullname = get_by_path(error, '../@namespace') + '.' + name.replace(' ', '')
0166 
0167             if self.old_prefix:
0168                 define = self.old_prefix + 'ERROR_' + name.replace(' ', '_').replace('.', '_').upper()
0169                 self.h("""\
0170 /**
0171  * \\ingroup errorstrconsts
0172  *
0173  * The error name "%(fullname)s".
0174 %(docstring)s\
0175  */
0176 #define %(DEFINE)s "%(fullname)s"
0177 
0178 """ % {'fullname' : fullname,
0179        'docstring': format_docstring(error, self.refs),
0180        'DEFINE' : define})
0181 
0182             if self.define_prefix:
0183                 define = self.define_prefix + 'ERROR_' + name.replace(' ', '_').replace('.', '_').upper()
0184                 self.h("""\
0185 /**
0186  * \\ingroup errorstrconsts
0187  *
0188  * The error name "%(fullname)s" as a QLatin1String, usable in QString requiring contexts even when
0189  * building with Q_NO_CAST_FROM_ASCII defined.
0190 %(docstring)s\
0191  */
0192 #define %(DEFINE)s QLatin1String("%(fullname)s")
0193 
0194 """ % {'fullname' : fullname,
0195        'docstring': format_docstring(error, self.refs),
0196        'DEFINE' : define})
0197 
0198     def do_flags(self, flags):
0199         singular = flags.getAttribute('singular') or \
0200                    flags.getAttribute('value-prefix')
0201 
0202         using_name = False
0203         if not singular:
0204             using_name = True
0205             singular = flags.getAttribute('name')
0206 
0207         if singular.endswith('lags'):
0208             singular = singular[:-1]
0209 
0210         if using_name and singular.endswith('s'):
0211             singular = singular[:-1]
0212 
0213         singular = singular.replace('_', '')
0214         plural = (flags.getAttribute('plural') or flags.getAttribute('name') or singular + 's').replace('_', '')
0215         self.h("""\
0216 /**
0217  * \\ingroup flagtypeconsts
0218  *
0219  * Flag type generated from the specification.
0220  */
0221 enum %(singular)s
0222 {
0223 """ % {'singular' : singular})
0224 
0225         flagvalues = get_by_path(flags, 'flag')
0226 
0227         for flag in flagvalues:
0228             self.do_val(flag, singular, flag == flagvalues[-1])
0229 
0230         self.h("""\
0231     %s = 0xffffffffU
0232 """ % ("_" + singular + "Padding"))
0233 
0234         self.h("""\
0235 };
0236 
0237 /**
0238  * \\typedef QFlags<%(singular)s> %(plural)s
0239  * \\ingroup flagtypeconsts
0240  *
0241  * Type representing combinations of #%(singular)s values.
0242 %(docstring)s\
0243  */
0244 typedef QFlags<%(singular)s> %(plural)s;
0245 Q_DECLARE_OPERATORS_FOR_FLAGS(%(plural)s)
0246 
0247 """ % {'singular' : singular, 'plural' : plural, 'docstring' : format_docstring(flags, self.refs)})
0248 
0249     def do_enum(self, enum):
0250         singular = enum.getAttribute('singular') or \
0251                    enum.getAttribute('name')
0252         value_prefix = enum.getAttribute('singular') or \
0253                        enum.getAttribute('value-prefix') or \
0254                        enum.getAttribute('name')
0255 
0256         if singular.endswith('lags'):
0257             singular = singular[:-1]
0258 
0259         plural = enum.getAttribute('plural') or singular + 's'
0260         singular = singular.replace('_', '')
0261         value_prefix = value_prefix.replace('_', '')
0262         vals = get_by_path(enum, 'enumvalue')
0263 
0264         self.h("""\
0265 /**
0266  * \\enum %(singular)s
0267  * \\ingroup enumtypeconsts
0268  *
0269  * Enumerated type generated from the specification.
0270 %(docstring)s\
0271  */
0272 enum %(singular)s
0273 {
0274 """ % {'singular' : singular, 'docstring' : format_docstring(enum, self.refs)})
0275 
0276         for val in vals:
0277             self.do_val(val, value_prefix, val == vals[-1])
0278 
0279         self.h("""\
0280     %s = 0xffffffffU
0281 };
0282 
0283 """ % ("_" + singular + "Padding"))
0284 
0285         self.h("""\
0286 /**
0287  * \\ingroup enumtypeconsts
0288  *
0289  * 1 higher than the highest valid value of %(singular)s.
0290  */
0291 const int NUM_%(upper-plural)s = (%(last-val)s+1);
0292 
0293 """ % {'singular' : singular,
0294        'upper-plural' : plural.upper(),
0295        'last-val' : vals[-1].getAttribute('value')})
0296 
0297     def do_val(self, val, prefix, last):
0298         name = (val.getAttribute('suffix') or val.getAttribute('name')).replace('_', '')
0299         self.h("""\
0300 %s\
0301     %s = %s,
0302 
0303 """ % (format_docstring(val, self.refs, indent='     * ', brackets=('    /**', '     */')), prefix + name, val.getAttribute('value')))
0304 
0305 if __name__ == '__main__':
0306     options, argv = gnu_getopt(argv[1:], '',
0307             ['namespace=',
0308              'str-constant-prefix=',
0309              'define-prefix=',
0310              'must-define=',
0311              'specxml='])
0312 
0313     Generator(dict(options))()