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))()