michael@0: #!/usr/bin/env python2 michael@0: # michael@0: # Copyright (c) 2005-2007 Niels Provos michael@0: # Copyright (c) 2007-2012 Niels Provos and Nick Mathewson michael@0: # All rights reserved. michael@0: # michael@0: # Generates marshaling code based on libevent. michael@0: michael@0: # TODO: michael@0: # 1) use optparse to allow the strategy shell to parse options, and michael@0: # to allow the instantiated factory (for the specific output language) michael@0: # to parse remaining options michael@0: # 2) move the globals into a class that manages execution (including the michael@0: # progress outputs that space stderr at the moment) michael@0: # 3) emit other languages michael@0: michael@0: import sys michael@0: import re michael@0: michael@0: _NAME = "event_rpcgen.py" michael@0: _VERSION = "0.1" michael@0: michael@0: # Globals michael@0: line_count = 0 michael@0: michael@0: white = re.compile(r'\s+') michael@0: cppcomment = re.compile(r'\/\/.*$') michael@0: nonident = re.compile(r'[^a-zA-Z0-9_]') michael@0: structref = re.compile(r'^struct\[([a-zA-Z_][a-zA-Z0-9_]*)\]$') michael@0: structdef = re.compile(r'^struct +[a-zA-Z_][a-zA-Z0-9_]* *{$') michael@0: michael@0: headerdirect = [] michael@0: cppdirect = [] michael@0: michael@0: def TranslateList(mylist, mydict): michael@0: return map(lambda x: x % mydict, mylist) michael@0: michael@0: # Exception class for parse errors michael@0: class RpcGenError(Exception): michael@0: def __init__(self, why): michael@0: self.why = why michael@0: def __str__(self): michael@0: return str(self.why) michael@0: michael@0: # Holds everything that makes a struct michael@0: class Struct: michael@0: def __init__(self, name): michael@0: self._name = name michael@0: self._entries = [] michael@0: self._tags = {} michael@0: print >>sys.stderr, ' Created struct: %s' % name michael@0: michael@0: def AddEntry(self, entry): michael@0: if self._tags.has_key(entry.Tag()): michael@0: raise RpcGenError( michael@0: 'Entry "%s" duplicates tag number %d from "%s" ' michael@0: 'around line %d' % (entry.Name(), entry.Tag(), michael@0: self._tags[entry.Tag()], line_count)) michael@0: self._entries.append(entry) michael@0: self._tags[entry.Tag()] = entry.Name() michael@0: print >>sys.stderr, ' Added entry: %s' % entry.Name() michael@0: michael@0: def Name(self): michael@0: return self._name michael@0: michael@0: def EntryTagName(self, entry): michael@0: """Creates the name inside an enumeration for distinguishing data michael@0: types.""" michael@0: name = "%s_%s" % (self._name, entry.Name()) michael@0: return name.upper() michael@0: michael@0: def PrintIndented(self, file, ident, code): michael@0: """Takes an array, add indentation to each entry and prints it.""" michael@0: for entry in code: michael@0: print >>file, '%s%s' % (ident, entry) michael@0: michael@0: class StructCCode(Struct): michael@0: """ Knows how to generate C code for a struct """ michael@0: michael@0: def __init__(self, name): michael@0: Struct.__init__(self, name) michael@0: michael@0: def PrintTags(self, file): michael@0: """Prints the tag definitions for a structure.""" michael@0: print >>file, '/* Tag definition for %s */' % self._name michael@0: print >>file, 'enum %s_ {' % self._name.lower() michael@0: for entry in self._entries: michael@0: print >>file, ' %s=%d,' % (self.EntryTagName(entry), michael@0: entry.Tag()) michael@0: print >>file, ' %s_MAX_TAGS' % (self._name.upper()) michael@0: print >>file, '};\n' michael@0: michael@0: def PrintForwardDeclaration(self, file): michael@0: print >>file, 'struct %s;' % self._name michael@0: michael@0: def PrintDeclaration(self, file): michael@0: print >>file, '/* Structure declaration for %s */' % self._name michael@0: print >>file, 'struct %s_access_ {' % self._name michael@0: for entry in self._entries: michael@0: dcl = entry.AssignDeclaration('(*%s_assign)' % entry.Name()) michael@0: dcl.extend( michael@0: entry.GetDeclaration('(*%s_get)' % entry.Name())) michael@0: if entry.Array(): michael@0: dcl.extend( michael@0: entry.AddDeclaration('(*%s_add)' % entry.Name())) michael@0: self.PrintIndented(file, ' ', dcl) michael@0: print >>file, '};\n' michael@0: michael@0: print >>file, 'struct %s {' % self._name michael@0: print >>file, ' struct %s_access_ *base;\n' % self._name michael@0: for entry in self._entries: michael@0: dcl = entry.Declaration() michael@0: self.PrintIndented(file, ' ', dcl) michael@0: print >>file, '' michael@0: for entry in self._entries: michael@0: print >>file, ' ev_uint8_t %s_set;' % entry.Name() michael@0: print >>file, '};\n' michael@0: michael@0: print >>file, \ michael@0: """struct %(name)s *%(name)s_new(void); michael@0: struct %(name)s *%(name)s_new_with_arg(void *); michael@0: void %(name)s_free(struct %(name)s *); michael@0: void %(name)s_clear(struct %(name)s *); michael@0: void %(name)s_marshal(struct evbuffer *, const struct %(name)s *); michael@0: int %(name)s_unmarshal(struct %(name)s *, struct evbuffer *); michael@0: int %(name)s_complete(struct %(name)s *); michael@0: void evtag_marshal_%(name)s(struct evbuffer *, ev_uint32_t, michael@0: const struct %(name)s *); michael@0: int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t, michael@0: struct %(name)s *);""" % { 'name' : self._name } michael@0: michael@0: michael@0: # Write a setting function of every variable michael@0: for entry in self._entries: michael@0: self.PrintIndented(file, '', entry.AssignDeclaration( michael@0: entry.AssignFuncName())) michael@0: self.PrintIndented(file, '', entry.GetDeclaration( michael@0: entry.GetFuncName())) michael@0: if entry.Array(): michael@0: self.PrintIndented(file, '', entry.AddDeclaration( michael@0: entry.AddFuncName())) michael@0: michael@0: print >>file, '/* --- %s done --- */\n' % self._name michael@0: michael@0: def PrintCode(self, file): michael@0: print >>file, ('/*\n' michael@0: ' * Implementation of %s\n' michael@0: ' */\n') % self._name michael@0: michael@0: print >>file, \ michael@0: 'static struct %(name)s_access_ __%(name)s_base = {' % \ michael@0: { 'name' : self._name } michael@0: for entry in self._entries: michael@0: self.PrintIndented(file, ' ', entry.CodeBase()) michael@0: print >>file, '};\n' michael@0: michael@0: # Creation michael@0: print >>file, ( michael@0: 'struct %(name)s *\n' michael@0: '%(name)s_new(void)\n' michael@0: '{\n' michael@0: ' return %(name)s_new_with_arg(NULL);\n' michael@0: '}\n' michael@0: '\n' michael@0: 'struct %(name)s *\n' michael@0: '%(name)s_new_with_arg(void *unused)\n' michael@0: '{\n' michael@0: ' struct %(name)s *tmp;\n' michael@0: ' if ((tmp = malloc(sizeof(struct %(name)s))) == NULL) {\n' michael@0: ' event_warn("%%s: malloc", __func__);\n' michael@0: ' return (NULL);\n' michael@0: ' }\n' michael@0: ' tmp->base = &__%(name)s_base;\n') % { 'name' : self._name } michael@0: michael@0: for entry in self._entries: michael@0: self.PrintIndented(file, ' ', entry.CodeInitialize('tmp')) michael@0: print >>file, ' tmp->%s_set = 0;\n' % entry.Name() michael@0: michael@0: print >>file, ( michael@0: ' return (tmp);\n' michael@0: '}\n') michael@0: michael@0: # Adding michael@0: for entry in self._entries: michael@0: if entry.Array(): michael@0: self.PrintIndented(file, '', entry.CodeAdd()) michael@0: print >>file, '' michael@0: michael@0: # Assigning michael@0: for entry in self._entries: michael@0: self.PrintIndented(file, '', entry.CodeAssign()) michael@0: print >>file, '' michael@0: michael@0: # Getting michael@0: for entry in self._entries: michael@0: self.PrintIndented(file, '', entry.CodeGet()) michael@0: print >>file, '' michael@0: michael@0: # Clearing michael@0: print >>file, ( 'void\n' michael@0: '%(name)s_clear(struct %(name)s *tmp)\n' michael@0: '{' michael@0: ) % { 'name' : self._name } michael@0: for entry in self._entries: michael@0: self.PrintIndented(file, ' ', entry.CodeClear('tmp')) michael@0: michael@0: print >>file, '}\n' michael@0: michael@0: # Freeing michael@0: print >>file, ( 'void\n' michael@0: '%(name)s_free(struct %(name)s *tmp)\n' michael@0: '{' michael@0: ) % { 'name' : self._name } michael@0: michael@0: for entry in self._entries: michael@0: self.PrintIndented(file, ' ', entry.CodeFree('tmp')) michael@0: michael@0: print >>file, (' free(tmp);\n' michael@0: '}\n') michael@0: michael@0: # Marshaling michael@0: print >>file, ('void\n' michael@0: '%(name)s_marshal(struct evbuffer *evbuf, ' michael@0: 'const struct %(name)s *tmp)' michael@0: '{') % { 'name' : self._name } michael@0: for entry in self._entries: michael@0: indent = ' ' michael@0: # Optional entries do not have to be set michael@0: if entry.Optional(): michael@0: indent += ' ' michael@0: print >>file, ' if (tmp->%s_set) {' % entry.Name() michael@0: self.PrintIndented( michael@0: file, indent, michael@0: entry.CodeMarshal('evbuf', self.EntryTagName(entry), michael@0: entry.GetVarName('tmp'), michael@0: entry.GetVarLen('tmp'))) michael@0: if entry.Optional(): michael@0: print >>file, ' }' michael@0: michael@0: print >>file, '}\n' michael@0: michael@0: # Unmarshaling michael@0: print >>file, ('int\n' michael@0: '%(name)s_unmarshal(struct %(name)s *tmp, ' michael@0: ' struct evbuffer *evbuf)\n' michael@0: '{\n' michael@0: ' ev_uint32_t tag;\n' michael@0: ' while (evbuffer_get_length(evbuf) > 0) {\n' michael@0: ' if (evtag_peek(evbuf, &tag) == -1)\n' michael@0: ' return (-1);\n' michael@0: ' switch (tag) {\n' michael@0: ) % { 'name' : self._name } michael@0: for entry in self._entries: michael@0: print >>file, ' case %s:\n' % self.EntryTagName(entry) michael@0: if not entry.Array(): michael@0: print >>file, ( michael@0: ' if (tmp->%s_set)\n' michael@0: ' return (-1);' michael@0: ) % (entry.Name()) michael@0: michael@0: self.PrintIndented( michael@0: file, ' ', michael@0: entry.CodeUnmarshal('evbuf', michael@0: self.EntryTagName(entry), michael@0: entry.GetVarName('tmp'), michael@0: entry.GetVarLen('tmp'))) michael@0: michael@0: print >>file, ( ' tmp->%s_set = 1;\n' % entry.Name() + michael@0: ' break;\n' ) michael@0: print >>file, ( ' default:\n' michael@0: ' return -1;\n' michael@0: ' }\n' michael@0: ' }\n' ) michael@0: # Check if it was decoded completely michael@0: print >>file, ( ' if (%(name)s_complete(tmp) == -1)\n' michael@0: ' return (-1);' michael@0: ) % { 'name' : self._name } michael@0: michael@0: # Successfully decoded michael@0: print >>file, ( ' return (0);\n' michael@0: '}\n') michael@0: michael@0: # Checking if a structure has all the required data michael@0: print >>file, ( michael@0: 'int\n' michael@0: '%(name)s_complete(struct %(name)s *msg)\n' michael@0: '{' ) % { 'name' : self._name } michael@0: for entry in self._entries: michael@0: if not entry.Optional(): michael@0: code = [ michael@0: 'if (!msg->%(name)s_set)', michael@0: ' return (-1);' ] michael@0: code = TranslateList(code, entry.GetTranslation()) michael@0: self.PrintIndented( michael@0: file, ' ', code) michael@0: michael@0: self.PrintIndented( michael@0: file, ' ', michael@0: entry.CodeComplete('msg', entry.GetVarName('msg'))) michael@0: print >>file, ( michael@0: ' return (0);\n' michael@0: '}\n' ) michael@0: michael@0: # Complete message unmarshaling michael@0: print >>file, ( michael@0: 'int\n' michael@0: 'evtag_unmarshal_%(name)s(struct evbuffer *evbuf, ' michael@0: 'ev_uint32_t need_tag, struct %(name)s *msg)\n' michael@0: '{\n' michael@0: ' ev_uint32_t tag;\n' michael@0: ' int res = -1;\n' michael@0: '\n' michael@0: ' struct evbuffer *tmp = evbuffer_new();\n' michael@0: '\n' michael@0: ' if (evtag_unmarshal(evbuf, &tag, tmp) == -1' michael@0: ' || tag != need_tag)\n' michael@0: ' goto error;\n' michael@0: '\n' michael@0: ' if (%(name)s_unmarshal(msg, tmp) == -1)\n' michael@0: ' goto error;\n' michael@0: '\n' michael@0: ' res = 0;\n' michael@0: '\n' michael@0: ' error:\n' michael@0: ' evbuffer_free(tmp);\n' michael@0: ' return (res);\n' michael@0: '}\n' ) % { 'name' : self._name } michael@0: michael@0: # Complete message marshaling michael@0: print >>file, ( michael@0: 'void\n' michael@0: 'evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag, ' michael@0: 'const struct %(name)s *msg)\n' michael@0: '{\n' michael@0: ' struct evbuffer *_buf = evbuffer_new();\n' michael@0: ' assert(_buf != NULL);\n' michael@0: ' %(name)s_marshal(_buf, msg);\n' michael@0: ' evtag_marshal_buffer(evbuf, tag, _buf);\n ' michael@0: ' evbuffer_free(_buf);\n' michael@0: '}\n' ) % { 'name' : self._name } michael@0: michael@0: class Entry: michael@0: def __init__(self, type, name, tag): michael@0: self._type = type michael@0: self._name = name michael@0: self._tag = int(tag) michael@0: self._ctype = type michael@0: self._optional = 0 michael@0: self._can_be_array = 0 michael@0: self._array = 0 michael@0: self._line_count = -1 michael@0: self._struct = None michael@0: self._refname = None michael@0: michael@0: self._optpointer = True michael@0: self._optaddarg = True michael@0: michael@0: def GetInitializer(self): michael@0: assert 0, "Entry does not provide initializer" michael@0: michael@0: def SetStruct(self, struct): michael@0: self._struct = struct michael@0: michael@0: def LineCount(self): michael@0: assert self._line_count != -1 michael@0: return self._line_count michael@0: michael@0: def SetLineCount(self, number): michael@0: self._line_count = number michael@0: michael@0: def Array(self): michael@0: return self._array michael@0: michael@0: def Optional(self): michael@0: return self._optional michael@0: michael@0: def Tag(self): michael@0: return self._tag michael@0: michael@0: def Name(self): michael@0: return self._name michael@0: michael@0: def Type(self): michael@0: return self._type michael@0: michael@0: def MakeArray(self, yes=1): michael@0: self._array = yes michael@0: michael@0: def MakeOptional(self): michael@0: self._optional = 1 michael@0: michael@0: def Verify(self): michael@0: if self.Array() and not self._can_be_array: michael@0: raise RpcGenError( michael@0: 'Entry "%s" cannot be created as an array ' michael@0: 'around line %d' % (self._name, self.LineCount())) michael@0: if not self._struct: michael@0: raise RpcGenError( michael@0: 'Entry "%s" does not know which struct it belongs to ' michael@0: 'around line %d' % (self._name, self.LineCount())) michael@0: if self._optional and self._array: michael@0: raise RpcGenError( michael@0: 'Entry "%s" has illegal combination of optional and array ' michael@0: 'around line %d' % (self._name, self.LineCount())) michael@0: michael@0: def GetTranslation(self, extradict = {}): michael@0: mapping = { michael@0: "parent_name" : self._struct.Name(), michael@0: "name" : self._name, michael@0: "ctype" : self._ctype, michael@0: "refname" : self._refname, michael@0: "optpointer" : self._optpointer and "*" or "", michael@0: "optreference" : self._optpointer and "&" or "", michael@0: "optaddarg" : michael@0: self._optaddarg and ", const %s value" % self._ctype or "" michael@0: } michael@0: for (k, v) in extradict.items(): michael@0: mapping[k] = v michael@0: michael@0: return mapping michael@0: michael@0: def GetVarName(self, var): michael@0: return '%(var)s->%(name)s_data' % self.GetTranslation({ 'var' : var }) michael@0: michael@0: def GetVarLen(self, var): michael@0: return 'sizeof(%s)' % self._ctype michael@0: michael@0: def GetFuncName(self): michael@0: return '%s_%s_get' % (self._struct.Name(), self._name) michael@0: michael@0: def GetDeclaration(self, funcname): michael@0: code = [ 'int %s(struct %s *, %s *);' % ( michael@0: funcname, self._struct.Name(), self._ctype ) ] michael@0: return code michael@0: michael@0: def CodeGet(self): michael@0: code = ( michael@0: 'int', michael@0: '%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, ' michael@0: '%(ctype)s *value)', michael@0: '{', michael@0: ' if (msg->%(name)s_set != 1)', michael@0: ' return (-1);', michael@0: ' *value = msg->%(name)s_data;', michael@0: ' return (0);', michael@0: '}' ) michael@0: code = '\n'.join(code) michael@0: code = code % self.GetTranslation() michael@0: return code.split('\n') michael@0: michael@0: def AssignFuncName(self): michael@0: return '%s_%s_assign' % (self._struct.Name(), self._name) michael@0: michael@0: def AddFuncName(self): michael@0: return '%s_%s_add' % (self._struct.Name(), self._name) michael@0: michael@0: def AssignDeclaration(self, funcname): michael@0: code = [ 'int %s(struct %s *, const %s);' % ( michael@0: funcname, self._struct.Name(), self._ctype ) ] michael@0: return code michael@0: michael@0: def CodeAssign(self): michael@0: code = [ 'int', michael@0: '%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,' michael@0: ' const %(ctype)s value)', michael@0: '{', michael@0: ' msg->%(name)s_set = 1;', michael@0: ' msg->%(name)s_data = value;', michael@0: ' return (0);', michael@0: '}' ] michael@0: code = '\n'.join(code) michael@0: code = code % self.GetTranslation() michael@0: return code.split('\n') michael@0: michael@0: def CodeClear(self, structname): michael@0: code = [ '%s->%s_set = 0;' % (structname, self.Name()) ] michael@0: michael@0: return code michael@0: michael@0: def CodeComplete(self, structname, var_name): michael@0: return [] michael@0: michael@0: def CodeFree(self, name): michael@0: return [] michael@0: michael@0: def CodeBase(self): michael@0: code = [ michael@0: '%(parent_name)s_%(name)s_assign,', michael@0: '%(parent_name)s_%(name)s_get,' michael@0: ] michael@0: if self.Array(): michael@0: code.append('%(parent_name)s_%(name)s_add,') michael@0: michael@0: code = '\n'.join(code) michael@0: code = code % self.GetTranslation() michael@0: return code.split('\n') michael@0: michael@0: class EntryBytes(Entry): michael@0: def __init__(self, type, name, tag, length): michael@0: # Init base class michael@0: Entry.__init__(self, type, name, tag) michael@0: michael@0: self._length = length michael@0: self._ctype = 'ev_uint8_t' michael@0: michael@0: def GetInitializer(self): michael@0: return "NULL" michael@0: michael@0: def GetVarLen(self, var): michael@0: return '(%s)' % self._length michael@0: michael@0: def CodeArrayAdd(self, varname, value): michael@0: # XXX: copy here michael@0: return [ '%(varname)s = NULL;' % { 'varname' : varname } ] michael@0: michael@0: def GetDeclaration(self, funcname): michael@0: code = [ 'int %s(struct %s *, %s **);' % ( michael@0: funcname, self._struct.Name(), self._ctype ) ] michael@0: return code michael@0: michael@0: def AssignDeclaration(self, funcname): michael@0: code = [ 'int %s(struct %s *, const %s *);' % ( michael@0: funcname, self._struct.Name(), self._ctype ) ] michael@0: return code michael@0: michael@0: def Declaration(self): michael@0: dcl = ['ev_uint8_t %s_data[%s];' % (self._name, self._length)] michael@0: michael@0: return dcl michael@0: michael@0: def CodeGet(self): michael@0: name = self._name michael@0: code = [ 'int', michael@0: '%s_%s_get(struct %s *msg, %s **value)' % ( michael@0: self._struct.Name(), name, michael@0: self._struct.Name(), self._ctype), michael@0: '{', michael@0: ' if (msg->%s_set != 1)' % name, michael@0: ' return (-1);', michael@0: ' *value = msg->%s_data;' % name, michael@0: ' return (0);', michael@0: '}' ] michael@0: return code michael@0: michael@0: def CodeAssign(self): michael@0: name = self._name michael@0: code = [ 'int', michael@0: '%s_%s_assign(struct %s *msg, const %s *value)' % ( michael@0: self._struct.Name(), name, michael@0: self._struct.Name(), self._ctype), michael@0: '{', michael@0: ' msg->%s_set = 1;' % name, michael@0: ' memcpy(msg->%s_data, value, %s);' % ( michael@0: name, self._length), michael@0: ' return (0);', michael@0: '}' ] michael@0: return code michael@0: michael@0: def CodeUnmarshal(self, buf, tag_name, var_name, var_len): michael@0: code = [ 'if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, ' michael@0: '%(var)s, %(varlen)s) == -1) {', michael@0: ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);', michael@0: ' return (-1);', michael@0: '}' michael@0: ] michael@0: return TranslateList(code, michael@0: self.GetTranslation({ michael@0: 'var' : var_name, michael@0: 'varlen' : var_len, michael@0: 'buf' : buf, michael@0: 'tag' : tag_name })) michael@0: michael@0: def CodeMarshal(self, buf, tag_name, var_name, var_len): michael@0: code = ['evtag_marshal(%s, %s, %s, %s);' % ( michael@0: buf, tag_name, var_name, var_len)] michael@0: return code michael@0: michael@0: def CodeClear(self, structname): michael@0: code = [ '%s->%s_set = 0;' % (structname, self.Name()), michael@0: 'memset(%s->%s_data, 0, sizeof(%s->%s_data));' % ( michael@0: structname, self._name, structname, self._name)] michael@0: michael@0: return code michael@0: michael@0: def CodeInitialize(self, name): michael@0: code = ['memset(%s->%s_data, 0, sizeof(%s->%s_data));' % ( michael@0: name, self._name, name, self._name)] michael@0: return code michael@0: michael@0: def Verify(self): michael@0: if not self._length: michael@0: raise RpcGenError( michael@0: 'Entry "%s" needs a length ' michael@0: 'around line %d' % (self._name, self.LineCount())) michael@0: michael@0: Entry.Verify(self) michael@0: michael@0: class EntryInt(Entry): michael@0: def __init__(self, type, name, tag, bits=32): michael@0: # Init base class michael@0: Entry.__init__(self, type, name, tag) michael@0: michael@0: self._can_be_array = 1 michael@0: if bits == 32: michael@0: self._ctype = 'ev_uint32_t' michael@0: self._marshal_type = 'int' michael@0: if bits == 64: michael@0: self._ctype = 'ev_uint64_t' michael@0: self._marshal_type = 'int64' michael@0: michael@0: def GetInitializer(self): michael@0: return "0" michael@0: michael@0: def CodeArrayFree(self, var): michael@0: return [] michael@0: michael@0: def CodeArrayAssign(self, varname, srcvar): michael@0: return [ '%(varname)s = %(srcvar)s;' % { 'varname' : varname, michael@0: 'srcvar' : srcvar } ] michael@0: michael@0: def CodeArrayAdd(self, varname, value): michael@0: """Returns a new entry of this type.""" michael@0: return [ '%(varname)s = %(value)s;' % { 'varname' : varname, michael@0: 'value' : value } ] michael@0: michael@0: def CodeUnmarshal(self, buf, tag_name, var_name, var_len): michael@0: code = [ michael@0: 'if (evtag_unmarshal_%(ma)s(%(buf)s, %(tag)s, &%(var)s) == -1) {', michael@0: ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);', michael@0: ' return (-1);', michael@0: '}' ] michael@0: code = '\n'.join(code) % self.GetTranslation({ michael@0: 'ma' : self._marshal_type, michael@0: 'buf' : buf, michael@0: 'tag' : tag_name, michael@0: 'var' : var_name }) michael@0: return code.split('\n') michael@0: michael@0: def CodeMarshal(self, buf, tag_name, var_name, var_len): michael@0: code = [ michael@0: 'evtag_marshal_%s(%s, %s, %s);' % ( michael@0: self._marshal_type, buf, tag_name, var_name)] michael@0: return code michael@0: michael@0: def Declaration(self): michael@0: dcl = ['%s %s_data;' % (self._ctype, self._name)] michael@0: michael@0: return dcl michael@0: michael@0: def CodeInitialize(self, name): michael@0: code = ['%s->%s_data = 0;' % (name, self._name)] michael@0: return code michael@0: michael@0: class EntryString(Entry): michael@0: def __init__(self, type, name, tag): michael@0: # Init base class michael@0: Entry.__init__(self, type, name, tag) michael@0: michael@0: self._can_be_array = 1 michael@0: self._ctype = 'char *' michael@0: michael@0: def GetInitializer(self): michael@0: return "NULL" michael@0: michael@0: def CodeArrayFree(self, varname): michael@0: code = [ michael@0: 'if (%(var)s != NULL) free(%(var)s);' ] michael@0: michael@0: return TranslateList(code, { 'var' : varname }) michael@0: michael@0: def CodeArrayAssign(self, varname, srcvar): michael@0: code = [ michael@0: 'if (%(var)s != NULL)', michael@0: ' free(%(var)s);', michael@0: '%(var)s = strdup(%(srcvar)s);', michael@0: 'if (%(var)s == NULL) {', michael@0: ' event_warnx("%%s: strdup", __func__);', michael@0: ' return (-1);', michael@0: '}' ] michael@0: michael@0: return TranslateList(code, { 'var' : varname, michael@0: 'srcvar' : srcvar }) michael@0: michael@0: def CodeArrayAdd(self, varname, value): michael@0: code = [ michael@0: 'if (%(value)s != NULL) {', michael@0: ' %(var)s = strdup(%(value)s);', michael@0: ' if (%(var)s == NULL) {', michael@0: ' goto error;', michael@0: ' }', michael@0: '} else {', michael@0: ' %(var)s = NULL;', michael@0: '}' ] michael@0: michael@0: return TranslateList(code, { 'var' : varname, michael@0: 'value' : value }) michael@0: michael@0: def GetVarLen(self, var): michael@0: return 'strlen(%s)' % self.GetVarName(var) michael@0: michael@0: def CodeMakeInitalize(self, varname): michael@0: return '%(varname)s = NULL;' % { 'varname' : varname } michael@0: michael@0: def CodeAssign(self): michael@0: name = self._name michael@0: code = """int michael@0: %(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, michael@0: const %(ctype)s value) michael@0: { michael@0: if (msg->%(name)s_data != NULL) michael@0: free(msg->%(name)s_data); michael@0: if ((msg->%(name)s_data = strdup(value)) == NULL) michael@0: return (-1); michael@0: msg->%(name)s_set = 1; michael@0: return (0); michael@0: }""" % self.GetTranslation() michael@0: michael@0: return code.split('\n') michael@0: michael@0: def CodeUnmarshal(self, buf, tag_name, var_name, var_len): michael@0: code = ['if (evtag_unmarshal_string(%(buf)s, %(tag)s, &%(var)s) == -1) {', michael@0: ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);', michael@0: ' return (-1);', michael@0: '}' michael@0: ] michael@0: code = '\n'.join(code) % self.GetTranslation({ michael@0: 'buf' : buf, michael@0: 'tag' : tag_name, michael@0: 'var' : var_name }) michael@0: return code.split('\n') michael@0: michael@0: def CodeMarshal(self, buf, tag_name, var_name, var_len): michael@0: code = ['evtag_marshal_string(%s, %s, %s);' % ( michael@0: buf, tag_name, var_name)] michael@0: return code michael@0: michael@0: def CodeClear(self, structname): michael@0: code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()), michael@0: ' free(%s->%s_data);' % (structname, self.Name()), michael@0: ' %s->%s_data = NULL;' % (structname, self.Name()), michael@0: ' %s->%s_set = 0;' % (structname, self.Name()), michael@0: '}' michael@0: ] michael@0: michael@0: return code michael@0: michael@0: def CodeInitialize(self, name): michael@0: code = ['%s->%s_data = NULL;' % (name, self._name)] michael@0: return code michael@0: michael@0: def CodeFree(self, name): michael@0: code = ['if (%s->%s_data != NULL)' % (name, self._name), michael@0: ' free (%s->%s_data);' % (name, self._name)] michael@0: michael@0: return code michael@0: michael@0: def Declaration(self): michael@0: dcl = ['char *%s_data;' % self._name] michael@0: michael@0: return dcl michael@0: michael@0: class EntryStruct(Entry): michael@0: def __init__(self, type, name, tag, refname): michael@0: # Init base class michael@0: Entry.__init__(self, type, name, tag) michael@0: michael@0: self._optpointer = False michael@0: self._can_be_array = 1 michael@0: self._refname = refname michael@0: self._ctype = 'struct %s*' % refname michael@0: self._optaddarg = False michael@0: michael@0: def GetInitializer(self): michael@0: return "NULL" michael@0: michael@0: def GetVarLen(self, var): michael@0: return '-1' michael@0: michael@0: def CodeArrayAdd(self, varname, value): michael@0: code = [ michael@0: '%(varname)s = %(refname)s_new();', michael@0: 'if (%(varname)s == NULL)', michael@0: ' goto error;' ] michael@0: michael@0: return TranslateList(code, self.GetTranslation({ 'varname' : varname })) michael@0: michael@0: def CodeArrayFree(self, var): michael@0: code = [ '%(refname)s_free(%(var)s);' % self.GetTranslation( michael@0: { 'var' : var }) ] michael@0: return code michael@0: michael@0: def CodeArrayAssign(self, var, srcvar): michael@0: code = [ michael@0: 'int had_error = 0;', michael@0: 'struct evbuffer *tmp = NULL;', michael@0: '%(refname)s_clear(%(var)s);', michael@0: 'if ((tmp = evbuffer_new()) == NULL) {', michael@0: ' event_warn("%%s: evbuffer_new()", __func__);', michael@0: ' had_error = 1;', michael@0: ' goto done;', michael@0: '}', michael@0: '%(refname)s_marshal(tmp, %(srcvar)s);', michael@0: 'if (%(refname)s_unmarshal(%(var)s, tmp) == -1) {', michael@0: ' event_warnx("%%s: %(refname)s_unmarshal", __func__);', michael@0: ' had_error = 1;', michael@0: ' goto done;', michael@0: '}', michael@0: 'done:' michael@0: 'if (tmp != NULL)', michael@0: ' evbuffer_free(tmp);', michael@0: 'if (had_error) {', michael@0: ' %(refname)s_clear(%(var)s);', michael@0: ' return (-1);', michael@0: '}' ] michael@0: michael@0: return TranslateList(code, self.GetTranslation({ michael@0: 'var' : var, michael@0: 'srcvar' : srcvar})) michael@0: michael@0: def CodeGet(self): michael@0: name = self._name michael@0: code = [ 'int', michael@0: '%s_%s_get(struct %s *msg, %s *value)' % ( michael@0: self._struct.Name(), name, michael@0: self._struct.Name(), self._ctype), michael@0: '{', michael@0: ' if (msg->%s_set != 1) {' % name, michael@0: ' msg->%s_data = %s_new();' % (name, self._refname), michael@0: ' if (msg->%s_data == NULL)' % name, michael@0: ' return (-1);', michael@0: ' msg->%s_set = 1;' % name, michael@0: ' }', michael@0: ' *value = msg->%s_data;' % name, michael@0: ' return (0);', michael@0: '}' ] michael@0: return code michael@0: michael@0: def CodeAssign(self): michael@0: name = self._name michael@0: code = """int michael@0: %(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, michael@0: const %(ctype)s value) michael@0: { michael@0: struct evbuffer *tmp = NULL; michael@0: if (msg->%(name)s_set) { michael@0: %(refname)s_clear(msg->%(name)s_data); michael@0: msg->%(name)s_set = 0; michael@0: } else { michael@0: msg->%(name)s_data = %(refname)s_new(); michael@0: if (msg->%(name)s_data == NULL) { michael@0: event_warn("%%s: %(refname)s_new()", __func__); michael@0: goto error; michael@0: } michael@0: } michael@0: if ((tmp = evbuffer_new()) == NULL) { michael@0: event_warn("%%s: evbuffer_new()", __func__); michael@0: goto error; michael@0: } michael@0: %(refname)s_marshal(tmp, value); michael@0: if (%(refname)s_unmarshal(msg->%(name)s_data, tmp) == -1) { michael@0: event_warnx("%%s: %(refname)s_unmarshal", __func__); michael@0: goto error; michael@0: } michael@0: msg->%(name)s_set = 1; michael@0: evbuffer_free(tmp); michael@0: return (0); michael@0: error: michael@0: if (tmp != NULL) michael@0: evbuffer_free(tmp); michael@0: if (msg->%(name)s_data != NULL) { michael@0: %(refname)s_free(msg->%(name)s_data); michael@0: msg->%(name)s_data = NULL; michael@0: } michael@0: return (-1); michael@0: }""" % self.GetTranslation() michael@0: return code.split('\n') michael@0: michael@0: def CodeComplete(self, structname, var_name): michael@0: code = [ 'if (%(structname)s->%(name)s_set && ' michael@0: '%(refname)s_complete(%(var)s) == -1)', michael@0: ' return (-1);' ] michael@0: michael@0: return TranslateList(code, self.GetTranslation({ michael@0: 'structname' : structname, michael@0: 'var' : var_name })) michael@0: michael@0: def CodeUnmarshal(self, buf, tag_name, var_name, var_len): michael@0: code = ['%(var)s = %(refname)s_new();', michael@0: 'if (%(var)s == NULL)', michael@0: ' return (-1);', michael@0: 'if (evtag_unmarshal_%(refname)s(%(buf)s, %(tag)s, ' michael@0: '%(var)s) == -1) {', michael@0: ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);', michael@0: ' return (-1);', michael@0: '}' michael@0: ] michael@0: code = '\n'.join(code) % self.GetTranslation({ michael@0: 'buf' : buf, michael@0: 'tag' : tag_name, michael@0: 'var' : var_name }) michael@0: return code.split('\n') michael@0: michael@0: def CodeMarshal(self, buf, tag_name, var_name, var_len): michael@0: code = ['evtag_marshal_%s(%s, %s, %s);' % ( michael@0: self._refname, buf, tag_name, var_name)] michael@0: return code michael@0: michael@0: def CodeClear(self, structname): michael@0: code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()), michael@0: ' %s_free(%s->%s_data);' % ( michael@0: self._refname, structname, self.Name()), michael@0: ' %s->%s_data = NULL;' % (structname, self.Name()), michael@0: ' %s->%s_set = 0;' % (structname, self.Name()), michael@0: '}' michael@0: ] michael@0: michael@0: return code michael@0: michael@0: def CodeInitialize(self, name): michael@0: code = ['%s->%s_data = NULL;' % (name, self._name)] michael@0: return code michael@0: michael@0: def CodeFree(self, name): michael@0: code = ['if (%s->%s_data != NULL)' % (name, self._name), michael@0: ' %s_free(%s->%s_data);' % ( michael@0: self._refname, name, self._name)] michael@0: michael@0: return code michael@0: michael@0: def Declaration(self): michael@0: dcl = ['%s %s_data;' % (self._ctype, self._name)] michael@0: michael@0: return dcl michael@0: michael@0: class EntryVarBytes(Entry): michael@0: def __init__(self, type, name, tag): michael@0: # Init base class michael@0: Entry.__init__(self, type, name, tag) michael@0: michael@0: self._ctype = 'ev_uint8_t *' michael@0: michael@0: def GetInitializer(self): michael@0: return "NULL" michael@0: michael@0: def GetVarLen(self, var): michael@0: return '%(var)s->%(name)s_length' % self.GetTranslation({ 'var' : var }) michael@0: michael@0: def CodeArrayAdd(self, varname, value): michael@0: # xxx: copy michael@0: return [ '%(varname)s = NULL;' % { 'varname' : varname } ] michael@0: michael@0: def GetDeclaration(self, funcname): michael@0: code = [ 'int %s(struct %s *, %s *, ev_uint32_t *);' % ( michael@0: funcname, self._struct.Name(), self._ctype ) ] michael@0: return code michael@0: michael@0: def AssignDeclaration(self, funcname): michael@0: code = [ 'int %s(struct %s *, const %s, ev_uint32_t);' % ( michael@0: funcname, self._struct.Name(), self._ctype ) ] michael@0: return code michael@0: michael@0: def CodeAssign(self): michael@0: name = self._name michael@0: code = [ 'int', michael@0: '%s_%s_assign(struct %s *msg, ' michael@0: 'const %s value, ev_uint32_t len)' % ( michael@0: self._struct.Name(), name, michael@0: self._struct.Name(), self._ctype), michael@0: '{', michael@0: ' if (msg->%s_data != NULL)' % name, michael@0: ' free (msg->%s_data);' % name, michael@0: ' msg->%s_data = malloc(len);' % name, michael@0: ' if (msg->%s_data == NULL)' % name, michael@0: ' return (-1);', michael@0: ' msg->%s_set = 1;' % name, michael@0: ' msg->%s_length = len;' % name, michael@0: ' memcpy(msg->%s_data, value, len);' % name, michael@0: ' return (0);', michael@0: '}' ] michael@0: return code michael@0: michael@0: def CodeGet(self): michael@0: name = self._name michael@0: code = [ 'int', michael@0: '%s_%s_get(struct %s *msg, %s *value, ev_uint32_t *plen)' % ( michael@0: self._struct.Name(), name, michael@0: self._struct.Name(), self._ctype), michael@0: '{', michael@0: ' if (msg->%s_set != 1)' % name, michael@0: ' return (-1);', michael@0: ' *value = msg->%s_data;' % name, michael@0: ' *plen = msg->%s_length;' % name, michael@0: ' return (0);', michael@0: '}' ] michael@0: return code michael@0: michael@0: def CodeUnmarshal(self, buf, tag_name, var_name, var_len): michael@0: code = ['if (evtag_payload_length(%(buf)s, &%(varlen)s) == -1)', michael@0: ' return (-1);', michael@0: # We do not want DoS opportunities michael@0: 'if (%(varlen)s > evbuffer_get_length(%(buf)s))', michael@0: ' return (-1);', michael@0: 'if ((%(var)s = malloc(%(varlen)s)) == NULL)', michael@0: ' return (-1);', michael@0: 'if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, %(var)s, ' michael@0: '%(varlen)s) == -1) {', michael@0: ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);', michael@0: ' return (-1);', michael@0: '}' michael@0: ] michael@0: code = '\n'.join(code) % self.GetTranslation({ michael@0: 'buf' : buf, michael@0: 'tag' : tag_name, michael@0: 'var' : var_name, michael@0: 'varlen' : var_len }) michael@0: return code.split('\n') michael@0: michael@0: def CodeMarshal(self, buf, tag_name, var_name, var_len): michael@0: code = ['evtag_marshal(%s, %s, %s, %s);' % ( michael@0: buf, tag_name, var_name, var_len)] michael@0: return code michael@0: michael@0: def CodeClear(self, structname): michael@0: code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()), michael@0: ' free (%s->%s_data);' % (structname, self.Name()), michael@0: ' %s->%s_data = NULL;' % (structname, self.Name()), michael@0: ' %s->%s_length = 0;' % (structname, self.Name()), michael@0: ' %s->%s_set = 0;' % (structname, self.Name()), michael@0: '}' michael@0: ] michael@0: michael@0: return code michael@0: michael@0: def CodeInitialize(self, name): michael@0: code = ['%s->%s_data = NULL;' % (name, self._name), michael@0: '%s->%s_length = 0;' % (name, self._name) ] michael@0: return code michael@0: michael@0: def CodeFree(self, name): michael@0: code = ['if (%s->%s_data != NULL)' % (name, self._name), michael@0: ' free(%s->%s_data);' % (name, self._name)] michael@0: michael@0: return code michael@0: michael@0: def Declaration(self): michael@0: dcl = ['ev_uint8_t *%s_data;' % self._name, michael@0: 'ev_uint32_t %s_length;' % self._name] michael@0: michael@0: return dcl michael@0: michael@0: class EntryArray(Entry): michael@0: def __init__(self, entry): michael@0: # Init base class michael@0: Entry.__init__(self, entry._type, entry._name, entry._tag) michael@0: michael@0: self._entry = entry michael@0: self._refname = entry._refname michael@0: self._ctype = self._entry._ctype michael@0: self._optional = True michael@0: self._optpointer = self._entry._optpointer michael@0: self._optaddarg = self._entry._optaddarg michael@0: michael@0: # provide a new function for accessing the variable name michael@0: def GetVarName(var_name): michael@0: return '%(var)s->%(name)s_data[%(index)s]' % \ michael@0: self._entry.GetTranslation({'var' : var_name, michael@0: 'index' : self._index}) michael@0: self._entry.GetVarName = GetVarName michael@0: michael@0: def GetInitializer(self): michael@0: return "NULL" michael@0: michael@0: def GetVarName(self, var_name): michael@0: return var_name michael@0: michael@0: def GetVarLen(self, var_name): michael@0: return '-1' michael@0: michael@0: def GetDeclaration(self, funcname): michael@0: """Allows direct access to elements of the array.""" michael@0: code = [ michael@0: 'int %(funcname)s(struct %(parent_name)s *, int, %(ctype)s *);' % michael@0: self.GetTranslation({ 'funcname' : funcname }) ] michael@0: return code michael@0: michael@0: def AssignDeclaration(self, funcname): michael@0: code = [ 'int %s(struct %s *, int, const %s);' % ( michael@0: funcname, self._struct.Name(), self._ctype ) ] michael@0: return code michael@0: michael@0: def AddDeclaration(self, funcname): michael@0: code = [ michael@0: '%(ctype)s %(optpointer)s ' michael@0: '%(funcname)s(struct %(parent_name)s *msg%(optaddarg)s);' % \ michael@0: self.GetTranslation({ 'funcname' : funcname }) ] michael@0: return code michael@0: michael@0: def CodeGet(self): michael@0: code = """int michael@0: %(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, int offset, michael@0: %(ctype)s *value) michael@0: { michael@0: if (!msg->%(name)s_set || offset < 0 || offset >= msg->%(name)s_length) michael@0: return (-1); michael@0: *value = msg->%(name)s_data[offset]; michael@0: return (0); michael@0: }""" % self.GetTranslation() michael@0: michael@0: return code.split('\n') michael@0: michael@0: def CodeAssign(self): michael@0: code = [ michael@0: 'int', michael@0: '%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, int off,', michael@0: ' const %(ctype)s value)', michael@0: '{', michael@0: ' if (!msg->%(name)s_set || off < 0 || off >= msg->%(name)s_length)', michael@0: ' return (-1);\n', michael@0: ' {' ] michael@0: code = TranslateList(code, self.GetTranslation()) michael@0: michael@0: codearrayassign = self._entry.CodeArrayAssign( michael@0: 'msg->%(name)s_data[off]' % self.GetTranslation(), 'value') michael@0: code += map(lambda x: ' ' + x, codearrayassign) michael@0: michael@0: code += TranslateList([ michael@0: ' }', michael@0: ' return (0);', michael@0: '}' ], self.GetTranslation()) michael@0: michael@0: return code michael@0: michael@0: def CodeAdd(self): michael@0: codearrayadd = self._entry.CodeArrayAdd( michael@0: 'msg->%(name)s_data[msg->%(name)s_length - 1]' % self.GetTranslation(), michael@0: 'value') michael@0: code = [ michael@0: 'static int', michael@0: '%(parent_name)s_%(name)s_expand_to_hold_more(' michael@0: 'struct %(parent_name)s *msg)', michael@0: '{', michael@0: ' int tobe_allocated = msg->%(name)s_num_allocated;', michael@0: ' %(ctype)s* new_data = NULL;', michael@0: ' tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;', michael@0: ' new_data = (%(ctype)s*) realloc(msg->%(name)s_data,', michael@0: ' tobe_allocated * sizeof(%(ctype)s));', michael@0: ' if (new_data == NULL)', michael@0: ' return -1;', michael@0: ' msg->%(name)s_data = new_data;', michael@0: ' msg->%(name)s_num_allocated = tobe_allocated;', michael@0: ' return 0;' michael@0: '}', michael@0: '', michael@0: '%(ctype)s %(optpointer)s', michael@0: '%(parent_name)s_%(name)s_add(' michael@0: 'struct %(parent_name)s *msg%(optaddarg)s)', michael@0: '{', michael@0: ' if (++msg->%(name)s_length >= msg->%(name)s_num_allocated) {', michael@0: ' if (%(parent_name)s_%(name)s_expand_to_hold_more(msg)<0)', michael@0: ' goto error;', michael@0: ' }' ] michael@0: michael@0: code = TranslateList(code, self.GetTranslation()) michael@0: michael@0: code += map(lambda x: ' ' + x, codearrayadd) michael@0: michael@0: code += TranslateList([ michael@0: ' msg->%(name)s_set = 1;', michael@0: ' return %(optreference)s(msg->%(name)s_data[' michael@0: 'msg->%(name)s_length - 1]);', michael@0: 'error:', michael@0: ' --msg->%(name)s_length;', michael@0: ' return (NULL);', michael@0: '}' ], self.GetTranslation()) michael@0: michael@0: return code michael@0: michael@0: def CodeComplete(self, structname, var_name): michael@0: self._index = 'i' michael@0: tmp = self._entry.CodeComplete(structname, self._entry.GetVarName(var_name)) michael@0: # skip the whole loop if there is nothing to check michael@0: if not tmp: michael@0: return [] michael@0: michael@0: translate = self.GetTranslation({ 'structname' : structname }) michael@0: code = [ michael@0: '{', michael@0: ' int i;', michael@0: ' for (i = 0; i < %(structname)s->%(name)s_length; ++i) {' ] michael@0: michael@0: code = TranslateList(code, translate) michael@0: michael@0: code += map(lambda x: ' ' + x, tmp) michael@0: michael@0: code += [ michael@0: ' }', michael@0: '}' ] michael@0: michael@0: return code michael@0: michael@0: def CodeUnmarshal(self, buf, tag_name, var_name, var_len): michael@0: translate = self.GetTranslation({ 'var' : var_name, michael@0: 'buf' : buf, michael@0: 'tag' : tag_name, michael@0: 'init' : self._entry.GetInitializer()}) michael@0: code = [ michael@0: 'if (%(var)s->%(name)s_length >= %(var)s->%(name)s_num_allocated &&', michael@0: ' %(parent_name)s_%(name)s_expand_to_hold_more(%(var)s) < 0) {', michael@0: ' puts("HEY NOW");', michael@0: ' return (-1);', michael@0: '}'] michael@0: michael@0: # the unmarshal code directly returns michael@0: code = TranslateList(code, translate) michael@0: michael@0: self._index = '%(var)s->%(name)s_length' % translate michael@0: code += self._entry.CodeUnmarshal(buf, tag_name, michael@0: self._entry.GetVarName(var_name), michael@0: self._entry.GetVarLen(var_name)) michael@0: michael@0: code += [ '++%(var)s->%(name)s_length;' % translate ] michael@0: michael@0: return code michael@0: michael@0: def CodeMarshal(self, buf, tag_name, var_name, var_len): michael@0: code = ['{', michael@0: ' int i;', michael@0: ' for (i = 0; i < %(var)s->%(name)s_length; ++i) {' ] michael@0: michael@0: self._index = 'i' michael@0: code += self._entry.CodeMarshal(buf, tag_name, michael@0: self._entry.GetVarName(var_name), michael@0: self._entry.GetVarLen(var_name)) michael@0: code += [' }', michael@0: '}' michael@0: ] michael@0: michael@0: code = "\n".join(code) % self.GetTranslation({ 'var' : var_name }) michael@0: michael@0: return code.split('\n') michael@0: michael@0: def CodeClear(self, structname): michael@0: translate = self.GetTranslation({ 'structname' : structname }) michael@0: codearrayfree = self._entry.CodeArrayFree( michael@0: '%(structname)s->%(name)s_data[i]' % self.GetTranslation( michael@0: { 'structname' : structname } )) michael@0: michael@0: code = [ 'if (%(structname)s->%(name)s_set == 1) {' ] michael@0: michael@0: if codearrayfree: michael@0: code += [ michael@0: ' int i;', michael@0: ' for (i = 0; i < %(structname)s->%(name)s_length; ++i) {' ] michael@0: michael@0: code = TranslateList(code, translate) michael@0: michael@0: if codearrayfree: michael@0: code += map(lambda x: ' ' + x, codearrayfree) michael@0: code += [ michael@0: ' }' ] michael@0: michael@0: code += TranslateList([ michael@0: ' free(%(structname)s->%(name)s_data);', michael@0: ' %(structname)s->%(name)s_data = NULL;', michael@0: ' %(structname)s->%(name)s_set = 0;', michael@0: ' %(structname)s->%(name)s_length = 0;', michael@0: ' %(structname)s->%(name)s_num_allocated = 0;', michael@0: '}' michael@0: ], translate) michael@0: michael@0: return code michael@0: michael@0: def CodeInitialize(self, name): michael@0: code = ['%s->%s_data = NULL;' % (name, self._name), michael@0: '%s->%s_length = 0;' % (name, self._name), michael@0: '%s->%s_num_allocated = 0;' % (name, self._name)] michael@0: return code michael@0: michael@0: def CodeFree(self, structname): michael@0: code = self.CodeClear(structname); michael@0: michael@0: code += TranslateList([ michael@0: 'free(%(structname)s->%(name)s_data);' ], michael@0: self.GetTranslation({'structname' : structname })) michael@0: michael@0: return code michael@0: michael@0: def Declaration(self): michael@0: dcl = ['%s *%s_data;' % (self._ctype, self._name), michael@0: 'int %s_length;' % self._name, michael@0: 'int %s_num_allocated;' % self._name ] michael@0: michael@0: return dcl michael@0: michael@0: def NormalizeLine(line): michael@0: global white michael@0: global cppcomment michael@0: michael@0: line = cppcomment.sub('', line) michael@0: line = line.strip() michael@0: line = white.sub(' ', line) michael@0: michael@0: return line michael@0: michael@0: def ProcessOneEntry(factory, newstruct, entry): michael@0: optional = 0 michael@0: array = 0 michael@0: entry_type = '' michael@0: name = '' michael@0: tag = '' michael@0: tag_set = None michael@0: separator = '' michael@0: fixed_length = '' michael@0: michael@0: tokens = entry.split(' ') michael@0: while tokens: michael@0: token = tokens[0] michael@0: tokens = tokens[1:] michael@0: michael@0: if not entry_type: michael@0: if not optional and token == 'optional': michael@0: optional = 1 michael@0: continue michael@0: michael@0: if not array and token == 'array': michael@0: array = 1 michael@0: continue michael@0: michael@0: if not entry_type: michael@0: entry_type = token michael@0: continue michael@0: michael@0: if not name: michael@0: res = re.match(r'^([^\[\]]+)(\[.*\])?$', token) michael@0: if not res: michael@0: raise RpcGenError( michael@0: 'Cannot parse name: \"%s\" ' michael@0: 'around line %d' % (entry, line_count)) michael@0: name = res.group(1) michael@0: fixed_length = res.group(2) michael@0: if fixed_length: michael@0: fixed_length = fixed_length[1:-1] michael@0: continue michael@0: michael@0: if not separator: michael@0: separator = token michael@0: if separator != '=': michael@0: raise RpcGenError('Expected "=" after name \"%s\" got %s' michael@0: % (name, token)) michael@0: continue michael@0: michael@0: if not tag_set: michael@0: tag_set = 1 michael@0: if not re.match(r'^(0x)?[0-9]+$', token): michael@0: raise RpcGenError('Expected tag number: \"%s\"' % entry) michael@0: tag = int(token, 0) michael@0: continue michael@0: michael@0: raise RpcGenError('Cannot parse \"%s\"' % entry) michael@0: michael@0: if not tag_set: michael@0: raise RpcGenError('Need tag number: \"%s\"' % entry) michael@0: michael@0: # Create the right entry michael@0: if entry_type == 'bytes': michael@0: if fixed_length: michael@0: newentry = factory.EntryBytes(entry_type, name, tag, fixed_length) michael@0: else: michael@0: newentry = factory.EntryVarBytes(entry_type, name, tag) michael@0: elif entry_type == 'int' and not fixed_length: michael@0: newentry = factory.EntryInt(entry_type, name, tag) michael@0: elif entry_type == 'int64' and not fixed_length: michael@0: newentry = factory.EntryInt(entry_type, name, tag, bits=64) michael@0: elif entry_type == 'string' and not fixed_length: michael@0: newentry = factory.EntryString(entry_type, name, tag) michael@0: else: michael@0: res = structref.match(entry_type) michael@0: if res: michael@0: # References another struct defined in our file michael@0: newentry = factory.EntryStruct(entry_type, name, tag, res.group(1)) michael@0: else: michael@0: raise RpcGenError('Bad type: "%s" in "%s"' % (entry_type, entry)) michael@0: michael@0: structs = [] michael@0: michael@0: if optional: michael@0: newentry.MakeOptional() michael@0: if array: michael@0: newentry.MakeArray() michael@0: michael@0: newentry.SetStruct(newstruct) michael@0: newentry.SetLineCount(line_count) michael@0: newentry.Verify() michael@0: michael@0: if array: michael@0: # We need to encapsulate this entry into a struct michael@0: newname = newentry.Name()+ '_array' michael@0: michael@0: # Now borgify the new entry. michael@0: newentry = factory.EntryArray(newentry) michael@0: newentry.SetStruct(newstruct) michael@0: newentry.SetLineCount(line_count) michael@0: newentry.MakeArray() michael@0: michael@0: newstruct.AddEntry(newentry) michael@0: michael@0: return structs michael@0: michael@0: def ProcessStruct(factory, data): michael@0: tokens = data.split(' ') michael@0: michael@0: # First three tokens are: 'struct' 'name' '{' michael@0: newstruct = factory.Struct(tokens[1]) michael@0: michael@0: inside = ' '.join(tokens[3:-1]) michael@0: michael@0: tokens = inside.split(';') michael@0: michael@0: structs = [] michael@0: michael@0: for entry in tokens: michael@0: entry = NormalizeLine(entry) michael@0: if not entry: michael@0: continue michael@0: michael@0: # It's possible that new structs get defined in here michael@0: structs.extend(ProcessOneEntry(factory, newstruct, entry)) michael@0: michael@0: structs.append(newstruct) michael@0: return structs michael@0: michael@0: def GetNextStruct(file): michael@0: global line_count michael@0: global cppdirect michael@0: michael@0: got_struct = 0 michael@0: michael@0: processed_lines = [] michael@0: michael@0: have_c_comment = 0 michael@0: data = '' michael@0: while 1: michael@0: line = file.readline() michael@0: if not line: michael@0: break michael@0: michael@0: line_count += 1 michael@0: line = line[:-1] michael@0: michael@0: if not have_c_comment and re.search(r'/\*', line): michael@0: if re.search(r'/\*.*?\*/', line): michael@0: line = re.sub(r'/\*.*?\*/', '', line) michael@0: else: michael@0: line = re.sub(r'/\*.*$', '', line) michael@0: have_c_comment = 1 michael@0: michael@0: if have_c_comment: michael@0: if not re.search(r'\*/', line): michael@0: continue michael@0: have_c_comment = 0 michael@0: line = re.sub(r'^.*\*/', '', line) michael@0: michael@0: line = NormalizeLine(line) michael@0: michael@0: if not line: michael@0: continue michael@0: michael@0: if not got_struct: michael@0: if re.match(r'#include ["<].*[>"]', line): michael@0: cppdirect.append(line) michael@0: continue michael@0: michael@0: if re.match(r'^#(if( |def)|endif)', line): michael@0: cppdirect.append(line) michael@0: continue michael@0: michael@0: if re.match(r'^#define', line): michael@0: headerdirect.append(line) michael@0: continue michael@0: michael@0: if not structdef.match(line): michael@0: raise RpcGenError('Missing struct on line %d: %s' michael@0: % (line_count, line)) michael@0: else: michael@0: got_struct = 1 michael@0: data += line michael@0: continue michael@0: michael@0: # We are inside the struct michael@0: tokens = line.split('}') michael@0: if len(tokens) == 1: michael@0: data += ' ' + line michael@0: continue michael@0: michael@0: if len(tokens[1]): michael@0: raise RpcGenError('Trailing garbage after struct on line %d' michael@0: % line_count) michael@0: michael@0: # We found the end of the struct michael@0: data += ' %s}' % tokens[0] michael@0: break michael@0: michael@0: # Remove any comments, that might be in there michael@0: data = re.sub(r'/\*.*\*/', '', data) michael@0: michael@0: return data michael@0: michael@0: michael@0: def Parse(factory, file): michael@0: """ michael@0: Parses the input file and returns C code and corresponding header file. michael@0: """ michael@0: michael@0: entities = [] michael@0: michael@0: while 1: michael@0: # Just gets the whole struct nicely formatted michael@0: data = GetNextStruct(file) michael@0: michael@0: if not data: michael@0: break michael@0: michael@0: entities.extend(ProcessStruct(factory, data)) michael@0: michael@0: return entities michael@0: michael@0: class CCodeGenerator: michael@0: def __init__(self): michael@0: pass michael@0: michael@0: def GuardName(self, name): michael@0: # Use the complete provided path to the input file, with all michael@0: # non-identifier characters replaced with underscores, to michael@0: # reduce the chance of a collision between guard macros. michael@0: return '_' + nonident.sub('_', name).upper() + '_' michael@0: michael@0: def HeaderPreamble(self, name): michael@0: guard = self.GuardName(name) michael@0: pre = ( michael@0: '/*\n' michael@0: ' * Automatically generated from %s\n' michael@0: ' */\n\n' michael@0: '#ifndef %s\n' michael@0: '#define %s\n\n' ) % ( michael@0: name, guard, guard) michael@0: michael@0: for statement in headerdirect: michael@0: pre += '%s\n' % statement michael@0: if headerdirect: michael@0: pre += '\n' michael@0: michael@0: pre += ( michael@0: '#include /* for ev_uint*_t */\n' michael@0: '#include \n' michael@0: ) michael@0: michael@0: return pre michael@0: michael@0: def HeaderPostamble(self, name): michael@0: guard = self.GuardName(name) michael@0: return '#endif /* %s */' % guard michael@0: michael@0: def BodyPreamble(self, name, header_file): michael@0: global _NAME michael@0: global _VERSION michael@0: michael@0: slash = header_file.rfind('/') michael@0: if slash != -1: michael@0: header_file = header_file[slash+1:] michael@0: michael@0: pre = ( '/*\n' michael@0: ' * Automatically generated from %s\n' michael@0: ' * by %s/%s. DO NOT EDIT THIS FILE.\n' michael@0: ' */\n\n' ) % (name, _NAME, _VERSION) michael@0: pre += ( '#include \n' michael@0: '#include \n' michael@0: '#include \n' michael@0: '#include \n' michael@0: '#include \n' michael@0: '#include \n' michael@0: '#include \n\n' michael@0: '#ifdef _EVENT___func__\n' michael@0: '#define __func__ _EVENT___func__\n' michael@0: '#endif\n\n' michael@0: ) michael@0: michael@0: for statement in cppdirect: michael@0: pre += '%s\n' % statement michael@0: michael@0: pre += '\n#include "%s"\n\n' % header_file michael@0: michael@0: pre += 'void event_warn(const char *fmt, ...);\n' michael@0: pre += 'void event_warnx(const char *fmt, ...);\n\n' michael@0: michael@0: return pre michael@0: michael@0: def HeaderFilename(self, filename): michael@0: return '.'.join(filename.split('.')[:-1]) + '.h' michael@0: michael@0: def CodeFilename(self, filename): michael@0: return '.'.join(filename.split('.')[:-1]) + '.gen.c' michael@0: michael@0: def Struct(self, name): michael@0: return StructCCode(name) michael@0: michael@0: def EntryBytes(self, entry_type, name, tag, fixed_length): michael@0: return EntryBytes(entry_type, name, tag, fixed_length) michael@0: michael@0: def EntryVarBytes(self, entry_type, name, tag): michael@0: return EntryVarBytes(entry_type, name, tag) michael@0: michael@0: def EntryInt(self, entry_type, name, tag, bits=32): michael@0: return EntryInt(entry_type, name, tag, bits) michael@0: michael@0: def EntryString(self, entry_type, name, tag): michael@0: return EntryString(entry_type, name, tag) michael@0: michael@0: def EntryStruct(self, entry_type, name, tag, struct_name): michael@0: return EntryStruct(entry_type, name, tag, struct_name) michael@0: michael@0: def EntryArray(self, entry): michael@0: return EntryArray(entry) michael@0: michael@0: class Usage(RpcGenError): michael@0: def __init__(self, argv0): michael@0: RpcGenError.__init__("usage: %s input.rpc [[output.h] output.c]" michael@0: % argv0) michael@0: michael@0: class CommandLine: michael@0: def __init__(self, argv): michael@0: """Initialize a command-line to launch event_rpcgen, as if michael@0: from a command-line with CommandLine(sys.argv). If you're michael@0: calling this directly, remember to provide a dummy value michael@0: for sys.argv[0] michael@0: """ michael@0: self.filename = None michael@0: self.header_file = None michael@0: self.impl_file = None michael@0: self.factory = CCodeGenerator() michael@0: michael@0: if len(argv) < 2 or len(argv) > 4: michael@0: raise Usage(argv[0]) michael@0: michael@0: self.filename = argv[1].replace('\\', '/') michael@0: if len(argv) == 3: michael@0: self.impl_file = argv[2].replace('\\', '/') michael@0: if len(argv) == 4: michael@0: self.header_file = argv[2].replace('\\', '/') michael@0: self.impl_file = argv[3].replace('\\', '/') michael@0: michael@0: if not self.filename: michael@0: raise Usage(argv[0]) michael@0: michael@0: if not self.impl_file: michael@0: self.impl_file = self.factory.CodeFilename(self.filename) michael@0: michael@0: if not self.header_file: michael@0: self.header_file = self.factory.HeaderFilename(self.impl_file) michael@0: michael@0: if not self.impl_file.endswith('.c'): michael@0: raise RpcGenError("can only generate C implementation files") michael@0: if not self.header_file.endswith('.h'): michael@0: raise RpcGenError("can only generate C header files") michael@0: michael@0: def run(self): michael@0: filename = self.filename michael@0: header_file = self.header_file michael@0: impl_file = self.impl_file michael@0: factory = self.factory michael@0: michael@0: print >>sys.stderr, 'Reading \"%s\"' % filename michael@0: michael@0: fp = open(filename, 'r') michael@0: entities = Parse(factory, fp) michael@0: fp.close() michael@0: michael@0: print >>sys.stderr, '... creating "%s"' % header_file michael@0: header_fp = open(header_file, 'w') michael@0: print >>header_fp, factory.HeaderPreamble(filename) michael@0: michael@0: # Create forward declarations: allows other structs to reference michael@0: # each other michael@0: for entry in entities: michael@0: entry.PrintForwardDeclaration(header_fp) michael@0: print >>header_fp, '' michael@0: michael@0: for entry in entities: michael@0: entry.PrintTags(header_fp) michael@0: entry.PrintDeclaration(header_fp) michael@0: print >>header_fp, factory.HeaderPostamble(filename) michael@0: header_fp.close() michael@0: michael@0: print >>sys.stderr, '... creating "%s"' % impl_file michael@0: impl_fp = open(impl_file, 'w') michael@0: print >>impl_fp, factory.BodyPreamble(filename, header_file) michael@0: for entry in entities: michael@0: entry.PrintCode(impl_fp) michael@0: impl_fp.close() michael@0: michael@0: if __name__ == '__main__': michael@0: try: michael@0: CommandLine(sys.argv).run() michael@0: sys.exit(0) michael@0: michael@0: except RpcGenError, e: michael@0: print >>sys.stderr, e michael@0: sys.exit(1) michael@0: michael@0: except EnvironmentError, e: michael@0: if e.filename and e.strerror: michael@0: print >>sys.stderr, "%s: %s" % (e.filename, e.strerror) michael@0: sys.exit(1) michael@0: elif e.strerror: michael@0: print >> sys.stderr, e.strerror michael@0: sys.exit(1) michael@0: else: michael@0: raise