2 # header.py - Generate C++ header files from IDL.
4 # ***** BEGIN LICENSE BLOCK *****
5 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 # The contents of this file are subject to the Mozilla Public License Version
8 # 1.1 (the "License"); you may not use this file except in compliance with
9 # the License. You may obtain a copy of the License at
10 # http://www.mozilla.org/MPL/
12 # Software distributed under the License is distributed on an "AS IS" basis,
13 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 # for the specific language governing rights and limitations under the
17 # The Original Code is mozilla.org code.
19 # The Initial Developer of the Original Code is
21 # Portions created by the Initial Developer are Copyright (C) 2008
22 # the Initial Developer. All Rights Reserved.
25 # Benjamin Smedberg <benjamin@smedbergs.us>
27 # Alternatively, the contents of this file may be used under the terms of
28 # either of the GNU General Public License Version 2 or later (the "GPL"),
29 # or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 # in which case the provisions of the GPL or the LGPL are applicable instead
31 # of those above. If you wish to allow use of your version of this file only
32 # under the terms of either the GPL or the LGPL, and not to allow others to
33 # use your version of this file under the terms of the MPL, indicate your
34 # decision by deleting the provisions above and replace them with the notice
35 # and other provisions required by the GPL or the LGPL. If you do not delete
36 # the provisions above, a recipient may use your version of this file under
37 # the terms of any one of the MPL, the GPL or the LGPL.
39 # ***** END LICENSE BLOCK *****
41 """Print a C++ header file for the IDL files specified on the command line"""
43 import sys
, os
.path
, re
, xpidl
45 printdoccomments
= False
48 def printComments(fd
, clist
, indent
):
50 fd
.write("%s%s\n" % (indent
, c
))
52 def printComments(fd
, clist
, indent
):
56 return str[0].upper() + str[1:]
58 def attributeParamName(a
):
59 return "a" + firstCap(a
.name
)
61 def attributeNativeName(a
, getter
):
62 binaryname
= a
.binaryname
is not None and a
.binaryname
or firstCap(a
.name
)
63 return "%s%s" % (getter
and 'Get' or 'Set', binaryname
)
65 def attributeParamlist(a
, getter
):
66 return "%s%s" % (a
.realtype
.nativeType(getter
and 'out' or 'in'),
67 attributeParamName(a
))
69 def attributeAsNative(a
, getter
):
70 scriptable
= a
.isScriptable() and "NS_SCRIPTABLE " or ""
71 params
= {'scriptable': scriptable
,
72 'binaryname': attributeNativeName(a
, getter
),
73 'paramlist': attributeParamlist(a
, getter
)}
74 return "%(scriptable)sNS_IMETHOD %(binaryname)s(%(paramlist)s)" % params
76 def methodNativeName(m
):
77 return m
.binaryname
is not None and m
.binaryname
or firstCap(m
.name
)
79 def methodReturnType(m
, macro
):
80 """macro should be NS_IMETHOD or NS_IMETHODIMP"""
82 return "%s_(%s)" % (macro
, m
.realtype
.nativeType('in').strip())
86 def methodAsNative(m
):
87 scriptable
= m
.isScriptable() and "NS_SCRIPTABLE " or ""
89 return "%s%s %s(%s)" % (scriptable
,
90 methodReturnType(m
, 'NS_IMETHOD'),
92 paramlistAsNative(m
.params
,
96 def paramlistAsNative(l
, rettype
, notxpcom
, empty
='void'):
98 if not notxpcom
and rettype
.name
!= 'void':
99 l
.append(xpidl
.Param(paramtype
='out',
109 return ", ".join([paramAsNative(p
) for p
in l
])
111 def paramAsNative(p
):
112 if p
.paramtype
== 'in':
115 typeannotate
= ' NS_%sPARAM' % p
.paramtype
.upper()
117 return "%s%s%s" % (p
.nativeType(),
121 def paramlistNames(l
, rettype
, notxpcom
):
122 names
= [p
.name
for p
in l
]
123 if not notxpcom
and rettype
.name
!= 'void':
124 names
.append('_retval')
127 return ', '.join(names
)
130 * DO NOT EDIT. THIS FILE IS GENERATED FROM %(filename)s
133 #ifndef __gen_%(basename)s_h__
134 #define __gen_%(basename)s_h__
138 #ifndef __gen_%(basename)s_h__
139 #include "%(basename)s.h"
143 header_end
= """/* For IDL files that don't want to include root IDL files. */
150 #endif /* __gen_%(basename)s_h__ */
153 forward_decl
= """class %(name)s; /* forward declaration */
158 """returns the base name of a file with the last extension stripped"""
159 return os
.path
.basename(f
).rpartition('.')[0]
161 def print_header(idl
, fd
, filename
):
162 fd
.write(header
% {'filename': filename
,
163 'basename': idl_basename(filename
)})
166 for inc
in idl
.includes():
170 fd
.write(include
% {'basename': idl_basename(inc
.filename
)})
175 for p
in idl
.productions
:
176 if p
.kind
== 'include': continue
177 if p
.kind
== 'cdata':
181 if p
.kind
== 'forward':
182 fd
.write(forward_decl
% {'name': p
.name
})
184 if p
.kind
== 'interface':
185 write_interface(p
, fd
)
187 if p
.kind
== 'typedef':
188 printComments(fd
, p
.doccomments
, '')
189 fd
.write("typedef %s %s;\n\n" % (p
.realtype
.nativeType('in'),
192 fd
.write(footer
% {'basename': idl_basename(filename
)})
195 /* starting interface: %(name)s */
196 #define %(defname)s_IID_STR "%(iid)s"
198 #define %(defname)s_IID \
199 {0x%(m0)s, 0x%(m1)s, 0x%(m2)s, \
204 uuid_decoder
= re
.compile(r
"""(?P<m0>[a-f0-9]{8})-
208 (?P<m4>[a-f0-9]{12})$""", re
.X
)
213 NS_DECLARE_STATIC_IID_ACCESSOR(%(defname)s_IID)
219 NS_DEFINE_STATIC_IID_ACCESSOR(%(name)s, %(defname)s_IID)
221 /* Use this macro when declaring classes that implement this interface. */
222 #define NS_DECL_%(macroname)s """
227 /* Use this macro to declare functions that forward the behavior of this interface to another object. */
228 #define NS_FORWARD_%(macroname)s(_to) """
230 iface_forward_safe
= """
232 /* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */
233 #define NS_FORWARD_SAFE_%(macroname)s(_to) """
235 iface_template_prolog
= """
238 /* Use the code below as a template for the implementation class for this interface. */
241 class %(implclass)s : public %(name)s
245 NS_DECL_%(macroname)s
253 /* additional members */
256 /* Implementation file */
257 NS_IMPL_ISUPPORTS1(%(implclass)s, %(name)s)
259 %(implclass)s::%(implclass)s()
261 /* member initializers and constructor code */
264 %(implclass)s::~%(implclass)s()
266 /* destructor code */
271 example_tmpl
= """%(returntype)s %(implclass)s::%(nativeName)s(%(paramList)s)
273 return NS_ERROR_NOT_IMPLEMENTED;
277 iface_template_epilog
= """/* End of implementation class template. */
282 def write_interface(iface
, fd
):
283 if iface
.namemap
is None:
284 raise Exception("Interface was not resolved.")
286 def write_const_decl(c
):
287 printComments(fd
, c
.doccomments
, ' ')
289 basetype
= c
.basetype
292 fd
.write(" enum { %(name)s = %(value)s%(signed)s };\n\n" % {
295 'signed': (not basetype
.signed
) and 'U' or ''})
297 def write_method_decl(m
):
298 printComments(fd
, m
.doccomments
, ' ')
300 fd
.write(" /* %s */\n" % m
.toIDL())
301 fd
.write(" %s = 0;\n\n" % methodAsNative(m
))
303 def write_attr_decl(a
):
304 printComments(fd
, a
.doccomments
, ' ')
306 fd
.write(" /* %s */\n" % a
.toIDL());
308 fd
.write(" %s = 0;\n" % attributeAsNative(a
, True))
310 fd
.write(" %s = 0;\n" % attributeAsNative(a
, False))
313 defname
= iface
.name
.upper()
314 if iface
.name
[0:2] == 'ns':
315 defname
= 'NS_' + defname
[2:]
317 names
= uuid_decoder
.match(iface
.attributes
.uuid
).groupdict()
318 m3str
= names
['m3'] + names
['m4']
319 names
['m3joined'] = ", ".join(["0x%s" % m3str
[i
:i
+2] for i
in xrange(0, 16, 2)])
321 if iface
.name
[2] == 'I':
322 implclass
= iface
.name
[:2] + iface
.name
[3:]
324 implclass
= '_MYCLASS_'
326 names
.update({'defname': defname
,
327 'macroname': iface
.name
.upper(),
329 'iid': iface
.attributes
.uuid
,
330 'implclass': implclass
})
332 fd
.write(iface_header
% names
)
334 printComments(fd
, iface
.doccomments
, '')
338 for m
in iface
.members
:
339 if isinstance(m
, xpidl
.CDATA
):
343 fd
.write("NS_NO_VTABLE ")
345 if iface
.attributes
.scriptable
:
346 fd
.write("NS_SCRIPTABLE ")
347 if iface
.attributes
.deprecated
:
348 fd
.write("NS_DEPRECATED ")
351 fd
.write(" : public %s" % iface
.base
)
352 fd
.write(iface_prolog
% names
)
353 for member
in iface
.members
:
354 if isinstance(member
, xpidl
.ConstMember
):
355 write_const_decl(member
)
356 elif isinstance(member
, xpidl
.Attribute
):
357 write_attr_decl(member
)
358 elif isinstance(member
, xpidl
.Method
):
359 write_method_decl(member
)
360 elif isinstance(member
, xpidl
.CDATA
):
361 fd
.write(" %s" % member
.data
)
363 raise Exception("Unexpected interface member: %s" % member
)
365 fd
.write(iface_epilog
% names
)
367 for member
in iface
.members
:
368 if isinstance(member
, xpidl
.Attribute
):
369 fd
.write("\\\n %s; " % attributeAsNative(member
, True))
370 if not member
.readonly
:
371 fd
.write("\\\n %s; " % attributeAsNative(member
, False))
372 elif isinstance(member
, xpidl
.Method
):
373 fd
.write("\\\n %s; " % methodAsNative(member
))
374 if len(iface
.members
) == 0:
375 fd
.write('\\\n /* no methods! */')
376 elif not member
.kind
in ('attribute', 'method'):
379 fd
.write(iface_forward
% names
)
381 def emitTemplate(tmpl
):
382 for member
in iface
.members
:
383 if isinstance(member
, xpidl
.Attribute
):
384 fd
.write(tmpl
% {'asNative': attributeAsNative(member
, True),
385 'nativeName': attributeNativeName(member
, True),
386 'paramList': attributeParamName(member
)})
387 if not member
.readonly
:
388 fd
.write(tmpl
% {'asNative': attributeAsNative(member
, False),
389 'nativeName': attributeNativeName(member
, False),
390 'paramList': attributeParamName(member
)})
391 elif isinstance(member
, xpidl
.Method
):
392 fd
.write(tmpl
% {'asNative': methodAsNative(member
),
393 'nativeName': methodNativeName(member
),
394 'paramList': paramlistNames(member
.params
, member
.realtype
, member
.notxpcom
)})
395 if len(iface
.members
) == 0:
396 fd
.write('\\\n /* no methods! */')
397 elif not member
.kind
in ('attribute', 'method'):
400 emitTemplate("\\\n %(asNative)s { return _to %(nativeName)s(%(paramList)s); } ")
402 fd
.write(iface_forward_safe
% names
)
404 emitTemplate("\\\n %(asNative)s { return !_to ? NS_ERROR_NULL_POINTER : _to->%(nativeName)s(%(paramList)s); } ")
406 fd
.write(iface_template_prolog
% names
)
408 for member
in iface
.members
:
409 if isinstance(member
, xpidl
.ConstMember
) or isinstance(member
, xpidl
.CDATA
): continue
410 fd
.write("/* %s */\n" % member
.toIDL())
411 if isinstance(member
, xpidl
.Attribute
):
412 fd
.write(example_tmpl
% {'implclass': implclass
,
413 'returntype': 'NS_IMETHODIMP',
414 'nativeName': attributeNativeName(member
, True),
415 'paramList': attributeParamlist(member
, True)})
416 if not member
.readonly
:
417 fd
.write(example_tmpl
% {'implclass': implclass
,
418 'returntype': 'NS_IMETHODIMP',
419 'nativeName': attributeNativeName(member
, False),
420 'paramList': attributeParamlist(member
, False)})
421 elif isinstance(member
, xpidl
.Method
):
422 fd
.write(example_tmpl
% {'implclass': implclass
,
423 'returntype': methodReturnType(member
, 'NS_IMETHODIMP'),
424 'nativeName': methodNativeName(member
),
425 'paramList': paramlistAsNative(member
.params
, member
.realtype
, notxpcom
=member
.notxpcom
, empty
='')})
428 fd
.write(iface_template_epilog
)
430 if __name__
== '__main__':
431 from optparse
import OptionParser
433 o
.add_option('-I', action
='append', dest
='incdirs', help="Directory to search for imported files", default
=[])
434 o
.add_option('--cachedir', dest
='cachedir', help="Directory in which to cache lex/parse tables.", default
='')
435 options
, args
= o
.parse_args()
438 if options
.cachedir
!= '':
439 sys
.path
.append(options
.cachedir
)
441 p
= xpidl
.IDLParser(outputdir
=options
.cachedir
)
442 idl
= p
.parse(open(file).read(), filename
=file)
443 idl
.resolve(options
.incdirs
, p
)
444 print_header(idl
, sys
.stdout
, file)