Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 #!/usr/bin/env python
2 # header.py - Generate C++ header files from IDL.
3 #
4 # This Source Code Form is subject to the terms of the Mozilla Public
5 # License, v. 2.0. If a copy of the MPL was not distributed with this
6 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 """Print a C++ header file for the IDL files specified on the command line"""
10 import sys, os.path, re, xpidl, itertools, glob
12 printdoccomments = False
14 if printdoccomments:
15 def printComments(fd, clist, indent):
16 for c in clist:
17 fd.write("%s%s\n" % (indent, c))
18 else:
19 def printComments(fd, clist, indent):
20 pass
22 def firstCap(str):
23 return str[0].upper() + str[1:]
25 def attributeParamName(a):
26 return "a" + firstCap(a.name)
28 def attributeParamNames(a):
29 l = [attributeParamName(a)]
30 if a.implicit_jscontext:
31 l.insert(0, "cx")
32 return ", ".join(l)
34 def attributeNativeName(a, getter):
35 binaryname = a.binaryname is not None and a.binaryname or firstCap(a.name)
36 return "%s%s" % (getter and 'Get' or 'Set', binaryname)
38 def attributeReturnType(a, macro):
39 """macro should be NS_IMETHOD or NS_IMETHODIMP"""
40 if (a.nostdcall):
41 return macro == "NS_IMETHOD" and "virtual nsresult" or "nsresult"
42 else:
43 return macro
45 def attributeParamlist(a, getter):
46 l = ["%s%s" % (a.realtype.nativeType(getter and 'out' or 'in'),
47 attributeParamName(a))]
48 if a.implicit_jscontext:
49 l.insert(0, "JSContext* cx")
51 return ", ".join(l)
53 def attributeAsNative(a, getter):
54 deprecated = a.deprecated and "NS_DEPRECATED " or ""
55 params = {'deprecated': deprecated,
56 'returntype': attributeReturnType(a, 'NS_IMETHOD'),
57 'binaryname': attributeNativeName(a, getter),
58 'paramlist': attributeParamlist(a, getter)}
59 return "%(deprecated)s%(returntype)s %(binaryname)s(%(paramlist)s)" % params
61 def methodNativeName(m):
62 return m.binaryname is not None and m.binaryname or firstCap(m.name)
64 def methodReturnType(m, macro):
65 """macro should be NS_IMETHOD or NS_IMETHODIMP"""
66 if m.nostdcall and m.notxpcom:
67 return "%s%s" % (macro == "NS_IMETHOD" and "virtual " or "",
68 m.realtype.nativeType('in').strip())
69 elif m.nostdcall:
70 return "%snsresult" % (macro == "NS_IMETHOD" and "virtual " or "")
71 elif m.notxpcom:
72 return "%s_(%s)" % (macro, m.realtype.nativeType('in').strip())
73 else:
74 return macro
76 def methodAsNative(m):
77 return "%s %s(%s)" % (methodReturnType(m, 'NS_IMETHOD'),
78 methodNativeName(m),
79 paramlistAsNative(m))
81 def paramlistAsNative(m, empty='void'):
82 l = [paramAsNative(p) for p in m.params]
84 if m.implicit_jscontext:
85 l.append("JSContext* cx")
87 if m.optional_argc:
88 l.append('uint8_t _argc')
90 if not m.notxpcom and m.realtype.name != 'void':
91 l.append(paramAsNative(xpidl.Param(paramtype='out',
92 type=None,
93 name='_retval',
94 attlist=[],
95 location=None,
96 realtype=m.realtype)))
98 if len(l) == 0:
99 return empty
101 return ", ".join(l)
103 def paramAsNative(p):
104 return "%s%s" % (p.nativeType(),
105 p.name)
107 def paramlistNames(m):
108 names = [p.name for p in m.params]
110 if m.implicit_jscontext:
111 names.append('cx')
113 if m.optional_argc:
114 names.append('_argc')
116 if not m.notxpcom and m.realtype.name != 'void':
117 names.append('_retval')
119 if len(names) == 0:
120 return ''
121 return ', '.join(names)
123 header = """/*
124 * DO NOT EDIT. THIS FILE IS GENERATED FROM %(filename)s
125 */
127 #ifndef __gen_%(basename)s_h__
128 #define __gen_%(basename)s_h__
129 """
131 include = """
132 #ifndef __gen_%(basename)s_h__
133 #include "%(basename)s.h"
134 #endif
135 """
137 jsvalue_include = """
138 #include "js/Value.h"
139 """
141 infallible_includes = """
142 #include "mozilla/Assertions.h"
143 #include "mozilla/DebugOnly.h"
144 """
146 header_end = """/* For IDL files that don't want to include root IDL files. */
147 #ifndef NS_NO_VTABLE
148 #define NS_NO_VTABLE
149 #endif
150 """
152 footer = """
153 #endif /* __gen_%(basename)s_h__ */
154 """
156 forward_decl = """class %(name)s; /* forward declaration */
158 """
160 def idl_basename(f):
161 """returns the base name of a file with the last extension stripped"""
162 return os.path.basename(f).rpartition('.')[0]
164 def print_header(idl, fd, filename):
165 fd.write(header % {'filename': filename,
166 'basename': idl_basename(filename)})
168 foundinc = False
169 for inc in idl.includes():
170 if not foundinc:
171 foundinc = True
172 fd.write('\n')
173 fd.write(include % {'basename': idl_basename(inc.filename)})
175 if idl.needsJSTypes():
176 fd.write(jsvalue_include)
178 # Include some extra files if any attributes are infallible.
179 for iface in [p for p in idl.productions if p.kind == 'interface']:
180 for attr in [m for m in iface.members if isinstance(m, xpidl.Attribute)]:
181 if attr.infallible:
182 fd.write(infallible_includes)
183 break
185 fd.write('\n')
186 fd.write(header_end)
188 for p in idl.productions:
189 if p.kind == 'include': continue
190 if p.kind == 'cdata':
191 fd.write(p.data)
192 continue
194 if p.kind == 'forward':
195 fd.write(forward_decl % {'name': p.name})
196 continue
197 if p.kind == 'interface':
198 write_interface(p, fd)
199 continue
200 if p.kind == 'typedef':
201 printComments(fd, p.doccomments, '')
202 fd.write("typedef %s %s;\n\n" % (p.realtype.nativeType('in'),
203 p.name))
205 fd.write(footer % {'basename': idl_basename(filename)})
207 iface_header = r"""
208 /* starting interface: %(name)s */
209 #define %(defname)s_IID_STR "%(iid)s"
211 #define %(defname)s_IID \
212 {0x%(m0)s, 0x%(m1)s, 0x%(m2)s, \
213 { %(m3joined)s }}
215 """
217 uuid_decoder = re.compile(r"""(?P<m0>[a-f0-9]{8})-
218 (?P<m1>[a-f0-9]{4})-
219 (?P<m2>[a-f0-9]{4})-
220 (?P<m3>[a-f0-9]{4})-
221 (?P<m4>[a-f0-9]{12})$""", re.X)
223 iface_prolog = """ {
224 public:
226 NS_DECLARE_STATIC_IID_ACCESSOR(%(defname)s_IID)
228 """
230 iface_epilog = """};
232 NS_DEFINE_STATIC_IID_ACCESSOR(%(name)s, %(defname)s_IID)
234 /* Use this macro when declaring classes that implement this interface. */
235 #define NS_DECL_%(macroname)s """
238 iface_forward = """
240 /* Use this macro to declare functions that forward the behavior of this interface to another object. */
241 #define NS_FORWARD_%(macroname)s(_to) """
243 iface_forward_safe = """
245 /* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */
246 #define NS_FORWARD_SAFE_%(macroname)s(_to) """
248 iface_template_prolog = """
250 #if 0
251 /* Use the code below as a template for the implementation class for this interface. */
253 /* Header file */
254 class %(implclass)s : public %(name)s
255 {
256 public:
257 NS_DECL_ISUPPORTS
258 NS_DECL_%(macroname)s
260 %(implclass)s();
262 private:
263 ~%(implclass)s();
265 protected:
266 /* additional members */
267 };
269 /* Implementation file */
270 NS_IMPL_ISUPPORTS(%(implclass)s, %(name)s)
272 %(implclass)s::%(implclass)s()
273 {
274 /* member initializers and constructor code */
275 }
277 %(implclass)s::~%(implclass)s()
278 {
279 /* destructor code */
280 }
282 """
284 example_tmpl = """%(returntype)s %(implclass)s::%(nativeName)s(%(paramList)s)
285 {
286 return NS_ERROR_NOT_IMPLEMENTED;
287 }
288 """
290 iface_template_epilog = """/* End of implementation class template. */
291 #endif
293 """
295 attr_infallible_tmpl = """\
296 inline %(realtype)s%(nativename)s(%(args)s)
297 {
298 %(realtype)sresult;
299 mozilla::DebugOnly<nsresult> rv = %(nativename)s(%(argnames)s&result);
300 MOZ_ASSERT(NS_SUCCEEDED(rv));
301 return result;
302 }
303 """
305 def write_interface(iface, fd):
306 if iface.namemap is None:
307 raise Exception("Interface was not resolved.")
309 def write_const_decls(g):
310 fd.write(" enum {\n")
311 enums = []
312 for c in g:
313 printComments(fd, c.doccomments, ' ')
314 basetype = c.basetype
315 value = c.getValue()
316 enums.append(" %(name)s = %(value)s%(signed)s" % {
317 'name': c.name,
318 'value': value,
319 'signed': (not basetype.signed) and 'U' or ''})
320 fd.write(",\n".join(enums))
321 fd.write("\n };\n\n")
323 def write_method_decl(m):
324 printComments(fd, m.doccomments, ' ')
326 fd.write(" /* %s */\n" % m.toIDL())
327 fd.write(" %s = 0;\n\n" % methodAsNative(m))
329 def write_attr_decl(a):
330 printComments(fd, a.doccomments, ' ')
332 fd.write(" /* %s */\n" % a.toIDL());
334 fd.write(" %s = 0;\n" % attributeAsNative(a, True))
335 if a.infallible:
336 fd.write(attr_infallible_tmpl %
337 {'realtype': a.realtype.nativeType('in'),
338 'nativename': attributeNativeName(a, getter=True),
339 'args': '' if not a.implicit_jscontext else 'JSContext* cx',
340 'argnames': '' if not a.implicit_jscontext else 'cx, '})
342 if not a.readonly:
343 fd.write(" %s = 0;\n" % attributeAsNative(a, False))
344 fd.write("\n")
346 defname = iface.name.upper()
347 if iface.name[0:2] == 'ns':
348 defname = 'NS_' + defname[2:]
350 names = uuid_decoder.match(iface.attributes.uuid).groupdict()
351 m3str = names['m3'] + names['m4']
352 names['m3joined'] = ", ".join(["0x%s" % m3str[i:i+2] for i in xrange(0, 16, 2)])
354 if iface.name[2] == 'I':
355 implclass = iface.name[:2] + iface.name[3:]
356 else:
357 implclass = '_MYCLASS_'
359 names.update({'defname': defname,
360 'macroname': iface.name.upper(),
361 'name': iface.name,
362 'iid': iface.attributes.uuid,
363 'implclass': implclass})
365 fd.write(iface_header % names)
367 printComments(fd, iface.doccomments, '')
369 fd.write("class ")
370 foundcdata = False
371 for m in iface.members:
372 if isinstance(m, xpidl.CDATA):
373 foundcdata = True
375 if not foundcdata:
376 fd.write("NS_NO_VTABLE ")
378 if iface.attributes.deprecated:
379 fd.write("MOZ_DEPRECATED ")
380 fd.write(iface.name)
381 if iface.base:
382 fd.write(" : public %s" % iface.base)
383 fd.write(iface_prolog % names)
385 for key, group in itertools.groupby(iface.members, key=type):
386 if key == xpidl.ConstMember:
387 write_const_decls(group) # iterator of all the consts
388 else:
389 for member in group:
390 if key == xpidl.Attribute:
391 write_attr_decl(member)
392 elif key == xpidl.Method:
393 write_method_decl(member)
394 elif key == xpidl.CDATA:
395 fd.write(" %s" % member.data)
396 else:
397 raise Exception("Unexpected interface member: %s" % member)
399 fd.write(iface_epilog % names)
401 for member in iface.members:
402 if isinstance(member, xpidl.Attribute):
403 fd.write("\\\n %s; " % attributeAsNative(member, True))
404 if not member.readonly:
405 fd.write("\\\n %s; " % attributeAsNative(member, False))
406 elif isinstance(member, xpidl.Method):
407 fd.write("\\\n %s; " % methodAsNative(member))
408 if len(iface.members) == 0:
409 fd.write('\\\n /* no methods! */')
410 elif not member.kind in ('attribute', 'method'):
411 fd.write('\\')
413 fd.write(iface_forward % names)
415 def emitTemplate(tmpl, tmpl_notxpcom=None):
416 if tmpl_notxpcom == None:
417 tmpl_notxpcom = tmpl
418 for member in iface.members:
419 if isinstance(member, xpidl.Attribute):
420 fd.write(tmpl % {'asNative': attributeAsNative(member, True),
421 'nativeName': attributeNativeName(member, True),
422 'paramList': attributeParamNames(member)})
423 if not member.readonly:
424 fd.write(tmpl % {'asNative': attributeAsNative(member, False),
425 'nativeName': attributeNativeName(member, False),
426 'paramList': attributeParamNames(member)})
427 elif isinstance(member, xpidl.Method):
428 if member.notxpcom:
429 fd.write(tmpl_notxpcom % {'asNative': methodAsNative(member),
430 'nativeName': methodNativeName(member),
431 'paramList': paramlistNames(member)})
432 else:
433 fd.write(tmpl % {'asNative': methodAsNative(member),
434 'nativeName': methodNativeName(member),
435 'paramList': paramlistNames(member)})
436 if len(iface.members) == 0:
437 fd.write('\\\n /* no methods! */')
438 elif not member.kind in ('attribute', 'method'):
439 fd.write('\\')
441 emitTemplate("\\\n %(asNative)s { return _to %(nativeName)s(%(paramList)s); } ")
443 fd.write(iface_forward_safe % names)
445 # Don't try to safely forward notxpcom functions, because we have no
446 # sensible default error return. Instead, the caller will have to
447 # implement them.
448 emitTemplate("\\\n %(asNative)s { return !_to ? NS_ERROR_NULL_POINTER : _to->%(nativeName)s(%(paramList)s); } ",
449 "\\\n %(asNative)s; ")
451 fd.write(iface_template_prolog % names)
453 for member in iface.members:
454 if isinstance(member, xpidl.ConstMember) or isinstance(member, xpidl.CDATA): continue
455 fd.write("/* %s */\n" % member.toIDL())
456 if isinstance(member, xpidl.Attribute):
457 fd.write(example_tmpl % {'implclass': implclass,
458 'returntype': attributeReturnType(member, 'NS_IMETHODIMP'),
459 'nativeName': attributeNativeName(member, True),
460 'paramList': attributeParamlist(member, True)})
461 if not member.readonly:
462 fd.write(example_tmpl % {'implclass': implclass,
463 'returntype': attributeReturnType(member, 'NS_IMETHODIMP'),
464 'nativeName': attributeNativeName(member, False),
465 'paramList': attributeParamlist(member, False)})
466 elif isinstance(member, xpidl.Method):
467 fd.write(example_tmpl % {'implclass': implclass,
468 'returntype': methodReturnType(member, 'NS_IMETHODIMP'),
469 'nativeName': methodNativeName(member),
470 'paramList': paramlistAsNative(member, empty='')})
471 fd.write('\n')
473 fd.write(iface_template_epilog)
475 if __name__ == '__main__':
476 from optparse import OptionParser
477 o = OptionParser()
478 o.add_option('-I', action='append', dest='incdirs', default=['.'],
479 help="Directory to search for imported files")
480 o.add_option('--cachedir', dest='cachedir', default=None,
481 help="Directory in which to cache lex/parse tables.")
482 o.add_option('-o', dest='outfile', default=None,
483 help="Output file (default is stdout)")
484 o.add_option('-d', dest='depfile', default=None,
485 help="Generate a make dependency file")
486 o.add_option('--regen', action='store_true', dest='regen', default=False,
487 help="Regenerate IDL Parser cache")
488 options, args = o.parse_args()
489 file = args[0] if args else None
491 if options.cachedir is not None:
492 if not os.path.isdir(options.cachedir):
493 os.mkdir(options.cachedir)
494 sys.path.append(options.cachedir)
496 # The only thing special about a regen is that there are no input files.
497 if options.regen:
498 if options.cachedir is None:
499 print >>sys.stderr, "--regen useless without --cachedir"
500 # Delete the lex/yacc files. Ply is too stupid to regenerate them
501 # properly
502 for fileglobs in [os.path.join(options.cachedir, f) for f in ["xpidllex.py*", "xpidlyacc.py*"]]:
503 for filename in glob.glob(fileglobs):
504 os.remove(filename)
506 # Instantiate the parser.
507 p = xpidl.IDLParser(outputdir=options.cachedir)
509 if options.regen:
510 sys.exit(0)
512 if options.depfile is not None and options.outfile is None:
513 print >>sys.stderr, "-d requires -o"
514 sys.exit(1)
516 if options.outfile is not None:
517 outfd = open(options.outfile, 'w')
518 closeoutfd = True
519 else:
520 outfd = sys.stdout
521 closeoutfd = False
523 idl = p.parse(open(file).read(), filename=file)
524 idl.resolve(options.incdirs, p)
525 print_header(idl, outfd, file)
527 if closeoutfd:
528 outfd.close()
530 if options.depfile is not None:
531 dirname = os.path.dirname(options.depfile)
532 if dirname:
533 try:
534 os.makedirs(dirname)
535 except:
536 pass
537 depfd = open(options.depfile, 'w')
538 deps = [dep.replace('\\', '/') for dep in idl.deps]
540 print >>depfd, "%s: %s" % (options.outfile, " ".join(deps))
541 for dep in deps:
542 print >>depfd, "%s:" % dep