From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../src/third_party/libevent/event_rpcgen.py | 1925 ++++++++++++++++++++ 1 file changed, 1925 insertions(+) create mode 100755 ipc/chromium/src/third_party/libevent/event_rpcgen.py (limited to 'ipc/chromium/src/third_party/libevent/event_rpcgen.py') 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 +# 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[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[^\[\]]+)(\[(?P.*)\])?") +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 /* for ev_uint*_t */ +#include +""" + + 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 +#include +#include +#include +#include +#include +#include + +#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:])) -- cgit v1.2.3