~ubuntu-branches/ubuntu/quantal/enigmail/quantal-security

« back to all changes in this revision

Viewing changes to mozilla/xpcom/idl-parser/header.py

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2013-09-13 16:02:15 UTC
  • mfrom: (0.12.16)
  • Revision ID: package-import@ubuntu.com-20130913160215-u3g8nmwa0pdwagwc
Tags: 2:1.5.2-0ubuntu0.12.10.1
* New upstream release v1.5.2 for Thunderbird 24

* Build enigmail using a stripped down Thunderbird 17 build system, as it's
  now quite difficult to build the way we were doing previously, with the
  latest Firefox build system
* Add debian/patches/no_libxpcom.patch - Don't link against libxpcom, as it
  doesn't exist anymore (but exists in the build system)
* Add debian/patches/use_sdk.patch - Use the SDK version of xpt.py and
  friends
* Drop debian/patches/ipc-pipe_rename.diff (not needed anymore)
* Drop debian/patches/makefile_depth.diff (not needed anymore)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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/.
 
7
 
 
8
"""Print a C++ header file for the IDL files specified on the command line"""
 
9
 
 
10
import sys, os.path, re, xpidl, itertools, glob
 
11
 
 
12
printdoccomments = False
 
13
 
 
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
 
21
 
 
22
def firstCap(str):
 
23
    return str[0].upper() + str[1:]
 
24
 
 
25
def attributeParamName(a):
 
26
    return "a" + firstCap(a.name)
 
27
 
 
28
def attributeParamNames(a):
 
29
    l = [attributeParamName(a)]
 
30
    if a.implicit_jscontext:
 
31
        l.insert(0, "cx")
 
32
    return ", ".join(l)
 
33
 
 
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)
 
37
 
 
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
 
44
 
 
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")
 
50
 
 
51
    return ", ".join(l)
 
52
 
 
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
 
60
 
 
61
def methodNativeName(m):
 
62
    return m.binaryname is not None and m.binaryname or firstCap(m.name)
 
63
 
 
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
 
75
 
 
76
def methodAsNative(m):
 
77
    return "%s %s(%s)" % (methodReturnType(m, 'NS_IMETHOD'),
 
78
                          methodNativeName(m),
 
79
                          paramlistAsNative(m))
 
80
 
 
81
def paramlistAsNative(m, empty='void'):
 
82
    l = [paramAsNative(p) for p in m.params]
 
83
 
 
84
    if m.implicit_jscontext:
 
85
        l.append("JSContext* cx")
 
86
 
 
87
    if m.optional_argc:
 
88
        l.append('uint8_t _argc')
 
89
 
 
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)))
 
97
 
 
98
    if len(l) == 0:
 
99
        return empty
 
100
 
 
101
    return ", ".join(l)
 
102
 
 
103
def paramAsNative(p):
 
104
    return "%s%s" % (p.nativeType(),
 
105
                     p.name)
 
106
 
 
107
def paramlistNames(m):
 
108
    names = [p.name for p in m.params]
 
109
 
 
110
    if m.implicit_jscontext:
 
111
        names.append('cx')
 
112
 
 
113
    if m.optional_argc:
 
114
        names.append('_argc')
 
115
 
 
116
    if not m.notxpcom and m.realtype.name != 'void':
 
117
        names.append('_retval')
 
118
 
 
119
    if len(names) == 0:
 
120
        return ''
 
121
    return ', '.join(names)
 
122
 
 
123
header = """/*
 
124
 * DO NOT EDIT.  THIS FILE IS GENERATED FROM %(filename)s
 
125
 */
 
126
 
 
127
#ifndef __gen_%(basename)s_h__
 
128
#define __gen_%(basename)s_h__
 
129
"""
 
130
 
 
131
include = """
 
132
#ifndef __gen_%(basename)s_h__
 
133
#include "%(basename)s.h"
 
134
#endif
 
135
"""
 
136
 
 
137
jspubtd_include = """
 
138
#include "jspubtd.h"
 
139
"""
 
140
 
 
141
infallible_includes = """
 
142
#include "mozilla/Assertions.h"
 
143
#include "mozilla/Util.h"
 
144
"""
 
145
 
 
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
"""
 
151
 
 
152
footer = """
 
153
#endif /* __gen_%(basename)s_h__ */
 
154
"""
 
155
 
 
156
forward_decl = """class %(name)s; /* forward declaration */
 
157
 
 
158
"""
 
159
 
 
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]
 
163
 
 
164
def print_header(idl, fd, filename):
 
165
    fd.write(header % {'filename': filename,
 
166
                       'basename': idl_basename(filename)})
 
167
 
 
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)})
 
174
 
 
175
    if idl.needsJSTypes():
 
176
        fd.write(jspubtd_include)
 
177
 
 
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
 
184
 
 
185
    fd.write('\n')
 
186
    fd.write(header_end)
 
187
 
 
188
    for p in idl.productions:
 
189
        if p.kind == 'include': continue
 
190
        if p.kind == 'cdata':
 
191
            fd.write(p.data)
 
192
            continue
 
193
 
 
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))
 
204
 
 
205
    fd.write(footer % {'basename': idl_basename(filename)})
 
206
 
 
207
iface_header = r"""
 
208
/* starting interface:    %(name)s */
 
209
#define %(defname)s_IID_STR "%(iid)s"
 
210
 
 
211
#define %(defname)s_IID \
 
212
  {0x%(m0)s, 0x%(m1)s, 0x%(m2)s, \
 
213
    { %(m3joined)s }}
 
214
 
 
215
"""
 
216
 
 
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)
 
222
 
 
223
iface_prolog = """ {
 
224
 public: 
 
225
 
 
226
  NS_DECLARE_STATIC_IID_ACCESSOR(%(defname)s_IID)
 
227
 
 
228
"""
 
229
 
 
230
iface_epilog = """};
 
231
 
 
232
  NS_DEFINE_STATIC_IID_ACCESSOR(%(name)s, %(defname)s_IID)
 
233
 
 
234
/* Use this macro when declaring classes that implement this interface. */
 
235
#define NS_DECL_%(macroname)s """
 
236
 
 
237
 
 
238
iface_forward = """
 
239
 
 
240
/* Use this macro to declare functions that forward the behavior of this interface to another object. */
 
241
#define NS_FORWARD_%(macroname)s(_to) """
 
242
 
 
243
iface_forward_safe = """
 
244
 
 
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) """
 
247
 
 
248
iface_template_prolog = """
 
249
 
 
250
#if 0
 
251
/* Use the code below as a template for the implementation class for this interface. */
 
252
 
 
253
/* Header file */
 
254
class %(implclass)s : public %(name)s
 
255
{
 
256
public:
 
257
  NS_DECL_ISUPPORTS
 
258
  NS_DECL_%(macroname)s
 
259
 
 
260
  %(implclass)s();
 
261
 
 
262
private:
 
263
  ~%(implclass)s();
 
264
 
 
265
protected:
 
266
  /* additional members */
 
267
};
 
268
 
 
269
/* Implementation file */
 
270
NS_IMPL_ISUPPORTS1(%(implclass)s, %(name)s)
 
271
 
 
272
%(implclass)s::%(implclass)s()
 
273
{
 
274
  /* member initializers and constructor code */
 
275
}
 
276
 
 
277
%(implclass)s::~%(implclass)s()
 
278
{
 
279
  /* destructor code */
 
280
}
 
281
 
 
282
"""
 
283
 
 
284
example_tmpl = """%(returntype)s %(implclass)s::%(nativeName)s(%(paramList)s)
 
285
{
 
286
    return NS_ERROR_NOT_IMPLEMENTED;
 
287
}
 
288
"""
 
289
 
 
290
iface_template_epilog = """/* End of implementation class template. */
 
291
#endif
 
292
 
 
293
"""
 
294
 
 
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
"""
 
304
 
 
305
def write_interface(iface, fd):
 
306
    if iface.namemap is None:
 
307
        raise Exception("Interface was not resolved.")
 
308
 
 
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")
 
322
 
 
323
    def write_method_decl(m):
 
324
        printComments(fd, m.doccomments, '  ')
 
325
 
 
326
        fd.write("  /* %s */\n" % m.toIDL())
 
327
        fd.write("  %s = 0;\n\n" % methodAsNative(m))
 
328
                                                                           
 
329
    def write_attr_decl(a):
 
330
        printComments(fd, a.doccomments, '  ')
 
331
 
 
332
        fd.write("  /* %s */\n" % a.toIDL());
 
333
 
 
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, '})
 
341
 
 
342
        if not a.readonly:
 
343
            fd.write("  %s = 0;\n" % attributeAsNative(a, False))
 
344
        fd.write("\n")
 
345
 
 
346
    defname = iface.name.upper()
 
347
    if iface.name[0:2] == 'ns':
 
348
        defname = 'NS_' + defname[2:]
 
349
 
 
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)])
 
353
 
 
354
    if iface.name[2] == 'I':
 
355
        implclass = iface.name[:2] + iface.name[3:]
 
356
    else:
 
357
        implclass = '_MYCLASS_'
 
358
 
 
359
    names.update({'defname': defname,
 
360
                  'macroname': iface.name.upper(),
 
361
                  'name': iface.name,
 
362
                  'iid': iface.attributes.uuid,
 
363
                  'implclass': implclass})
 
364
 
 
365
    fd.write(iface_header % names)
 
366
 
 
367
    printComments(fd, iface.doccomments, '')
 
368
 
 
369
    fd.write("class ")
 
370
    foundcdata = False
 
371
    for m in iface.members:
 
372
        if isinstance(m, xpidl.CDATA):
 
373
            foundcdata = True
 
374
 
 
375
    if not foundcdata:
 
376
        fd.write("NS_NO_VTABLE ")
 
377
 
 
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)
 
384
 
 
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)
 
398
 
 
399
    fd.write(iface_epilog % names)
 
400
 
 
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('\\')
 
412
 
 
413
    fd.write(iface_forward % names)
 
414
 
 
415
    def emitTemplate(tmpl):
 
416
        for member in iface.members:
 
417
            if isinstance(member, xpidl.Attribute):
 
418
                fd.write(tmpl % {'asNative': attributeAsNative(member, True),
 
419
                                 'nativeName': attributeNativeName(member, True),
 
420
                                 'paramList': attributeParamNames(member)})
 
421
                if not member.readonly:
 
422
                    fd.write(tmpl % {'asNative': attributeAsNative(member, False),
 
423
                                     'nativeName': attributeNativeName(member, False),
 
424
                                     'paramList': attributeParamNames(member)})
 
425
            elif isinstance(member, xpidl.Method):
 
426
                fd.write(tmpl % {'asNative': methodAsNative(member),
 
427
                                 'nativeName': methodNativeName(member),
 
428
                                 'paramList': paramlistNames(member)})
 
429
        if len(iface.members) == 0:
 
430
            fd.write('\\\n  /* no methods! */')
 
431
        elif not member.kind in ('attribute', 'method'):
 
432
            fd.write('\\')
 
433
 
 
434
    emitTemplate("\\\n  %(asNative)s { return _to %(nativeName)s(%(paramList)s); } ")
 
435
 
 
436
    fd.write(iface_forward_safe % names)
 
437
 
 
438
    emitTemplate("\\\n  %(asNative)s { return !_to ? NS_ERROR_NULL_POINTER : _to->%(nativeName)s(%(paramList)s); } ")
 
439
 
 
440
    fd.write(iface_template_prolog % names)
 
441
 
 
442
    for member in iface.members:
 
443
        if isinstance(member, xpidl.ConstMember) or isinstance(member, xpidl.CDATA): continue
 
444
        fd.write("/* %s */\n" % member.toIDL())
 
445
        if isinstance(member, xpidl.Attribute):
 
446
            fd.write(example_tmpl % {'implclass': implclass,
 
447
                                     'returntype': attributeReturnType(member, 'NS_IMETHODIMP'),
 
448
                                     'nativeName': attributeNativeName(member, True),
 
449
                                     'paramList': attributeParamlist(member, True)})
 
450
            if not member.readonly:
 
451
                fd.write(example_tmpl % {'implclass': implclass,
 
452
                                         'returntype': attributeReturnType(member, 'NS_IMETHODIMP'),
 
453
                                         'nativeName': attributeNativeName(member, False),
 
454
                                         'paramList': attributeParamlist(member, False)})
 
455
        elif isinstance(member, xpidl.Method):
 
456
            fd.write(example_tmpl % {'implclass': implclass,
 
457
                                     'returntype': methodReturnType(member, 'NS_IMETHODIMP'),
 
458
                                     'nativeName': methodNativeName(member),
 
459
                                     'paramList': paramlistAsNative(member, empty='')})
 
460
        fd.write('\n')
 
461
 
 
462
    fd.write(iface_template_epilog)
 
463
 
 
464
if __name__ == '__main__':
 
465
    from optparse import OptionParser
 
466
    o = OptionParser()
 
467
    o.add_option('-I', action='append', dest='incdirs', default=['.'],
 
468
                 help="Directory to search for imported files")
 
469
    o.add_option('--cachedir', dest='cachedir', default=None,
 
470
                 help="Directory in which to cache lex/parse tables.")
 
471
    o.add_option('-o', dest='outfile', default=None,
 
472
                 help="Output file (default is stdout)")
 
473
    o.add_option('-d', dest='depfile', default=None,
 
474
                 help="Generate a make dependency file")
 
475
    o.add_option('--regen', action='store_true', dest='regen', default=False,
 
476
                 help="Regenerate IDL Parser cache")
 
477
    options, args = o.parse_args()
 
478
    file = args[0] if args else None
 
479
 
 
480
    if options.cachedir is not None:
 
481
        if not os.path.isdir(options.cachedir):
 
482
            os.mkdir(options.cachedir)
 
483
        sys.path.append(options.cachedir)
 
484
 
 
485
    # The only thing special about a regen is that there are no input files.
 
486
    if options.regen:
 
487
        if options.cachedir is None:
 
488
            print >>sys.stderr, "--regen useless without --cachedir"
 
489
        # Delete the lex/yacc files.  Ply is too stupid to regenerate them
 
490
        # properly
 
491
        for fileglobs in [os.path.join(options.cachedir, f) for f in ["xpidllex.py*", "xpidlyacc.py*"]]:
 
492
            for filename in glob.glob(fileglobs):
 
493
                os.remove(filename)
 
494
 
 
495
    # Instantiate the parser.
 
496
    p = xpidl.IDLParser(outputdir=options.cachedir)
 
497
 
 
498
    if options.regen:
 
499
        sys.exit(0)
 
500
 
 
501
    if options.depfile is not None and options.outfile is None:
 
502
        print >>sys.stderr, "-d requires -o"
 
503
        sys.exit(1)
 
504
 
 
505
    if options.outfile is not None:
 
506
        outfd = open(options.outfile, 'w')
 
507
        closeoutfd = True
 
508
    else:
 
509
        outfd = sys.stdout
 
510
        closeoutfd = False
 
511
 
 
512
    idl = p.parse(open(file).read(), filename=file)
 
513
    idl.resolve(options.incdirs, p)
 
514
    print_header(idl, outfd, file)
 
515
 
 
516
    if closeoutfd:
 
517
        outfd.close()
 
518
 
 
519
    if options.depfile is not None:
 
520
        dirname = os.path.dirname(options.depfile)
 
521
        if dirname:
 
522
            try:
 
523
                os.makedirs(dirname)
 
524
            except:
 
525
                pass
 
526
        depfd = open(options.depfile, 'w')
 
527
        deps = [dep.replace('\\', '/') for dep in idl.deps]
 
528
 
 
529
        print >>depfd, "%s: %s" % (options.outfile, " ".join(deps))