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