libevent (2.1.12)

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