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