| #!/usr/bin/env python | 
 | # | 
 | # Copyright (c) 2005 Niels Provos <provos@citi.umich.edu> | 
 | # All rights reserved. | 
 | # | 
 | # Generates marshaling code based on libevent. | 
 |  | 
 | import sys | 
 | import re | 
 |  | 
 | # | 
 | _NAME = "event_rpcgen.py" | 
 | _VERSION = "0.1" | 
 | _STRUCT_RE = '[a-z][a-z_0-9]*' | 
 |  | 
 | # Globals | 
 | line_count = 0 | 
 |  | 
 | white = re.compile(r'^\s+') | 
 | cppcomment = re.compile(r'\/\/.*$') | 
 | headerdirect = [] | 
 | cppdirect = [] | 
 |  | 
 | # Holds everything that makes a struct | 
 | class Struct: | 
 |     def __init__(self, name): | 
 |         self._name = name | 
 |         self._entries = [] | 
 |         self._tags = {} | 
 |         print >>sys.stderr, '  Created struct: %s' % name | 
 |  | 
 |     def AddEntry(self, entry): | 
 |         if self._tags.has_key(entry.Tag()): | 
 |             print >>sys.stderr, ( 'Entry "%s" duplicates tag number ' | 
 |                                   '%d from "%s" around line %d' ) % ( | 
 |                 entry.Name(), entry.Tag(), | 
 |                 self._tags[entry.Tag()], line_count) | 
 |             sys.exit(1) | 
 |         self._entries.append(entry) | 
 |         self._tags[entry.Tag()] = entry.Name() | 
 |         print >>sys.stderr, '    Added entry: %s' % entry.Name() | 
 |  | 
 |     def Name(self): | 
 |         return self._name | 
 |  | 
 |     def EntryTagName(self, entry): | 
 |         """Creates the name inside an enumeration for distinguishing data | 
 |         types.""" | 
 |         name = "%s_%s" % (self._name, entry.Name()) | 
 |         return name.upper() | 
 |  | 
 |     def PrintIdented(self, file, ident, code): | 
 |         """Takes an array, add indentation to each entry and prints it.""" | 
 |         for entry in code: | 
 |             print >>file, '%s%s' % (ident, entry) | 
 |  | 
 |     def PrintTags(self, file): | 
 |         """Prints the tag definitions for a structure.""" | 
 |         print >>file, '/* Tag definition for %s */' % self._name | 
 |         print >>file, 'enum %s_ {' % self._name.lower() | 
 |         for entry in self._entries: | 
 |             print >>file, '  %s=%d,' % (self.EntryTagName(entry), | 
 |                                         entry.Tag()) | 
 |         print >>file, '  %s_MAX_TAGS' % (self._name.upper()) | 
 |         print >>file, '};\n' | 
 |  | 
 |     def PrintForwardDeclaration(self, file): | 
 |         print >>file, 'struct %s;' % self._name | 
 |  | 
 |     def PrintDeclaration(self, file): | 
 |         print >>file, '/* Structure declaration for %s */' % self._name | 
 |         print >>file, 'struct %s_access_ {' % self._name | 
 |         for entry in self._entries: | 
 |             dcl = entry.AssignDeclaration('(*%s_assign)' % entry.Name()) | 
 |             dcl.extend( | 
 |                 entry.GetDeclaration('(*%s_get)' % entry.Name())) | 
 |             if entry.Array(): | 
 |                 dcl.extend( | 
 |                     entry.AddDeclaration('(*%s_add)' % entry.Name())) | 
 |             self.PrintIdented(file, '  ', dcl) | 
 |         print >>file, '};\n' | 
 |  | 
 |         print >>file, 'struct %s {' % self._name | 
 |         print >>file, '  struct %s_access_ *base;\n' % self._name | 
 |         for entry in self._entries: | 
 |             dcl = entry.Declaration() | 
 |             self.PrintIdented(file, '  ', dcl) | 
 |         print >>file, '' | 
 |         for entry in self._entries: | 
 |             print >>file, '  ev_uint8_t %s_set;' % entry.Name() | 
 |         print >>file, '};\n' | 
 |  | 
 |         print >>file, \ | 
 | """struct %(name)s *%(name)s_new(void); | 
 | void %(name)s_free(struct %(name)s *); | 
 | void %(name)s_clear(struct %(name)s *); | 
 | void %(name)s_marshal(struct evbuffer *, const struct %(name)s *); | 
 | int %(name)s_unmarshal(struct %(name)s *, struct evbuffer *); | 
 | int %(name)s_complete(struct %(name)s *); | 
 | void evtag_marshal_%(name)s(struct evbuffer *, ev_uint32_t,  | 
 |     const struct %(name)s *); | 
 | int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t, | 
 |     struct %(name)s *);""" % { 'name' : self._name } | 
 |  | 
 |  | 
 |         # Write a setting function of every variable | 
 |         for entry in self._entries: | 
 |             self.PrintIdented(file, '', entry.AssignDeclaration( | 
 |                 entry.AssignFuncName())) | 
 |             self.PrintIdented(file, '', entry.GetDeclaration( | 
 |                 entry.GetFuncName())) | 
 |             if entry.Array(): | 
 |                 self.PrintIdented(file, '', entry.AddDeclaration( | 
 |                     entry.AddFuncName())) | 
 |  | 
 |         print >>file, '/* --- %s done --- */\n' % self._name | 
 |  | 
 |     def PrintCode(self, file): | 
 |         print >>file, ('/*\n' | 
 |                        ' * Implementation of %s\n' | 
 |                        ' */\n') % self._name | 
 |  | 
 |         print >>file, \ | 
 |               'static struct %(name)s_access_ __%(name)s_base = {' % \ | 
 |               { 'name' : self._name } | 
 |         for entry in self._entries: | 
 |             self.PrintIdented(file, '  ', entry.CodeBase()) | 
 |         print >>file, '};\n' | 
 |  | 
 |         # Creation | 
 |         print >>file, ( | 
 |             'struct %(name)s *\n' | 
 |             '%(name)s_new(void)\n' | 
 |             '{\n' | 
 |             '  struct %(name)s *tmp;\n' | 
 |             '  if ((tmp = malloc(sizeof(struct %(name)s))) == NULL) {\n' | 
 |             '    event_warn("%%s: malloc", __func__);\n' | 
 |             '    return (NULL);\n' | 
 |             '  }\n' | 
 |             '  tmp->base = &__%(name)s_base;\n') % { 'name' : self._name } | 
 |  | 
 |         for entry in self._entries: | 
 |             self.PrintIdented(file, '  ', entry.CodeNew('tmp')) | 
 |             print >>file, '  tmp->%s_set = 0;\n' % entry.Name() | 
 |  | 
 |         print >>file, ( | 
 |             '  return (tmp);\n' | 
 |             '}\n') | 
 |  | 
 |         # Adding | 
 |         for entry in self._entries: | 
 |             if entry.Array(): | 
 |                 self.PrintIdented(file, '', entry.CodeAdd()) | 
 |             print >>file, '' | 
 |              | 
 |         # Assigning | 
 |         for entry in self._entries: | 
 |             self.PrintIdented(file, '', entry.CodeAssign()) | 
 |             print >>file, '' | 
 |  | 
 |         # Getting | 
 |         for entry in self._entries: | 
 |             self.PrintIdented(file, '', entry.CodeGet()) | 
 |             print >>file, '' | 
 |              | 
 |         # Clearing | 
 |         print >>file, ( 'void\n' | 
 |                         '%(name)s_clear(struct %(name)s *tmp)\n' | 
 |                         '{' | 
 |                         ) % { 'name' : self._name } | 
 |         for entry in self._entries: | 
 |             self.PrintIdented(file, '  ', entry.CodeClear('tmp')) | 
 |  | 
 |         print >>file, '}\n' | 
 |  | 
 |         # Freeing | 
 |         print >>file, ( 'void\n' | 
 |                         '%(name)s_free(struct %(name)s *tmp)\n' | 
 |                         '{' | 
 |                         ) % { 'name' : self._name } | 
 |          | 
 |         for entry in self._entries: | 
 |             self.PrintIdented(file, '  ', entry.CodeFree('tmp')) | 
 |  | 
 |         print >>file, ('  free(tmp);\n' | 
 |                        '}\n') | 
 |  | 
 |         # Marshaling | 
 |         print >>file, ('void\n' | 
 |                        '%(name)s_marshal(struct evbuffer *evbuf, ' | 
 |                        'const struct %(name)s *tmp)' | 
 |                        '{') % { 'name' : self._name } | 
 |         for entry in self._entries: | 
 |             indent = '  ' | 
 |             # Optional entries do not have to be set | 
 |             if entry.Optional(): | 
 |                 indent += '  ' | 
 |                 print >>file, '  if (tmp->%s_set) {' % entry.Name() | 
 |             self.PrintIdented( | 
 |                 file, indent, | 
 |                 entry.CodeMarshal('evbuf', self.EntryTagName(entry), 'tmp')) | 
 |             if entry.Optional(): | 
 |                 print >>file, '  }' | 
 |  | 
 |         print >>file, '}\n' | 
 |                         | 
 |         # Unmarshaling | 
 |         print >>file, ('int\n' | 
 |                        '%(name)s_unmarshal(struct %(name)s *tmp, ' | 
 |                        ' struct evbuffer *evbuf)\n' | 
 |                        '{\n' | 
 |                        '  ev_uint32_t tag;\n' | 
 |                        '  while (EVBUFFER_LENGTH(evbuf) > 0) {\n' | 
 |                        '    if (evtag_peek(evbuf, &tag) == -1)\n' | 
 |                        '      return (-1);\n' | 
 |                        '    switch (tag) {\n' | 
 |                        ) % { 'name' : self._name } | 
 |         for entry in self._entries: | 
 |             print >>file, '      case %s:\n' % self.EntryTagName(entry) | 
 |             if not entry.Array(): | 
 |                 print >>file, ( | 
 |                     '        if (tmp->%s_set)\n' | 
 |                     '          return (-1);' | 
 |                     ) % (entry.Name()) | 
 |  | 
 |             self.PrintIdented( | 
 |                 file, '        ', | 
 |                 entry.CodeUnmarshal('evbuf', | 
 |                                     self.EntryTagName(entry), 'tmp')) | 
 |  | 
 |             print >>file, ( '        tmp->%s_set = 1;\n' % entry.Name() + | 
 |                             '        break;\n' ) | 
 |         print >>file, ( '      default:\n' | 
 |                         '        return -1;\n' | 
 |                         '    }\n' | 
 |                         '  }\n' ) | 
 |         # Check if it was decoded completely | 
 |         print >>file, ( '  if (%(name)s_complete(tmp) == -1)\n' | 
 |                         '    return (-1);' | 
 |                         ) % { 'name' : self._name } | 
 |  | 
 |         # Successfully decoded | 
 |         print >>file, ( '  return (0);\n' | 
 |                         '}\n') | 
 |  | 
 |         # Checking if a structure has all the required data | 
 |         print >>file, ( | 
 |             'int\n' | 
 |             '%(name)s_complete(struct %(name)s *msg)\n' | 
 |             '{' ) % { 'name' : self._name } | 
 |         for entry in self._entries: | 
 |             self.PrintIdented( | 
 |                 file, '  ', | 
 |                 entry.CodeComplete('msg')) | 
 |         print >>file, ( | 
 |             '  return (0);\n' | 
 |             '}\n' ) | 
 |  | 
 |         # Complete message unmarshaling | 
 |         print >>file, ( | 
 |             'int\n' | 
 |             'evtag_unmarshal_%(name)s(struct evbuffer *evbuf, ' | 
 |             'ev_uint32_t need_tag, struct %(name)s *msg)\n' | 
 |             '{\n' | 
 |             '  ev_uint32_t tag;\n' | 
 |             '  int res = -1;\n' | 
 |             '\n' | 
 |             '  struct evbuffer *tmp = evbuffer_new();\n' | 
 |             '\n' | 
 |             '  if (evtag_unmarshal(evbuf, &tag, tmp) == -1' | 
 |             ' || tag != need_tag)\n' | 
 |             '    goto error;\n' | 
 |             '\n' | 
 |             '  if (%(name)s_unmarshal(msg, tmp) == -1)\n' | 
 |             '    goto error;\n' | 
 |             '\n' | 
 |             '  res = 0;\n' | 
 |             '\n' | 
 |             ' error:\n' | 
 |             '  evbuffer_free(tmp);\n' | 
 |             '  return (res);\n' | 
 |             '}\n' ) % { 'name' : self._name } | 
 |  | 
 |         # Complete message marshaling | 
 |         print >>file, ( | 
 |             'void\n' | 
 |             'evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag, ' | 
 |             'const struct %(name)s *msg)\n' | 
 |             '{\n' | 
 |             '  struct evbuffer *_buf = evbuffer_new();\n' | 
 |             '  assert(_buf != NULL);\n' | 
 |             '  evbuffer_drain(_buf, -1);\n' | 
 |             '  %(name)s_marshal(_buf, msg);\n' | 
 |             '  evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf), ' | 
 |             'EVBUFFER_LENGTH(_buf));\n' | 
 |             '  evbuffer_free(_buf);\n' | 
 |             '}\n' ) % { 'name' : self._name } | 
 |  | 
 | class Entry: | 
 |     def __init__(self, type, name, tag): | 
 |         self._type = type | 
 |         self._name = name | 
 |         self._tag = int(tag) | 
 |         self._ctype = type | 
 |         self._optional = 0 | 
 |         self._can_be_array = 0 | 
 |         self._array = 0 | 
 |         self._line_count = -1 | 
 |         self._struct = None | 
 |         self._refname = None | 
 |  | 
 |     def GetTranslation(self): | 
 |         return { "parent_name" : self._struct.Name(), | 
 |                  "name" : self._name, | 
 |                  "ctype" : self._ctype, | 
 |                  "refname" : self._refname | 
 |                  } | 
 |      | 
 |     def SetStruct(self, struct): | 
 |         self._struct = struct | 
 |  | 
 |     def LineCount(self): | 
 |         assert self._line_count != -1 | 
 |         return self._line_count | 
 |  | 
 |     def SetLineCount(self, number): | 
 |         self._line_count = number | 
 |  | 
 |     def Array(self): | 
 |         return self._array | 
 |  | 
 |     def Optional(self): | 
 |         return self._optional | 
 |  | 
 |     def Tag(self): | 
 |         return self._tag | 
 |  | 
 |     def Name(self): | 
 |         return self._name | 
 |  | 
 |     def Type(self): | 
 |         return self._type | 
 |  | 
 |     def MakeArray(self, yes=1): | 
 |         self._array = yes | 
 |          | 
 |     def MakeOptional(self): | 
 |         self._optional = 1 | 
 |  | 
 |     def GetFuncName(self): | 
 |         return '%s_%s_get' % (self._struct.Name(), self._name) | 
 |      | 
 |     def GetDeclaration(self, funcname): | 
 |         code = [ 'int %s(struct %s *, %s *);' % ( | 
 |             funcname, self._struct.Name(), self._ctype ) ] | 
 |         return code | 
 |  | 
 |     def CodeGet(self): | 
 |         code = ( | 
 |             'int', | 
 |             '%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, ' | 
 |             '%(ctype)s *value)', | 
 |             '{', | 
 |             '  if (msg->%(name)s_set != 1)', | 
 |             '    return (-1);', | 
 |             '  *value = msg->%(name)s_data;', | 
 |             '  return (0);', | 
 |             '}' ) | 
 |         code = '\n'.join(code) | 
 |         code = code % self.GetTranslation() | 
 |         return code.split('\n') | 
 |          | 
 |     def AssignFuncName(self): | 
 |         return '%s_%s_assign' % (self._struct.Name(), self._name) | 
 |      | 
 |     def AddFuncName(self): | 
 |         return '%s_%s_add' % (self._struct.Name(), self._name) | 
 |      | 
 |     def AssignDeclaration(self, funcname): | 
 |         code = [ 'int %s(struct %s *, const %s);' % ( | 
 |             funcname, self._struct.Name(), self._ctype ) ] | 
 |         return code | 
 |  | 
 |     def CodeAssign(self): | 
 |         code = [ 'int', | 
 |                  '%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,' | 
 |                  ' const %(ctype)s value)', | 
 |                  '{', | 
 |                  '  msg->%(name)s_set = 1;', | 
 |                  '  msg->%(name)s_data = value;', | 
 |                  '  return (0);', | 
 |                  '}' ] | 
 |         code = '\n'.join(code) | 
 |         code = code % self.GetTranslation() | 
 |         return code.split('\n') | 
 |  | 
 |     def CodeClear(self, structname): | 
 |         code = [ '%s->%s_set = 0;' % (structname, self.Name()) ] | 
 |  | 
 |         return code | 
 |          | 
 |     def CodeComplete(self, structname): | 
 |         if self.Optional(): | 
 |             return [] | 
 |          | 
 |         code = [ 'if (!%s->%s_set)' % (structname, self.Name()), | 
 |                  '  return (-1);' ] | 
 |  | 
 |         return code | 
 |  | 
 |     def CodeFree(self, name): | 
 |         return [] | 
 |  | 
 |     def CodeBase(self): | 
 |         code = [ | 
 |             '%(parent_name)s_%(name)s_assign,', | 
 |             '%(parent_name)s_%(name)s_get,' | 
 |             ] | 
 |         if self.Array(): | 
 |             code.append('%(parent_name)s_%(name)s_add,') | 
 |  | 
 |         code = '\n'.join(code) | 
 |         code = code % self.GetTranslation() | 
 |         return code.split('\n') | 
 |  | 
 |     def Verify(self): | 
 |         if self.Array() and not self._can_be_array: | 
 |             print >>sys.stderr, ( | 
 |                 'Entry "%s" cannot be created as an array ' | 
 |                 'around line %d' ) % (self._name, self.LineCount()) | 
 |             sys.exit(1) | 
 |         if not self._struct: | 
 |             print >>sys.stderr, ( | 
 |                 'Entry "%s" does not know which struct it belongs to ' | 
 |                 'around line %d' ) % (self._name, self.LineCount()) | 
 |             sys.exit(1) | 
 |         if self._optional and self._array: | 
 |             print >>sys.stderr,  ( 'Entry "%s" has illegal combination of ' | 
 |                                    'optional and array around line %d' ) % ( | 
 |                 self._name, self.LineCount() ) | 
 |             sys.exit(1) | 
 |  | 
 | class EntryBytes(Entry): | 
 |     def __init__(self, type, name, tag, length): | 
 |         # Init base class | 
 |         Entry.__init__(self, type, name, tag) | 
 |  | 
 |         self._length = length | 
 |         self._ctype = 'ev_uint8_t' | 
 |  | 
 |     def GetDeclaration(self, funcname): | 
 |         code = [ 'int %s(struct %s *, %s **);' % ( | 
 |             funcname, self._struct.Name(), self._ctype ) ] | 
 |         return code | 
 |          | 
 |     def AssignDeclaration(self, funcname): | 
 |         code = [ 'int %s(struct %s *, const %s *);' % ( | 
 |             funcname, self._struct.Name(), self._ctype ) ] | 
 |         return code | 
 |          | 
 |     def Declaration(self): | 
 |         dcl  = ['ev_uint8_t %s_data[%s];' % (self._name, self._length)] | 
 |          | 
 |         return dcl | 
 |  | 
 |     def CodeGet(self): | 
 |         name = self._name | 
 |         code = [ 'int', | 
 |                  '%s_%s_get(struct %s *msg, %s **value)' % ( | 
 |             self._struct.Name(), name, | 
 |             self._struct.Name(), self._ctype), | 
 |                  '{', | 
 |                  '  if (msg->%s_set != 1)' % name, | 
 |                  '    return (-1);', | 
 |                  '  *value = msg->%s_data;' % name, | 
 |                  '  return (0);', | 
 |                  '}' ] | 
 |         return code | 
 |          | 
 |     def CodeAssign(self): | 
 |         name = self._name | 
 |         code = [ 'int', | 
 |                  '%s_%s_assign(struct %s *msg, const %s *value)' % ( | 
 |             self._struct.Name(), name, | 
 |             self._struct.Name(), self._ctype), | 
 |                  '{', | 
 |                  '  msg->%s_set = 1;' % name, | 
 |                  '  memcpy(msg->%s_data, value, %s);' % ( | 
 |             name, self._length), | 
 |                  '  return (0);', | 
 |                  '}' ] | 
 |         return code | 
 |          | 
 |     def CodeUnmarshal(self, buf, tag_name, var_name): | 
 |         code = [  'if (evtag_unmarshal_fixed(%s, %s, ' % (buf, tag_name) + | 
 |                   '%s->%s_data, ' % (var_name, self._name) + | 
 |                   'sizeof(%s->%s_data)) == -1) {' % ( | 
 |             var_name, self._name), | 
 |                   '  event_warnx("%%s: failed to unmarshal %s", __func__);' % ( | 
 |             self._name ), | 
 |                   '  return (-1);', | 
 |                   '}' | 
 |                   ] | 
 |         return code | 
 |  | 
 |     def CodeMarshal(self, buf, tag_name, var_name): | 
 |         code = ['evtag_marshal(%s, %s, %s->%s_data, sizeof(%s->%s_data));' % ( | 
 |             buf, tag_name, var_name, self._name, var_name, self._name )] | 
 |         return code | 
 |  | 
 |     def CodeClear(self, structname): | 
 |         code = [ '%s->%s_set = 0;' % (structname, self.Name()), | 
 |                  'memset(%s->%s_data, 0, sizeof(%s->%s_data));' % ( | 
 |             structname, self._name, structname, self._name)] | 
 |  | 
 |         return code | 
 |          | 
 |     def CodeNew(self, name): | 
 |         code  = ['memset(%s->%s_data, 0, sizeof(%s->%s_data));' % ( | 
 |             name, self._name, name, self._name)] | 
 |         return code | 
 |  | 
 |     def Verify(self): | 
 |         if not self._length: | 
 |             print >>sys.stderr, 'Entry "%s" needs a length around line %d' % ( | 
 |                 self._name, self.LineCount() ) | 
 |             sys.exit(1) | 
 |  | 
 |         Entry.Verify(self) | 
 |  | 
 | class EntryInt(Entry): | 
 |     def __init__(self, type, name, tag): | 
 |         # Init base class | 
 |         Entry.__init__(self, type, name, tag) | 
 |  | 
 |         self._ctype = 'ev_uint32_t' | 
 |  | 
 |     def CodeUnmarshal(self, buf, tag_name, var_name): | 
 |         code = ['if (evtag_unmarshal_int(%s, %s, &%s->%s_data) == -1) {' % ( | 
 |             buf, tag_name, var_name, self._name), | 
 |                   '  event_warnx("%%s: failed to unmarshal %s", __func__);' % ( | 
 |             self._name ), | 
 |                 '  return (-1);', | 
 |                 '}' ]  | 
 |         return code | 
 |  | 
 |     def CodeMarshal(self, buf, tag_name, var_name): | 
 |         code = ['evtag_marshal_int(%s, %s, %s->%s_data);' % ( | 
 |             buf, tag_name, var_name, self._name)] | 
 |         return code | 
 |  | 
 |     def Declaration(self): | 
 |         dcl  = ['ev_uint32_t %s_data;' % self._name] | 
 |  | 
 |         return dcl | 
 |  | 
 |     def CodeNew(self, name): | 
 |         code = ['%s->%s_data = 0;' % (name, self._name)] | 
 |         return code | 
 |  | 
 | class EntryString(Entry): | 
 |     def __init__(self, type, name, tag): | 
 |         # Init base class | 
 |         Entry.__init__(self, type, name, tag) | 
 |  | 
 |         self._ctype = 'char *' | 
 |  | 
 |     def CodeAssign(self): | 
 |         name = self._name | 
 |         code = """int | 
 | %(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, | 
 |     const %(ctype)s value) | 
 | { | 
 |   if (msg->%(name)s_data != NULL) | 
 |     free(msg->%(name)s_data); | 
 |   if ((msg->%(name)s_data = strdup(value)) == NULL) | 
 |     return (-1); | 
 |   msg->%(name)s_set = 1; | 
 |   return (0); | 
 | }""" % self.GetTranslation() | 
 |  | 
 |         return code.split('\n') | 
 |          | 
 |     def CodeUnmarshal(self, buf, tag_name, var_name): | 
 |         code = ['if (evtag_unmarshal_string(%s, %s, &%s->%s_data) == -1) {' % ( | 
 |             buf, tag_name, var_name, self._name), | 
 |                 '  event_warnx("%%s: failed to unmarshal %s", __func__);' % ( | 
 |             self._name ), | 
 |                 '  return (-1);', | 
 |                 '}' | 
 |                 ] | 
 |         return code | 
 |  | 
 |     def CodeMarshal(self, buf, tag_name, var_name): | 
 |         code = ['evtag_marshal_string(%s, %s, %s->%s_data);' % ( | 
 |             buf, tag_name, var_name, self._name)] | 
 |         return code | 
 |  | 
 |     def CodeClear(self, structname): | 
 |         code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()), | 
 |                  '  free (%s->%s_data);' % (structname, self.Name()), | 
 |                  '  %s->%s_data = NULL;' % (structname, self.Name()), | 
 |                  '  %s->%s_set = 0;' % (structname, self.Name()), | 
 |                  '}' | 
 |                  ] | 
 |  | 
 |         return code | 
 |          | 
 |     def CodeNew(self, name): | 
 |         code  = ['%s->%s_data = NULL;' % (name, self._name)] | 
 |         return code | 
 |  | 
 |     def CodeFree(self, name): | 
 |         code  = ['if (%s->%s_data != NULL)' % (name, self._name), | 
 |                  '    free (%s->%s_data); ' % (name, self._name)] | 
 |  | 
 |         return code | 
 |  | 
 |     def Declaration(self): | 
 |         dcl  = ['char *%s_data;' % self._name] | 
 |  | 
 |         return dcl | 
 |  | 
 | class EntryStruct(Entry): | 
 |     def __init__(self, type, name, tag, refname): | 
 |         # Init base class | 
 |         Entry.__init__(self, type, name, tag) | 
 |  | 
 |         self._can_be_array = 1 | 
 |         self._refname = refname | 
 |         self._ctype = 'struct %s*' % refname | 
 |  | 
 |     def CodeGet(self): | 
 |         name = self._name | 
 |         code = [ 'int', | 
 |                  '%s_%s_get(struct %s *msg, %s *value)' % ( | 
 |             self._struct.Name(), name, | 
 |             self._struct.Name(), self._ctype), | 
 |                  '{', | 
 |                  '  if (msg->%s_set != 1) {' % name, | 
 |                  '    msg->%s_data = %s_new();' % (name, self._refname), | 
 |                  '    if (msg->%s_data == NULL)' % name, | 
 |                  '      return (-1);', | 
 |                  '    msg->%s_set = 1;' % name, | 
 |                  '  }', | 
 |                  '  *value = msg->%s_data;' % name, | 
 |                  '  return (0);', | 
 |                  '}' ] | 
 |         return code | 
 |          | 
 |     def CodeAssign(self): | 
 |         name = self._name | 
 |         code = """int | 
 | %(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, | 
 |     const %(ctype)s value) | 
 | { | 
 |    struct evbuffer *tmp = NULL; | 
 |    if (msg->%(name)s_set) { | 
 |      %(refname)s_clear(msg->%(name)s_data); | 
 |      msg->%(name)s_set = 0; | 
 |    } else { | 
 |      msg->%(name)s_data = %(refname)s_new(); | 
 |      if (msg->%(name)s_data == NULL) { | 
 |        event_warn("%%s: %(refname)s_new()", __func__); | 
 |        goto error; | 
 |      } | 
 |    } | 
 |    if ((tmp = evbuffer_new()) == NULL) { | 
 |      event_warn("%%s: evbuffer_new()", __func__); | 
 |      goto error; | 
 |    } | 
 |    %(refname)s_marshal(tmp, value); | 
 |    if (%(refname)s_unmarshal(msg->%(name)s_data, tmp) == -1) { | 
 |      event_warnx("%%s: %(refname)s_unmarshal", __func__); | 
 |      goto error; | 
 |    } | 
 |    msg->%(name)s_set = 1; | 
 |    evbuffer_free(tmp); | 
 |    return (0); | 
 |  error: | 
 |    if (tmp != NULL) | 
 |      evbuffer_free(tmp); | 
 |    if (msg->%(name)s_data != NULL) { | 
 |      %(refname)s_free(msg->%(name)s_data); | 
 |      msg->%(name)s_data = NULL; | 
 |    } | 
 |    return (-1); | 
 | }""" % self.GetTranslation() | 
 |         return code.split('\n') | 
 |          | 
 |     def CodeComplete(self, structname): | 
 |         if self.Optional(): | 
 |             code = [ 'if (%s->%s_set && %s_complete(%s->%s_data) == -1)' % ( | 
 |                 structname, self.Name(), | 
 |                 self._refname, structname, self.Name()), | 
 |                      '  return (-1);' ] | 
 |         else: | 
 |             code = [ 'if (%s_complete(%s->%s_data) == -1)' % ( | 
 |                 self._refname, structname, self.Name()), | 
 |                      '  return (-1);' ] | 
 |  | 
 |         return code | 
 |      | 
 |     def CodeUnmarshal(self, buf, tag_name, var_name): | 
 |         code = ['%s->%s_data = %s_new();' % ( | 
 |             var_name, self._name, self._refname), | 
 |                 'if (%s->%s_data == NULL)' % (var_name, self._name), | 
 |                 '  return (-1);', | 
 |                 'if (evtag_unmarshal_%s(%s, %s, %s->%s_data) == -1) {' % ( | 
 |             self._refname, buf, tag_name, var_name, self._name), | 
 |                   '  event_warnx("%%s: failed to unmarshal %s", __func__);' % ( | 
 |             self._name ), | 
 |                 '  return (-1);', | 
 |                 '}' | 
 |                 ] | 
 |         return code | 
 |  | 
 |     def CodeMarshal(self, buf, tag_name, var_name): | 
 |         code = ['evtag_marshal_%s(%s, %s, %s->%s_data);' % ( | 
 |             self._refname, buf, tag_name, var_name, self._name)] | 
 |         return code | 
 |  | 
 |     def CodeClear(self, structname): | 
 |         code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()), | 
 |                  '  %s_free(%s->%s_data);' % ( | 
 |             self._refname, structname, self.Name()), | 
 |                  '  %s->%s_data = NULL;' % (structname, self.Name()), | 
 |                  '  %s->%s_set = 0;' % (structname, self.Name()), | 
 |                  '}' | 
 |                  ] | 
 |  | 
 |         return code | 
 |          | 
 |     def CodeNew(self, name): | 
 |         code  = ['%s->%s_data = NULL;' % (name, self._name)] | 
 |         return code | 
 |  | 
 |     def CodeFree(self, name): | 
 |         code  = ['if (%s->%s_data != NULL)' % (name, self._name), | 
 |                  '    %s_free(%s->%s_data); ' % ( | 
 |             self._refname, name, self._name)] | 
 |  | 
 |         return code | 
 |  | 
 |     def Declaration(self): | 
 |         dcl  = ['%s %s_data;' % (self._ctype, self._name)] | 
 |  | 
 |         return dcl | 
 |  | 
 | class EntryVarBytes(Entry): | 
 |     def __init__(self, type, name, tag): | 
 |         # Init base class | 
 |         Entry.__init__(self, type, name, tag) | 
 |  | 
 |         self._ctype = 'ev_uint8_t *' | 
 |  | 
 |     def GetDeclaration(self, funcname): | 
 |         code = [ 'int %s(struct %s *, %s *, ev_uint32_t *);' % ( | 
 |             funcname, self._struct.Name(), self._ctype ) ] | 
 |         return code | 
 |          | 
 |     def AssignDeclaration(self, funcname): | 
 |         code = [ 'int %s(struct %s *, const %s, ev_uint32_t);' % ( | 
 |             funcname, self._struct.Name(), self._ctype ) ] | 
 |         return code | 
 |          | 
 |     def CodeAssign(self): | 
 |         name = self._name | 
 |         code = [ 'int', | 
 |                  '%s_%s_assign(struct %s *msg, ' | 
 |                  'const %s value, ev_uint32_t len)' % ( | 
 |             self._struct.Name(), name, | 
 |             self._struct.Name(), self._ctype), | 
 |                  '{', | 
 |                  '  if (msg->%s_data != NULL)' % name, | 
 |                  '    free (msg->%s_data);' % name, | 
 |                  '  msg->%s_data = malloc(len);' % name, | 
 |                  '  if (msg->%s_data == NULL)' % name, | 
 |                  '    return (-1);', | 
 |                  '  msg->%s_set = 1;' % name, | 
 |                  '  msg->%s_length = len;' % name, | 
 |                  '  memcpy(msg->%s_data, value, len);' % name, | 
 |                  '  return (0);', | 
 |                  '}' ] | 
 |         return code | 
 |          | 
 |     def CodeGet(self): | 
 |         name = self._name | 
 |         code = [ 'int', | 
 |                  '%s_%s_get(struct %s *msg, %s *value, ev_uint32_t *plen)' % ( | 
 |             self._struct.Name(), name, | 
 |             self._struct.Name(), self._ctype), | 
 |                  '{', | 
 |                  '  if (msg->%s_set != 1)' % name, | 
 |                  '    return (-1);', | 
 |                  '  *value = msg->%s_data;' % name, | 
 |                  '  *plen = msg->%s_length;' % name, | 
 |                  '  return (0);', | 
 |                  '}' ] | 
 |         return code | 
 |  | 
 |     def CodeUnmarshal(self, buf, tag_name, var_name): | 
 |         code = ['if (evtag_payload_length(%s, &%s->%s_length) == -1)' % ( | 
 |             buf, var_name, self._name), | 
 |                 '  return (-1);', | 
 |                 # We do not want DoS opportunities | 
 |                 'if (%s->%s_length > EVBUFFER_LENGTH(%s))' % ( | 
 |             var_name, self._name, buf), | 
 |                 '  return (-1);', | 
 |                 'if ((%s->%s_data = malloc(%s->%s_length)) == NULL)' % ( | 
 |             var_name, self._name, var_name, self._name), | 
 |                 '  return (-1);', | 
 |                 'if (evtag_unmarshal_fixed(%s, %s, %s->%s_data, ' | 
 |                 '%s->%s_length) == -1) {' % ( | 
 |             buf, tag_name, var_name, self._name, var_name, self._name), | 
 |                 '  event_warnx("%%s: failed to unmarshal %s", __func__);' % ( | 
 |             self._name ), | 
 |                 '  return (-1);', | 
 |                 '}' | 
 |                 ] | 
 |         return code | 
 |  | 
 |     def CodeMarshal(self, buf, tag_name, var_name): | 
 |         code = ['evtag_marshal(%s, %s, %s->%s_data, %s->%s_length);' % ( | 
 |             buf, tag_name, var_name, self._name, var_name, self._name)] | 
 |         return code | 
 |  | 
 |     def CodeClear(self, structname): | 
 |         code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()), | 
 |                  '  free (%s->%s_data);' % (structname, self.Name()), | 
 |                  '  %s->%s_data = NULL;' % (structname, self.Name()), | 
 |                  '  %s->%s_length = 0;' % (structname, self.Name()), | 
 |                  '  %s->%s_set = 0;' % (structname, self.Name()), | 
 |                  '}' | 
 |                  ] | 
 |  | 
 |         return code | 
 |          | 
 |     def CodeNew(self, name): | 
 |         code  = ['%s->%s_data = NULL;' % (name, self._name), | 
 |                  '%s->%s_length = 0;' % (name, self._name) ] | 
 |         return code | 
 |  | 
 |     def CodeFree(self, name): | 
 |         code  = ['if (%s->%s_data != NULL)' % (name, self._name), | 
 |                  '    free (%s->%s_data); ' % (name, self._name)] | 
 |  | 
 |         return code | 
 |  | 
 |     def Declaration(self): | 
 |         dcl  = ['ev_uint8_t *%s_data;' % self._name, | 
 |                 'ev_uint32_t %s_length;' % self._name] | 
 |  | 
 |         return dcl | 
 |  | 
 | class EntryArray(Entry): | 
 |     def __init__(self, entry): | 
 |         # Init base class | 
 |         Entry.__init__(self, entry._type, entry._name, entry._tag) | 
 |  | 
 |         self._entry = entry | 
 |         self._refname = entry._refname | 
 |         self._ctype = 'struct %s *' % self._refname | 
 |  | 
 |     def GetDeclaration(self, funcname): | 
 |         """Allows direct access to elements of the array.""" | 
 |         translate = self.GetTranslation() | 
 |         translate["funcname"] = funcname | 
 |         code = [ | 
 |             'int %(funcname)s(struct %(parent_name)s *, int, %(ctype)s *);' % | 
 |             translate ] | 
 |         return code | 
 |          | 
 |     def AssignDeclaration(self, funcname): | 
 |         code = [ 'int %s(struct %s *, int, const %s);' % ( | 
 |             funcname, self._struct.Name(), self._ctype ) ] | 
 |         return code | 
 |          | 
 |     def AddDeclaration(self, funcname): | 
 |         code = [ '%s %s(struct %s *);' % ( | 
 |             self._ctype, funcname, self._struct.Name() ) ] | 
 |         return code | 
 |          | 
 |     def CodeGet(self): | 
 |         code = """int | 
 | %(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, int offset, | 
 |     %(ctype)s *value) | 
 | { | 
 |   if (!msg->%(name)s_set || offset < 0 || offset >= msg->%(name)s_length) | 
 |     return (-1); | 
 |   *value = msg->%(name)s_data[offset]; | 
 |   return (0); | 
 | }""" % self.GetTranslation() | 
 |  | 
 |         return code.split('\n') | 
 |          | 
 |     def CodeAssign(self): | 
 |         code = """int | 
 | %(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, int off, | 
 |     const %(ctype)s value) | 
 | { | 
 |   struct evbuffer *tmp = NULL; | 
 |   if (!msg->%(name)s_set || off < 0 || off >= msg->%(name)s_length) | 
 |     return (-1); | 
 |   %(refname)s_clear(msg->%(name)s_data[off]); | 
 |   if ((tmp = evbuffer_new()) == NULL) { | 
 |     event_warn("%%s: evbuffer_new()", __func__); | 
 |     goto error; | 
 |   } | 
 |   %(refname)s_marshal(tmp, value); | 
 |   if (%(refname)s_unmarshal(msg->%(name)s_data[off], tmp) == -1) { | 
 |     event_warnx("%%s: %(refname)s_unmarshal", __func__); | 
 |     goto error; | 
 |   } | 
 |   evbuffer_free(tmp); | 
 |   return (0); | 
 | error: | 
 |   if (tmp != NULL) | 
 |     evbuffer_free(tmp); | 
 |   %(refname)s_clear(msg->%(name)s_data[off]); | 
 |   return (-1); | 
 | }""" % self.GetTranslation() | 
 |  | 
 |         return code.split('\n') | 
 |          | 
 |     def CodeAdd(self): | 
 |         code = \ | 
 | """%(ctype)s | 
 | %(parent_name)s_%(name)s_add(struct %(parent_name)s *msg) | 
 | { | 
 |   if (++msg->%(name)s_length >= msg->%(name)s_num_allocated) { | 
 |     int tobe_allocated = msg->%(name)s_num_allocated; | 
 |     %(ctype)s* new_data = NULL; | 
 |     tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1; | 
 |     new_data = (%(ctype)s*) realloc(msg->%(name)s_data, | 
 |         tobe_allocated * sizeof(%(ctype)s)); | 
 |     if (new_data == NULL) | 
 |       goto error; | 
 |     msg->%(name)s_data = new_data; | 
 |     msg->%(name)s_num_allocated = tobe_allocated; | 
 |   } | 
 |   msg->%(name)s_data[msg->%(name)s_length - 1] = %(refname)s_new(); | 
 |   if (msg->%(name)s_data[msg->%(name)s_length - 1] == NULL) | 
 |     goto error; | 
 |   msg->%(name)s_set = 1; | 
 |   return (msg->%(name)s_data[msg->%(name)s_length - 1]); | 
 | error: | 
 |   --msg->%(name)s_length; | 
 |   return (NULL); | 
 | } | 
 |         """ % self.GetTranslation() | 
 |  | 
 |         return code.split('\n') | 
 |  | 
 |     def CodeComplete(self, structname): | 
 |         code = [] | 
 |         translate = self.GetTranslation() | 
 |  | 
 |         if self.Optional(): | 
 |             code.append( 'if (%(structname)s->%(name)s_set)'  % translate) | 
 |  | 
 |         translate["structname"] = structname | 
 |         tmp = """{ | 
 |   int i; | 
 |   for (i = 0; i < %(structname)s->%(name)s_length; ++i) { | 
 |     if (%(refname)s_complete(%(structname)s->%(name)s_data[i]) == -1) | 
 |       return (-1); | 
 |   } | 
 | }""" % translate | 
 |         code.extend(tmp.split('\n')) | 
 |  | 
 |         return code | 
 |      | 
 |     def CodeUnmarshal(self, buf, tag_name, var_name): | 
 |         translate = self.GetTranslation() | 
 |         translate["var_name"] = var_name | 
 |         translate["buf"] = buf | 
 |         translate["tag_name"] = tag_name | 
 |         code = """if (%(parent_name)s_%(name)s_add(%(var_name)s) == NULL) | 
 |   return (-1); | 
 | if (evtag_unmarshal_%(refname)s(%(buf)s, %(tag_name)s, | 
 |   %(var_name)s->%(name)s_data[%(var_name)s->%(name)s_length - 1]) == -1) { | 
 |   --%(var_name)s->%(name)s_length; | 
 |   event_warnx("%%s: failed to unmarshal %(name)s", __func__); | 
 |   return (-1); | 
 | }""" % translate | 
 |  | 
 |         return code.split('\n') | 
 |  | 
 |     def CodeMarshal(self, buf, tag_name, var_name): | 
 |         code = ['{', | 
 |                 '  int i;', | 
 |                 '  for (i = 0; i < %s->%s_length; ++i) {' % ( | 
 |             var_name, self._name), | 
 |                 '    evtag_marshal_%s(%s, %s, %s->%s_data[i]);' % ( | 
 |             self._refname, buf, tag_name, var_name, self._name), | 
 |                 '  }', | 
 |                 '}' | 
 |                 ] | 
 |         return code | 
 |  | 
 |     def CodeClear(self, structname): | 
 |         code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()), | 
 |                  '  int i;', | 
 |                  '  for (i = 0; i < %s->%s_length; ++i) {' % ( | 
 |             structname, self.Name()), | 
 |                  '    %s_free(%s->%s_data[i]);' % ( | 
 |             self._refname, structname, self.Name()), | 
 |                  '  }', | 
 |                  '  free(%s->%s_data);' % (structname, self.Name()), | 
 |                  '  %s->%s_data = NULL;' % (structname, self.Name()), | 
 |                  '  %s->%s_set = 0;' % (structname, self.Name()), | 
 |                  '  %s->%s_length = 0;' % (structname, self.Name()), | 
 |                  '  %s->%s_num_allocated = 0;' % (structname, self.Name()), | 
 |                  '}' | 
 |                  ] | 
 |  | 
 |         return code | 
 |          | 
 |     def CodeNew(self, name): | 
 |         code  = ['%s->%s_data = NULL;' % (name, self._name), | 
 |                  '%s->%s_length = 0;' % (name, self._name), | 
 |                  '%s->%s_num_allocated = 0;' % (name, self._name)] | 
 |         return code | 
 |  | 
 |     def CodeFree(self, name): | 
 |         code  = ['if (%s->%s_data != NULL) {' % (name, self._name), | 
 |                  '  int i;', | 
 |                  '  for (i = 0; i < %s->%s_length; ++i) {' % ( | 
 |             name, self._name), | 
 |                  '    %s_free(%s->%s_data[i]); ' % ( | 
 |             self._refname, name, self._name), | 
 |                  '    %s->%s_data[i] = NULL;' % (name, self._name), | 
 |                  '  }', | 
 |                  '  free(%s->%s_data);' % (name, self._name), | 
 |                  '  %s->%s_data = NULL;' % (name, self._name), | 
 |                  '  %s->%s_length = 0;' % (name, self._name), | 
 |                  '  %s->%s_num_allocated = 0;' % (name, self._name), | 
 |                  '}' | 
 |                  ] | 
 |  | 
 |         return code | 
 |  | 
 |     def Declaration(self): | 
 |         dcl  = ['struct %s **%s_data;' % (self._refname, self._name), | 
 |                 'int %s_length;' % self._name, | 
 |                 'int %s_num_allocated;' % self._name ] | 
 |  | 
 |         return dcl | 
 |  | 
 | def NormalizeLine(line): | 
 |     global white | 
 |     global cppcomment | 
 |      | 
 |     line = cppcomment.sub('', line) | 
 |     line = line.strip() | 
 |     line = white.sub(' ', line) | 
 |  | 
 |     return line | 
 |  | 
 | def ProcessOneEntry(newstruct, entry): | 
 |     optional = 0 | 
 |     array = 0 | 
 |     entry_type = '' | 
 |     name = '' | 
 |     tag = '' | 
 |     tag_set = None | 
 |     separator = '' | 
 |     fixed_length = '' | 
 |  | 
 |     tokens = entry.split(' ') | 
 |     while tokens: | 
 |         token = tokens[0] | 
 |         tokens = tokens[1:] | 
 |  | 
 |         if not entry_type: | 
 |             if not optional and token == 'optional': | 
 |                 optional = 1 | 
 |                 continue | 
 |  | 
 |             if not array and token == 'array': | 
 |                 array = 1 | 
 |                 continue | 
 |  | 
 |         if not entry_type: | 
 |             entry_type = token | 
 |             continue | 
 |  | 
 |         if not name: | 
 |             res = re.match(r'^([^\[\]]+)(\[.*\])?$', token) | 
 |             if not res: | 
 |                 print >>sys.stderr, 'Cannot parse name: \"%s\" around %d' % ( | 
 |                     entry, line_count) | 
 |                 sys.exit(1) | 
 |             name = res.group(1) | 
 |             fixed_length = res.group(2) | 
 |             if fixed_length: | 
 |                 fixed_length = fixed_length[1:-1] | 
 |             continue | 
 |  | 
 |         if not separator: | 
 |             separator = token | 
 |             if separator != '=': | 
 |                 print >>sys.stderr, 'Expected "=" after name \"%s\" got %s' % ( | 
 |                     name, token) | 
 |                 sys.exit(1) | 
 |             continue | 
 |  | 
 |         if not tag_set: | 
 |             tag_set = 1 | 
 |             if not re.match(r'^(0x)?[0-9]+$', token): | 
 |                 print >>sys.stderr, 'Expected tag number: \"%s\"' % entry | 
 |                 sys.exit(1) | 
 |             tag = int(token, 0) | 
 |             continue | 
 |  | 
 |         print >>sys.stderr, 'Cannot parse \"%s\"' % entry | 
 |         sys.exit(1) | 
 |  | 
 |     if not tag_set: | 
 |         print >>sys.stderr, 'Need tag number: \"%s\"' % entry | 
 |         sys.exit(1) | 
 |  | 
 |     # Create the right entry | 
 |     if entry_type == 'bytes': | 
 |         if fixed_length: | 
 |             newentry = EntryBytes(entry_type, name, tag, fixed_length) | 
 |         else: | 
 |             newentry = EntryVarBytes(entry_type, name, tag) | 
 |     elif entry_type == 'int' and not fixed_length: | 
 |         newentry = EntryInt(entry_type, name, tag) | 
 |     elif entry_type == 'string' and not fixed_length: | 
 |         newentry = EntryString(entry_type, name, tag) | 
 |     else: | 
 |         res = re.match(r'^struct\[(%s)\]$' % _STRUCT_RE, | 
 |                        entry_type, re.IGNORECASE) | 
 |         if res: | 
 |             # References another struct defined in our file | 
 |             newentry = EntryStruct(entry_type, name, tag, res.group(1)) | 
 |         else: | 
 |             print >>sys.stderr, 'Bad type: "%s" in "%s"' % (entry_type, entry) | 
 |             sys.exit(1) | 
 |  | 
 |     structs = [] | 
 |          | 
 |     if optional: | 
 |         newentry.MakeOptional() | 
 |     if array: | 
 |         newentry.MakeArray() | 
 |  | 
 |     newentry.SetStruct(newstruct) | 
 |     newentry.SetLineCount(line_count) | 
 |     newentry.Verify() | 
 |  | 
 |     if array: | 
 |         # We need to encapsulate this entry into a struct | 
 |         newname = newentry.Name()+ '_array' | 
 |  | 
 |         # Now borgify the new entry. | 
 |         newentry = EntryArray(newentry) | 
 |         newentry.SetStruct(newstruct) | 
 |         newentry.SetLineCount(line_count) | 
 |         newentry.MakeArray() | 
 |  | 
 |     newstruct.AddEntry(newentry) | 
 |  | 
 |     return structs | 
 |  | 
 | def ProcessStruct(data): | 
 |     tokens = data.split(' ') | 
 |  | 
 |     # First three tokens are: 'struct' 'name' '{' | 
 |     newstruct = Struct(tokens[1]) | 
 |  | 
 |     inside = ' '.join(tokens[3:-1]) | 
 |  | 
 |     tokens = inside.split(';') | 
 |  | 
 |     structs = [] | 
 |  | 
 |     for entry in tokens: | 
 |         entry = NormalizeLine(entry) | 
 |         if not entry: | 
 |             continue | 
 |  | 
 |         # It's possible that new structs get defined in here | 
 |         structs.extend(ProcessOneEntry(newstruct, entry)) | 
 |  | 
 |     structs.append(newstruct) | 
 |     return structs | 
 |  | 
 | def GetNextStruct(file): | 
 |     global line_count | 
 |     global cppdirect | 
 |  | 
 |     got_struct = 0 | 
 |  | 
 |     processed_lines = [] | 
 |  | 
 |     have_c_comment = 0 | 
 |     data = '' | 
 |     while 1: | 
 |         line = file.readline() | 
 |         if not line: | 
 |             break | 
 |          | 
 |         line_count += 1 | 
 |         line = line[:-1] | 
 |  | 
 |         if not have_c_comment and re.search(r'/\*', line): | 
 |             if re.search(r'/\*.*\*/', line): | 
 |                 line = re.sub(r'/\*.*\*/', '', line) | 
 |             else: | 
 |                 line = re.sub(r'/\*.*$', '', line) | 
 |                 have_c_comment = 1 | 
 |  | 
 |         if have_c_comment: | 
 |             if not re.search(r'\*/', line): | 
 |                 continue | 
 |             have_c_comment = 0 | 
 |             line = re.sub(r'^.*\*/', '', line) | 
 |  | 
 |         line = NormalizeLine(line) | 
 |  | 
 |         if not line: | 
 |             continue | 
 |  | 
 |         if not got_struct: | 
 |             if re.match(r'#include ["<].*[>"]', line): | 
 |                 cppdirect.append(line) | 
 |                 continue | 
 |              | 
 |             if re.match(r'^#(if( |def)|endif)', line): | 
 |                 cppdirect.append(line) | 
 |                 continue | 
 |  | 
 |             if re.match(r'^#define', line): | 
 |                 headerdirect.append(line) | 
 |                 continue | 
 |  | 
 |             if not re.match(r'^struct %s {$' % _STRUCT_RE, | 
 |                             line, re.IGNORECASE): | 
 |                 print >>sys.stderr, 'Missing struct on line %d: %s' % ( | 
 |                     line_count, line) | 
 |                 sys.exit(1) | 
 |             else: | 
 |                 got_struct = 1 | 
 |                 data += line | 
 |             continue | 
 |  | 
 |         # We are inside the struct | 
 |         tokens = line.split('}') | 
 |         if len(tokens) == 1: | 
 |             data += ' ' + line | 
 |             continue | 
 |  | 
 |         if len(tokens[1]): | 
 |             print >>sys.stderr, 'Trailing garbage after struct on line %d' % ( | 
 |                 line_count ) | 
 |             sys.exit(1) | 
 |  | 
 |         # We found the end of the struct | 
 |         data += ' %s}' % tokens[0] | 
 |         break | 
 |  | 
 |     # Remove any comments, that might be in there | 
 |     data = re.sub(r'/\*.*\*/', '', data) | 
 |      | 
 |     return data | 
 |          | 
 |  | 
 | def Parse(file): | 
 |     """ | 
 |     Parses the input file and returns C code and corresponding header file. | 
 |     """ | 
 |  | 
 |     entities = [] | 
 |  | 
 |     while 1: | 
 |         # Just gets the whole struct nicely formatted | 
 |         data = GetNextStruct(file) | 
 |  | 
 |         if not data: | 
 |             break | 
 |  | 
 |         entities.extend(ProcessStruct(data)) | 
 |  | 
 |     return entities | 
 |  | 
 | def GuardName(name): | 
 |     name = '_'.join(name.split('.')) | 
 |     name = '_'.join(name.split('/')) | 
 |     guard = '_'+name.upper()+'_' | 
 |  | 
 |     return guard | 
 |  | 
 | def HeaderPreamble(name): | 
 |     guard = GuardName(name) | 
 |     pre = ( | 
 |         '/*\n' | 
 |         ' * Automatically generated from %s\n' | 
 |         ' */\n\n' | 
 |         '#ifndef %s\n' | 
 |         '#define %s\n\n' ) % ( | 
 |         name, guard, guard) | 
 |  | 
 |     # insert stdint.h - let's hope everyone has it | 
 |     pre += ( | 
 |         '#include <event-config.h>\n' | 
 |         '#ifdef _EVENT_HAVE_STDINT_H\n' | 
 |         '#include <stdint.h>\n' | 
 |         '#endif\n' ) | 
 |  | 
 |     for statement in headerdirect: | 
 |         pre += '%s\n' % statement | 
 |     if headerdirect: | 
 |         pre += '\n' | 
 |  | 
 |     pre += ( | 
 |         '#define EVTAG_HAS(msg, member) ((msg)->member##_set == 1)\n' | 
 |         '#ifdef __GNUC__\n' | 
 |         '#define EVTAG_ASSIGN(msg, member, args...) ' | 
 |         '(*(msg)->base->member##_assign)(msg, ## args)\n' | 
 |         '#define EVTAG_GET(msg, member, args...) ' | 
 |         '(*(msg)->base->member##_get)(msg, ## args)\n' | 
 |         '#else\n' | 
 |         '#define EVTAG_ASSIGN(msg, member, ...) ' | 
 |         '(*(msg)->base->member##_assign)(msg, ## __VA_ARGS__)\n' | 
 |         '#define EVTAG_GET(msg, member, ...) ' | 
 |         '(*(msg)->base->member##_get)(msg, ## __VA_ARGS__)\n' | 
 |         '#endif\n' | 
 |         '#define EVTAG_ADD(msg, member) (*(msg)->base->member##_add)(msg)\n' | 
 |         '#define EVTAG_LEN(msg, member) ((msg)->member##_length)\n' | 
 |         ) | 
 |  | 
 |     return pre | 
 |       | 
 |  | 
 | def HeaderPostamble(name): | 
 |     guard = GuardName(name) | 
 |     return '#endif  /* %s */' % guard | 
 |  | 
 | def BodyPreamble(name): | 
 |     global _NAME | 
 |     global _VERSION | 
 |      | 
 |     header_file = '.'.join(name.split('.')[:-1]) + '.gen.h' | 
 |  | 
 |     pre = ( '/*\n' | 
 |             ' * Automatically generated from %s\n' | 
 |             ' * by %s/%s.  DO NOT EDIT THIS FILE.\n' | 
 |             ' */\n\n' ) % (name, _NAME, _VERSION) | 
 |     pre += ( '#include <sys/types.h>\n' | 
 |              '#ifdef _EVENT_HAVE_SYS_TIME_H\n' | 
 |              '#include <sys/time.h>\n' | 
 |              '#endif\n' | 
 |              '#include <stdlib.h>\n' | 
 |              '#include <string.h>\n' | 
 |              '#include <assert.h>\n' | 
 |              '#define EVENT_NO_STRUCT\n' | 
 |              '#include <event.h>\n\n' | 
 |              '#ifdef _EVENT___func__\n' | 
 |              '#define __func__ _EVENT___func__\n' | 
 |              '#endif\n' ) | 
 |  | 
 |     for statement in cppdirect: | 
 |         pre += '%s\n' % statement | 
 |      | 
 |     pre += '\n#include "%s"\n\n' % header_file | 
 |  | 
 |     pre += 'void event_err(int eval, const char *fmt, ...);\n' | 
 |     pre += 'void event_warn(const char *fmt, ...);\n' | 
 |     pre += 'void event_errx(int eval, const char *fmt, ...);\n' | 
 |     pre += 'void event_warnx(const char *fmt, ...);\n\n' | 
 |  | 
 |     return pre | 
 |  | 
 | def main(argv): | 
 |     if len(argv) < 2 or not argv[1]: | 
 |         print >>sys.stderr, 'Need RPC description file as first argument.' | 
 |         sys.exit(1) | 
 |  | 
 |     filename = argv[1] | 
 |  | 
 |     ext = filename.split('.')[-1] | 
 |     if ext != 'rpc': | 
 |         print >>sys.stderr, 'Unrecognized file extension: %s' % ext | 
 |         sys.exit(1) | 
 |  | 
 |     print >>sys.stderr, 'Reading \"%s\"' % filename | 
 |  | 
 |     fp = open(filename, 'r') | 
 |     entities = Parse(fp) | 
 |     fp.close() | 
 |  | 
 |     header_file = '.'.join(filename.split('.')[:-1]) + '.gen.h' | 
 |     impl_file = '.'.join(filename.split('.')[:-1]) + '.gen.c' | 
 |  | 
 |     print >>sys.stderr, '... creating "%s"' % header_file | 
 |     header_fp = open(header_file, 'w') | 
 |     print >>header_fp, HeaderPreamble(filename) | 
 |  | 
 |     # Create forward declarations: allows other structs to reference | 
 |     # each other | 
 |     for entry in entities: | 
 |         entry.PrintForwardDeclaration(header_fp) | 
 |     print >>header_fp, '' | 
 |  | 
 |     for entry in entities: | 
 |         entry.PrintTags(header_fp) | 
 |         entry.PrintDeclaration(header_fp) | 
 |     print >>header_fp, HeaderPostamble(filename) | 
 |     header_fp.close() | 
 |  | 
 |     print >>sys.stderr, '... creating "%s"' % impl_file | 
 |     impl_fp = open(impl_file, 'w') | 
 |     print >>impl_fp, BodyPreamble(filename) | 
 |     for entry in entities: | 
 |         entry.PrintCode(impl_fp) | 
 |     impl_fp.close() | 
 |  | 
 | if __name__ == '__main__': | 
 |     main(sys.argv) |