1*2b3787f6Schristos#!/usr/bin/env python2
2*2b3787f6Schristos#
3*2b3787f6Schristos# Copyright (c) 2005-2007 Niels Provos <provos@citi.umich.edu>
4*2b3787f6Schristos# Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
5*2b3787f6Schristos# All rights reserved.
6*2b3787f6Schristos#
7*2b3787f6Schristos# Generates marshaling code based on libevent.
8*2b3787f6Schristos
9*2b3787f6Schristos# TODO:
10*2b3787f6Schristos# 1) use optparse to allow the strategy shell to parse options, and
11*2b3787f6Schristos#    to allow the instantiated factory (for the specific output language)
12*2b3787f6Schristos#    to parse remaining options
13*2b3787f6Schristos# 2) move the globals into a class that manages execution (including the
14*2b3787f6Schristos#    progress outputs that space stderr at the moment)
15*2b3787f6Schristos# 3) emit other languages
16*2b3787f6Schristos
17*2b3787f6Schristosimport sys
18*2b3787f6Schristosimport re
19*2b3787f6Schristos
20*2b3787f6Schristos_NAME = "event_rpcgen.py"
21*2b3787f6Schristos_VERSION = "0.1"
22*2b3787f6Schristos
23*2b3787f6Schristos# Globals
24*2b3787f6Schristosline_count = 0
25*2b3787f6Schristos
26*2b3787f6Schristoswhite = re.compile(r'\s+')
27*2b3787f6Schristoscppcomment = re.compile(r'\/\/.*$')
28*2b3787f6Schristosnonident = re.compile(r'[^a-zA-Z0-9_]')
29*2b3787f6Schristosstructref = re.compile(r'^struct\[([a-zA-Z_][a-zA-Z0-9_]*)\]$')
30*2b3787f6Schristosstructdef = re.compile(r'^struct +[a-zA-Z_][a-zA-Z0-9_]* *{$')
31*2b3787f6Schristos
32*2b3787f6Schristosheaderdirect = []
33*2b3787f6Schristoscppdirect = []
34*2b3787f6Schristos
35*2b3787f6SchristosQUIETLY = 0
36*2b3787f6Schristos
37*2b3787f6Schristosdef declare(s):
38*2b3787f6Schristos    if not QUIETLY:
39*2b3787f6Schristos        print s
40*2b3787f6Schristos
41*2b3787f6Schristosdef TranslateList(mylist, mydict):
42*2b3787f6Schristos    return map(lambda x: x % mydict, mylist)
43*2b3787f6Schristos
44*2b3787f6Schristos# Exception class for parse errors
45*2b3787f6Schristosclass RpcGenError(Exception):
46*2b3787f6Schristos        def __init__(self, why):
47*2b3787f6Schristos                self.why = why
48*2b3787f6Schristos        def __str__(self):
49*2b3787f6Schristos                return str(self.why)
50*2b3787f6Schristos
51*2b3787f6Schristos# Holds everything that makes a struct
52*2b3787f6Schristosclass Struct:
53*2b3787f6Schristos    def __init__(self, name):
54*2b3787f6Schristos        self._name = name
55*2b3787f6Schristos        self._entries = []
56*2b3787f6Schristos        self._tags = {}
57*2b3787f6Schristos        declare('  Created struct: %s' % name)
58*2b3787f6Schristos
59*2b3787f6Schristos    def AddEntry(self, entry):
60*2b3787f6Schristos        if self._tags.has_key(entry.Tag()):
61*2b3787f6Schristos            raise RpcGenError(
62*2b3787f6Schristos                'Entry "%s" duplicates tag number %d from "%s" '
63*2b3787f6Schristos                'around line %d' % (entry.Name(), entry.Tag(),
64*2b3787f6Schristos                                    self._tags[entry.Tag()], line_count))
65*2b3787f6Schristos        self._entries.append(entry)
66*2b3787f6Schristos        self._tags[entry.Tag()] = entry.Name()
67*2b3787f6Schristos        declare('    Added entry: %s' % entry.Name())
68*2b3787f6Schristos
69*2b3787f6Schristos    def Name(self):
70*2b3787f6Schristos        return self._name
71*2b3787f6Schristos
72*2b3787f6Schristos    def EntryTagName(self, entry):
73*2b3787f6Schristos        """Creates the name inside an enumeration for distinguishing data
74*2b3787f6Schristos        types."""
75*2b3787f6Schristos        name = "%s_%s" % (self._name, entry.Name())
76*2b3787f6Schristos        return name.upper()
77*2b3787f6Schristos
78*2b3787f6Schristos    def PrintIndented(self, file, ident, code):
79*2b3787f6Schristos        """Takes an array, add indentation to each entry and prints it."""
80*2b3787f6Schristos        for entry in code:
81*2b3787f6Schristos            print >>file, '%s%s' % (ident, entry)
82*2b3787f6Schristos
83*2b3787f6Schristosclass StructCCode(Struct):
84*2b3787f6Schristos    """ Knows how to generate C code for a struct """
85*2b3787f6Schristos
86*2b3787f6Schristos    def __init__(self, name):
87*2b3787f6Schristos        Struct.__init__(self, name)
88*2b3787f6Schristos
89*2b3787f6Schristos    def PrintTags(self, file):
90*2b3787f6Schristos        """Prints the tag definitions for a structure."""
91*2b3787f6Schristos        print >>file, '/* Tag definition for %s */' % self._name
92*2b3787f6Schristos        print >>file, 'enum %s_ {' % self._name.lower()
93*2b3787f6Schristos        for entry in self._entries:
94*2b3787f6Schristos            print >>file, '  %s=%d,' % (self.EntryTagName(entry),
95*2b3787f6Schristos                                        entry.Tag())
96*2b3787f6Schristos        print >>file, '  %s_MAX_TAGS' % (self._name.upper())
97*2b3787f6Schristos        print >>file, '};\n'
98*2b3787f6Schristos
99*2b3787f6Schristos    def PrintForwardDeclaration(self, file):
100*2b3787f6Schristos        print >>file, 'struct %s;' % self._name
101*2b3787f6Schristos
102*2b3787f6Schristos    def PrintDeclaration(self, file):
103*2b3787f6Schristos        print >>file, '/* Structure declaration for %s */' % self._name
104*2b3787f6Schristos        print >>file, 'struct %s_access_ {' % self._name
105*2b3787f6Schristos        for entry in self._entries:
106*2b3787f6Schristos            dcl = entry.AssignDeclaration('(*%s_assign)' % entry.Name())
107*2b3787f6Schristos            dcl.extend(
108*2b3787f6Schristos                entry.GetDeclaration('(*%s_get)' % entry.Name()))
109*2b3787f6Schristos            if entry.Array():
110*2b3787f6Schristos                dcl.extend(
111*2b3787f6Schristos                    entry.AddDeclaration('(*%s_add)' % entry.Name()))
112*2b3787f6Schristos            self.PrintIndented(file, '  ', dcl)
113*2b3787f6Schristos        print >>file, '};\n'
114*2b3787f6Schristos
115*2b3787f6Schristos        print >>file, 'struct %s {' % self._name
116*2b3787f6Schristos        print >>file, '  struct %s_access_ *base;\n' % self._name
117*2b3787f6Schristos        for entry in self._entries:
118*2b3787f6Schristos            dcl = entry.Declaration()
119*2b3787f6Schristos            self.PrintIndented(file, '  ', dcl)
120*2b3787f6Schristos        print >>file, ''
121*2b3787f6Schristos        for entry in self._entries:
122*2b3787f6Schristos            print >>file, '  ev_uint8_t %s_set;' % entry.Name()
123*2b3787f6Schristos        print >>file, '};\n'
124*2b3787f6Schristos
125*2b3787f6Schristos        print >>file, \
126*2b3787f6Schristos"""struct %(name)s *%(name)s_new(void);
127*2b3787f6Schristosstruct %(name)s *%(name)s_new_with_arg(void *);
128*2b3787f6Schristosvoid %(name)s_free(struct %(name)s *);
129*2b3787f6Schristosvoid %(name)s_clear(struct %(name)s *);
130*2b3787f6Schristosvoid %(name)s_marshal(struct evbuffer *, const struct %(name)s *);
131*2b3787f6Schristosint %(name)s_unmarshal(struct %(name)s *, struct evbuffer *);
132*2b3787f6Schristosint %(name)s_complete(struct %(name)s *);
133*2b3787f6Schristosvoid evtag_marshal_%(name)s(struct evbuffer *, ev_uint32_t,
134*2b3787f6Schristos    const struct %(name)s *);
135*2b3787f6Schristosint evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
136*2b3787f6Schristos    struct %(name)s *);""" % { 'name' : self._name }
137*2b3787f6Schristos
138*2b3787f6Schristos
139*2b3787f6Schristos        # Write a setting function of every variable
140*2b3787f6Schristos        for entry in self._entries:
141*2b3787f6Schristos            self.PrintIndented(file, '', entry.AssignDeclaration(
142*2b3787f6Schristos                entry.AssignFuncName()))
143*2b3787f6Schristos            self.PrintIndented(file, '', entry.GetDeclaration(
144*2b3787f6Schristos                entry.GetFuncName()))
145*2b3787f6Schristos            if entry.Array():
146*2b3787f6Schristos                self.PrintIndented(file, '', entry.AddDeclaration(
147*2b3787f6Schristos                    entry.AddFuncName()))
148*2b3787f6Schristos
149*2b3787f6Schristos        print >>file, '/* --- %s done --- */\n' % self._name
150*2b3787f6Schristos
151*2b3787f6Schristos    def PrintCode(self, file):
152*2b3787f6Schristos        print >>file, ('/*\n'
153*2b3787f6Schristos                       ' * Implementation of %s\n'
154*2b3787f6Schristos                       ' */\n') % self._name
155*2b3787f6Schristos
156*2b3787f6Schristos        print >>file, \
157*2b3787f6Schristos              'static struct %(name)s_access_ %(name)s_base__ = {' % \
158*2b3787f6Schristos              { 'name' : self._name }
159*2b3787f6Schristos        for entry in self._entries:
160*2b3787f6Schristos            self.PrintIndented(file, '  ', entry.CodeBase())
161*2b3787f6Schristos        print >>file, '};\n'
162*2b3787f6Schristos
163*2b3787f6Schristos        # Creation
164*2b3787f6Schristos        print >>file, (
165*2b3787f6Schristos            'struct %(name)s *\n'
166*2b3787f6Schristos            '%(name)s_new(void)\n'
167*2b3787f6Schristos            '{\n'
168*2b3787f6Schristos            '  return %(name)s_new_with_arg(NULL);\n'
169*2b3787f6Schristos            '}\n'
170*2b3787f6Schristos            '\n'
171*2b3787f6Schristos            'struct %(name)s *\n'
172*2b3787f6Schristos            '%(name)s_new_with_arg(void *unused)\n'
173*2b3787f6Schristos            '{\n'
174*2b3787f6Schristos            '  struct %(name)s *tmp;\n'
175*2b3787f6Schristos            '  if ((tmp = malloc(sizeof(struct %(name)s))) == NULL) {\n'
176*2b3787f6Schristos            '    event_warn("%%s: malloc", __func__);\n'
177*2b3787f6Schristos            '    return (NULL);\n'
178*2b3787f6Schristos            '  }\n'
179*2b3787f6Schristos            '  tmp->base = &%(name)s_base__;\n') % { 'name' : self._name }
180*2b3787f6Schristos
181*2b3787f6Schristos        for entry in self._entries:
182*2b3787f6Schristos            self.PrintIndented(file, '  ', entry.CodeInitialize('tmp'))
183*2b3787f6Schristos            print >>file, '  tmp->%s_set = 0;\n' % entry.Name()
184*2b3787f6Schristos
185*2b3787f6Schristos        print >>file, (
186*2b3787f6Schristos            '  return (tmp);\n'
187*2b3787f6Schristos            '}\n')
188*2b3787f6Schristos
189*2b3787f6Schristos        # Adding
190*2b3787f6Schristos        for entry in self._entries:
191*2b3787f6Schristos            if entry.Array():
192*2b3787f6Schristos                self.PrintIndented(file, '', entry.CodeAdd())
193*2b3787f6Schristos            print >>file, ''
194*2b3787f6Schristos
195*2b3787f6Schristos        # Assigning
196*2b3787f6Schristos        for entry in self._entries:
197*2b3787f6Schristos            self.PrintIndented(file, '', entry.CodeAssign())
198*2b3787f6Schristos            print >>file, ''
199*2b3787f6Schristos
200*2b3787f6Schristos        # Getting
201*2b3787f6Schristos        for entry in self._entries:
202*2b3787f6Schristos            self.PrintIndented(file, '', entry.CodeGet())
203*2b3787f6Schristos            print >>file, ''
204*2b3787f6Schristos
205*2b3787f6Schristos        # Clearing
206*2b3787f6Schristos        print >>file, ( 'void\n'
207*2b3787f6Schristos                        '%(name)s_clear(struct %(name)s *tmp)\n'
208*2b3787f6Schristos                        '{'
209*2b3787f6Schristos                        ) % { 'name' : self._name }
210*2b3787f6Schristos        for entry in self._entries:
211*2b3787f6Schristos            self.PrintIndented(file, '  ', entry.CodeClear('tmp'))
212*2b3787f6Schristos
213*2b3787f6Schristos        print >>file, '}\n'
214*2b3787f6Schristos
215*2b3787f6Schristos        # Freeing
216*2b3787f6Schristos        print >>file, ( 'void\n'
217*2b3787f6Schristos                        '%(name)s_free(struct %(name)s *tmp)\n'
218*2b3787f6Schristos                        '{'
219*2b3787f6Schristos                        ) % { 'name' : self._name }
220*2b3787f6Schristos
221*2b3787f6Schristos        for entry in self._entries:
222*2b3787f6Schristos            self.PrintIndented(file, '  ', entry.CodeFree('tmp'))
223*2b3787f6Schristos
224*2b3787f6Schristos        print >>file, ('  free(tmp);\n'
225*2b3787f6Schristos                       '}\n')
226*2b3787f6Schristos
227*2b3787f6Schristos        # Marshaling
228*2b3787f6Schristos        print >>file, ('void\n'
229*2b3787f6Schristos                       '%(name)s_marshal(struct evbuffer *evbuf, '
230*2b3787f6Schristos                       'const struct %(name)s *tmp)'
231*2b3787f6Schristos                       '{') % { 'name' : self._name }
232*2b3787f6Schristos        for entry in self._entries:
233*2b3787f6Schristos            indent = '  '
234*2b3787f6Schristos            # Optional entries do not have to be set
235*2b3787f6Schristos            if entry.Optional():
236*2b3787f6Schristos                indent += '  '
237*2b3787f6Schristos                print >>file, '  if (tmp->%s_set) {' % entry.Name()
238*2b3787f6Schristos            self.PrintIndented(
239*2b3787f6Schristos                file, indent,
240*2b3787f6Schristos                entry.CodeMarshal('evbuf', self.EntryTagName(entry),
241*2b3787f6Schristos                                  entry.GetVarName('tmp'),
242*2b3787f6Schristos                                  entry.GetVarLen('tmp')))
243*2b3787f6Schristos            if entry.Optional():
244*2b3787f6Schristos                print >>file, '  }'
245*2b3787f6Schristos
246*2b3787f6Schristos        print >>file, '}\n'
247*2b3787f6Schristos
248*2b3787f6Schristos        # Unmarshaling
249*2b3787f6Schristos        print >>file, ('int\n'
250*2b3787f6Schristos                       '%(name)s_unmarshal(struct %(name)s *tmp, '
251*2b3787f6Schristos                       ' struct evbuffer *evbuf)\n'
252*2b3787f6Schristos                       '{\n'
253*2b3787f6Schristos                       '  ev_uint32_t tag;\n'
254*2b3787f6Schristos                       '  while (evbuffer_get_length(evbuf) > 0) {\n'
255*2b3787f6Schristos                       '    if (evtag_peek(evbuf, &tag) == -1)\n'
256*2b3787f6Schristos                       '      return (-1);\n'
257*2b3787f6Schristos                       '    switch (tag) {\n'
258*2b3787f6Schristos                       ) % { 'name' : self._name }
259*2b3787f6Schristos        for entry in self._entries:
260*2b3787f6Schristos            print >>file, '      case %s:\n' % self.EntryTagName(entry)
261*2b3787f6Schristos            if not entry.Array():
262*2b3787f6Schristos                print >>file, (
263*2b3787f6Schristos                    '        if (tmp->%s_set)\n'
264*2b3787f6Schristos                    '          return (-1);'
265*2b3787f6Schristos                    ) % (entry.Name())
266*2b3787f6Schristos
267*2b3787f6Schristos            self.PrintIndented(
268*2b3787f6Schristos                file, '        ',
269*2b3787f6Schristos                entry.CodeUnmarshal('evbuf',
270*2b3787f6Schristos                                    self.EntryTagName(entry),
271*2b3787f6Schristos                                    entry.GetVarName('tmp'),
272*2b3787f6Schristos                                    entry.GetVarLen('tmp')))
273*2b3787f6Schristos
274*2b3787f6Schristos            print >>file, ( '        tmp->%s_set = 1;\n' % entry.Name() +
275*2b3787f6Schristos                            '        break;\n' )
276*2b3787f6Schristos        print >>file, ( '      default:\n'
277*2b3787f6Schristos                        '        return -1;\n'
278*2b3787f6Schristos                        '    }\n'
279*2b3787f6Schristos                        '  }\n' )
280*2b3787f6Schristos        # Check if it was decoded completely
281*2b3787f6Schristos        print >>file, ( '  if (%(name)s_complete(tmp) == -1)\n'
282*2b3787f6Schristos                        '    return (-1);'
283*2b3787f6Schristos                        ) % { 'name' : self._name }
284*2b3787f6Schristos
285*2b3787f6Schristos        # Successfully decoded
286*2b3787f6Schristos        print >>file, ( '  return (0);\n'
287*2b3787f6Schristos                        '}\n')
288*2b3787f6Schristos
289*2b3787f6Schristos        # Checking if a structure has all the required data
290*2b3787f6Schristos        print >>file, (
291*2b3787f6Schristos            'int\n'
292*2b3787f6Schristos            '%(name)s_complete(struct %(name)s *msg)\n'
293*2b3787f6Schristos            '{' ) % { 'name' : self._name }
294*2b3787f6Schristos        for entry in self._entries:
295*2b3787f6Schristos            if not entry.Optional():
296*2b3787f6Schristos                code = [
297*2b3787f6Schristos                    'if (!msg->%(name)s_set)',
298*2b3787f6Schristos                    '  return (-1);' ]
299*2b3787f6Schristos                code = TranslateList(code, entry.GetTranslation())
300*2b3787f6Schristos                self.PrintIndented(
301*2b3787f6Schristos                    file, '  ', code)
302*2b3787f6Schristos
303*2b3787f6Schristos            self.PrintIndented(
304*2b3787f6Schristos                file, '  ',
305*2b3787f6Schristos                entry.CodeComplete('msg', entry.GetVarName('msg')))
306*2b3787f6Schristos        print >>file, (
307*2b3787f6Schristos            '  return (0);\n'
308*2b3787f6Schristos            '}\n' )
309*2b3787f6Schristos
310*2b3787f6Schristos        # Complete message unmarshaling
311*2b3787f6Schristos        print >>file, (
312*2b3787f6Schristos            'int\n'
313*2b3787f6Schristos            'evtag_unmarshal_%(name)s(struct evbuffer *evbuf, '
314*2b3787f6Schristos            'ev_uint32_t need_tag, struct %(name)s *msg)\n'
315*2b3787f6Schristos            '{\n'
316*2b3787f6Schristos            '  ev_uint32_t tag;\n'
317*2b3787f6Schristos            '  int res = -1;\n'
318*2b3787f6Schristos            '\n'
319*2b3787f6Schristos            '  struct evbuffer *tmp = evbuffer_new();\n'
320*2b3787f6Schristos            '\n'
321*2b3787f6Schristos            '  if (evtag_unmarshal(evbuf, &tag, tmp) == -1'
322*2b3787f6Schristos            ' || tag != need_tag)\n'
323*2b3787f6Schristos            '    goto error;\n'
324*2b3787f6Schristos            '\n'
325*2b3787f6Schristos            '  if (%(name)s_unmarshal(msg, tmp) == -1)\n'
326*2b3787f6Schristos            '    goto error;\n'
327*2b3787f6Schristos            '\n'
328*2b3787f6Schristos            '  res = 0;\n'
329*2b3787f6Schristos            '\n'
330*2b3787f6Schristos            ' error:\n'
331*2b3787f6Schristos            '  evbuffer_free(tmp);\n'
332*2b3787f6Schristos            '  return (res);\n'
333*2b3787f6Schristos            '}\n' ) % { 'name' : self._name }
334*2b3787f6Schristos
335*2b3787f6Schristos        # Complete message marshaling
336*2b3787f6Schristos        print >>file, (
337*2b3787f6Schristos            'void\n'
338*2b3787f6Schristos            'evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag, '
339*2b3787f6Schristos            'const struct %(name)s *msg)\n'
340*2b3787f6Schristos            '{\n'
341*2b3787f6Schristos            '  struct evbuffer *buf_ = evbuffer_new();\n'
342*2b3787f6Schristos            '  assert(buf_ != NULL);\n'
343*2b3787f6Schristos            '  %(name)s_marshal(buf_, msg);\n'
344*2b3787f6Schristos            '  evtag_marshal_buffer(evbuf, tag, buf_);\n '
345*2b3787f6Schristos            '  evbuffer_free(buf_);\n'
346*2b3787f6Schristos            '}\n' ) % { 'name' : self._name }
347*2b3787f6Schristos
348*2b3787f6Schristosclass Entry:
349*2b3787f6Schristos    def __init__(self, type, name, tag):
350*2b3787f6Schristos        self._type = type
351*2b3787f6Schristos        self._name = name
352*2b3787f6Schristos        self._tag = int(tag)
353*2b3787f6Schristos        self._ctype = type
354*2b3787f6Schristos        self._optional = 0
355*2b3787f6Schristos        self._can_be_array = 0
356*2b3787f6Schristos        self._array = 0
357*2b3787f6Schristos        self._line_count = -1
358*2b3787f6Schristos        self._struct = None
359*2b3787f6Schristos        self._refname = None
360*2b3787f6Schristos
361*2b3787f6Schristos        self._optpointer = True
362*2b3787f6Schristos        self._optaddarg = True
363*2b3787f6Schristos
364*2b3787f6Schristos    def GetInitializer(self):
365*2b3787f6Schristos        assert 0, "Entry does not provide initializer"
366*2b3787f6Schristos
367*2b3787f6Schristos    def SetStruct(self, struct):
368*2b3787f6Schristos        self._struct = struct
369*2b3787f6Schristos
370*2b3787f6Schristos    def LineCount(self):
371*2b3787f6Schristos        assert self._line_count != -1
372*2b3787f6Schristos        return self._line_count
373*2b3787f6Schristos
374*2b3787f6Schristos    def SetLineCount(self, number):
375*2b3787f6Schristos        self._line_count = number
376*2b3787f6Schristos
377*2b3787f6Schristos    def Array(self):
378*2b3787f6Schristos        return self._array
379*2b3787f6Schristos
380*2b3787f6Schristos    def Optional(self):
381*2b3787f6Schristos        return self._optional
382*2b3787f6Schristos
383*2b3787f6Schristos    def Tag(self):
384*2b3787f6Schristos        return self._tag
385*2b3787f6Schristos
386*2b3787f6Schristos    def Name(self):
387*2b3787f6Schristos        return self._name
388*2b3787f6Schristos
389*2b3787f6Schristos    def Type(self):
390*2b3787f6Schristos        return self._type
391*2b3787f6Schristos
392*2b3787f6Schristos    def MakeArray(self, yes=1):
393*2b3787f6Schristos        self._array = yes
394*2b3787f6Schristos
395*2b3787f6Schristos    def MakeOptional(self):
396*2b3787f6Schristos        self._optional = 1
397*2b3787f6Schristos
398*2b3787f6Schristos    def Verify(self):
399*2b3787f6Schristos        if self.Array() and not self._can_be_array:
400*2b3787f6Schristos            raise RpcGenError(
401*2b3787f6Schristos                'Entry "%s" cannot be created as an array '
402*2b3787f6Schristos                'around line %d' % (self._name, self.LineCount()))
403*2b3787f6Schristos        if not self._struct:
404*2b3787f6Schristos            raise RpcGenError(
405*2b3787f6Schristos                'Entry "%s" does not know which struct it belongs to '
406*2b3787f6Schristos                'around line %d' % (self._name, self.LineCount()))
407*2b3787f6Schristos        if self._optional and self._array:
408*2b3787f6Schristos            raise RpcGenError(
409*2b3787f6Schristos                'Entry "%s" has illegal combination of optional and array '
410*2b3787f6Schristos                'around line %d' % (self._name, self.LineCount()))
411*2b3787f6Schristos
412*2b3787f6Schristos    def GetTranslation(self, extradict = {}):
413*2b3787f6Schristos        mapping = {
414*2b3787f6Schristos            "parent_name" : self._struct.Name(),
415*2b3787f6Schristos            "name" : self._name,
416*2b3787f6Schristos            "ctype" : self._ctype,
417*2b3787f6Schristos            "refname" : self._refname,
418*2b3787f6Schristos            "optpointer" : self._optpointer and "*" or "",
419*2b3787f6Schristos            "optreference" : self._optpointer and "&" or "",
420*2b3787f6Schristos            "optaddarg" :
421*2b3787f6Schristos            self._optaddarg and ", const %s value" % self._ctype or ""
422*2b3787f6Schristos            }
423*2b3787f6Schristos        for (k, v) in extradict.items():
424*2b3787f6Schristos            mapping[k] = v
425*2b3787f6Schristos
426*2b3787f6Schristos        return mapping
427*2b3787f6Schristos
428*2b3787f6Schristos    def GetVarName(self, var):
429*2b3787f6Schristos        return '%(var)s->%(name)s_data' % self.GetTranslation({ 'var' : var })
430*2b3787f6Schristos
431*2b3787f6Schristos    def GetVarLen(self, var):
432*2b3787f6Schristos        return 'sizeof(%s)' % self._ctype
433*2b3787f6Schristos
434*2b3787f6Schristos    def GetFuncName(self):
435*2b3787f6Schristos        return '%s_%s_get' % (self._struct.Name(), self._name)
436*2b3787f6Schristos
437*2b3787f6Schristos    def GetDeclaration(self, funcname):
438*2b3787f6Schristos        code = [ 'int %s(struct %s *, %s *);' % (
439*2b3787f6Schristos            funcname, self._struct.Name(), self._ctype ) ]
440*2b3787f6Schristos        return code
441*2b3787f6Schristos
442*2b3787f6Schristos    def CodeGet(self):
443*2b3787f6Schristos        code = (
444*2b3787f6Schristos            'int',
445*2b3787f6Schristos            '%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, '
446*2b3787f6Schristos            '%(ctype)s *value)',
447*2b3787f6Schristos            '{',
448*2b3787f6Schristos            '  if (msg->%(name)s_set != 1)',
449*2b3787f6Schristos            '    return (-1);',
450*2b3787f6Schristos            '  *value = msg->%(name)s_data;',
451*2b3787f6Schristos            '  return (0);',
452*2b3787f6Schristos            '}' )
453*2b3787f6Schristos        code = '\n'.join(code)
454*2b3787f6Schristos        code = code % self.GetTranslation()
455*2b3787f6Schristos        return code.split('\n')
456*2b3787f6Schristos
457*2b3787f6Schristos    def AssignFuncName(self):
458*2b3787f6Schristos        return '%s_%s_assign' % (self._struct.Name(), self._name)
459*2b3787f6Schristos
460*2b3787f6Schristos    def AddFuncName(self):
461*2b3787f6Schristos        return '%s_%s_add' % (self._struct.Name(), self._name)
462*2b3787f6Schristos
463*2b3787f6Schristos    def AssignDeclaration(self, funcname):
464*2b3787f6Schristos        code = [ 'int %s(struct %s *, const %s);' % (
465*2b3787f6Schristos            funcname, self._struct.Name(), self._ctype ) ]
466*2b3787f6Schristos        return code
467*2b3787f6Schristos
468*2b3787f6Schristos    def CodeAssign(self):
469*2b3787f6Schristos        code = [ 'int',
470*2b3787f6Schristos                 '%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,'
471*2b3787f6Schristos                 ' const %(ctype)s value)',
472*2b3787f6Schristos                 '{',
473*2b3787f6Schristos                 '  msg->%(name)s_set = 1;',
474*2b3787f6Schristos                 '  msg->%(name)s_data = value;',
475*2b3787f6Schristos                 '  return (0);',
476*2b3787f6Schristos                 '}' ]
477*2b3787f6Schristos        code = '\n'.join(code)
478*2b3787f6Schristos        code = code % self.GetTranslation()
479*2b3787f6Schristos        return code.split('\n')
480*2b3787f6Schristos
481*2b3787f6Schristos    def CodeClear(self, structname):
482*2b3787f6Schristos        code = [ '%s->%s_set = 0;' % (structname, self.Name()) ]
483*2b3787f6Schristos
484*2b3787f6Schristos        return code
485*2b3787f6Schristos
486*2b3787f6Schristos    def CodeComplete(self, structname, var_name):
487*2b3787f6Schristos        return []
488*2b3787f6Schristos
489*2b3787f6Schristos    def CodeFree(self, name):
490*2b3787f6Schristos        return []
491*2b3787f6Schristos
492*2b3787f6Schristos    def CodeBase(self):
493*2b3787f6Schristos        code = [
494*2b3787f6Schristos            '%(parent_name)s_%(name)s_assign,',
495*2b3787f6Schristos            '%(parent_name)s_%(name)s_get,'
496*2b3787f6Schristos            ]
497*2b3787f6Schristos        if self.Array():
498*2b3787f6Schristos            code.append('%(parent_name)s_%(name)s_add,')
499*2b3787f6Schristos
500*2b3787f6Schristos        code = '\n'.join(code)
501*2b3787f6Schristos        code = code % self.GetTranslation()
502*2b3787f6Schristos        return code.split('\n')
503*2b3787f6Schristos
504*2b3787f6Schristosclass EntryBytes(Entry):
505*2b3787f6Schristos    def __init__(self, type, name, tag, length):
506*2b3787f6Schristos        # Init base class
507*2b3787f6Schristos        Entry.__init__(self, type, name, tag)
508*2b3787f6Schristos
509*2b3787f6Schristos        self._length = length
510*2b3787f6Schristos        self._ctype = 'ev_uint8_t'
511*2b3787f6Schristos
512*2b3787f6Schristos    def GetInitializer(self):
513*2b3787f6Schristos        return "NULL"
514*2b3787f6Schristos
515*2b3787f6Schristos    def GetVarLen(self, var):
516*2b3787f6Schristos        return '(%s)' % self._length
517*2b3787f6Schristos
518*2b3787f6Schristos    def CodeArrayAdd(self, varname, value):
519*2b3787f6Schristos        # XXX: copy here
520*2b3787f6Schristos        return [ '%(varname)s = NULL;' % { 'varname' : varname } ]
521*2b3787f6Schristos
522*2b3787f6Schristos    def GetDeclaration(self, funcname):
523*2b3787f6Schristos        code = [ 'int %s(struct %s *, %s **);' % (
524*2b3787f6Schristos            funcname, self._struct.Name(), self._ctype ) ]
525*2b3787f6Schristos        return code
526*2b3787f6Schristos
527*2b3787f6Schristos    def AssignDeclaration(self, funcname):
528*2b3787f6Schristos        code = [ 'int %s(struct %s *, const %s *);' % (
529*2b3787f6Schristos            funcname, self._struct.Name(), self._ctype ) ]
530*2b3787f6Schristos        return code
531*2b3787f6Schristos
532*2b3787f6Schristos    def Declaration(self):
533*2b3787f6Schristos        dcl  = ['ev_uint8_t %s_data[%s];' % (self._name, self._length)]
534*2b3787f6Schristos
535*2b3787f6Schristos        return dcl
536*2b3787f6Schristos
537*2b3787f6Schristos    def CodeGet(self):
538*2b3787f6Schristos        name = self._name
539*2b3787f6Schristos        code = [ 'int',
540*2b3787f6Schristos                 '%s_%s_get(struct %s *msg, %s **value)' % (
541*2b3787f6Schristos            self._struct.Name(), name,
542*2b3787f6Schristos            self._struct.Name(), self._ctype),
543*2b3787f6Schristos                 '{',
544*2b3787f6Schristos                 '  if (msg->%s_set != 1)' % name,
545*2b3787f6Schristos                 '    return (-1);',
546*2b3787f6Schristos                 '  *value = msg->%s_data;' % name,
547*2b3787f6Schristos                 '  return (0);',
548*2b3787f6Schristos                 '}' ]
549*2b3787f6Schristos        return code
550*2b3787f6Schristos
551*2b3787f6Schristos    def CodeAssign(self):
552*2b3787f6Schristos        name = self._name
553*2b3787f6Schristos        code = [ 'int',
554*2b3787f6Schristos                 '%s_%s_assign(struct %s *msg, const %s *value)' % (
555*2b3787f6Schristos            self._struct.Name(), name,
556*2b3787f6Schristos            self._struct.Name(), self._ctype),
557*2b3787f6Schristos                 '{',
558*2b3787f6Schristos                 '  msg->%s_set = 1;' % name,
559*2b3787f6Schristos                 '  memcpy(msg->%s_data, value, %s);' % (
560*2b3787f6Schristos            name, self._length),
561*2b3787f6Schristos                 '  return (0);',
562*2b3787f6Schristos                 '}' ]
563*2b3787f6Schristos        return code
564*2b3787f6Schristos
565*2b3787f6Schristos    def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
566*2b3787f6Schristos        code = [  'if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, '
567*2b3787f6Schristos                  '%(var)s, %(varlen)s) == -1) {',
568*2b3787f6Schristos                  '  event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
569*2b3787f6Schristos                  '  return (-1);',
570*2b3787f6Schristos                  '}'
571*2b3787f6Schristos                  ]
572*2b3787f6Schristos        return TranslateList(code,
573*2b3787f6Schristos                             self.GetTranslation({
574*2b3787f6Schristos            'var' : var_name,
575*2b3787f6Schristos            'varlen' : var_len,
576*2b3787f6Schristos            'buf' : buf,
577*2b3787f6Schristos            'tag' : tag_name }))
578*2b3787f6Schristos
579*2b3787f6Schristos    def CodeMarshal(self, buf, tag_name, var_name, var_len):
580*2b3787f6Schristos        code = ['evtag_marshal(%s, %s, %s, %s);' % (
581*2b3787f6Schristos            buf, tag_name, var_name, var_len)]
582*2b3787f6Schristos        return code
583*2b3787f6Schristos
584*2b3787f6Schristos    def CodeClear(self, structname):
585*2b3787f6Schristos        code = [ '%s->%s_set = 0;' % (structname, self.Name()),
586*2b3787f6Schristos                 'memset(%s->%s_data, 0, sizeof(%s->%s_data));' % (
587*2b3787f6Schristos            structname, self._name, structname, self._name)]
588*2b3787f6Schristos
589*2b3787f6Schristos        return code
590*2b3787f6Schristos
591*2b3787f6Schristos    def CodeInitialize(self, name):
592*2b3787f6Schristos        code  = ['memset(%s->%s_data, 0, sizeof(%s->%s_data));' % (
593*2b3787f6Schristos            name, self._name, name, self._name)]
594*2b3787f6Schristos        return code
595*2b3787f6Schristos
596*2b3787f6Schristos    def Verify(self):
597*2b3787f6Schristos        if not self._length:
598*2b3787f6Schristos            raise RpcGenError(
599*2b3787f6Schristos                'Entry "%s" needs a length '
600*2b3787f6Schristos                'around line %d' % (self._name, self.LineCount()))
601*2b3787f6Schristos
602*2b3787f6Schristos        Entry.Verify(self)
603*2b3787f6Schristos
604*2b3787f6Schristosclass EntryInt(Entry):
605*2b3787f6Schristos    def __init__(self, type, name, tag, bits=32):
606*2b3787f6Schristos        # Init base class
607*2b3787f6Schristos        Entry.__init__(self, type, name, tag)
608*2b3787f6Schristos
609*2b3787f6Schristos        self._can_be_array = 1
610*2b3787f6Schristos        if bits == 32:
611*2b3787f6Schristos            self._ctype = 'ev_uint32_t'
612*2b3787f6Schristos            self._marshal_type = 'int'
613*2b3787f6Schristos        if bits == 64:
614*2b3787f6Schristos            self._ctype = 'ev_uint64_t'
615*2b3787f6Schristos            self._marshal_type = 'int64'
616*2b3787f6Schristos
617*2b3787f6Schristos    def GetInitializer(self):
618*2b3787f6Schristos        return "0"
619*2b3787f6Schristos
620*2b3787f6Schristos    def CodeArrayFree(self, var):
621*2b3787f6Schristos        return []
622*2b3787f6Schristos
623*2b3787f6Schristos    def CodeArrayAssign(self, varname, srcvar):
624*2b3787f6Schristos        return [ '%(varname)s = %(srcvar)s;' % { 'varname' : varname,
625*2b3787f6Schristos                                                'srcvar' : srcvar } ]
626*2b3787f6Schristos
627*2b3787f6Schristos    def CodeArrayAdd(self, varname, value):
628*2b3787f6Schristos        """Returns a new entry of this type."""
629*2b3787f6Schristos        return [ '%(varname)s = %(value)s;' % { 'varname' : varname,
630*2b3787f6Schristos                                              'value' : value } ]
631*2b3787f6Schristos
632*2b3787f6Schristos    def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
633*2b3787f6Schristos        code = [
634*2b3787f6Schristos            'if (evtag_unmarshal_%(ma)s(%(buf)s, %(tag)s, &%(var)s) == -1) {',
635*2b3787f6Schristos            '  event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
636*2b3787f6Schristos            '  return (-1);',
637*2b3787f6Schristos            '}' ]
638*2b3787f6Schristos        code = '\n'.join(code) % self.GetTranslation({
639*2b3787f6Schristos            'ma'  : self._marshal_type,
640*2b3787f6Schristos            'buf' : buf,
641*2b3787f6Schristos            'tag' : tag_name,
642*2b3787f6Schristos            'var' : var_name })
643*2b3787f6Schristos        return code.split('\n')
644*2b3787f6Schristos
645*2b3787f6Schristos    def CodeMarshal(self, buf, tag_name, var_name, var_len):
646*2b3787f6Schristos        code = [
647*2b3787f6Schristos            'evtag_marshal_%s(%s, %s, %s);' % (
648*2b3787f6Schristos            self._marshal_type, buf, tag_name, var_name)]
649*2b3787f6Schristos        return code
650*2b3787f6Schristos
651*2b3787f6Schristos    def Declaration(self):
652*2b3787f6Schristos        dcl  = ['%s %s_data;' % (self._ctype, self._name)]
653*2b3787f6Schristos
654*2b3787f6Schristos        return dcl
655*2b3787f6Schristos
656*2b3787f6Schristos    def CodeInitialize(self, name):
657*2b3787f6Schristos        code = ['%s->%s_data = 0;' % (name, self._name)]
658*2b3787f6Schristos        return code
659*2b3787f6Schristos
660*2b3787f6Schristosclass EntryString(Entry):
661*2b3787f6Schristos    def __init__(self, type, name, tag):
662*2b3787f6Schristos        # Init base class
663*2b3787f6Schristos        Entry.__init__(self, type, name, tag)
664*2b3787f6Schristos
665*2b3787f6Schristos        self._can_be_array = 1
666*2b3787f6Schristos        self._ctype = 'char *'
667*2b3787f6Schristos
668*2b3787f6Schristos    def GetInitializer(self):
669*2b3787f6Schristos        return "NULL"
670*2b3787f6Schristos
671*2b3787f6Schristos    def CodeArrayFree(self, varname):
672*2b3787f6Schristos        code = [
673*2b3787f6Schristos            'if (%(var)s != NULL) free(%(var)s);' ]
674*2b3787f6Schristos
675*2b3787f6Schristos        return TranslateList(code, { 'var' : varname })
676*2b3787f6Schristos
677*2b3787f6Schristos    def CodeArrayAssign(self, varname, srcvar):
678*2b3787f6Schristos        code = [
679*2b3787f6Schristos            'if (%(var)s != NULL)',
680*2b3787f6Schristos            '  free(%(var)s);',
681*2b3787f6Schristos            '%(var)s = strdup(%(srcvar)s);',
682*2b3787f6Schristos            'if (%(var)s == NULL) {',
683*2b3787f6Schristos            '  event_warnx("%%s: strdup", __func__);',
684*2b3787f6Schristos            '  return (-1);',
685*2b3787f6Schristos            '}' ]
686*2b3787f6Schristos
687*2b3787f6Schristos        return TranslateList(code, { 'var' : varname,
688*2b3787f6Schristos                                     'srcvar' : srcvar })
689*2b3787f6Schristos
690*2b3787f6Schristos    def CodeArrayAdd(self, varname, value):
691*2b3787f6Schristos        code = [
692*2b3787f6Schristos            'if (%(value)s != NULL) {',
693*2b3787f6Schristos            '  %(var)s = strdup(%(value)s);',
694*2b3787f6Schristos            '  if (%(var)s == NULL) {',
695*2b3787f6Schristos            '    goto error;',
696*2b3787f6Schristos            '  }',
697*2b3787f6Schristos            '} else {',
698*2b3787f6Schristos            '  %(var)s = NULL;',
699*2b3787f6Schristos            '}' ]
700*2b3787f6Schristos
701*2b3787f6Schristos        return TranslateList(code, { 'var' : varname,
702*2b3787f6Schristos                                     'value' : value })
703*2b3787f6Schristos
704*2b3787f6Schristos    def GetVarLen(self, var):
705*2b3787f6Schristos        return 'strlen(%s)' % self.GetVarName(var)
706*2b3787f6Schristos
707*2b3787f6Schristos    def CodeMakeInitalize(self, varname):
708*2b3787f6Schristos        return '%(varname)s = NULL;' % { 'varname' : varname }
709*2b3787f6Schristos
710*2b3787f6Schristos    def CodeAssign(self):
711*2b3787f6Schristos        name = self._name
712*2b3787f6Schristos        code = """int
713*2b3787f6Schristos%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
714*2b3787f6Schristos    const %(ctype)s value)
715*2b3787f6Schristos{
716*2b3787f6Schristos  if (msg->%(name)s_data != NULL)
717*2b3787f6Schristos    free(msg->%(name)s_data);
718*2b3787f6Schristos  if ((msg->%(name)s_data = strdup(value)) == NULL)
719*2b3787f6Schristos    return (-1);
720*2b3787f6Schristos  msg->%(name)s_set = 1;
721*2b3787f6Schristos  return (0);
722*2b3787f6Schristos}""" % self.GetTranslation()
723*2b3787f6Schristos
724*2b3787f6Schristos        return code.split('\n')
725*2b3787f6Schristos
726*2b3787f6Schristos    def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
727*2b3787f6Schristos        code = ['if (evtag_unmarshal_string(%(buf)s, %(tag)s, &%(var)s) == -1) {',
728*2b3787f6Schristos                '  event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
729*2b3787f6Schristos                '  return (-1);',
730*2b3787f6Schristos                '}'
731*2b3787f6Schristos                ]
732*2b3787f6Schristos        code = '\n'.join(code) % self.GetTranslation({
733*2b3787f6Schristos            'buf' : buf,
734*2b3787f6Schristos            'tag' : tag_name,
735*2b3787f6Schristos            'var' : var_name })
736*2b3787f6Schristos        return code.split('\n')
737*2b3787f6Schristos
738*2b3787f6Schristos    def CodeMarshal(self, buf, tag_name, var_name, var_len):
739*2b3787f6Schristos        code = ['evtag_marshal_string(%s, %s, %s);' % (
740*2b3787f6Schristos            buf, tag_name, var_name)]
741*2b3787f6Schristos        return code
742*2b3787f6Schristos
743*2b3787f6Schristos    def CodeClear(self, structname):
744*2b3787f6Schristos        code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
745*2b3787f6Schristos                 '  free(%s->%s_data);' % (structname, self.Name()),
746*2b3787f6Schristos                 '  %s->%s_data = NULL;' % (structname, self.Name()),
747*2b3787f6Schristos                 '  %s->%s_set = 0;' % (structname, self.Name()),
748*2b3787f6Schristos                 '}'
749*2b3787f6Schristos                 ]
750*2b3787f6Schristos
751*2b3787f6Schristos        return code
752*2b3787f6Schristos
753*2b3787f6Schristos    def CodeInitialize(self, name):
754*2b3787f6Schristos        code  = ['%s->%s_data = NULL;' % (name, self._name)]
755*2b3787f6Schristos        return code
756*2b3787f6Schristos
757*2b3787f6Schristos    def CodeFree(self, name):
758*2b3787f6Schristos        code  = ['if (%s->%s_data != NULL)' % (name, self._name),
759*2b3787f6Schristos                 '    free (%s->%s_data);' % (name, self._name)]
760*2b3787f6Schristos
761*2b3787f6Schristos        return code
762*2b3787f6Schristos
763*2b3787f6Schristos    def Declaration(self):
764*2b3787f6Schristos        dcl  = ['char *%s_data;' % self._name]
765*2b3787f6Schristos
766*2b3787f6Schristos        return dcl
767*2b3787f6Schristos
768*2b3787f6Schristosclass EntryStruct(Entry):
769*2b3787f6Schristos    def __init__(self, type, name, tag, refname):
770*2b3787f6Schristos        # Init base class
771*2b3787f6Schristos        Entry.__init__(self, type, name, tag)
772*2b3787f6Schristos
773*2b3787f6Schristos        self._optpointer = False
774*2b3787f6Schristos        self._can_be_array = 1
775*2b3787f6Schristos        self._refname = refname
776*2b3787f6Schristos        self._ctype = 'struct %s*' % refname
777*2b3787f6Schristos        self._optaddarg = False
778*2b3787f6Schristos
779*2b3787f6Schristos    def GetInitializer(self):
780*2b3787f6Schristos        return "NULL"
781*2b3787f6Schristos
782*2b3787f6Schristos    def GetVarLen(self, var):
783*2b3787f6Schristos        return '-1'
784*2b3787f6Schristos
785*2b3787f6Schristos    def CodeArrayAdd(self, varname, value):
786*2b3787f6Schristos        code = [
787*2b3787f6Schristos            '%(varname)s = %(refname)s_new();',
788*2b3787f6Schristos            'if (%(varname)s == NULL)',
789*2b3787f6Schristos            '  goto error;' ]
790*2b3787f6Schristos
791*2b3787f6Schristos        return TranslateList(code, self.GetTranslation({ 'varname' : varname }))
792*2b3787f6Schristos
793*2b3787f6Schristos    def CodeArrayFree(self, var):
794*2b3787f6Schristos        code = [ '%(refname)s_free(%(var)s);' % self.GetTranslation(
795*2b3787f6Schristos            { 'var' : var }) ]
796*2b3787f6Schristos        return code
797*2b3787f6Schristos
798*2b3787f6Schristos    def CodeArrayAssign(self, var, srcvar):
799*2b3787f6Schristos        code = [
800*2b3787f6Schristos            'int had_error = 0;',
801*2b3787f6Schristos            'struct evbuffer *tmp = NULL;',
802*2b3787f6Schristos            '%(refname)s_clear(%(var)s);',
803*2b3787f6Schristos            'if ((tmp = evbuffer_new()) == NULL) {',
804*2b3787f6Schristos            '  event_warn("%%s: evbuffer_new()", __func__);',
805*2b3787f6Schristos            '  had_error = 1;',
806*2b3787f6Schristos            '  goto done;',
807*2b3787f6Schristos            '}',
808*2b3787f6Schristos            '%(refname)s_marshal(tmp, %(srcvar)s);',
809*2b3787f6Schristos            'if (%(refname)s_unmarshal(%(var)s, tmp) == -1) {',
810*2b3787f6Schristos            '  event_warnx("%%s: %(refname)s_unmarshal", __func__);',
811*2b3787f6Schristos            '  had_error = 1;',
812*2b3787f6Schristos            '  goto done;',
813*2b3787f6Schristos            '}',
814*2b3787f6Schristos            'done:'
815*2b3787f6Schristos            'if (tmp != NULL)',
816*2b3787f6Schristos            '  evbuffer_free(tmp);',
817*2b3787f6Schristos            'if (had_error) {',
818*2b3787f6Schristos            '  %(refname)s_clear(%(var)s);',
819*2b3787f6Schristos            '  return (-1);',
820*2b3787f6Schristos            '}' ]
821*2b3787f6Schristos
822*2b3787f6Schristos        return TranslateList(code, self.GetTranslation({
823*2b3787f6Schristos            'var' : var,
824*2b3787f6Schristos            'srcvar' : srcvar}))
825*2b3787f6Schristos
826*2b3787f6Schristos    def CodeGet(self):
827*2b3787f6Schristos        name = self._name
828*2b3787f6Schristos        code = [ 'int',
829*2b3787f6Schristos                 '%s_%s_get(struct %s *msg, %s *value)' % (
830*2b3787f6Schristos            self._struct.Name(), name,
831*2b3787f6Schristos            self._struct.Name(), self._ctype),
832*2b3787f6Schristos                 '{',
833*2b3787f6Schristos                 '  if (msg->%s_set != 1) {' % name,
834*2b3787f6Schristos                 '    msg->%s_data = %s_new();' % (name, self._refname),
835*2b3787f6Schristos                 '    if (msg->%s_data == NULL)' % name,
836*2b3787f6Schristos                 '      return (-1);',
837*2b3787f6Schristos                 '    msg->%s_set = 1;' % name,
838*2b3787f6Schristos                 '  }',
839*2b3787f6Schristos                 '  *value = msg->%s_data;' % name,
840*2b3787f6Schristos                 '  return (0);',
841*2b3787f6Schristos                 '}' ]
842*2b3787f6Schristos        return code
843*2b3787f6Schristos
844*2b3787f6Schristos    def CodeAssign(self):
845*2b3787f6Schristos        name = self._name
846*2b3787f6Schristos        code = """int
847*2b3787f6Schristos%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
848*2b3787f6Schristos    const %(ctype)s value)
849*2b3787f6Schristos{
850*2b3787f6Schristos   struct evbuffer *tmp = NULL;
851*2b3787f6Schristos   if (msg->%(name)s_set) {
852*2b3787f6Schristos     %(refname)s_clear(msg->%(name)s_data);
853*2b3787f6Schristos     msg->%(name)s_set = 0;
854*2b3787f6Schristos   } else {
855*2b3787f6Schristos     msg->%(name)s_data = %(refname)s_new();
856*2b3787f6Schristos     if (msg->%(name)s_data == NULL) {
857*2b3787f6Schristos       event_warn("%%s: %(refname)s_new()", __func__);
858*2b3787f6Schristos       goto error;
859*2b3787f6Schristos     }
860*2b3787f6Schristos   }
861*2b3787f6Schristos   if ((tmp = evbuffer_new()) == NULL) {
862*2b3787f6Schristos     event_warn("%%s: evbuffer_new()", __func__);
863*2b3787f6Schristos     goto error;
864*2b3787f6Schristos   }
865*2b3787f6Schristos   %(refname)s_marshal(tmp, value);
866*2b3787f6Schristos   if (%(refname)s_unmarshal(msg->%(name)s_data, tmp) == -1) {
867*2b3787f6Schristos     event_warnx("%%s: %(refname)s_unmarshal", __func__);
868*2b3787f6Schristos     goto error;
869*2b3787f6Schristos   }
870*2b3787f6Schristos   msg->%(name)s_set = 1;
871*2b3787f6Schristos   evbuffer_free(tmp);
872*2b3787f6Schristos   return (0);
873*2b3787f6Schristos error:
874*2b3787f6Schristos   if (tmp != NULL)
875*2b3787f6Schristos     evbuffer_free(tmp);
876*2b3787f6Schristos   if (msg->%(name)s_data != NULL) {
877*2b3787f6Schristos     %(refname)s_free(msg->%(name)s_data);
878*2b3787f6Schristos     msg->%(name)s_data = NULL;
879*2b3787f6Schristos   }
880*2b3787f6Schristos   return (-1);
881*2b3787f6Schristos}""" % self.GetTranslation()
882*2b3787f6Schristos        return code.split('\n')
883*2b3787f6Schristos
884*2b3787f6Schristos    def CodeComplete(self, structname, var_name):
885*2b3787f6Schristos        code = [ 'if (%(structname)s->%(name)s_set && '
886*2b3787f6Schristos                 '%(refname)s_complete(%(var)s) == -1)',
887*2b3787f6Schristos                 '  return (-1);' ]
888*2b3787f6Schristos
889*2b3787f6Schristos        return TranslateList(code, self.GetTranslation({
890*2b3787f6Schristos            'structname' : structname,
891*2b3787f6Schristos            'var' : var_name }))
892*2b3787f6Schristos
893*2b3787f6Schristos    def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
894*2b3787f6Schristos        code = ['%(var)s = %(refname)s_new();',
895*2b3787f6Schristos                'if (%(var)s == NULL)',
896*2b3787f6Schristos                '  return (-1);',
897*2b3787f6Schristos                'if (evtag_unmarshal_%(refname)s(%(buf)s, %(tag)s, '
898*2b3787f6Schristos                '%(var)s) == -1) {',
899*2b3787f6Schristos                  '  event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
900*2b3787f6Schristos                '  return (-1);',
901*2b3787f6Schristos                '}'
902*2b3787f6Schristos                ]
903*2b3787f6Schristos        code = '\n'.join(code) % self.GetTranslation({
904*2b3787f6Schristos            'buf' : buf,
905*2b3787f6Schristos            'tag' : tag_name,
906*2b3787f6Schristos            'var' : var_name })
907*2b3787f6Schristos        return code.split('\n')
908*2b3787f6Schristos
909*2b3787f6Schristos    def CodeMarshal(self, buf, tag_name, var_name, var_len):
910*2b3787f6Schristos        code = ['evtag_marshal_%s(%s, %s, %s);' % (
911*2b3787f6Schristos            self._refname, buf, tag_name, var_name)]
912*2b3787f6Schristos        return code
913*2b3787f6Schristos
914*2b3787f6Schristos    def CodeClear(self, structname):
915*2b3787f6Schristos        code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
916*2b3787f6Schristos                 '  %s_free(%s->%s_data);' % (
917*2b3787f6Schristos            self._refname, structname, self.Name()),
918*2b3787f6Schristos                 '  %s->%s_data = NULL;' % (structname, self.Name()),
919*2b3787f6Schristos                 '  %s->%s_set = 0;' % (structname, self.Name()),
920*2b3787f6Schristos                 '}'
921*2b3787f6Schristos                 ]
922*2b3787f6Schristos
923*2b3787f6Schristos        return code
924*2b3787f6Schristos
925*2b3787f6Schristos    def CodeInitialize(self, name):
926*2b3787f6Schristos        code  = ['%s->%s_data = NULL;' % (name, self._name)]
927*2b3787f6Schristos        return code
928*2b3787f6Schristos
929*2b3787f6Schristos    def CodeFree(self, name):
930*2b3787f6Schristos        code  = ['if (%s->%s_data != NULL)' % (name, self._name),
931*2b3787f6Schristos                 '    %s_free(%s->%s_data);' % (
932*2b3787f6Schristos            self._refname, name, self._name)]
933*2b3787f6Schristos
934*2b3787f6Schristos        return code
935*2b3787f6Schristos
936*2b3787f6Schristos    def Declaration(self):
937*2b3787f6Schristos        dcl  = ['%s %s_data;' % (self._ctype, self._name)]
938*2b3787f6Schristos
939*2b3787f6Schristos        return dcl
940*2b3787f6Schristos
941*2b3787f6Schristosclass EntryVarBytes(Entry):
942*2b3787f6Schristos    def __init__(self, type, name, tag):
943*2b3787f6Schristos        # Init base class
944*2b3787f6Schristos        Entry.__init__(self, type, name, tag)
945*2b3787f6Schristos
946*2b3787f6Schristos        self._ctype = 'ev_uint8_t *'
947*2b3787f6Schristos
948*2b3787f6Schristos    def GetInitializer(self):
949*2b3787f6Schristos        return "NULL"
950*2b3787f6Schristos
951*2b3787f6Schristos    def GetVarLen(self, var):
952*2b3787f6Schristos        return '%(var)s->%(name)s_length' % self.GetTranslation({ 'var' : var })
953*2b3787f6Schristos
954*2b3787f6Schristos    def CodeArrayAdd(self, varname, value):
955*2b3787f6Schristos        # xxx: copy
956*2b3787f6Schristos        return [ '%(varname)s = NULL;' % { 'varname' : varname } ]
957*2b3787f6Schristos
958*2b3787f6Schristos    def GetDeclaration(self, funcname):
959*2b3787f6Schristos        code = [ 'int %s(struct %s *, %s *, ev_uint32_t *);' % (
960*2b3787f6Schristos            funcname, self._struct.Name(), self._ctype ) ]
961*2b3787f6Schristos        return code
962*2b3787f6Schristos
963*2b3787f6Schristos    def AssignDeclaration(self, funcname):
964*2b3787f6Schristos        code = [ 'int %s(struct %s *, const %s, ev_uint32_t);' % (
965*2b3787f6Schristos            funcname, self._struct.Name(), self._ctype ) ]
966*2b3787f6Schristos        return code
967*2b3787f6Schristos
968*2b3787f6Schristos    def CodeAssign(self):
969*2b3787f6Schristos        name = self._name
970*2b3787f6Schristos        code = [ 'int',
971*2b3787f6Schristos                 '%s_%s_assign(struct %s *msg, '
972*2b3787f6Schristos                 'const %s value, ev_uint32_t len)' % (
973*2b3787f6Schristos            self._struct.Name(), name,
974*2b3787f6Schristos            self._struct.Name(), self._ctype),
975*2b3787f6Schristos                 '{',
976*2b3787f6Schristos                 '  if (msg->%s_data != NULL)' % name,
977*2b3787f6Schristos                 '    free (msg->%s_data);' % name,
978*2b3787f6Schristos                 '  msg->%s_data = malloc(len);' % name,
979*2b3787f6Schristos                 '  if (msg->%s_data == NULL)' % name,
980*2b3787f6Schristos                 '    return (-1);',
981*2b3787f6Schristos                 '  msg->%s_set = 1;' % name,
982*2b3787f6Schristos                 '  msg->%s_length = len;' % name,
983*2b3787f6Schristos                 '  memcpy(msg->%s_data, value, len);' % name,
984*2b3787f6Schristos                 '  return (0);',
985*2b3787f6Schristos                 '}' ]
986*2b3787f6Schristos        return code
987*2b3787f6Schristos
988*2b3787f6Schristos    def CodeGet(self):
989*2b3787f6Schristos        name = self._name
990*2b3787f6Schristos        code = [ 'int',
991*2b3787f6Schristos                 '%s_%s_get(struct %s *msg, %s *value, ev_uint32_t *plen)' % (
992*2b3787f6Schristos            self._struct.Name(), name,
993*2b3787f6Schristos            self._struct.Name(), self._ctype),
994*2b3787f6Schristos                 '{',
995*2b3787f6Schristos                 '  if (msg->%s_set != 1)' % name,
996*2b3787f6Schristos                 '    return (-1);',
997*2b3787f6Schristos                 '  *value = msg->%s_data;' % name,
998*2b3787f6Schristos                 '  *plen = msg->%s_length;' % name,
999*2b3787f6Schristos                 '  return (0);',
1000*2b3787f6Schristos                 '}' ]
1001*2b3787f6Schristos        return code
1002*2b3787f6Schristos
1003*2b3787f6Schristos    def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
1004*2b3787f6Schristos        code = ['if (evtag_payload_length(%(buf)s, &%(varlen)s) == -1)',
1005*2b3787f6Schristos                '  return (-1);',
1006*2b3787f6Schristos                # We do not want DoS opportunities
1007*2b3787f6Schristos                'if (%(varlen)s > evbuffer_get_length(%(buf)s))',
1008*2b3787f6Schristos                '  return (-1);',
1009*2b3787f6Schristos                'if ((%(var)s = malloc(%(varlen)s)) == NULL)',
1010*2b3787f6Schristos                '  return (-1);',
1011*2b3787f6Schristos                'if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, %(var)s, '
1012*2b3787f6Schristos                '%(varlen)s) == -1) {',
1013*2b3787f6Schristos                '  event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
1014*2b3787f6Schristos                '  return (-1);',
1015*2b3787f6Schristos                '}'
1016*2b3787f6Schristos                ]
1017*2b3787f6Schristos        code = '\n'.join(code) % self.GetTranslation({
1018*2b3787f6Schristos            'buf' : buf,
1019*2b3787f6Schristos            'tag' : tag_name,
1020*2b3787f6Schristos            'var' : var_name,
1021*2b3787f6Schristos            'varlen' : var_len })
1022*2b3787f6Schristos        return code.split('\n')
1023*2b3787f6Schristos
1024*2b3787f6Schristos    def CodeMarshal(self, buf, tag_name, var_name, var_len):
1025*2b3787f6Schristos        code = ['evtag_marshal(%s, %s, %s, %s);' % (
1026*2b3787f6Schristos            buf, tag_name, var_name, var_len)]
1027*2b3787f6Schristos        return code
1028*2b3787f6Schristos
1029*2b3787f6Schristos    def CodeClear(self, structname):
1030*2b3787f6Schristos        code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
1031*2b3787f6Schristos                 '  free (%s->%s_data);' % (structname, self.Name()),
1032*2b3787f6Schristos                 '  %s->%s_data = NULL;' % (structname, self.Name()),
1033*2b3787f6Schristos                 '  %s->%s_length = 0;' % (structname, self.Name()),
1034*2b3787f6Schristos                 '  %s->%s_set = 0;' % (structname, self.Name()),
1035*2b3787f6Schristos                 '}'
1036*2b3787f6Schristos                 ]
1037*2b3787f6Schristos
1038*2b3787f6Schristos        return code
1039*2b3787f6Schristos
1040*2b3787f6Schristos    def CodeInitialize(self, name):
1041*2b3787f6Schristos        code  = ['%s->%s_data = NULL;' % (name, self._name),
1042*2b3787f6Schristos                 '%s->%s_length = 0;' % (name, self._name) ]
1043*2b3787f6Schristos        return code
1044*2b3787f6Schristos
1045*2b3787f6Schristos    def CodeFree(self, name):
1046*2b3787f6Schristos        code  = ['if (%s->%s_data != NULL)' % (name, self._name),
1047*2b3787f6Schristos                 '    free(%s->%s_data);' % (name, self._name)]
1048*2b3787f6Schristos
1049*2b3787f6Schristos        return code
1050*2b3787f6Schristos
1051*2b3787f6Schristos    def Declaration(self):
1052*2b3787f6Schristos        dcl  = ['ev_uint8_t *%s_data;' % self._name,
1053*2b3787f6Schristos                'ev_uint32_t %s_length;' % self._name]
1054*2b3787f6Schristos
1055*2b3787f6Schristos        return dcl
1056*2b3787f6Schristos
1057*2b3787f6Schristosclass EntryArray(Entry):
1058*2b3787f6Schristos    def __init__(self, entry):
1059*2b3787f6Schristos        # Init base class
1060*2b3787f6Schristos        Entry.__init__(self, entry._type, entry._name, entry._tag)
1061*2b3787f6Schristos
1062*2b3787f6Schristos        self._entry = entry
1063*2b3787f6Schristos        self._refname = entry._refname
1064*2b3787f6Schristos        self._ctype = self._entry._ctype
1065*2b3787f6Schristos        self._optional = True
1066*2b3787f6Schristos        self._optpointer = self._entry._optpointer
1067*2b3787f6Schristos        self._optaddarg = self._entry._optaddarg
1068*2b3787f6Schristos
1069*2b3787f6Schristos        # provide a new function for accessing the variable name
1070*2b3787f6Schristos        def GetVarName(var_name):
1071*2b3787f6Schristos            return '%(var)s->%(name)s_data[%(index)s]' % \
1072*2b3787f6Schristos                   self._entry.GetTranslation({'var' : var_name,
1073*2b3787f6Schristos                                               'index' : self._index})
1074*2b3787f6Schristos        self._entry.GetVarName = GetVarName
1075*2b3787f6Schristos
1076*2b3787f6Schristos    def GetInitializer(self):
1077*2b3787f6Schristos        return "NULL"
1078*2b3787f6Schristos
1079*2b3787f6Schristos    def GetVarName(self, var_name):
1080*2b3787f6Schristos        return var_name
1081*2b3787f6Schristos
1082*2b3787f6Schristos    def GetVarLen(self, var_name):
1083*2b3787f6Schristos        return '-1'
1084*2b3787f6Schristos
1085*2b3787f6Schristos    def GetDeclaration(self, funcname):
1086*2b3787f6Schristos        """Allows direct access to elements of the array."""
1087*2b3787f6Schristos        code = [
1088*2b3787f6Schristos            'int %(funcname)s(struct %(parent_name)s *, int, %(ctype)s *);' %
1089*2b3787f6Schristos            self.GetTranslation({ 'funcname' : funcname }) ]
1090*2b3787f6Schristos        return code
1091*2b3787f6Schristos
1092*2b3787f6Schristos    def AssignDeclaration(self, funcname):
1093*2b3787f6Schristos        code = [ 'int %s(struct %s *, int, const %s);' % (
1094*2b3787f6Schristos            funcname, self._struct.Name(), self._ctype ) ]
1095*2b3787f6Schristos        return code
1096*2b3787f6Schristos
1097*2b3787f6Schristos    def AddDeclaration(self, funcname):
1098*2b3787f6Schristos        code = [
1099*2b3787f6Schristos            '%(ctype)s %(optpointer)s '
1100*2b3787f6Schristos            '%(funcname)s(struct %(parent_name)s *msg%(optaddarg)s);' % \
1101*2b3787f6Schristos            self.GetTranslation({ 'funcname' : funcname }) ]
1102*2b3787f6Schristos        return code
1103*2b3787f6Schristos
1104*2b3787f6Schristos    def CodeGet(self):
1105*2b3787f6Schristos        code = """int
1106*2b3787f6Schristos%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, int offset,
1107*2b3787f6Schristos    %(ctype)s *value)
1108*2b3787f6Schristos{
1109*2b3787f6Schristos  if (!msg->%(name)s_set || offset < 0 || offset >= msg->%(name)s_length)
1110*2b3787f6Schristos    return (-1);
1111*2b3787f6Schristos  *value = msg->%(name)s_data[offset];
1112*2b3787f6Schristos  return (0);
1113*2b3787f6Schristos}""" % self.GetTranslation()
1114*2b3787f6Schristos
1115*2b3787f6Schristos        return code.split('\n')
1116*2b3787f6Schristos
1117*2b3787f6Schristos    def CodeAssign(self):
1118*2b3787f6Schristos        code = [
1119*2b3787f6Schristos            'int',
1120*2b3787f6Schristos            '%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, int off,',
1121*2b3787f6Schristos            '    const %(ctype)s value)',
1122*2b3787f6Schristos            '{',
1123*2b3787f6Schristos            '  if (!msg->%(name)s_set || off < 0 || off >= msg->%(name)s_length)',
1124*2b3787f6Schristos            '    return (-1);\n',
1125*2b3787f6Schristos            '  {' ]
1126*2b3787f6Schristos        code = TranslateList(code, self.GetTranslation())
1127*2b3787f6Schristos
1128*2b3787f6Schristos        codearrayassign = self._entry.CodeArrayAssign(
1129*2b3787f6Schristos            'msg->%(name)s_data[off]' % self.GetTranslation(), 'value')
1130*2b3787f6Schristos        code += map(lambda x: '    ' + x, codearrayassign)
1131*2b3787f6Schristos
1132*2b3787f6Schristos        code += TranslateList([
1133*2b3787f6Schristos            '  }',
1134*2b3787f6Schristos            '  return (0);',
1135*2b3787f6Schristos            '}' ], self.GetTranslation())
1136*2b3787f6Schristos
1137*2b3787f6Schristos        return code
1138*2b3787f6Schristos
1139*2b3787f6Schristos    def CodeAdd(self):
1140*2b3787f6Schristos        codearrayadd = self._entry.CodeArrayAdd(
1141*2b3787f6Schristos            'msg->%(name)s_data[msg->%(name)s_length - 1]' % self.GetTranslation(),
1142*2b3787f6Schristos            'value')
1143*2b3787f6Schristos        code = [
1144*2b3787f6Schristos            'static int',
1145*2b3787f6Schristos            '%(parent_name)s_%(name)s_expand_to_hold_more('
1146*2b3787f6Schristos            'struct %(parent_name)s *msg)',
1147*2b3787f6Schristos            '{',
1148*2b3787f6Schristos            '  int tobe_allocated = msg->%(name)s_num_allocated;',
1149*2b3787f6Schristos            '  %(ctype)s* new_data = NULL;',
1150*2b3787f6Schristos            '  tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;',
1151*2b3787f6Schristos            '  new_data = (%(ctype)s*) realloc(msg->%(name)s_data,',
1152*2b3787f6Schristos            '      tobe_allocated * sizeof(%(ctype)s));',
1153*2b3787f6Schristos            '  if (new_data == NULL)',
1154*2b3787f6Schristos            '    return -1;',
1155*2b3787f6Schristos            '  msg->%(name)s_data = new_data;',
1156*2b3787f6Schristos            '  msg->%(name)s_num_allocated = tobe_allocated;',
1157*2b3787f6Schristos            '  return 0;'
1158*2b3787f6Schristos            '}',
1159*2b3787f6Schristos            '',
1160*2b3787f6Schristos            '%(ctype)s %(optpointer)s',
1161*2b3787f6Schristos            '%(parent_name)s_%(name)s_add('
1162*2b3787f6Schristos            'struct %(parent_name)s *msg%(optaddarg)s)',
1163*2b3787f6Schristos            '{',
1164*2b3787f6Schristos            '  if (++msg->%(name)s_length >= msg->%(name)s_num_allocated) {',
1165*2b3787f6Schristos            '    if (%(parent_name)s_%(name)s_expand_to_hold_more(msg)<0)',
1166*2b3787f6Schristos            '      goto error;',
1167*2b3787f6Schristos            '  }' ]
1168*2b3787f6Schristos
1169*2b3787f6Schristos        code = TranslateList(code, self.GetTranslation())
1170*2b3787f6Schristos
1171*2b3787f6Schristos        code += map(lambda x: '  ' + x, codearrayadd)
1172*2b3787f6Schristos
1173*2b3787f6Schristos        code += TranslateList([
1174*2b3787f6Schristos            '  msg->%(name)s_set = 1;',
1175*2b3787f6Schristos            '  return %(optreference)s(msg->%(name)s_data['
1176*2b3787f6Schristos            'msg->%(name)s_length - 1]);',
1177*2b3787f6Schristos            'error:',
1178*2b3787f6Schristos            '  --msg->%(name)s_length;',
1179*2b3787f6Schristos            '  return (NULL);',
1180*2b3787f6Schristos            '}' ], self.GetTranslation())
1181*2b3787f6Schristos
1182*2b3787f6Schristos        return code
1183*2b3787f6Schristos
1184*2b3787f6Schristos    def CodeComplete(self, structname, var_name):
1185*2b3787f6Schristos        self._index = 'i'
1186*2b3787f6Schristos        tmp = self._entry.CodeComplete(structname, self._entry.GetVarName(var_name))
1187*2b3787f6Schristos        # skip the whole loop if there is nothing to check
1188*2b3787f6Schristos        if not tmp:
1189*2b3787f6Schristos            return []
1190*2b3787f6Schristos
1191*2b3787f6Schristos        translate = self.GetTranslation({ 'structname' : structname })
1192*2b3787f6Schristos        code = [
1193*2b3787f6Schristos            '{',
1194*2b3787f6Schristos            '  int i;',
1195*2b3787f6Schristos            '  for (i = 0; i < %(structname)s->%(name)s_length; ++i) {' ]
1196*2b3787f6Schristos
1197*2b3787f6Schristos        code = TranslateList(code, translate)
1198*2b3787f6Schristos
1199*2b3787f6Schristos        code += map(lambda x: '    ' + x, tmp)
1200*2b3787f6Schristos
1201*2b3787f6Schristos        code += [
1202*2b3787f6Schristos            '  }',
1203*2b3787f6Schristos            '}' ]
1204*2b3787f6Schristos
1205*2b3787f6Schristos        return code
1206*2b3787f6Schristos
1207*2b3787f6Schristos    def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
1208*2b3787f6Schristos        translate = self.GetTranslation({ 'var' : var_name,
1209*2b3787f6Schristos                                          'buf' : buf,
1210*2b3787f6Schristos                                          'tag' : tag_name,
1211*2b3787f6Schristos                                          'init' : self._entry.GetInitializer()})
1212*2b3787f6Schristos        code = [
1213*2b3787f6Schristos            'if (%(var)s->%(name)s_length >= %(var)s->%(name)s_num_allocated &&',
1214*2b3787f6Schristos            '    %(parent_name)s_%(name)s_expand_to_hold_more(%(var)s) < 0) {',
1215*2b3787f6Schristos            '  puts("HEY NOW");',
1216*2b3787f6Schristos            '  return (-1);',
1217*2b3787f6Schristos            '}']
1218*2b3787f6Schristos
1219*2b3787f6Schristos        # the unmarshal code directly returns
1220*2b3787f6Schristos        code = TranslateList(code, translate)
1221*2b3787f6Schristos
1222*2b3787f6Schristos        self._index = '%(var)s->%(name)s_length' % translate
1223*2b3787f6Schristos        code += self._entry.CodeUnmarshal(buf, tag_name,
1224*2b3787f6Schristos                                        self._entry.GetVarName(var_name),
1225*2b3787f6Schristos                                        self._entry.GetVarLen(var_name))
1226*2b3787f6Schristos
1227*2b3787f6Schristos        code += [ '++%(var)s->%(name)s_length;' % translate ]
1228*2b3787f6Schristos
1229*2b3787f6Schristos        return code
1230*2b3787f6Schristos
1231*2b3787f6Schristos    def CodeMarshal(self, buf, tag_name, var_name, var_len):
1232*2b3787f6Schristos        code = ['{',
1233*2b3787f6Schristos                '  int i;',
1234*2b3787f6Schristos                '  for (i = 0; i < %(var)s->%(name)s_length; ++i) {' ]
1235*2b3787f6Schristos
1236*2b3787f6Schristos        self._index = 'i'
1237*2b3787f6Schristos        code += self._entry.CodeMarshal(buf, tag_name,
1238*2b3787f6Schristos                                        self._entry.GetVarName(var_name),
1239*2b3787f6Schristos                                        self._entry.GetVarLen(var_name))
1240*2b3787f6Schristos        code += ['  }',
1241*2b3787f6Schristos                 '}'
1242*2b3787f6Schristos                 ]
1243*2b3787f6Schristos
1244*2b3787f6Schristos        code = "\n".join(code) % self.GetTranslation({ 'var' : var_name })
1245*2b3787f6Schristos
1246*2b3787f6Schristos        return code.split('\n')
1247*2b3787f6Schristos
1248*2b3787f6Schristos    def CodeClear(self, structname):
1249*2b3787f6Schristos        translate = self.GetTranslation({ 'structname' : structname })
1250*2b3787f6Schristos        codearrayfree = self._entry.CodeArrayFree(
1251*2b3787f6Schristos            '%(structname)s->%(name)s_data[i]' % self.GetTranslation(
1252*2b3787f6Schristos            { 'structname' : structname } ))
1253*2b3787f6Schristos
1254*2b3787f6Schristos        code = [ 'if (%(structname)s->%(name)s_set == 1) {' ]
1255*2b3787f6Schristos
1256*2b3787f6Schristos        if codearrayfree:
1257*2b3787f6Schristos            code += [
1258*2b3787f6Schristos                '  int i;',
1259*2b3787f6Schristos                '  for (i = 0; i < %(structname)s->%(name)s_length; ++i) {' ]
1260*2b3787f6Schristos
1261*2b3787f6Schristos        code = TranslateList(code, translate)
1262*2b3787f6Schristos
1263*2b3787f6Schristos        if codearrayfree:
1264*2b3787f6Schristos            code += map(lambda x: '    ' + x, codearrayfree)
1265*2b3787f6Schristos            code += [
1266*2b3787f6Schristos                '  }' ]
1267*2b3787f6Schristos
1268*2b3787f6Schristos        code += TranslateList([
1269*2b3787f6Schristos                 '  free(%(structname)s->%(name)s_data);',
1270*2b3787f6Schristos                 '  %(structname)s->%(name)s_data = NULL;',
1271*2b3787f6Schristos                 '  %(structname)s->%(name)s_set = 0;',
1272*2b3787f6Schristos                 '  %(structname)s->%(name)s_length = 0;',
1273*2b3787f6Schristos                 '  %(structname)s->%(name)s_num_allocated = 0;',
1274*2b3787f6Schristos                 '}'
1275*2b3787f6Schristos                 ], translate)
1276*2b3787f6Schristos
1277*2b3787f6Schristos        return code
1278*2b3787f6Schristos
1279*2b3787f6Schristos    def CodeInitialize(self, name):
1280*2b3787f6Schristos        code  = ['%s->%s_data = NULL;' % (name, self._name),
1281*2b3787f6Schristos                 '%s->%s_length = 0;' % (name, self._name),
1282*2b3787f6Schristos                 '%s->%s_num_allocated = 0;' % (name, self._name)]
1283*2b3787f6Schristos        return code
1284*2b3787f6Schristos
1285*2b3787f6Schristos    def CodeFree(self, structname):
1286*2b3787f6Schristos        code = self.CodeClear(structname);
1287*2b3787f6Schristos
1288*2b3787f6Schristos        code += TranslateList([
1289*2b3787f6Schristos            'free(%(structname)s->%(name)s_data);' ],
1290*2b3787f6Schristos                              self.GetTranslation({'structname' : structname }))
1291*2b3787f6Schristos
1292*2b3787f6Schristos        return code
1293*2b3787f6Schristos
1294*2b3787f6Schristos    def Declaration(self):
1295*2b3787f6Schristos        dcl  = ['%s *%s_data;' % (self._ctype, self._name),
1296*2b3787f6Schristos                'int %s_length;' % self._name,
1297*2b3787f6Schristos                'int %s_num_allocated;' % self._name ]
1298*2b3787f6Schristos
1299*2b3787f6Schristos        return dcl
1300*2b3787f6Schristos
1301*2b3787f6Schristosdef NormalizeLine(line):
1302*2b3787f6Schristos    global white
1303*2b3787f6Schristos    global cppcomment
1304*2b3787f6Schristos
1305*2b3787f6Schristos    line = cppcomment.sub('', line)
1306*2b3787f6Schristos    line = line.strip()
1307*2b3787f6Schristos    line = white.sub(' ', line)
1308*2b3787f6Schristos
1309*2b3787f6Schristos    return line
1310*2b3787f6Schristos
1311*2b3787f6Schristosdef ProcessOneEntry(factory, newstruct, entry):
1312*2b3787f6Schristos    optional = 0
1313*2b3787f6Schristos    array = 0
1314*2b3787f6Schristos    entry_type = ''
1315*2b3787f6Schristos    name = ''
1316*2b3787f6Schristos    tag = ''
1317*2b3787f6Schristos    tag_set = None
1318*2b3787f6Schristos    separator = ''
1319*2b3787f6Schristos    fixed_length = ''
1320*2b3787f6Schristos
1321*2b3787f6Schristos    tokens = entry.split(' ')
1322*2b3787f6Schristos    while tokens:
1323*2b3787f6Schristos        token = tokens[0]
1324*2b3787f6Schristos        tokens = tokens[1:]
1325*2b3787f6Schristos
1326*2b3787f6Schristos        if not entry_type:
1327*2b3787f6Schristos            if not optional and token == 'optional':
1328*2b3787f6Schristos                optional = 1
1329*2b3787f6Schristos                continue
1330*2b3787f6Schristos
1331*2b3787f6Schristos            if not array and token == 'array':
1332*2b3787f6Schristos                array = 1
1333*2b3787f6Schristos                continue
1334*2b3787f6Schristos
1335*2b3787f6Schristos        if not entry_type:
1336*2b3787f6Schristos            entry_type = token
1337*2b3787f6Schristos            continue
1338*2b3787f6Schristos
1339*2b3787f6Schristos        if not name:
1340*2b3787f6Schristos            res = re.match(r'^([^\[\]]+)(\[.*\])?$', token)
1341*2b3787f6Schristos            if not res:
1342*2b3787f6Schristos                 raise RpcGenError(
1343*2b3787f6Schristos                     'Cannot parse name: \"%s\" '
1344*2b3787f6Schristos                     'around line %d' % (entry, line_count))
1345*2b3787f6Schristos            name = res.group(1)
1346*2b3787f6Schristos            fixed_length = res.group(2)
1347*2b3787f6Schristos            if fixed_length:
1348*2b3787f6Schristos                fixed_length = fixed_length[1:-1]
1349*2b3787f6Schristos            continue
1350*2b3787f6Schristos
1351*2b3787f6Schristos        if not separator:
1352*2b3787f6Schristos            separator = token
1353*2b3787f6Schristos            if separator != '=':
1354*2b3787f6Schristos                 raise RpcGenError('Expected "=" after name \"%s\" got %s'
1355*2b3787f6Schristos                                   % (name, token))
1356*2b3787f6Schristos            continue
1357*2b3787f6Schristos
1358*2b3787f6Schristos        if not tag_set:
1359*2b3787f6Schristos            tag_set = 1
1360*2b3787f6Schristos            if not re.match(r'^(0x)?[0-9]+$', token):
1361*2b3787f6Schristos                raise RpcGenError('Expected tag number: \"%s\"' % entry)
1362*2b3787f6Schristos            tag = int(token, 0)
1363*2b3787f6Schristos            continue
1364*2b3787f6Schristos
1365*2b3787f6Schristos        raise RpcGenError('Cannot parse \"%s\"' % entry)
1366*2b3787f6Schristos
1367*2b3787f6Schristos    if not tag_set:
1368*2b3787f6Schristos        raise RpcGenError('Need tag number: \"%s\"' % entry)
1369*2b3787f6Schristos
1370*2b3787f6Schristos    # Create the right entry
1371*2b3787f6Schristos    if entry_type == 'bytes':
1372*2b3787f6Schristos        if fixed_length:
1373*2b3787f6Schristos            newentry = factory.EntryBytes(entry_type, name, tag, fixed_length)
1374*2b3787f6Schristos        else:
1375*2b3787f6Schristos            newentry = factory.EntryVarBytes(entry_type, name, tag)
1376*2b3787f6Schristos    elif entry_type == 'int' and not fixed_length:
1377*2b3787f6Schristos        newentry = factory.EntryInt(entry_type, name, tag)
1378*2b3787f6Schristos    elif entry_type == 'int64' and not fixed_length:
1379*2b3787f6Schristos        newentry = factory.EntryInt(entry_type, name, tag, bits=64)
1380*2b3787f6Schristos    elif entry_type == 'string' and not fixed_length:
1381*2b3787f6Schristos        newentry = factory.EntryString(entry_type, name, tag)
1382*2b3787f6Schristos    else:
1383*2b3787f6Schristos        res = structref.match(entry_type)
1384*2b3787f6Schristos        if res:
1385*2b3787f6Schristos            # References another struct defined in our file
1386*2b3787f6Schristos            newentry = factory.EntryStruct(entry_type, name, tag, res.group(1))
1387*2b3787f6Schristos        else:
1388*2b3787f6Schristos            raise RpcGenError('Bad type: "%s" in "%s"' % (entry_type, entry))
1389*2b3787f6Schristos
1390*2b3787f6Schristos    structs = []
1391*2b3787f6Schristos
1392*2b3787f6Schristos    if optional:
1393*2b3787f6Schristos        newentry.MakeOptional()
1394*2b3787f6Schristos    if array:
1395*2b3787f6Schristos        newentry.MakeArray()
1396*2b3787f6Schristos
1397*2b3787f6Schristos    newentry.SetStruct(newstruct)
1398*2b3787f6Schristos    newentry.SetLineCount(line_count)
1399*2b3787f6Schristos    newentry.Verify()
1400*2b3787f6Schristos
1401*2b3787f6Schristos    if array:
1402*2b3787f6Schristos        # We need to encapsulate this entry into a struct
1403*2b3787f6Schristos        newname = newentry.Name()+ '_array'
1404*2b3787f6Schristos
1405*2b3787f6Schristos        # Now borgify the new entry.
1406*2b3787f6Schristos        newentry = factory.EntryArray(newentry)
1407*2b3787f6Schristos        newentry.SetStruct(newstruct)
1408*2b3787f6Schristos        newentry.SetLineCount(line_count)
1409*2b3787f6Schristos        newentry.MakeArray()
1410*2b3787f6Schristos
1411*2b3787f6Schristos    newstruct.AddEntry(newentry)
1412*2b3787f6Schristos
1413*2b3787f6Schristos    return structs
1414*2b3787f6Schristos
1415*2b3787f6Schristosdef ProcessStruct(factory, data):
1416*2b3787f6Schristos    tokens = data.split(' ')
1417*2b3787f6Schristos
1418*2b3787f6Schristos    # First three tokens are: 'struct' 'name' '{'
1419*2b3787f6Schristos    newstruct = factory.Struct(tokens[1])
1420*2b3787f6Schristos
1421*2b3787f6Schristos    inside = ' '.join(tokens[3:-1])
1422*2b3787f6Schristos
1423*2b3787f6Schristos    tokens = inside.split(';')
1424*2b3787f6Schristos
1425*2b3787f6Schristos    structs = []
1426*2b3787f6Schristos
1427*2b3787f6Schristos    for entry in tokens:
1428*2b3787f6Schristos        entry = NormalizeLine(entry)
1429*2b3787f6Schristos        if not entry:
1430*2b3787f6Schristos            continue
1431*2b3787f6Schristos
1432*2b3787f6Schristos        # It's possible that new structs get defined in here
1433*2b3787f6Schristos        structs.extend(ProcessOneEntry(factory, newstruct, entry))
1434*2b3787f6Schristos
1435*2b3787f6Schristos    structs.append(newstruct)
1436*2b3787f6Schristos    return structs
1437*2b3787f6Schristos
1438*2b3787f6Schristosdef GetNextStruct(file):
1439*2b3787f6Schristos    global line_count
1440*2b3787f6Schristos    global cppdirect
1441*2b3787f6Schristos
1442*2b3787f6Schristos    got_struct = 0
1443*2b3787f6Schristos
1444*2b3787f6Schristos    processed_lines = []
1445*2b3787f6Schristos
1446*2b3787f6Schristos    have_c_comment = 0
1447*2b3787f6Schristos    data = ''
1448*2b3787f6Schristos    while 1:
1449*2b3787f6Schristos        line = file.readline()
1450*2b3787f6Schristos        if not line:
1451*2b3787f6Schristos            break
1452*2b3787f6Schristos
1453*2b3787f6Schristos        line_count += 1
1454*2b3787f6Schristos        line = line[:-1]
1455*2b3787f6Schristos
1456*2b3787f6Schristos        if not have_c_comment and re.search(r'/\*', line):
1457*2b3787f6Schristos            if re.search(r'/\*.*?\*/', line):
1458*2b3787f6Schristos                line = re.sub(r'/\*.*?\*/', '', line)
1459*2b3787f6Schristos            else:
1460*2b3787f6Schristos                line = re.sub(r'/\*.*$', '', line)
1461*2b3787f6Schristos                have_c_comment = 1
1462*2b3787f6Schristos
1463*2b3787f6Schristos        if have_c_comment:
1464*2b3787f6Schristos            if not re.search(r'\*/', line):
1465*2b3787f6Schristos                continue
1466*2b3787f6Schristos            have_c_comment = 0
1467*2b3787f6Schristos            line = re.sub(r'^.*\*/', '', line)
1468*2b3787f6Schristos
1469*2b3787f6Schristos        line = NormalizeLine(line)
1470*2b3787f6Schristos
1471*2b3787f6Schristos        if not line:
1472*2b3787f6Schristos            continue
1473*2b3787f6Schristos
1474*2b3787f6Schristos        if not got_struct:
1475*2b3787f6Schristos            if re.match(r'#include ["<].*[>"]', line):
1476*2b3787f6Schristos                cppdirect.append(line)
1477*2b3787f6Schristos                continue
1478*2b3787f6Schristos
1479*2b3787f6Schristos            if re.match(r'^#(if( |def)|endif)', line):
1480*2b3787f6Schristos                cppdirect.append(line)
1481*2b3787f6Schristos                continue
1482*2b3787f6Schristos
1483*2b3787f6Schristos            if re.match(r'^#define', line):
1484*2b3787f6Schristos                headerdirect.append(line)
1485*2b3787f6Schristos                continue
1486*2b3787f6Schristos
1487*2b3787f6Schristos            if not structdef.match(line):
1488*2b3787f6Schristos                raise RpcGenError('Missing struct on line %d: %s'
1489*2b3787f6Schristos                                  % (line_count, line))
1490*2b3787f6Schristos            else:
1491*2b3787f6Schristos                got_struct = 1
1492*2b3787f6Schristos                data += line
1493*2b3787f6Schristos            continue
1494*2b3787f6Schristos
1495*2b3787f6Schristos        # We are inside the struct
1496*2b3787f6Schristos        tokens = line.split('}')
1497*2b3787f6Schristos        if len(tokens) == 1:
1498*2b3787f6Schristos            data += ' ' + line
1499*2b3787f6Schristos            continue
1500*2b3787f6Schristos
1501*2b3787f6Schristos        if len(tokens[1]):
1502*2b3787f6Schristos            raise RpcGenError('Trailing garbage after struct on line %d'
1503*2b3787f6Schristos                              % line_count)
1504*2b3787f6Schristos
1505*2b3787f6Schristos        # We found the end of the struct
1506*2b3787f6Schristos        data += ' %s}' % tokens[0]
1507*2b3787f6Schristos        break
1508*2b3787f6Schristos
1509*2b3787f6Schristos    # Remove any comments, that might be in there
1510*2b3787f6Schristos    data = re.sub(r'/\*.*\*/', '', data)
1511*2b3787f6Schristos
1512*2b3787f6Schristos    return data
1513*2b3787f6Schristos
1514*2b3787f6Schristos
1515*2b3787f6Schristosdef Parse(factory, file):
1516*2b3787f6Schristos    """
1517*2b3787f6Schristos    Parses the input file and returns C code and corresponding header file.
1518*2b3787f6Schristos    """
1519*2b3787f6Schristos
1520*2b3787f6Schristos    entities = []
1521*2b3787f6Schristos
1522*2b3787f6Schristos    while 1:
1523*2b3787f6Schristos        # Just gets the whole struct nicely formatted
1524*2b3787f6Schristos        data = GetNextStruct(file)
1525*2b3787f6Schristos
1526*2b3787f6Schristos        if not data:
1527*2b3787f6Schristos            break
1528*2b3787f6Schristos
1529*2b3787f6Schristos        entities.extend(ProcessStruct(factory, data))
1530*2b3787f6Schristos
1531*2b3787f6Schristos    return entities
1532*2b3787f6Schristos
1533*2b3787f6Schristosclass CCodeGenerator:
1534*2b3787f6Schristos    def __init__(self):
1535*2b3787f6Schristos        pass
1536*2b3787f6Schristos
1537*2b3787f6Schristos    def GuardName(self, name):
1538*2b3787f6Schristos        # Use the complete provided path to the input file, with all
1539*2b3787f6Schristos        # non-identifier characters replaced with underscores, to
1540*2b3787f6Schristos        # reduce the chance of a collision between guard macros.
1541*2b3787f6Schristos        return 'EVENT_RPCOUT_' + nonident.sub('_', name).upper() + '_'
1542*2b3787f6Schristos
1543*2b3787f6Schristos    def HeaderPreamble(self, name):
1544*2b3787f6Schristos        guard = self.GuardName(name)
1545*2b3787f6Schristos        pre = (
1546*2b3787f6Schristos            '/*\n'
1547*2b3787f6Schristos            ' * Automatically generated from %s\n'
1548*2b3787f6Schristos            ' */\n\n'
1549*2b3787f6Schristos            '#ifndef %s\n'
1550*2b3787f6Schristos            '#define %s\n\n' ) % (
1551*2b3787f6Schristos            name, guard, guard)
1552*2b3787f6Schristos
1553*2b3787f6Schristos        for statement in headerdirect:
1554*2b3787f6Schristos            pre += '%s\n' % statement
1555*2b3787f6Schristos        if headerdirect:
1556*2b3787f6Schristos            pre += '\n'
1557*2b3787f6Schristos
1558*2b3787f6Schristos        pre += (
1559*2b3787f6Schristos            '#include <event2/util.h> /* for ev_uint*_t */\n'
1560*2b3787f6Schristos            '#include <event2/rpc.h>\n'
1561*2b3787f6Schristos        )
1562*2b3787f6Schristos
1563*2b3787f6Schristos        return pre
1564*2b3787f6Schristos
1565*2b3787f6Schristos    def HeaderPostamble(self, name):
1566*2b3787f6Schristos        guard = self.GuardName(name)
1567*2b3787f6Schristos        return '#endif  /* %s */' % guard
1568*2b3787f6Schristos
1569*2b3787f6Schristos    def BodyPreamble(self, name, header_file):
1570*2b3787f6Schristos        global _NAME
1571*2b3787f6Schristos        global _VERSION
1572*2b3787f6Schristos
1573*2b3787f6Schristos        slash = header_file.rfind('/')
1574*2b3787f6Schristos        if slash != -1:
1575*2b3787f6Schristos            header_file = header_file[slash+1:]
1576*2b3787f6Schristos
1577*2b3787f6Schristos        pre = ( '/*\n'
1578*2b3787f6Schristos                ' * Automatically generated from %s\n'
1579*2b3787f6Schristos                ' * by %s/%s.  DO NOT EDIT THIS FILE.\n'
1580*2b3787f6Schristos                ' */\n\n' ) % (name, _NAME, _VERSION)
1581*2b3787f6Schristos        pre += ( '#include <stdlib.h>\n'
1582*2b3787f6Schristos                 '#include <string.h>\n'
1583*2b3787f6Schristos                 '#include <assert.h>\n'
1584*2b3787f6Schristos                 '#include <event2/event-config.h>\n'
1585*2b3787f6Schristos                 '#include <event2/event.h>\n'
1586*2b3787f6Schristos                 '#include <event2/buffer.h>\n'
1587*2b3787f6Schristos                 '#include <event2/tag.h>\n\n'
1588*2b3787f6Schristos                 '#ifdef EVENT____func__\n'
1589*2b3787f6Schristos                 '#define __func__ EVENT____func__\n'
1590*2b3787f6Schristos                 '#endif\n\n'
1591*2b3787f6Schristos                 )
1592*2b3787f6Schristos
1593*2b3787f6Schristos        for statement in cppdirect:
1594*2b3787f6Schristos            pre += '%s\n' % statement
1595*2b3787f6Schristos
1596*2b3787f6Schristos        pre += '\n#include "%s"\n\n' % header_file
1597*2b3787f6Schristos
1598*2b3787f6Schristos        pre += 'void event_warn(const char *fmt, ...);\n'
1599*2b3787f6Schristos        pre += 'void event_warnx(const char *fmt, ...);\n\n'
1600*2b3787f6Schristos
1601*2b3787f6Schristos        return pre
1602*2b3787f6Schristos
1603*2b3787f6Schristos    def HeaderFilename(self, filename):
1604*2b3787f6Schristos        return '.'.join(filename.split('.')[:-1]) + '.h'
1605*2b3787f6Schristos
1606*2b3787f6Schristos    def CodeFilename(self, filename):
1607*2b3787f6Schristos        return '.'.join(filename.split('.')[:-1]) + '.gen.c'
1608*2b3787f6Schristos
1609*2b3787f6Schristos    def Struct(self, name):
1610*2b3787f6Schristos        return StructCCode(name)
1611*2b3787f6Schristos
1612*2b3787f6Schristos    def EntryBytes(self, entry_type, name, tag, fixed_length):
1613*2b3787f6Schristos        return EntryBytes(entry_type, name, tag, fixed_length)
1614*2b3787f6Schristos
1615*2b3787f6Schristos    def EntryVarBytes(self, entry_type, name, tag):
1616*2b3787f6Schristos        return EntryVarBytes(entry_type, name, tag)
1617*2b3787f6Schristos
1618*2b3787f6Schristos    def EntryInt(self, entry_type, name, tag, bits=32):
1619*2b3787f6Schristos        return EntryInt(entry_type, name, tag, bits)
1620*2b3787f6Schristos
1621*2b3787f6Schristos    def EntryString(self, entry_type, name, tag):
1622*2b3787f6Schristos        return EntryString(entry_type, name, tag)
1623*2b3787f6Schristos
1624*2b3787f6Schristos    def EntryStruct(self, entry_type, name, tag, struct_name):
1625*2b3787f6Schristos        return EntryStruct(entry_type, name, tag, struct_name)
1626*2b3787f6Schristos
1627*2b3787f6Schristos    def EntryArray(self, entry):
1628*2b3787f6Schristos        return EntryArray(entry)
1629*2b3787f6Schristos
1630*2b3787f6Schristosclass Usage(RpcGenError):
1631*2b3787f6Schristos    def __init__(self, argv0):
1632*2b3787f6Schristos        RpcGenError.__init__("usage: %s input.rpc [[output.h] output.c]"
1633*2b3787f6Schristos                             % argv0)
1634*2b3787f6Schristos
1635*2b3787f6Schristosclass CommandLine:
1636*2b3787f6Schristos    def __init__(self, argv):
1637*2b3787f6Schristos        """Initialize a command-line to launch event_rpcgen, as if
1638*2b3787f6Schristos           from a command-line with CommandLine(sys.argv).  If you're
1639*2b3787f6Schristos           calling this directly, remember to provide a dummy value
1640*2b3787f6Schristos           for sys.argv[0]
1641*2b3787f6Schristos        """
1642*2b3787f6Schristos        self.filename = None
1643*2b3787f6Schristos        self.header_file = None
1644*2b3787f6Schristos        self.impl_file = None
1645*2b3787f6Schristos        self.factory = CCodeGenerator()
1646*2b3787f6Schristos
1647*2b3787f6Schristos        if len(argv) >= 2 and argv[1] == '--quiet':
1648*2b3787f6Schristos            global QUIETLY
1649*2b3787f6Schristos            QUIETLY = 1
1650*2b3787f6Schristos            del argv[1]
1651*2b3787f6Schristos
1652*2b3787f6Schristos        if len(argv) < 2 or len(argv) > 4:
1653*2b3787f6Schristos            raise Usage(argv[0])
1654*2b3787f6Schristos
1655*2b3787f6Schristos        self.filename = argv[1].replace('\\', '/')
1656*2b3787f6Schristos        if len(argv) == 3:
1657*2b3787f6Schristos            self.impl_file = argv[2].replace('\\', '/')
1658*2b3787f6Schristos        if len(argv) == 4:
1659*2b3787f6Schristos            self.header_file = argv[2].replace('\\', '/')
1660*2b3787f6Schristos            self.impl_file = argv[3].replace('\\', '/')
1661*2b3787f6Schristos
1662*2b3787f6Schristos        if not self.filename:
1663*2b3787f6Schristos            raise Usage(argv[0])
1664*2b3787f6Schristos
1665*2b3787f6Schristos        if not self.impl_file:
1666*2b3787f6Schristos            self.impl_file = self.factory.CodeFilename(self.filename)
1667*2b3787f6Schristos
1668*2b3787f6Schristos        if not self.header_file:
1669*2b3787f6Schristos            self.header_file = self.factory.HeaderFilename(self.impl_file)
1670*2b3787f6Schristos
1671*2b3787f6Schristos        if not self.impl_file.endswith('.c'):
1672*2b3787f6Schristos            raise RpcGenError("can only generate C implementation files")
1673*2b3787f6Schristos        if not self.header_file.endswith('.h'):
1674*2b3787f6Schristos            raise RpcGenError("can only generate C header files")
1675*2b3787f6Schristos
1676*2b3787f6Schristos    def run(self):
1677*2b3787f6Schristos        filename = self.filename
1678*2b3787f6Schristos        header_file = self.header_file
1679*2b3787f6Schristos        impl_file = self.impl_file
1680*2b3787f6Schristos        factory = self.factory
1681*2b3787f6Schristos
1682*2b3787f6Schristos        declare('Reading \"%s\"' % filename)
1683*2b3787f6Schristos
1684*2b3787f6Schristos        fp = open(filename, 'r')
1685*2b3787f6Schristos        entities = Parse(factory, fp)
1686*2b3787f6Schristos        fp.close()
1687*2b3787f6Schristos
1688*2b3787f6Schristos        declare('... creating "%s"' % header_file)
1689*2b3787f6Schristos        header_fp = open(header_file, 'w')
1690*2b3787f6Schristos        print >>header_fp, factory.HeaderPreamble(filename)
1691*2b3787f6Schristos
1692*2b3787f6Schristos        # Create forward declarations: allows other structs to reference
1693*2b3787f6Schristos        # each other
1694*2b3787f6Schristos        for entry in entities:
1695*2b3787f6Schristos            entry.PrintForwardDeclaration(header_fp)
1696*2b3787f6Schristos        print >>header_fp, ''
1697*2b3787f6Schristos
1698*2b3787f6Schristos        for entry in entities:
1699*2b3787f6Schristos            entry.PrintTags(header_fp)
1700*2b3787f6Schristos            entry.PrintDeclaration(header_fp)
1701*2b3787f6Schristos        print >>header_fp, factory.HeaderPostamble(filename)
1702*2b3787f6Schristos        header_fp.close()
1703*2b3787f6Schristos
1704*2b3787f6Schristos        declare('... creating "%s"' % impl_file)
1705*2b3787f6Schristos        impl_fp = open(impl_file, 'w')
1706*2b3787f6Schristos        print >>impl_fp, factory.BodyPreamble(filename, header_file)
1707*2b3787f6Schristos        for entry in entities:
1708*2b3787f6Schristos            entry.PrintCode(impl_fp)
1709*2b3787f6Schristos        impl_fp.close()
1710*2b3787f6Schristos
1711*2b3787f6Schristosif __name__ == '__main__':
1712*2b3787f6Schristos    try:
1713*2b3787f6Schristos        CommandLine(sys.argv).run()
1714*2b3787f6Schristos        sys.exit(0)
1715*2b3787f6Schristos
1716*2b3787f6Schristos    except RpcGenError, e:
1717*2b3787f6Schristos        print >>sys.stderr, e
1718*2b3787f6Schristos        sys.exit(1)
1719*2b3787f6Schristos
1720*2b3787f6Schristos    except EnvironmentError, e:
1721*2b3787f6Schristos        if e.filename and e.strerror:
1722*2b3787f6Schristos            print >>sys.stderr, "%s: %s" % (e.filename, e.strerror)
1723*2b3787f6Schristos            sys.exit(1)
1724*2b3787f6Schristos        elif e.strerror:
1725*2b3787f6Schristos            print >> sys.stderr, e.strerror
1726*2b3787f6Schristos            sys.exit(1)
1727*2b3787f6Schristos        else:
1728*2b3787f6Schristos            raise
1729