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