Home | History | Annotate | Download | only in libevent
      1 #!/usr/bin/env python2
      2 #
      3 # Copyright (c) 2005-2007 Niels Provos <provos (at] 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                  '#if defined(EVENT____func__) && !defined(__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
   1729