~ubuntu-branches/ubuntu/trusty/enigmail/trusty-security

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2011-11-16 21:30:26 UTC
  • mfrom: (0.12.7)
  • Revision ID: package-import@ubuntu.com-20111116213026-7i0cpxql4kyjcdg4
Tags: 2:1.3.3-0ubuntu1
* New upstream release v1.3.3
* Add patch to define constants in nsIEnigmail.idl as unsigned long, so
  that the new IDL parser doesn't fall over
  - add debian/patches/new_idl_parser_compat.patch
  - update debian/patches/series

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
# ***** BEGIN LICENSE BLOCK *****
 
5
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
6
#
 
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/
 
11
#
 
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
 
15
# License.
 
16
#
 
17
# The Original Code is mozilla.org code.
 
18
#
 
19
# The Initial Developer of the Original Code is
 
20
#   Mozilla Foundation.
 
21
# Portions created by the Initial Developer are Copyright (C) 2008
 
22
# the Initial Developer. All Rights Reserved.
 
23
#
 
24
# Contributor(s):
 
25
#   Benjamin Smedberg <benjamin@smedbergs.us>
 
26
#
 
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.
 
38
#
 
39
# ***** END LICENSE BLOCK *****
 
40
 
 
41
"""Print a C++ header file for the IDL files specified on the command line"""
 
42
 
 
43
import sys, os.path, re, xpidl
 
44
 
 
45
printdoccomments = False
 
46
 
 
47
if printdoccomments:
 
48
    def printComments(fd, clist, indent):
 
49
        for c in clist:
 
50
            fd.write("%s%s\n" % (indent, c))
 
51
else:
 
52
    def printComments(fd, clist, indent):
 
53
        pass
 
54
 
 
55
def firstCap(str):
 
56
    return str[0].upper() + str[1:]
 
57
 
 
58
def attributeParamName(a):
 
59
    return "a" + firstCap(a.name)
 
60
 
 
61
def attributeParamNames(a):
 
62
    l = [attributeParamName(a)]
 
63
    if a.implicit_jscontext:
 
64
        l.insert(0, "cx")
 
65
    return ", ".join(l)
 
66
 
 
67
def attributeNativeName(a, getter):
 
68
    binaryname = a.binaryname is not None and a.binaryname or firstCap(a.name)
 
69
    return "%s%s" % (getter and 'Get' or 'Set', binaryname)
 
70
 
 
71
def attributeReturnType(a, macro):
 
72
    """macro should be NS_IMETHOD or NS_IMETHODIMP"""
 
73
    if (a.nostdcall):
 
74
        return macro == "NS_IMETHOD" and "virtual nsresult" or "nsresult"
 
75
    else:
 
76
        return macro
 
77
 
 
78
def attributeParamlist(a, getter):
 
79
    l = ["%s%s" % (a.realtype.nativeType(getter and 'out' or 'in'),
 
80
                   attributeParamName(a))]
 
81
    if a.implicit_jscontext:
 
82
        l.insert(0, "JSContext* cx")
 
83
 
 
84
    return ", ".join(l)
 
85
 
 
86
def attributeAsNative(a, getter):
 
87
        scriptable = a.isScriptable() and "NS_SCRIPTABLE " or ""
 
88
        deprecated = a.deprecated and "NS_DEPRECATED " or ""
 
89
        params = {'scriptable': scriptable,
 
90
                  'deprecated': deprecated,
 
91
                  'returntype': attributeReturnType(a, 'NS_IMETHOD'),
 
92
                  'binaryname': attributeNativeName(a, getter),
 
93
                  'paramlist': attributeParamlist(a, getter)}
 
94
        return "%(deprecated)s%(scriptable)s%(returntype)s %(binaryname)s(%(paramlist)s)" % params
 
95
 
 
96
def methodNativeName(m):
 
97
    return m.binaryname is not None and m.binaryname or firstCap(m.name)
 
98
 
 
99
def methodReturnType(m, macro):
 
100
    """macro should be NS_IMETHOD or NS_IMETHODIMP"""
 
101
    if m.nostdcall and m.notxpcom:
 
102
        return "%s%s" % (macro == "NS_IMETHOD" and "virtual " or "",
 
103
                         m.realtype.nativeType('in').strip())
 
104
    elif m.nostdcall:
 
105
        return "%snsresult" % (macro == "NS_IMETHOD" and "virtual " or "")
 
106
    elif m.notxpcom:
 
107
        return "%s_(%s)" % (macro, m.realtype.nativeType('in').strip())
 
108
    else:
 
109
        return macro
 
110
 
 
111
def methodAsNative(m):
 
112
    scriptable = m.isScriptable() and "NS_SCRIPTABLE " or ""
 
113
 
 
114
    return "%s%s %s(%s)" % (scriptable,
 
115
                            methodReturnType(m, 'NS_IMETHOD'),
 
116
                            methodNativeName(m),
 
117
                            paramlistAsNative(m))
 
118
 
 
119
def paramlistAsNative(m, empty='void'):
 
120
    l = [paramAsNative(p) for p in m.params]
 
121
 
 
122
    if m.implicit_jscontext:
 
123
        l.append("JSContext* cx")
 
124
 
 
125
    if m.optional_argc:
 
126
        l.append('PRUint8 _argc')
 
127
 
 
128
    if not m.notxpcom and m.realtype.name != 'void':
 
129
        l.append(paramAsNative(xpidl.Param(paramtype='out',
 
130
                                           type=None,
 
131
                                           name='_retval',
 
132
                                           attlist=[],
 
133
                                           location=None,
 
134
                                           realtype=m.realtype)))
 
135
 
 
136
    if len(l) == 0:
 
137
        return empty
 
138
 
 
139
    return ", ".join(l)
 
140
 
 
141
def paramAsNative(p):
 
142
    if p.paramtype == 'in':
 
143
        typeannotate = ''
 
144
    else:
 
145
        typeannotate = ' NS_%sPARAM' % p.paramtype.upper()
 
146
 
 
147
    return "%s%s%s" % (p.nativeType(),
 
148
                       p.name,
 
149
                       typeannotate)
 
150
 
 
151
def paramlistNames(m):
 
152
    names = [p.name for p in m.params]
 
153
 
 
154
    if m.implicit_jscontext:
 
155
        names.append('cx')
 
156
 
 
157
    if m.optional_argc:
 
158
        names.append('_argc')
 
159
 
 
160
    if not m.notxpcom and m.realtype.name != 'void':
 
161
        names.append('_retval')
 
162
 
 
163
    if len(names) == 0:
 
164
        return ''
 
165
    return ', '.join(names)
 
166
 
 
167
header = """/*
 
168
 * DO NOT EDIT.  THIS FILE IS GENERATED FROM %(filename)s
 
169
 */
 
170
 
 
171
#ifndef __gen_%(basename)s_h__
 
172
#define __gen_%(basename)s_h__
 
173
"""
 
174
 
 
175
include = """
 
176
#ifndef __gen_%(basename)s_h__
 
177
#include "%(basename)s.h"
 
178
#endif
 
179
"""
 
180
 
 
181
jspubtd_include = """
 
182
#include "jspubtd.h"
 
183
"""
 
184
 
 
185
header_end = """/* For IDL files that don't want to include root IDL files. */
 
186
#ifndef NS_NO_VTABLE
 
187
#define NS_NO_VTABLE
 
188
#endif
 
189
"""
 
190
 
 
191
footer = """
 
192
#endif /* __gen_%(basename)s_h__ */
 
193
"""
 
194
 
 
195
forward_decl = """class %(name)s; /* forward declaration */
 
196
 
 
197
"""
 
198
 
 
199
def idl_basename(f):
 
200
    """returns the base name of a file with the last extension stripped"""
 
201
    return os.path.basename(f).rpartition('.')[0]
 
202
 
 
203
def print_header(idl, fd, filename):
 
204
    fd.write(header % {'filename': filename,
 
205
                       'basename': idl_basename(filename)})
 
206
 
 
207
    foundinc = False
 
208
    for inc in idl.includes():
 
209
        if not foundinc:
 
210
            foundinc = True
 
211
            fd.write('\n')
 
212
        fd.write(include % {'basename': idl_basename(inc.filename)})
 
213
 
 
214
    if idl.needsJSTypes():
 
215
        fd.write(jspubtd_include)
 
216
 
 
217
    fd.write('\n')
 
218
    fd.write(header_end)
 
219
 
 
220
    for p in idl.productions:
 
221
        if p.kind == 'include': continue
 
222
        if p.kind == 'cdata':
 
223
            fd.write(p.data)
 
224
            continue
 
225
 
 
226
        if p.kind == 'forward':
 
227
            fd.write(forward_decl % {'name': p.name})
 
228
            continue
 
229
        if p.kind == 'interface':
 
230
            write_interface(p, fd)
 
231
            continue
 
232
        if p.kind == 'typedef':
 
233
            printComments(fd, p.doccomments, '')
 
234
            fd.write("typedef %s %s;\n\n" % (p.realtype.nativeType('in'),
 
235
                                             p.name))
 
236
 
 
237
    fd.write(footer % {'basename': idl_basename(filename)})
 
238
 
 
239
iface_header = r"""
 
240
/* starting interface:    %(name)s */
 
241
#define %(defname)s_IID_STR "%(iid)s"
 
242
 
 
243
#define %(defname)s_IID \
 
244
  {0x%(m0)s, 0x%(m1)s, 0x%(m2)s, \
 
245
    { %(m3joined)s }}
 
246
 
 
247
"""
 
248
 
 
249
uuid_decoder = re.compile(r"""(?P<m0>[a-f0-9]{8})-
 
250
                              (?P<m1>[a-f0-9]{4})-
 
251
                              (?P<m2>[a-f0-9]{4})-
 
252
                              (?P<m3>[a-f0-9]{4})-
 
253
                              (?P<m4>[a-f0-9]{12})$""", re.X)
 
254
 
 
255
iface_prolog = """ {
 
256
 public: 
 
257
 
 
258
  NS_DECLARE_STATIC_IID_ACCESSOR(%(defname)s_IID)
 
259
 
 
260
"""
 
261
 
 
262
iface_epilog = """};
 
263
 
 
264
  NS_DEFINE_STATIC_IID_ACCESSOR(%(name)s, %(defname)s_IID)
 
265
 
 
266
/* Use this macro when declaring classes that implement this interface. */
 
267
#define NS_DECL_%(macroname)s """
 
268
 
 
269
 
 
270
iface_forward = """
 
271
 
 
272
/* Use this macro to declare functions that forward the behavior of this interface to another object. */
 
273
#define NS_FORWARD_%(macroname)s(_to) """
 
274
 
 
275
iface_forward_safe = """
 
276
 
 
277
/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */
 
278
#define NS_FORWARD_SAFE_%(macroname)s(_to) """
 
279
 
 
280
iface_template_prolog = """
 
281
 
 
282
#if 0
 
283
/* Use the code below as a template for the implementation class for this interface. */
 
284
 
 
285
/* Header file */
 
286
class %(implclass)s : public %(name)s
 
287
{
 
288
public:
 
289
  NS_DECL_ISUPPORTS
 
290
  NS_DECL_%(macroname)s
 
291
 
 
292
  %(implclass)s();
 
293
 
 
294
private:
 
295
  ~%(implclass)s();
 
296
 
 
297
protected:
 
298
  /* additional members */
 
299
};
 
300
 
 
301
/* Implementation file */
 
302
NS_IMPL_ISUPPORTS1(%(implclass)s, %(name)s)
 
303
 
 
304
%(implclass)s::%(implclass)s()
 
305
{
 
306
  /* member initializers and constructor code */
 
307
}
 
308
 
 
309
%(implclass)s::~%(implclass)s()
 
310
{
 
311
  /* destructor code */
 
312
}
 
313
 
 
314
"""
 
315
 
 
316
example_tmpl = """%(returntype)s %(implclass)s::%(nativeName)s(%(paramList)s)
 
317
{
 
318
    return NS_ERROR_NOT_IMPLEMENTED;
 
319
}
 
320
"""
 
321
 
 
322
iface_template_epilog = """/* End of implementation class template. */
 
323
#endif
 
324
 
 
325
"""
 
326
 
 
327
def write_interface(iface, fd):
 
328
    if iface.namemap is None:
 
329
        raise Exception("Interface was not resolved.")
 
330
 
 
331
    def write_const_decl(c):
 
332
        printComments(fd, c.doccomments, '  ')
 
333
 
 
334
        basetype = c.basetype
 
335
        value = c.getValue()
 
336
 
 
337
        fd.write("  enum { %(name)s = %(value)s%(signed)s };\n\n" % {
 
338
                     'name': c.name,
 
339
                     'value': value,
 
340
                     'signed': (not basetype.signed) and 'U' or ''})
 
341
 
 
342
    def write_method_decl(m):
 
343
        printComments(fd, m.doccomments, '  ')
 
344
 
 
345
        fd.write("  /* %s */\n" % m.toIDL())
 
346
        fd.write("  %s = 0;\n\n" % methodAsNative(m))
 
347
                                                                           
 
348
    def write_attr_decl(a):
 
349
        printComments(fd, a.doccomments, '  ')
 
350
 
 
351
        fd.write("  /* %s */\n" % a.toIDL());
 
352
 
 
353
        fd.write("  %s = 0;\n" % attributeAsNative(a, True))
 
354
        if not a.readonly:
 
355
            fd.write("  %s = 0;\n" % attributeAsNative(a, False))
 
356
        fd.write("\n")
 
357
 
 
358
    defname = iface.name.upper()
 
359
    if iface.name[0:2] == 'ns':
 
360
        defname = 'NS_' + defname[2:]
 
361
 
 
362
    names = uuid_decoder.match(iface.attributes.uuid).groupdict()
 
363
    m3str = names['m3'] + names['m4']
 
364
    names['m3joined'] = ", ".join(["0x%s" % m3str[i:i+2] for i in xrange(0, 16, 2)])
 
365
 
 
366
    if iface.name[2] == 'I':
 
367
        implclass = iface.name[:2] + iface.name[3:]
 
368
    else:
 
369
        implclass = '_MYCLASS_'
 
370
 
 
371
    names.update({'defname': defname,
 
372
                  'macroname': iface.name.upper(),
 
373
                  'name': iface.name,
 
374
                  'iid': iface.attributes.uuid,
 
375
                  'implclass': implclass})
 
376
 
 
377
    fd.write(iface_header % names)
 
378
 
 
379
    printComments(fd, iface.doccomments, '')
 
380
 
 
381
    fd.write("class ")
 
382
    foundcdata = False
 
383
    for m in iface.members:
 
384
        if isinstance(m, xpidl.CDATA):
 
385
            foundcdata = True
 
386
 
 
387
    if not foundcdata:
 
388
        fd.write("NS_NO_VTABLE ")
 
389
 
 
390
    if iface.attributes.scriptable:
 
391
        fd.write("NS_SCRIPTABLE ")
 
392
    if iface.attributes.deprecated:
 
393
        fd.write("MOZ_DEPRECATED ")
 
394
    fd.write(iface.name)
 
395
    if iface.base:
 
396
        fd.write(" : public %s" % iface.base)
 
397
    fd.write(iface_prolog % names)
 
398
    for member in iface.members:
 
399
        if isinstance(member, xpidl.ConstMember):
 
400
            write_const_decl(member)
 
401
        elif isinstance(member, xpidl.Attribute):
 
402
            write_attr_decl(member)
 
403
        elif isinstance(member, xpidl.Method):
 
404
            write_method_decl(member)
 
405
        elif isinstance(member, xpidl.CDATA):
 
406
            fd.write("  %s" % member.data)
 
407
        else:
 
408
            raise Exception("Unexpected interface member: %s" % member)
 
409
 
 
410
    fd.write(iface_epilog % names)
 
411
 
 
412
    for member in iface.members:
 
413
        if isinstance(member, xpidl.Attribute):
 
414
            fd.write("\\\n  %s; " % attributeAsNative(member, True))
 
415
            if not member.readonly:
 
416
                fd.write("\\\n  %s; " % attributeAsNative(member, False))
 
417
        elif isinstance(member, xpidl.Method):
 
418
            fd.write("\\\n  %s; " % methodAsNative(member))
 
419
    if len(iface.members) == 0:
 
420
        fd.write('\\\n  /* no methods! */')
 
421
    elif not member.kind in ('attribute', 'method'):
 
422
       fd.write('\\')
 
423
 
 
424
    fd.write(iface_forward % names)
 
425
 
 
426
    def emitTemplate(tmpl):
 
427
        for member in iface.members:
 
428
            if isinstance(member, xpidl.Attribute):
 
429
                fd.write(tmpl % {'asNative': attributeAsNative(member, True),
 
430
                                 'nativeName': attributeNativeName(member, True),
 
431
                                 'paramList': attributeParamNames(member)})
 
432
                if not member.readonly:
 
433
                    fd.write(tmpl % {'asNative': attributeAsNative(member, False),
 
434
                                     'nativeName': attributeNativeName(member, False),
 
435
                                     'paramList': attributeParamNames(member)})
 
436
            elif isinstance(member, xpidl.Method):
 
437
                fd.write(tmpl % {'asNative': methodAsNative(member),
 
438
                                 'nativeName': methodNativeName(member),
 
439
                                 'paramList': paramlistNames(member)})
 
440
        if len(iface.members) == 0:
 
441
            fd.write('\\\n  /* no methods! */')
 
442
        elif not member.kind in ('attribute', 'method'):
 
443
            fd.write('\\')
 
444
 
 
445
    emitTemplate("\\\n  %(asNative)s { return _to %(nativeName)s(%(paramList)s); } ")
 
446
 
 
447
    fd.write(iface_forward_safe % names)
 
448
 
 
449
    emitTemplate("\\\n  %(asNative)s { return !_to ? NS_ERROR_NULL_POINTER : _to->%(nativeName)s(%(paramList)s); } ")
 
450
 
 
451
    fd.write(iface_template_prolog % names)
 
452
 
 
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')
 
472
 
 
473
    fd.write(iface_template_epilog)
 
474
 
 
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
 
490
 
 
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)
 
495
 
 
496
    if options.regen:
 
497
        if options.cachedir is None:
 
498
            print >>sys.stderr, "--regen requires --cachedir"
 
499
            sys.exit(1)
 
500
 
 
501
        p = xpidl.IDLParser(outputdir=options.cachedir, regen=True)
 
502
        sys.exit(0)
 
503
 
 
504
    if options.depfile is not None and options.outfile is None:
 
505
        print >>sys.stderr, "-d requires -o"
 
506
        sys.exit(1)
 
507
 
 
508
    if options.outfile is not None:
 
509
        outfd = open(options.outfile, 'w')
 
510
        closeoutfd = True
 
511
    else:
 
512
        outfd = sys.stdout
 
513
        closeoutfd = False
 
514
 
 
515
    p = xpidl.IDLParser(outputdir=options.cachedir)
 
516
    idl = p.parse(open(file).read(), filename=file)
 
517
    idl.resolve(options.incdirs, p)
 
518
    print_header(idl, outfd, file)
 
519
 
 
520
    if closeoutfd:
 
521
        outfd.close()
 
522
 
 
523
    if options.depfile is not None:
 
524
        depfd = open(options.depfile, 'w')
 
525
        deps = [dep.replace('\\', '/') for dep in idl.deps]
 
526
 
 
527
        print >>depfd, "%s: %s" % (options.outfile, " ".join(deps))