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