summaryrefslogtreecommitdiffstats
path: root/ipc/chromium/src/third_party/libevent/event_rpcgen.py
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/chromium/src/third_party/libevent/event_rpcgen.py')
-rwxr-xr-xipc/chromium/src/third_party/libevent/event_rpcgen.py1925
1 files changed, 1925 insertions, 0 deletions
diff --git a/ipc/chromium/src/third_party/libevent/event_rpcgen.py b/ipc/chromium/src/third_party/libevent/event_rpcgen.py
new file mode 100755
index 0000000000..0bae3b0fe6
--- /dev/null
+++ b/ipc/chromium/src/third_party/libevent/event_rpcgen.py
@@ -0,0 +1,1925 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2005-2007 Niels Provos <provos@citi.umich.edu>
+# Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
+# All rights reserved.
+#
+# Generates marshaling code based on libevent.
+
+# pylint: disable=too-many-lines
+# pylint: disable=too-many-branches
+# pylint: disable=too-many-public-methods
+# pylint: disable=too-many-statements
+# pylint: disable=global-statement
+
+# TODO:
+# 1) propagate the arguments/options parsed by argparse down to the
+# instantiated factory objects.
+# 2) move the globals into a class that manages execution, including the
+# progress outputs that go to stderr at the moment.
+# 3) emit other languages.
+
+import argparse
+import re
+import sys
+
+_NAME = "event_rpcgen.py"
+_VERSION = "0.1"
+
+# Globals
+LINE_COUNT = 0
+
+CPPCOMMENT_RE = re.compile(r"\/\/.*$")
+NONIDENT_RE = re.compile(r"\W")
+PREPROCESSOR_DEF_RE = re.compile(r"^#define")
+STRUCT_REF_RE = re.compile(r"^struct\[(?P<name>[a-zA-Z_][a-zA-Z0-9_]*)\]$")
+STRUCT_DEF_RE = re.compile(r"^struct +[a-zA-Z_][a-zA-Z0-9_]* *{$")
+WHITESPACE_RE = re.compile(r"\s+")
+
+HEADER_DIRECT = []
+CPP_DIRECT = []
+
+QUIETLY = False
+
+
+def declare(s):
+ if not QUIETLY:
+ print(s)
+
+
+def TranslateList(mylist, mydict):
+ return [x % mydict for x in mylist]
+
+
+class RpcGenError(Exception):
+ """An Exception class for parse errors."""
+
+ def __init__(self, why): # pylint: disable=super-init-not-called
+ self.why = why
+
+ def __str__(self):
+ return str(self.why)
+
+
+# Holds everything that makes a struct
+class Struct(object):
+ def __init__(self, name):
+ self._name = name
+ self._entries = []
+ self._tags = {}
+ declare(" Created struct: %s" % name)
+
+ def AddEntry(self, entry):
+ if entry.Tag() in self._tags:
+ raise RpcGenError(
+ 'Entry "%s" duplicates tag number %d from "%s" '
+ "around line %d"
+ % (entry.Name(), entry.Tag(), self._tags[entry.Tag()], LINE_COUNT)
+ )
+ self._entries.append(entry)
+ self._tags[entry.Tag()] = entry.Name()
+ declare(" Added entry: %s" % entry.Name())
+
+ def Name(self):
+ return self._name
+
+ def EntryTagName(self, entry):
+ """Creates the name inside an enumeration for distinguishing data
+ types."""
+ name = "%s_%s" % (self._name, entry.Name())
+ return name.upper()
+
+ @staticmethod
+ def PrintIndented(filep, ident, code):
+ """Takes an array, add indentation to each entry and prints it."""
+ for entry in code:
+ filep.write("%s%s\n" % (ident, entry))
+
+
+class StructCCode(Struct):
+ """ Knows how to generate C code for a struct """
+
+ def __init__(self, name):
+ Struct.__init__(self, name)
+
+ def PrintTags(self, filep):
+ """Prints the tag definitions for a structure."""
+ filep.write("/* Tag definition for %s */\n" % self._name)
+ filep.write("enum %s_ {\n" % self._name.lower())
+ for entry in self._entries:
+ filep.write(" %s=%d,\n" % (self.EntryTagName(entry), entry.Tag()))
+ filep.write(" %s_MAX_TAGS\n" % (self._name.upper()))
+ filep.write("};\n\n")
+
+ def PrintForwardDeclaration(self, filep):
+ filep.write("struct %s;\n" % self._name)
+
+ def PrintDeclaration(self, filep):
+ filep.write("/* Structure declaration for %s */\n" % self._name)
+ filep.write("struct %s_access_ {\n" % self._name)
+ for entry in self._entries:
+ dcl = entry.AssignDeclaration("(*%s_assign)" % entry.Name())
+ dcl.extend(entry.GetDeclaration("(*%s_get)" % entry.Name()))
+ if entry.Array():
+ dcl.extend(entry.AddDeclaration("(*%s_add)" % entry.Name()))
+ self.PrintIndented(filep, " ", dcl)
+ filep.write("};\n\n")
+
+ filep.write("struct %s {\n" % self._name)
+ filep.write(" struct %s_access_ *base;\n\n" % self._name)
+ for entry in self._entries:
+ dcl = entry.Declaration()
+ self.PrintIndented(filep, " ", dcl)
+ filep.write("\n")
+ for entry in self._entries:
+ filep.write(" ev_uint8_t %s_set;\n" % entry.Name())
+ filep.write("};\n\n")
+
+ filep.write(
+ """struct %(name)s *%(name)s_new(void);
+struct %(name)s *%(name)s_new_with_arg(void *);
+void %(name)s_free(struct %(name)s *);
+void %(name)s_clear(struct %(name)s *);
+void %(name)s_marshal(struct evbuffer *, const struct %(name)s *);
+int %(name)s_unmarshal(struct %(name)s *, struct evbuffer *);
+int %(name)s_complete(struct %(name)s *);
+void evtag_marshal_%(name)s(struct evbuffer *, ev_uint32_t,
+ const struct %(name)s *);
+int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
+ struct %(name)s *);\n"""
+ % {"name": self._name}
+ )
+
+ # Write a setting function of every variable
+ for entry in self._entries:
+ self.PrintIndented(
+ filep, "", entry.AssignDeclaration(entry.AssignFuncName())
+ )
+ self.PrintIndented(filep, "", entry.GetDeclaration(entry.GetFuncName()))
+ if entry.Array():
+ self.PrintIndented(filep, "", entry.AddDeclaration(entry.AddFuncName()))
+
+ filep.write("/* --- %s done --- */\n\n" % self._name)
+
+ def PrintCode(self, filep):
+ filep.write(
+ """/*
+ * Implementation of %s
+ */
+"""
+ % (self._name)
+ )
+
+ filep.write(
+ """
+static struct %(name)s_access_ %(name)s_base__ = {
+"""
+ % {"name": self._name}
+ )
+ for entry in self._entries:
+ self.PrintIndented(filep, " ", entry.CodeBase())
+ filep.write("};\n\n")
+
+ # Creation
+ filep.write(
+ """struct %(name)s *
+%(name)s_new(void)
+{
+ return %(name)s_new_with_arg(NULL);
+}
+
+struct %(name)s *
+%(name)s_new_with_arg(void *unused)
+{
+ struct %(name)s *tmp;
+ if ((tmp = malloc(sizeof(struct %(name)s))) == NULL) {
+ event_warn("%%s: malloc", __func__);
+ return (NULL);
+ }
+ tmp->base = &%(name)s_base__;
+
+"""
+ % {"name": self._name}
+ )
+
+ for entry in self._entries:
+ self.PrintIndented(filep, " ", entry.CodeInitialize("tmp"))
+ filep.write(" tmp->%s_set = 0;\n\n" % entry.Name())
+
+ filep.write(
+ """ return (tmp);
+}
+
+"""
+ )
+
+ # Adding
+ for entry in self._entries:
+ if entry.Array():
+ self.PrintIndented(filep, "", entry.CodeAdd())
+ filep.write("\n")
+
+ # Assigning
+ for entry in self._entries:
+ self.PrintIndented(filep, "", entry.CodeAssign())
+ filep.write("\n")
+
+ # Getting
+ for entry in self._entries:
+ self.PrintIndented(filep, "", entry.CodeGet())
+ filep.write("\n")
+
+ # Clearing
+ filep.write(
+ """void
+%(name)s_clear(struct %(name)s *tmp)
+{
+"""
+ % {"name": self._name}
+ )
+ for entry in self._entries:
+ self.PrintIndented(filep, " ", entry.CodeClear("tmp"))
+
+ filep.write("}\n\n")
+
+ # Freeing
+ filep.write(
+ """void
+%(name)s_free(struct %(name)s *tmp)
+{
+"""
+ % {"name": self._name}
+ )
+
+ for entry in self._entries:
+ self.PrintIndented(filep, " ", entry.CodeFree("tmp"))
+
+ filep.write(
+ """ free(tmp);
+}
+
+"""
+ )
+
+ # Marshaling
+ filep.write(
+ """void
+%(name)s_marshal(struct evbuffer *evbuf, const struct %(name)s *tmp) {
+"""
+ % {"name": self._name}
+ )
+ for entry in self._entries:
+ indent = " "
+ # Optional entries do not have to be set
+ if entry.Optional():
+ indent += " "
+ filep.write(" if (tmp->%s_set) {\n" % entry.Name())
+ self.PrintIndented(
+ filep,
+ indent,
+ entry.CodeMarshal(
+ "evbuf",
+ self.EntryTagName(entry),
+ entry.GetVarName("tmp"),
+ entry.GetVarLen("tmp"),
+ ),
+ )
+ if entry.Optional():
+ filep.write(" }\n")
+
+ filep.write("}\n\n")
+
+ # Unmarshaling
+ filep.write(
+ """int
+%(name)s_unmarshal(struct %(name)s *tmp, struct evbuffer *evbuf)
+{
+ ev_uint32_t tag;
+ while (evbuffer_get_length(evbuf) > 0) {
+ if (evtag_peek(evbuf, &tag) == -1)
+ return (-1);
+ switch (tag) {
+
+"""
+ % {"name": self._name}
+ )
+ for entry in self._entries:
+ filep.write(" case %s:\n" % (self.EntryTagName(entry)))
+ if not entry.Array():
+ filep.write(
+ """ if (tmp->%s_set)
+ return (-1);
+"""
+ % (entry.Name())
+ )
+
+ self.PrintIndented(
+ filep,
+ " ",
+ entry.CodeUnmarshal(
+ "evbuf",
+ self.EntryTagName(entry),
+ entry.GetVarName("tmp"),
+ entry.GetVarLen("tmp"),
+ ),
+ )
+
+ filep.write(
+ """ tmp->%s_set = 1;
+ break;
+"""
+ % (entry.Name())
+ )
+ filep.write(
+ """ default:
+ return -1;
+ }
+ }
+
+"""
+ )
+ # Check if it was decoded completely
+ filep.write(
+ """ if (%(name)s_complete(tmp) == -1)
+ return (-1);
+ return (0);
+}
+"""
+ % {"name": self._name}
+ )
+
+ # Checking if a structure has all the required data
+ filep.write(
+ """
+int
+%(name)s_complete(struct %(name)s *msg)
+{
+"""
+ % {"name": self._name}
+ )
+ for entry in self._entries:
+ if not entry.Optional():
+ code = [
+ """if (!msg->%(name)s_set)
+ return (-1);"""
+ ]
+ code = TranslateList(code, entry.GetTranslation())
+ self.PrintIndented(filep, " ", code)
+
+ self.PrintIndented(
+ filep, " ", entry.CodeComplete("msg", entry.GetVarName("msg"))
+ )
+ filep.write(
+ """ return (0);
+}
+"""
+ )
+
+ # Complete message unmarshaling
+ filep.write(
+ """
+int
+evtag_unmarshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t need_tag,
+ struct %(name)s *msg)
+{
+ ev_uint32_t tag;
+ int res = -1;
+
+ struct evbuffer *tmp = evbuffer_new();
+
+ if (evtag_unmarshal(evbuf, &tag, tmp) == -1 || tag != need_tag)
+ goto error;
+
+ if (%(name)s_unmarshal(msg, tmp) == -1)
+ goto error;
+
+ res = 0;
+
+ error:
+ evbuffer_free(tmp);
+ return (res);
+}
+"""
+ % {"name": self._name}
+ )
+
+ # Complete message marshaling
+ filep.write(
+ """
+void
+evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag,
+ const struct %(name)s *msg)
+{
+ struct evbuffer *buf_ = evbuffer_new();
+ assert(buf_ != NULL);
+ %(name)s_marshal(buf_, msg);
+ evtag_marshal_buffer(evbuf, tag, buf_);
+ evbuffer_free(buf_);
+}
+
+"""
+ % {"name": self._name}
+ )
+
+
+class Entry(object):
+ def __init__(self, ent_type, name, tag):
+ self._type = ent_type
+ self._name = name
+ self._tag = int(tag)
+ self._ctype = ent_type
+ self._optional = False
+ self._can_be_array = False
+ self._array = False
+ self._line_count = -1
+ self._struct = None
+ self._refname = None
+
+ self._optpointer = True
+ self._optaddarg = True
+
+ @staticmethod
+ def GetInitializer():
+ raise NotImplementedError("Entry does not provide an initializer")
+
+ def SetStruct(self, struct):
+ self._struct = struct
+
+ def LineCount(self):
+ assert self._line_count != -1
+ return self._line_count
+
+ def SetLineCount(self, number):
+ self._line_count = number
+
+ def Array(self):
+ return self._array
+
+ def Optional(self):
+ return self._optional
+
+ def Tag(self):
+ return self._tag
+
+ def Name(self):
+ return self._name
+
+ def Type(self):
+ return self._type
+
+ def MakeArray(self):
+ self._array = True
+
+ def MakeOptional(self):
+ self._optional = True
+
+ def Verify(self):
+ if self.Array() and not self._can_be_array:
+ raise RpcGenError(
+ 'Entry "%s" cannot be created as an array '
+ "around line %d" % (self._name, self.LineCount())
+ )
+ if not self._struct:
+ raise RpcGenError(
+ 'Entry "%s" does not know which struct it belongs to '
+ "around line %d" % (self._name, self.LineCount())
+ )
+ if self._optional and self._array:
+ raise RpcGenError(
+ 'Entry "%s" has illegal combination of optional and array '
+ "around line %d" % (self._name, self.LineCount())
+ )
+
+ def GetTranslation(self, extradict=None):
+ if extradict is None:
+ extradict = {}
+ mapping = {
+ "parent_name": self._struct.Name(),
+ "name": self._name,
+ "ctype": self._ctype,
+ "refname": self._refname,
+ "optpointer": self._optpointer and "*" or "",
+ "optreference": self._optpointer and "&" or "",
+ "optaddarg": self._optaddarg and ", const %s value" % self._ctype or "",
+ }
+ for (k, v) in list(extradict.items()):
+ mapping[k] = v
+
+ return mapping
+
+ def GetVarName(self, var):
+ return "%(var)s->%(name)s_data" % self.GetTranslation({"var": var})
+
+ def GetVarLen(self, _var):
+ return "sizeof(%s)" % self._ctype
+
+ def GetFuncName(self):
+ return "%s_%s_get" % (self._struct.Name(), self._name)
+
+ def GetDeclaration(self, funcname):
+ code = [
+ "int %s(struct %s *, %s *);" % (funcname, self._struct.Name(), self._ctype)
+ ]
+ return code
+
+ def CodeGet(self):
+ code = """int
+%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, %(ctype)s *value)
+{
+ if (msg->%(name)s_set != 1)
+ return (-1);
+ *value = msg->%(name)s_data;
+ return (0);
+}"""
+ code = code % self.GetTranslation()
+ return code.split("\n")
+
+ def AssignFuncName(self):
+ return "%s_%s_assign" % (self._struct.Name(), self._name)
+
+ def AddFuncName(self):
+ return "%s_%s_add" % (self._struct.Name(), self._name)
+
+ def AssignDeclaration(self, funcname):
+ code = [
+ "int %s(struct %s *, const %s);"
+ % (funcname, self._struct.Name(), self._ctype)
+ ]
+ return code
+
+ def CodeAssign(self):
+ code = [
+ "int",
+ "%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,"
+ " const %(ctype)s value)",
+ "{",
+ " msg->%(name)s_set = 1;",
+ " msg->%(name)s_data = value;",
+ " return (0);",
+ "}",
+ ]
+ code = "\n".join(code)
+ code = code % self.GetTranslation()
+ return code.split("\n")
+
+ def CodeClear(self, structname):
+ code = ["%s->%s_set = 0;" % (structname, self.Name())]
+
+ return code
+
+ @staticmethod
+ def CodeComplete(_structname, _var_name):
+ return []
+
+ @staticmethod
+ def CodeFree(_name):
+ return []
+
+ def CodeBase(self):
+ code = ["%(parent_name)s_%(name)s_assign,", "%(parent_name)s_%(name)s_get,"]
+ if self.Array():
+ code.append("%(parent_name)s_%(name)s_add,")
+
+ code = "\n".join(code)
+ code = code % self.GetTranslation()
+ return code.split("\n")
+
+
+class EntryBytes(Entry):
+ def __init__(self, ent_type, name, tag, length):
+ # Init base class
+ super(EntryBytes, self).__init__(ent_type, name, tag)
+
+ self._length = length
+ self._ctype = "ev_uint8_t"
+
+ @staticmethod
+ def GetInitializer():
+ return "NULL"
+
+ def GetVarLen(self, _var):
+ return "(%s)" % self._length
+
+ @staticmethod
+ def CodeArrayAdd(varname, _value):
+ # XXX: copy here
+ return ["%(varname)s = NULL;" % {"varname": varname}]
+
+ def GetDeclaration(self, funcname):
+ code = [
+ "int %s(struct %s *, %s **);" % (funcname, self._struct.Name(), self._ctype)
+ ]
+ return code
+
+ def AssignDeclaration(self, funcname):
+ code = [
+ "int %s(struct %s *, const %s *);"
+ % (funcname, self._struct.Name(), self._ctype)
+ ]
+ return code
+
+ def Declaration(self):
+ dcl = ["ev_uint8_t %s_data[%s];" % (self._name, self._length)]
+
+ return dcl
+
+ def CodeGet(self):
+ name = self._name
+ code = [
+ "int",
+ "%s_%s_get(struct %s *msg, %s **value)"
+ % (self._struct.Name(), name, self._struct.Name(), self._ctype),
+ "{",
+ " if (msg->%s_set != 1)" % name,
+ " return (-1);",
+ " *value = msg->%s_data;" % name,
+ " return (0);",
+ "}",
+ ]
+ return code
+
+ def CodeAssign(self):
+ name = self._name
+ code = [
+ "int",
+ "%s_%s_assign(struct %s *msg, const %s *value)"
+ % (self._struct.Name(), name, self._struct.Name(), self._ctype),
+ "{",
+ " msg->%s_set = 1;" % name,
+ " memcpy(msg->%s_data, value, %s);" % (name, self._length),
+ " return (0);",
+ "}",
+ ]
+ return code
+
+ def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
+ code = [
+ "if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, "
+ "%(var)s, %(varlen)s) == -1) {",
+ ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
+ " return (-1);",
+ "}",
+ ]
+ return TranslateList(
+ code,
+ self.GetTranslation(
+ {"var": var_name, "varlen": var_len, "buf": buf, "tag": tag_name}
+ ),
+ )
+
+ @staticmethod
+ def CodeMarshal(buf, tag_name, var_name, var_len):
+ code = ["evtag_marshal(%s, %s, %s, %s);" % (buf, tag_name, var_name, var_len)]
+ return code
+
+ def CodeClear(self, structname):
+ code = [
+ "%s->%s_set = 0;" % (structname, self.Name()),
+ "memset(%s->%s_data, 0, sizeof(%s->%s_data));"
+ % (structname, self._name, structname, self._name),
+ ]
+
+ return code
+
+ def CodeInitialize(self, name):
+ code = [
+ "memset(%s->%s_data, 0, sizeof(%s->%s_data));"
+ % (name, self._name, name, self._name)
+ ]
+ return code
+
+ def Verify(self):
+ if not self._length:
+ raise RpcGenError(
+ 'Entry "%s" needs a length '
+ "around line %d" % (self._name, self.LineCount())
+ )
+
+ super(EntryBytes, self).Verify()
+
+
+class EntryInt(Entry):
+ def __init__(self, ent_type, name, tag, bits=32):
+ # Init base class
+ super(EntryInt, self).__init__(ent_type, name, tag)
+
+ self._can_be_array = True
+ if bits == 32:
+ self._ctype = "ev_uint32_t"
+ self._marshal_type = "int"
+ if bits == 64:
+ self._ctype = "ev_uint64_t"
+ self._marshal_type = "int64"
+
+ @staticmethod
+ def GetInitializer():
+ return "0"
+
+ @staticmethod
+ def CodeArrayFree(_var):
+ return []
+
+ @staticmethod
+ def CodeArrayAssign(varname, srcvar):
+ return ["%(varname)s = %(srcvar)s;" % {"varname": varname, "srcvar": srcvar}]
+
+ @staticmethod
+ def CodeArrayAdd(varname, value):
+ """Returns a new entry of this type."""
+ return ["%(varname)s = %(value)s;" % {"varname": varname, "value": value}]
+
+ def CodeUnmarshal(self, buf, tag_name, var_name, _var_len):
+ code = [
+ "if (evtag_unmarshal_%(ma)s(%(buf)s, %(tag)s, &%(var)s) == -1) {",
+ ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
+ " return (-1);",
+ "}",
+ ]
+ code = "\n".join(code) % self.GetTranslation(
+ {"ma": self._marshal_type, "buf": buf, "tag": tag_name, "var": var_name}
+ )
+ return code.split("\n")
+
+ def CodeMarshal(self, buf, tag_name, var_name, _var_len):
+ code = [
+ "evtag_marshal_%s(%s, %s, %s);"
+ % (self._marshal_type, buf, tag_name, var_name)
+ ]
+ return code
+
+ def Declaration(self):
+ dcl = ["%s %s_data;" % (self._ctype, self._name)]
+
+ return dcl
+
+ def CodeInitialize(self, name):
+ code = ["%s->%s_data = 0;" % (name, self._name)]
+ return code
+
+
+class EntryString(Entry):
+ def __init__(self, ent_type, name, tag):
+ # Init base class
+ super(EntryString, self).__init__(ent_type, name, tag)
+
+ self._can_be_array = True
+ self._ctype = "char *"
+
+ @staticmethod
+ def GetInitializer():
+ return "NULL"
+
+ @staticmethod
+ def CodeArrayFree(varname):
+ code = ["if (%(var)s != NULL) free(%(var)s);"]
+
+ return TranslateList(code, {"var": varname})
+
+ @staticmethod
+ def CodeArrayAssign(varname, srcvar):
+ code = [
+ "if (%(var)s != NULL)",
+ " free(%(var)s);",
+ "%(var)s = strdup(%(srcvar)s);",
+ "if (%(var)s == NULL) {",
+ ' event_warnx("%%s: strdup", __func__);',
+ " return (-1);",
+ "}",
+ ]
+
+ return TranslateList(code, {"var": varname, "srcvar": srcvar})
+
+ @staticmethod
+ def CodeArrayAdd(varname, value):
+ code = [
+ "if (%(value)s != NULL) {",
+ " %(var)s = strdup(%(value)s);",
+ " if (%(var)s == NULL) {",
+ " goto error;",
+ " }",
+ "} else {",
+ " %(var)s = NULL;",
+ "}",
+ ]
+
+ return TranslateList(code, {"var": varname, "value": value})
+
+ def GetVarLen(self, var):
+ return "strlen(%s)" % self.GetVarName(var)
+
+ @staticmethod
+ def CodeMakeInitalize(varname):
+ return "%(varname)s = NULL;" % {"varname": varname}
+
+ def CodeAssign(self):
+ code = """int
+%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
+ const %(ctype)s value)
+{
+ if (msg->%(name)s_data != NULL)
+ free(msg->%(name)s_data);
+ if ((msg->%(name)s_data = strdup(value)) == NULL)
+ return (-1);
+ msg->%(name)s_set = 1;
+ return (0);
+}""" % (
+ self.GetTranslation()
+ )
+
+ return code.split("\n")
+
+ def CodeUnmarshal(self, buf, tag_name, var_name, _var_len):
+ code = [
+ "if (evtag_unmarshal_string(%(buf)s, %(tag)s, &%(var)s) == -1) {",
+ ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
+ " return (-1);",
+ "}",
+ ]
+ code = "\n".join(code) % self.GetTranslation(
+ {"buf": buf, "tag": tag_name, "var": var_name}
+ )
+ return code.split("\n")
+
+ @staticmethod
+ def CodeMarshal(buf, tag_name, var_name, _var_len):
+ code = ["evtag_marshal_string(%s, %s, %s);" % (buf, tag_name, var_name)]
+ return code
+
+ def CodeClear(self, structname):
+ code = [
+ "if (%s->%s_set == 1) {" % (structname, self.Name()),
+ " free(%s->%s_data);" % (structname, self.Name()),
+ " %s->%s_data = NULL;" % (structname, self.Name()),
+ " %s->%s_set = 0;" % (structname, self.Name()),
+ "}",
+ ]
+
+ return code
+
+ def CodeInitialize(self, name):
+ code = ["%s->%s_data = NULL;" % (name, self._name)]
+ return code
+
+ def CodeFree(self, name):
+ code = [
+ "if (%s->%s_data != NULL)" % (name, self._name),
+ " free (%s->%s_data);" % (name, self._name),
+ ]
+
+ return code
+
+ def Declaration(self):
+ dcl = ["char *%s_data;" % self._name]
+
+ return dcl
+
+
+class EntryStruct(Entry):
+ def __init__(self, ent_type, name, tag, refname):
+ # Init base class
+ super(EntryStruct, self).__init__(ent_type, name, tag)
+
+ self._optpointer = False
+ self._can_be_array = True
+ self._refname = refname
+ self._ctype = "struct %s*" % refname
+ self._optaddarg = False
+
+ def GetInitializer(self):
+ return "NULL"
+
+ def GetVarLen(self, _var):
+ return "-1"
+
+ def CodeArrayAdd(self, varname, _value):
+ code = [
+ "%(varname)s = %(refname)s_new();",
+ "if (%(varname)s == NULL)",
+ " goto error;",
+ ]
+
+ return TranslateList(code, self.GetTranslation({"varname": varname}))
+
+ def CodeArrayFree(self, var):
+ code = ["%(refname)s_free(%(var)s);" % self.GetTranslation({"var": var})]
+ return code
+
+ def CodeArrayAssign(self, var, srcvar):
+ code = [
+ "int had_error = 0;",
+ "struct evbuffer *tmp = NULL;",
+ "%(refname)s_clear(%(var)s);",
+ "if ((tmp = evbuffer_new()) == NULL) {",
+ ' event_warn("%%s: evbuffer_new()", __func__);',
+ " had_error = 1;",
+ " goto done;",
+ "}",
+ "%(refname)s_marshal(tmp, %(srcvar)s);",
+ "if (%(refname)s_unmarshal(%(var)s, tmp) == -1) {",
+ ' event_warnx("%%s: %(refname)s_unmarshal", __func__);',
+ " had_error = 1;",
+ " goto done;",
+ "}",
+ "done:",
+ "if (tmp != NULL)",
+ " evbuffer_free(tmp);",
+ "if (had_error) {",
+ " %(refname)s_clear(%(var)s);",
+ " return (-1);",
+ "}",
+ ]
+
+ return TranslateList(code, self.GetTranslation({"var": var, "srcvar": srcvar}))
+
+ def CodeGet(self):
+ name = self._name
+ code = [
+ "int",
+ "%s_%s_get(struct %s *msg, %s *value)"
+ % (self._struct.Name(), name, self._struct.Name(), self._ctype),
+ "{",
+ " if (msg->%s_set != 1) {" % name,
+ " msg->%s_data = %s_new();" % (name, self._refname),
+ " if (msg->%s_data == NULL)" % name,
+ " return (-1);",
+ " msg->%s_set = 1;" % name,
+ " }",
+ " *value = msg->%s_data;" % name,
+ " return (0);",
+ "}",
+ ]
+ return code
+
+ def CodeAssign(self):
+ code = (
+ """int
+%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
+ const %(ctype)s value)
+{
+ struct evbuffer *tmp = NULL;
+ if (msg->%(name)s_set) {
+ %(refname)s_clear(msg->%(name)s_data);
+ msg->%(name)s_set = 0;
+ } else {
+ msg->%(name)s_data = %(refname)s_new();
+ if (msg->%(name)s_data == NULL) {
+ event_warn("%%s: %(refname)s_new()", __func__);
+ goto error;
+ }
+ }
+ if ((tmp = evbuffer_new()) == NULL) {
+ event_warn("%%s: evbuffer_new()", __func__);
+ goto error;
+ }
+ %(refname)s_marshal(tmp, value);
+ if (%(refname)s_unmarshal(msg->%(name)s_data, tmp) == -1) {
+ event_warnx("%%s: %(refname)s_unmarshal", __func__);
+ goto error;
+ }
+ msg->%(name)s_set = 1;
+ evbuffer_free(tmp);
+ return (0);
+ error:
+ if (tmp != NULL)
+ evbuffer_free(tmp);
+ if (msg->%(name)s_data != NULL) {
+ %(refname)s_free(msg->%(name)s_data);
+ msg->%(name)s_data = NULL;
+ }
+ return (-1);
+}"""
+ % self.GetTranslation()
+ )
+ return code.split("\n")
+
+ def CodeComplete(self, structname, var_name):
+ code = [
+ "if (%(structname)s->%(name)s_set && "
+ "%(refname)s_complete(%(var)s) == -1)",
+ " return (-1);",
+ ]
+
+ return TranslateList(
+ code, self.GetTranslation({"structname": structname, "var": var_name})
+ )
+
+ def CodeUnmarshal(self, buf, tag_name, var_name, _var_len):
+ code = [
+ "%(var)s = %(refname)s_new();",
+ "if (%(var)s == NULL)",
+ " return (-1);",
+ "if (evtag_unmarshal_%(refname)s(%(buf)s, %(tag)s, ",
+ " %(var)s) == -1) {",
+ ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
+ " return (-1);",
+ "}",
+ ]
+ code = "\n".join(code) % self.GetTranslation(
+ {"buf": buf, "tag": tag_name, "var": var_name}
+ )
+ return code.split("\n")
+
+ def CodeMarshal(self, buf, tag_name, var_name, _var_len):
+ code = [
+ "evtag_marshal_%s(%s, %s, %s);" % (self._refname, buf, tag_name, var_name)
+ ]
+ return code
+
+ def CodeClear(self, structname):
+ code = [
+ "if (%s->%s_set == 1) {" % (structname, self.Name()),
+ " %s_free(%s->%s_data);" % (self._refname, structname, self.Name()),
+ " %s->%s_data = NULL;" % (structname, self.Name()),
+ " %s->%s_set = 0;" % (structname, self.Name()),
+ "}",
+ ]
+
+ return code
+
+ def CodeInitialize(self, name):
+ code = ["%s->%s_data = NULL;" % (name, self._name)]
+ return code
+
+ def CodeFree(self, name):
+ code = [
+ "if (%s->%s_data != NULL)" % (name, self._name),
+ " %s_free(%s->%s_data);" % (self._refname, name, self._name),
+ ]
+
+ return code
+
+ def Declaration(self):
+ dcl = ["%s %s_data;" % (self._ctype, self._name)]
+
+ return dcl
+
+
+class EntryVarBytes(Entry):
+ def __init__(self, ent_type, name, tag):
+ # Init base class
+ super(EntryVarBytes, self).__init__(ent_type, name, tag)
+
+ self._ctype = "ev_uint8_t *"
+
+ @staticmethod
+ def GetInitializer():
+ return "NULL"
+
+ def GetVarLen(self, var):
+ return "%(var)s->%(name)s_length" % self.GetTranslation({"var": var})
+
+ @staticmethod
+ def CodeArrayAdd(varname, _value):
+ # xxx: copy
+ return ["%(varname)s = NULL;" % {"varname": varname}]
+
+ def GetDeclaration(self, funcname):
+ code = [
+ "int %s(struct %s *, %s *, ev_uint32_t *);"
+ % (funcname, self._struct.Name(), self._ctype)
+ ]
+ return code
+
+ def AssignDeclaration(self, funcname):
+ code = [
+ "int %s(struct %s *, const %s, ev_uint32_t);"
+ % (funcname, self._struct.Name(), self._ctype)
+ ]
+ return code
+
+ def CodeAssign(self):
+ name = self._name
+ code = [
+ "int",
+ "%s_%s_assign(struct %s *msg, "
+ "const %s value, ev_uint32_t len)"
+ % (self._struct.Name(), name, self._struct.Name(), self._ctype),
+ "{",
+ " if (msg->%s_data != NULL)" % name,
+ " free (msg->%s_data);" % name,
+ " msg->%s_data = malloc(len);" % name,
+ " if (msg->%s_data == NULL)" % name,
+ " return (-1);",
+ " msg->%s_set = 1;" % name,
+ " msg->%s_length = len;" % name,
+ " memcpy(msg->%s_data, value, len);" % name,
+ " return (0);",
+ "}",
+ ]
+ return code
+
+ def CodeGet(self):
+ name = self._name
+ code = [
+ "int",
+ "%s_%s_get(struct %s *msg, %s *value, ev_uint32_t *plen)"
+ % (self._struct.Name(), name, self._struct.Name(), self._ctype),
+ "{",
+ " if (msg->%s_set != 1)" % name,
+ " return (-1);",
+ " *value = msg->%s_data;" % name,
+ " *plen = msg->%s_length;" % name,
+ " return (0);",
+ "}",
+ ]
+ return code
+
+ def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
+ code = [
+ "if (evtag_payload_length(%(buf)s, &%(varlen)s) == -1)",
+ " return (-1);",
+ # We do not want DoS opportunities
+ "if (%(varlen)s > evbuffer_get_length(%(buf)s))",
+ " return (-1);",
+ "if ((%(var)s = malloc(%(varlen)s)) == NULL)",
+ " return (-1);",
+ "if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, %(var)s, "
+ "%(varlen)s) == -1) {",
+ ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
+ " return (-1);",
+ "}",
+ ]
+ code = "\n".join(code) % self.GetTranslation(
+ {"buf": buf, "tag": tag_name, "var": var_name, "varlen": var_len}
+ )
+ return code.split("\n")
+
+ @staticmethod
+ def CodeMarshal(buf, tag_name, var_name, var_len):
+ code = ["evtag_marshal(%s, %s, %s, %s);" % (buf, tag_name, var_name, var_len)]
+ return code
+
+ def CodeClear(self, structname):
+ code = [
+ "if (%s->%s_set == 1) {" % (structname, self.Name()),
+ " free (%s->%s_data);" % (structname, self.Name()),
+ " %s->%s_data = NULL;" % (structname, self.Name()),
+ " %s->%s_length = 0;" % (structname, self.Name()),
+ " %s->%s_set = 0;" % (structname, self.Name()),
+ "}",
+ ]
+
+ return code
+
+ def CodeInitialize(self, name):
+ code = [
+ "%s->%s_data = NULL;" % (name, self._name),
+ "%s->%s_length = 0;" % (name, self._name),
+ ]
+ return code
+
+ def CodeFree(self, name):
+ code = [
+ "if (%s->%s_data != NULL)" % (name, self._name),
+ " free(%s->%s_data);" % (name, self._name),
+ ]
+
+ return code
+
+ def Declaration(self):
+ dcl = [
+ "ev_uint8_t *%s_data;" % self._name,
+ "ev_uint32_t %s_length;" % self._name,
+ ]
+
+ return dcl
+
+
+class EntryArray(Entry):
+ _index = None
+
+ def __init__(self, entry):
+ # Init base class
+ super(EntryArray, self).__init__(entry._type, entry._name, entry._tag)
+
+ self._entry = entry
+ self._refname = entry._refname
+ self._ctype = self._entry._ctype
+ self._optional = True
+ self._optpointer = self._entry._optpointer
+ self._optaddarg = self._entry._optaddarg
+
+ # provide a new function for accessing the variable name
+ def GetVarName(var_name):
+ return "%(var)s->%(name)s_data[%(index)s]" % self._entry.GetTranslation(
+ {"var": var_name, "index": self._index}
+ )
+
+ self._entry.GetVarName = GetVarName
+
+ def GetInitializer(self):
+ return "NULL"
+
+ def GetVarName(self, var):
+ return var
+
+ def GetVarLen(self, _var_name):
+ return "-1"
+
+ def GetDeclaration(self, funcname):
+ """Allows direct access to elements of the array."""
+ code = [
+ "int %(funcname)s(struct %(parent_name)s *, int, %(ctype)s *);"
+ % self.GetTranslation({"funcname": funcname})
+ ]
+ return code
+
+ def AssignDeclaration(self, funcname):
+ code = [
+ "int %s(struct %s *, int, const %s);"
+ % (funcname, self._struct.Name(), self._ctype)
+ ]
+ return code
+
+ def AddDeclaration(self, funcname):
+ code = [
+ "%(ctype)s %(optpointer)s "
+ "%(funcname)s(struct %(parent_name)s *msg%(optaddarg)s);"
+ % self.GetTranslation({"funcname": funcname})
+ ]
+ return code
+
+ def CodeGet(self):
+ code = """int
+%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, int offset,
+ %(ctype)s *value)
+{
+ if (!msg->%(name)s_set || offset < 0 || offset >= msg->%(name)s_length)
+ return (-1);
+ *value = msg->%(name)s_data[offset];
+ return (0);
+}
+""" % (
+ self.GetTranslation()
+ )
+
+ return code.splitlines()
+
+ def CodeAssign(self):
+ code = [
+ "int",
+ "%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, int off,",
+ " const %(ctype)s value)",
+ "{",
+ " if (!msg->%(name)s_set || off < 0 || off >= msg->%(name)s_length)",
+ " return (-1);",
+ "",
+ " {",
+ ]
+ code = TranslateList(code, self.GetTranslation())
+
+ codearrayassign = self._entry.CodeArrayAssign(
+ "msg->%(name)s_data[off]" % self.GetTranslation(), "value"
+ )
+ code += [" " + x for x in codearrayassign]
+
+ code += TranslateList([" }", " return (0);", "}"], self.GetTranslation())
+
+ return code
+
+ def CodeAdd(self):
+ codearrayadd = self._entry.CodeArrayAdd(
+ "msg->%(name)s_data[msg->%(name)s_length - 1]" % self.GetTranslation(),
+ "value",
+ )
+ code = [
+ "static int",
+ "%(parent_name)s_%(name)s_expand_to_hold_more("
+ "struct %(parent_name)s *msg)",
+ "{",
+ " int tobe_allocated = msg->%(name)s_num_allocated;",
+ " %(ctype)s* new_data = NULL;",
+ " tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;",
+ " new_data = (%(ctype)s*) realloc(msg->%(name)s_data,",
+ " tobe_allocated * sizeof(%(ctype)s));",
+ " if (new_data == NULL)",
+ " return -1;",
+ " msg->%(name)s_data = new_data;",
+ " msg->%(name)s_num_allocated = tobe_allocated;",
+ " return 0;",
+ "}",
+ "",
+ "%(ctype)s %(optpointer)s",
+ "%(parent_name)s_%(name)s_add(struct %(parent_name)s *msg%(optaddarg)s)",
+ "{",
+ " if (++msg->%(name)s_length >= msg->%(name)s_num_allocated) {",
+ " if (%(parent_name)s_%(name)s_expand_to_hold_more(msg)<0)",
+ " goto error;",
+ " }",
+ ]
+
+ code = TranslateList(code, self.GetTranslation())
+
+ code += [" " + x for x in codearrayadd]
+
+ code += TranslateList(
+ [
+ " msg->%(name)s_set = 1;",
+ " return %(optreference)s(msg->%(name)s_data["
+ "msg->%(name)s_length - 1]);",
+ "error:",
+ " --msg->%(name)s_length;",
+ " return (NULL);",
+ "}",
+ ],
+ self.GetTranslation(),
+ )
+
+ return code
+
+ def CodeComplete(self, structname, var_name):
+ self._index = "i"
+ tmp = self._entry.CodeComplete(structname, self._entry.GetVarName(var_name))
+ # skip the whole loop if there is nothing to check
+ if not tmp:
+ return []
+
+ translate = self.GetTranslation({"structname": structname})
+ code = [
+ "{",
+ " int i;",
+ " for (i = 0; i < %(structname)s->%(name)s_length; ++i) {",
+ ]
+
+ code = TranslateList(code, translate)
+
+ code += [" " + x for x in tmp]
+
+ code += [" }", "}"]
+
+ return code
+
+ def CodeUnmarshal(self, buf, tag_name, var_name, _var_len):
+ translate = self.GetTranslation(
+ {
+ "var": var_name,
+ "buf": buf,
+ "tag": tag_name,
+ "init": self._entry.GetInitializer(),
+ }
+ )
+ code = [
+ "if (%(var)s->%(name)s_length >= %(var)s->%(name)s_num_allocated &&",
+ " %(parent_name)s_%(name)s_expand_to_hold_more(%(var)s) < 0) {",
+ ' puts("HEY NOW");',
+ " return (-1);",
+ "}",
+ ]
+
+ # the unmarshal code directly returns
+ code = TranslateList(code, translate)
+
+ self._index = "%(var)s->%(name)s_length" % translate
+ code += self._entry.CodeUnmarshal(
+ buf,
+ tag_name,
+ self._entry.GetVarName(var_name),
+ self._entry.GetVarLen(var_name),
+ )
+
+ code += ["++%(var)s->%(name)s_length;" % translate]
+
+ return code
+
+ def CodeMarshal(self, buf, tag_name, var_name, _var_len):
+ code = ["{", " int i;", " for (i = 0; i < %(var)s->%(name)s_length; ++i) {"]
+
+ self._index = "i"
+ code += self._entry.CodeMarshal(
+ buf,
+ tag_name,
+ self._entry.GetVarName(var_name),
+ self._entry.GetVarLen(var_name),
+ )
+ code += [" }", "}"]
+
+ code = "\n".join(code) % self.GetTranslation({"var": var_name})
+
+ return code.split("\n")
+
+ def CodeClear(self, structname):
+ translate = self.GetTranslation({"structname": structname})
+ codearrayfree = self._entry.CodeArrayFree(
+ "%(structname)s->%(name)s_data[i]"
+ % self.GetTranslation({"structname": structname})
+ )
+
+ code = ["if (%(structname)s->%(name)s_set == 1) {"]
+
+ if codearrayfree:
+ code += [
+ " int i;",
+ " for (i = 0; i < %(structname)s->%(name)s_length; ++i) {",
+ ]
+
+ code = TranslateList(code, translate)
+
+ if codearrayfree:
+ code += [" " + x for x in codearrayfree]
+ code += [" }"]
+
+ code += TranslateList(
+ [
+ " free(%(structname)s->%(name)s_data);",
+ " %(structname)s->%(name)s_data = NULL;",
+ " %(structname)s->%(name)s_set = 0;",
+ " %(structname)s->%(name)s_length = 0;",
+ " %(structname)s->%(name)s_num_allocated = 0;",
+ "}",
+ ],
+ translate,
+ )
+
+ return code
+
+ def CodeInitialize(self, name):
+ code = [
+ "%s->%s_data = NULL;" % (name, self._name),
+ "%s->%s_length = 0;" % (name, self._name),
+ "%s->%s_num_allocated = 0;" % (name, self._name),
+ ]
+ return code
+
+ def CodeFree(self, structname):
+ code = self.CodeClear(structname)
+
+ code += TranslateList(
+ ["free(%(structname)s->%(name)s_data);"],
+ self.GetTranslation({"structname": structname}),
+ )
+
+ return code
+
+ def Declaration(self):
+ dcl = [
+ "%s *%s_data;" % (self._ctype, self._name),
+ "int %s_length;" % self._name,
+ "int %s_num_allocated;" % self._name,
+ ]
+
+ return dcl
+
+
+def NormalizeLine(line):
+
+ line = CPPCOMMENT_RE.sub("", line)
+ line = line.strip()
+ line = WHITESPACE_RE.sub(" ", line)
+
+ return line
+
+
+ENTRY_NAME_RE = re.compile(r"(?P<name>[^\[\]]+)(\[(?P<fixed_length>.*)\])?")
+ENTRY_TAG_NUMBER_RE = re.compile(r"(0x)?\d+", re.I)
+
+
+def ProcessOneEntry(factory, newstruct, entry):
+ optional = False
+ array = False
+ entry_type = ""
+ name = ""
+ tag = ""
+ tag_set = None
+ separator = ""
+ fixed_length = ""
+
+ for token in entry.split(" "):
+ if not entry_type:
+ if not optional and token == "optional":
+ optional = True
+ continue
+
+ if not array and token == "array":
+ array = True
+ continue
+
+ if not entry_type:
+ entry_type = token
+ continue
+
+ if not name:
+ res = ENTRY_NAME_RE.match(token)
+ if not res:
+ raise RpcGenError(
+ r"""Cannot parse name: "%s" around line %d""" % (entry, LINE_COUNT)
+ )
+ name = res.group("name")
+ fixed_length = res.group("fixed_length")
+ continue
+
+ if not separator:
+ separator = token
+ if separator != "=":
+ raise RpcGenError(
+ r'''Expected "=" after name "%s" got "%s"''' % (name, token)
+ )
+ continue
+
+ if not tag_set:
+ tag_set = 1
+ if not ENTRY_TAG_NUMBER_RE.match(token):
+ raise RpcGenError(r'''Expected tag number: "%s"''' % (entry))
+ tag = int(token, 0)
+ continue
+
+ raise RpcGenError(r'''Cannot parse "%s"''' % (entry))
+
+ if not tag_set:
+ raise RpcGenError(r'''Need tag number: "%s"''' % (entry))
+
+ # Create the right entry
+ if entry_type == "bytes":
+ if fixed_length:
+ newentry = factory.EntryBytes(entry_type, name, tag, fixed_length)
+ else:
+ newentry = factory.EntryVarBytes(entry_type, name, tag)
+ elif entry_type == "int" and not fixed_length:
+ newentry = factory.EntryInt(entry_type, name, tag)
+ elif entry_type == "int64" and not fixed_length:
+ newentry = factory.EntryInt(entry_type, name, tag, bits=64)
+ elif entry_type == "string" and not fixed_length:
+ newentry = factory.EntryString(entry_type, name, tag)
+ else:
+ res = STRUCT_REF_RE.match(entry_type)
+ if res:
+ # References another struct defined in our file
+ newentry = factory.EntryStruct(entry_type, name, tag, res.group("name"))
+ else:
+ raise RpcGenError('Bad type: "%s" in "%s"' % (entry_type, entry))
+
+ structs = []
+
+ if optional:
+ newentry.MakeOptional()
+ if array:
+ newentry.MakeArray()
+
+ newentry.SetStruct(newstruct)
+ newentry.SetLineCount(LINE_COUNT)
+ newentry.Verify()
+
+ if array:
+ # We need to encapsulate this entry into a struct
+ newentry = factory.EntryArray(newentry)
+ newentry.SetStruct(newstruct)
+ newentry.SetLineCount(LINE_COUNT)
+ newentry.MakeArray()
+
+ newstruct.AddEntry(newentry)
+
+ return structs
+
+
+def ProcessStruct(factory, data):
+ tokens = data.split(" ")
+
+ # First three tokens are: 'struct' 'name' '{'
+ newstruct = factory.Struct(tokens[1])
+
+ inside = " ".join(tokens[3:-1])
+
+ tokens = inside.split(";")
+
+ structs = []
+
+ for entry in tokens:
+ entry = NormalizeLine(entry)
+ if not entry:
+ continue
+
+ # It's possible that new structs get defined in here
+ structs.extend(ProcessOneEntry(factory, newstruct, entry))
+
+ structs.append(newstruct)
+ return structs
+
+
+C_COMMENT_START = "/*"
+C_COMMENT_END = "*/"
+
+C_COMMENT_START_RE = re.compile(re.escape(C_COMMENT_START))
+C_COMMENT_END_RE = re.compile(re.escape(C_COMMENT_END))
+
+C_COMMENT_START_SUB_RE = re.compile(r"%s.*$" % (re.escape(C_COMMENT_START)))
+C_COMMENT_END_SUB_RE = re.compile(r"%s.*$" % (re.escape(C_COMMENT_END)))
+
+C_MULTILINE_COMMENT_SUB_RE = re.compile(
+ r"%s.*?%s" % (re.escape(C_COMMENT_START), re.escape(C_COMMENT_END))
+)
+CPP_CONDITIONAL_BLOCK_RE = re.compile(r"#(if( |def)|endif)")
+INCLUDE_RE = re.compile(r'#include (".+"|<.+>)')
+
+
+def GetNextStruct(filep):
+ global CPP_DIRECT
+ global LINE_COUNT
+
+ got_struct = False
+ have_c_comment = False
+
+ data = ""
+
+ while True:
+ line = filep.readline()
+ if not line:
+ break
+
+ LINE_COUNT += 1
+ line = line[:-1]
+
+ if not have_c_comment and C_COMMENT_START_RE.search(line):
+ if C_MULTILINE_COMMENT_SUB_RE.search(line):
+ line = C_MULTILINE_COMMENT_SUB_RE.sub("", line)
+ else:
+ line = C_COMMENT_START_SUB_RE.sub("", line)
+ have_c_comment = True
+
+ if have_c_comment:
+ if not C_COMMENT_END_RE.search(line):
+ continue
+ have_c_comment = False
+ line = C_COMMENT_END_SUB_RE.sub("", line)
+
+ line = NormalizeLine(line)
+
+ if not line:
+ continue
+
+ if not got_struct:
+ if INCLUDE_RE.match(line):
+ CPP_DIRECT.append(line)
+ elif CPP_CONDITIONAL_BLOCK_RE.match(line):
+ CPP_DIRECT.append(line)
+ elif PREPROCESSOR_DEF_RE.match(line):
+ HEADER_DIRECT.append(line)
+ elif not STRUCT_DEF_RE.match(line):
+ raise RpcGenError("Missing struct on line %d: %s" % (LINE_COUNT, line))
+ else:
+ got_struct = True
+ data += line
+ continue
+
+ # We are inside the struct
+ tokens = line.split("}")
+ if len(tokens) == 1:
+ data += " " + line
+ continue
+
+ if tokens[1]:
+ raise RpcGenError("Trailing garbage after struct on line %d" % LINE_COUNT)
+
+ # We found the end of the struct
+ data += " %s}" % tokens[0]
+ break
+
+ # Remove any comments, that might be in there
+ data = re.sub(r"/\*.*\*/", "", data)
+
+ return data
+
+
+def Parse(factory, filep):
+ """
+ Parses the input file and returns C code and corresponding header file.
+ """
+
+ entities = []
+
+ while 1:
+ # Just gets the whole struct nicely formatted
+ data = GetNextStruct(filep)
+
+ if not data:
+ break
+
+ entities.extend(ProcessStruct(factory, data))
+
+ return entities
+
+
+class CCodeGenerator(object):
+ def __init__(self):
+ pass
+
+ @staticmethod
+ def GuardName(name):
+ # Use the complete provided path to the input file, with all
+ # non-identifier characters replaced with underscores, to
+ # reduce the chance of a collision between guard macros.
+ return "EVENT_RPCOUT_%s_" % (NONIDENT_RE.sub("_", name).upper())
+
+ def HeaderPreamble(self, name):
+ guard = self.GuardName(name)
+ pre = """
+/*
+ * Automatically generated from %s
+ */
+
+#ifndef %s
+#define %s
+
+""" % (
+ name,
+ guard,
+ guard,
+ )
+
+ if HEADER_DIRECT:
+ for statement in HEADER_DIRECT:
+ pre += "%s\n" % statement
+ pre += "\n"
+
+ pre += """
+#include <event2/util.h> /* for ev_uint*_t */
+#include <event2/rpc.h>
+"""
+
+ return pre
+
+ def HeaderPostamble(self, name):
+ guard = self.GuardName(name)
+ return "#endif /* %s */" % (guard)
+
+ @staticmethod
+ def BodyPreamble(name, header_file):
+ global _NAME
+ global _VERSION
+
+ slash = header_file.rfind("/")
+ if slash != -1:
+ header_file = header_file[slash + 1 :]
+
+ pre = """
+/*
+ * Automatically generated from %(name)s
+ * by %(script_name)s/%(script_version)s. DO NOT EDIT THIS FILE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <event2/event-config.h>
+#include <event2/event.h>
+#include <event2/buffer.h>
+#include <event2/tag.h>
+
+#if defined(EVENT__HAVE___func__)
+# ifndef __func__
+# define __func__ __func__
+# endif
+#elif defined(EVENT__HAVE___FUNCTION__)
+# define __func__ __FUNCTION__
+#else
+# define __func__ __FILE__
+#endif
+
+""" % {
+ "name": name,
+ "script_name": _NAME,
+ "script_version": _VERSION,
+ }
+
+ for statement in CPP_DIRECT:
+ pre += "%s\n" % statement
+
+ pre += '\n#include "%s"\n\n' % header_file
+
+ pre += "void event_warn(const char *fmt, ...);\n"
+ pre += "void event_warnx(const char *fmt, ...);\n\n"
+
+ return pre
+
+ @staticmethod
+ def HeaderFilename(filename):
+ return ".".join(filename.split(".")[:-1]) + ".h"
+
+ @staticmethod
+ def CodeFilename(filename):
+ return ".".join(filename.split(".")[:-1]) + ".gen.c"
+
+ @staticmethod
+ def Struct(name):
+ return StructCCode(name)
+
+ @staticmethod
+ def EntryBytes(entry_type, name, tag, fixed_length):
+ return EntryBytes(entry_type, name, tag, fixed_length)
+
+ @staticmethod
+ def EntryVarBytes(entry_type, name, tag):
+ return EntryVarBytes(entry_type, name, tag)
+
+ @staticmethod
+ def EntryInt(entry_type, name, tag, bits=32):
+ return EntryInt(entry_type, name, tag, bits)
+
+ @staticmethod
+ def EntryString(entry_type, name, tag):
+ return EntryString(entry_type, name, tag)
+
+ @staticmethod
+ def EntryStruct(entry_type, name, tag, struct_name):
+ return EntryStruct(entry_type, name, tag, struct_name)
+
+ @staticmethod
+ def EntryArray(entry):
+ return EntryArray(entry)
+
+
+class CommandLine(object):
+ def __init__(self, argv=None):
+ """Initialize a command-line to launch event_rpcgen, as if
+ from a command-line with CommandLine(sys.argv). If you're
+ calling this directly, remember to provide a dummy value
+ for sys.argv[0]
+ """
+ global QUIETLY
+
+ self.filename = None
+ self.header_file = None
+ self.impl_file = None
+ self.factory = CCodeGenerator()
+
+ parser = argparse.ArgumentParser(
+ usage="%(prog)s [options] rpc-file [[h-file] c-file]"
+ )
+ parser.add_argument("--quiet", action="store_true", default=False)
+ parser.add_argument("rpc_file", type=argparse.FileType("r"))
+
+ args, extra_args = parser.parse_known_args(args=argv)
+
+ QUIETLY = args.quiet
+
+ if extra_args:
+ if len(extra_args) == 1:
+ self.impl_file = extra_args[0].replace("\\", "/")
+ elif len(extra_args) == 2:
+ self.header_file = extra_args[0].replace("\\", "/")
+ self.impl_file = extra_args[1].replace("\\", "/")
+ else:
+ parser.error("Spurious arguments provided")
+
+ self.rpc_file = args.rpc_file
+
+ if not self.impl_file:
+ self.impl_file = self.factory.CodeFilename(self.rpc_file.name)
+
+ if not self.header_file:
+ self.header_file = self.factory.HeaderFilename(self.impl_file)
+
+ if not self.impl_file.endswith(".c"):
+ parser.error("can only generate C implementation files")
+ if not self.header_file.endswith(".h"):
+ parser.error("can only generate C header files")
+
+ def run(self):
+ filename = self.rpc_file.name
+ header_file = self.header_file
+ impl_file = self.impl_file
+ factory = self.factory
+
+ declare('Reading "%s"' % filename)
+
+ with self.rpc_file:
+ entities = Parse(factory, self.rpc_file)
+
+ declare('... creating "%s"' % header_file)
+ with open(header_file, "w") as header_fp:
+ header_fp.write(factory.HeaderPreamble(filename))
+
+ # Create forward declarations: allows other structs to reference
+ # each other
+ for entry in entities:
+ entry.PrintForwardDeclaration(header_fp)
+ header_fp.write("\n")
+
+ for entry in entities:
+ entry.PrintTags(header_fp)
+ entry.PrintDeclaration(header_fp)
+ header_fp.write(factory.HeaderPostamble(filename))
+
+ declare('... creating "%s"' % impl_file)
+ with open(impl_file, "w") as impl_fp:
+ impl_fp.write(factory.BodyPreamble(filename, header_file))
+ for entry in entities:
+ entry.PrintCode(impl_fp)
+
+
+def main(argv=None):
+ try:
+ CommandLine(argv=argv).run()
+ return 0
+ except RpcGenError as e:
+ sys.stderr.write(e)
+ except EnvironmentError as e:
+ if e.filename and e.strerror:
+ sys.stderr.write("%s: %s" % (e.filename, e.strerror))
+ elif e.strerror:
+ sys.stderr.write(e.strerror)
+ else:
+ raise
+ return 1
+
+
+if __name__ == "__main__":
+ sys.exit(main(argv=sys.argv[1:]))