3 # Copyright (c) 2005-2007 Niels Provos <provos@citi.umich.edu>
4 # Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
7 # Generates marshaling code based on libevent.
9 # pylint: disable=too-many-lines
10 # pylint: disable=too-many-branches
11 # pylint: disable=too-many-public-methods
12 # pylint: disable=too-many-statements
13 # pylint: disable=global-statement
16 # 1) propagate the arguments/options parsed by argparse down to the
17 # instantiated factory objects.
18 # 2) move the globals into a class that manages execution, including the
19 # progress outputs that go to stderr at the moment.
20 # 3) emit other languages.
26 _NAME = "event_rpcgen.py"
32 CPPCOMMENT_RE = re.compile(r"\/\/.*$")
33 NONIDENT_RE = re.compile(r"\W")
34 PREPROCESSOR_DEF_RE = re.compile(r"^#define")
35 STRUCT_REF_RE = re.compile(r"^struct\[(?P<name>[a-zA-Z_][a-zA-Z0-9_]*)\]$")
36 STRUCT_DEF_RE = re.compile(r"^struct +[a-zA-Z_][a-zA-Z0-9_]* *{$")
37 WHITESPACE_RE = re.compile(r"\s+")
50 def TranslateList(mylist, mydict):
51 return [x % mydict for x in mylist]
54 class RpcGenError(Exception):
55 """An Exception class for parse errors."""
57 def __init__(self, why): # pylint: disable=super-init-not-called
64 # Holds everything that makes a struct
66 def __init__(self, name):
70 declare(" Created struct: %s" % name)
72 def AddEntry(self, entry):
73 if entry.Tag() in self._tags:
75 'Entry "%s" duplicates tag number %d from "%s" '
77 % (entry.Name(), entry.Tag(), self._tags[entry.Tag()], LINE_COUNT)
79 self._entries.append(entry)
80 self._tags[entry.Tag()] = entry.Name()
81 declare(" Added entry: %s" % entry.Name())
86 def EntryTagName(self, entry):
87 """Creates the name inside an enumeration for distinguishing data
89 name = "%s_%s" % (self._name, entry.Name())
93 def PrintIndented(filep, ident, code):
94 """Takes an array, add indentation to each entry and prints it."""
96 filep.write("%s%s\n" % (ident, entry))
99 class StructCCode(Struct):
100 """ Knows how to generate C code for a struct """
102 def __init__(self, name):
103 Struct.__init__(self, name)
105 def PrintTags(self, filep):
106 """Prints the tag definitions for a structure."""
107 filep.write("/* Tag definition for %s */\n" % self._name)
108 filep.write("enum %s_ {\n" % self._name.lower())
109 for entry in self._entries:
110 filep.write(" %s=%d,\n" % (self.EntryTagName(entry), entry.Tag()))
111 filep.write(" %s_MAX_TAGS\n" % (self._name.upper()))
112 filep.write("};\n\n")
114 def PrintForwardDeclaration(self, filep):
115 filep.write("struct %s;\n" % self._name)
117 def PrintDeclaration(self, filep):
118 filep.write("/* Structure declaration for %s */\n" % self._name)
119 filep.write("struct %s_access_ {\n" % self._name)
120 for entry in self._entries:
121 dcl = entry.AssignDeclaration("(*%s_assign)" % entry.Name())
122 dcl.extend(entry.GetDeclaration("(*%s_get)" % entry.Name()))
124 dcl.extend(entry.AddDeclaration("(*%s_add)" % entry.Name()))
125 self.PrintIndented(filep, " ", dcl)
126 filep.write("};\n\n")
128 filep.write("struct %s {\n" % self._name)
129 filep.write(" struct %s_access_ *base;\n\n" % self._name)
130 for entry in self._entries:
131 dcl = entry.Declaration()
132 self.PrintIndented(filep, " ", dcl)
134 for entry in self._entries:
135 filep.write(" ev_uint8_t %s_set;\n" % entry.Name())
136 filep.write("};\n\n")
139 """struct %(name)s *%(name)s_new(void);
140 struct %(name)s *%(name)s_new_with_arg(void *);
141 void %(name)s_free(struct %(name)s *);
142 void %(name)s_clear(struct %(name)s *);
143 void %(name)s_marshal(struct evbuffer *, const struct %(name)s *);
144 int %(name)s_unmarshal(struct %(name)s *, struct evbuffer *);
145 int %(name)s_complete(struct %(name)s *);
146 void evtag_marshal_%(name)s(struct evbuffer *, ev_uint32_t,
147 const struct %(name)s *);
148 int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
149 struct %(name)s *);\n"""
150 % {"name": self._name}
153 # Write a setting function of every variable
154 for entry in self._entries:
156 filep, "", entry.AssignDeclaration(entry.AssignFuncName())
158 self.PrintIndented(filep, "", entry.GetDeclaration(entry.GetFuncName()))
160 self.PrintIndented(filep, "", entry.AddDeclaration(entry.AddFuncName()))
162 filep.write("/* --- %s done --- */\n\n" % self._name)
164 def PrintCode(self, filep):
167 * Implementation of %s
175 static struct %(name)s_access_ %(name)s_base__ = {
177 % {"name": self._name}
179 for entry in self._entries:
180 self.PrintIndented(filep, " ", entry.CodeBase())
181 filep.write("};\n\n")
188 return %(name)s_new_with_arg(NULL);
192 %(name)s_new_with_arg(void *unused)
194 struct %(name)s *tmp;
195 if ((tmp = malloc(sizeof(struct %(name)s))) == NULL) {
196 event_warn("%%s: malloc", __func__);
199 tmp->base = &%(name)s_base__;
202 % {"name": self._name}
205 for entry in self._entries:
206 self.PrintIndented(filep, " ", entry.CodeInitialize("tmp"))
207 filep.write(" tmp->%s_set = 0;\n\n" % entry.Name())
217 for entry in self._entries:
219 self.PrintIndented(filep, "", entry.CodeAdd())
223 for entry in self._entries:
224 self.PrintIndented(filep, "", entry.CodeAssign())
228 for entry in self._entries:
229 self.PrintIndented(filep, "", entry.CodeGet())
235 %(name)s_clear(struct %(name)s *tmp)
238 % {"name": self._name}
240 for entry in self._entries:
241 self.PrintIndented(filep, " ", entry.CodeClear("tmp"))
248 %(name)s_free(struct %(name)s *tmp)
251 % {"name": self._name}
254 for entry in self._entries:
255 self.PrintIndented(filep, " ", entry.CodeFree("tmp"))
267 %(name)s_marshal(struct evbuffer *evbuf, const struct %(name)s *tmp) {
269 % {"name": self._name}
271 for entry in self._entries:
273 # Optional entries do not have to be set
276 filep.write(" if (tmp->%s_set) {\n" % entry.Name())
282 self.EntryTagName(entry),
283 entry.GetVarName("tmp"),
284 entry.GetVarLen("tmp"),
295 %(name)s_unmarshal(struct %(name)s *tmp, struct evbuffer *evbuf)
298 while (evbuffer_get_length(evbuf) > 0) {
299 if (evtag_peek(evbuf, &tag) == -1)
304 % {"name": self._name}
306 for entry in self._entries:
307 filep.write(" case %s:\n" % (self.EntryTagName(entry)))
308 if not entry.Array():
321 self.EntryTagName(entry),
322 entry.GetVarName("tmp"),
323 entry.GetVarLen("tmp"),
341 # Check if it was decoded completely
343 """ if (%(name)s_complete(tmp) == -1)
348 % {"name": self._name}
351 # Checking if a structure has all the required data
355 %(name)s_complete(struct %(name)s *msg)
358 % {"name": self._name}
360 for entry in self._entries:
361 if not entry.Optional():
363 """if (!msg->%(name)s_set)
366 code = TranslateList(code, entry.GetTranslation())
367 self.PrintIndented(filep, " ", code)
370 filep, " ", entry.CodeComplete("msg", entry.GetVarName("msg"))
378 # Complete message unmarshaling
382 evtag_unmarshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t need_tag,
383 struct %(name)s *msg)
388 struct evbuffer *tmp = evbuffer_new();
390 if (evtag_unmarshal(evbuf, &tag, tmp) == -1 || tag != need_tag)
393 if (%(name)s_unmarshal(msg, tmp) == -1)
403 % {"name": self._name}
406 # Complete message marshaling
410 evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag,
411 const struct %(name)s *msg)
413 struct evbuffer *buf_ = evbuffer_new();
414 assert(buf_ != NULL);
415 %(name)s_marshal(buf_, msg);
416 evtag_marshal_buffer(evbuf, tag, buf_);
421 % {"name": self._name}
426 def __init__(self, ent_type, name, tag):
427 self._type = ent_type
430 self._ctype = ent_type
431 self._optional = False
432 self._can_be_array = False
434 self._line_count = -1
438 self._optpointer = True
439 self._optaddarg = True
442 def GetInitializer():
443 raise NotImplementedError("Entry does not provide an initializer")
445 def SetStruct(self, struct):
446 self._struct = struct
449 assert self._line_count != -1
450 return self._line_count
452 def SetLineCount(self, number):
453 self._line_count = number
459 return self._optional
473 def MakeOptional(self):
474 self._optional = True
477 if self.Array() and not self._can_be_array:
479 'Entry "%s" cannot be created as an array '
480 "around line %d" % (self._name, self.LineCount())
484 'Entry "%s" does not know which struct it belongs to '
485 "around line %d" % (self._name, self.LineCount())
487 if self._optional and self._array:
489 'Entry "%s" has illegal combination of optional and array '
490 "around line %d" % (self._name, self.LineCount())
493 def GetTranslation(self, extradict=None):
494 if extradict is None:
497 "parent_name": self._struct.Name(),
499 "ctype": self._ctype,
500 "refname": self._refname,
501 "optpointer": self._optpointer and "*" or "",
502 "optreference": self._optpointer and "&" or "",
503 "optaddarg": self._optaddarg and ", const %s value" % self._ctype or "",
505 for (k, v) in list(extradict.items()):
510 def GetVarName(self, var):
511 return "%(var)s->%(name)s_data" % self.GetTranslation({"var": var})
513 def GetVarLen(self, _var):
514 return "sizeof(%s)" % self._ctype
516 def GetFuncName(self):
517 return "%s_%s_get" % (self._struct.Name(), self._name)
519 def GetDeclaration(self, funcname):
521 "int %s(struct %s *, %s *);" % (funcname, self._struct.Name(), self._ctype)
527 %(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, %(ctype)s *value)
529 if (msg->%(name)s_set != 1)
531 *value = msg->%(name)s_data;
534 code = code % self.GetTranslation()
535 return code.split("\n")
537 def AssignFuncName(self):
538 return "%s_%s_assign" % (self._struct.Name(), self._name)
540 def AddFuncName(self):
541 return "%s_%s_add" % (self._struct.Name(), self._name)
543 def AssignDeclaration(self, funcname):
545 "int %s(struct %s *, const %s);"
546 % (funcname, self._struct.Name(), self._ctype)
550 def CodeAssign(self):
553 "%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,"
554 " const %(ctype)s value)",
556 " msg->%(name)s_set = 1;",
557 " msg->%(name)s_data = value;",
561 code = "\n".join(code)
562 code = code % self.GetTranslation()
563 return code.split("\n")
565 def CodeClear(self, structname):
566 code = ["%s->%s_set = 0;" % (structname, self.Name())]
571 def CodeComplete(_structname, _var_name):
579 code = ["%(parent_name)s_%(name)s_assign,", "%(parent_name)s_%(name)s_get,"]
581 code.append("%(parent_name)s_%(name)s_add,")
583 code = "\n".join(code)
584 code = code % self.GetTranslation()
585 return code.split("\n")
588 class EntryBytes(Entry):
589 def __init__(self, ent_type, name, tag, length):
591 super(EntryBytes, self).__init__(ent_type, name, tag)
593 self._length = length
594 self._ctype = "ev_uint8_t"
597 def GetInitializer():
600 def GetVarLen(self, _var):
601 return "(%s)" % self._length
604 def CodeArrayAdd(varname, _value):
606 return ["%(varname)s = NULL;" % {"varname": varname}]
608 def GetDeclaration(self, funcname):
610 "int %s(struct %s *, %s **);" % (funcname, self._struct.Name(), self._ctype)
614 def AssignDeclaration(self, funcname):
616 "int %s(struct %s *, const %s *);"
617 % (funcname, self._struct.Name(), self._ctype)
621 def Declaration(self):
622 dcl = ["ev_uint8_t %s_data[%s];" % (self._name, self._length)]
630 "%s_%s_get(struct %s *msg, %s **value)"
631 % (self._struct.Name(), name, self._struct.Name(), self._ctype),
633 " if (msg->%s_set != 1)" % name,
635 " *value = msg->%s_data;" % name,
641 def CodeAssign(self):
645 "%s_%s_assign(struct %s *msg, const %s *value)"
646 % (self._struct.Name(), name, self._struct.Name(), self._ctype),
648 " msg->%s_set = 1;" % name,
649 " memcpy(msg->%s_data, value, %s);" % (name, self._length),
655 def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
657 "if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, "
658 "%(var)s, %(varlen)s) == -1) {",
659 ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
663 return TranslateList(
666 {"var": var_name, "varlen": var_len, "buf": buf, "tag": tag_name}
671 def CodeMarshal(buf, tag_name, var_name, var_len):
672 code = ["evtag_marshal(%s, %s, %s, %s);" % (buf, tag_name, var_name, var_len)]
675 def CodeClear(self, structname):
677 "%s->%s_set = 0;" % (structname, self.Name()),
678 "memset(%s->%s_data, 0, sizeof(%s->%s_data));"
679 % (structname, self._name, structname, self._name),
684 def CodeInitialize(self, name):
686 "memset(%s->%s_data, 0, sizeof(%s->%s_data));"
687 % (name, self._name, name, self._name)
694 'Entry "%s" needs a length '
695 "around line %d" % (self._name, self.LineCount())
698 super(EntryBytes, self).Verify()
701 class EntryInt(Entry):
702 def __init__(self, ent_type, name, tag, bits=32):
704 super(EntryInt, self).__init__(ent_type, name, tag)
706 self._can_be_array = True
708 self._ctype = "ev_uint32_t"
709 self._marshal_type = "int"
711 self._ctype = "ev_uint64_t"
712 self._marshal_type = "int64"
715 def GetInitializer():
719 def CodeArrayFree(_var):
723 def CodeArrayAssign(varname, srcvar):
724 return ["%(varname)s = %(srcvar)s;" % {"varname": varname, "srcvar": srcvar}]
727 def CodeArrayAdd(varname, value):
728 """Returns a new entry of this type."""
729 return ["%(varname)s = %(value)s;" % {"varname": varname, "value": value}]
731 def CodeUnmarshal(self, buf, tag_name, var_name, _var_len):
733 "if (evtag_unmarshal_%(ma)s(%(buf)s, %(tag)s, &%(var)s) == -1) {",
734 ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
738 code = "\n".join(code) % self.GetTranslation(
739 {"ma": self._marshal_type, "buf": buf, "tag": tag_name, "var": var_name}
741 return code.split("\n")
743 def CodeMarshal(self, buf, tag_name, var_name, _var_len):
745 "evtag_marshal_%s(%s, %s, %s);"
746 % (self._marshal_type, buf, tag_name, var_name)
750 def Declaration(self):
751 dcl = ["%s %s_data;" % (self._ctype, self._name)]
755 def CodeInitialize(self, name):
756 code = ["%s->%s_data = 0;" % (name, self._name)]
760 class EntryString(Entry):
761 def __init__(self, ent_type, name, tag):
763 super(EntryString, self).__init__(ent_type, name, tag)
765 self._can_be_array = True
766 self._ctype = "char *"
769 def GetInitializer():
773 def CodeArrayFree(varname):
774 code = ["if (%(var)s != NULL) free(%(var)s);"]
776 return TranslateList(code, {"var": varname})
779 def CodeArrayAssign(varname, srcvar):
781 "if (%(var)s != NULL)",
783 "%(var)s = strdup(%(srcvar)s);",
784 "if (%(var)s == NULL) {",
785 ' event_warnx("%%s: strdup", __func__);',
790 return TranslateList(code, {"var": varname, "srcvar": srcvar})
793 def CodeArrayAdd(varname, value):
795 "if (%(value)s != NULL) {",
796 " %(var)s = strdup(%(value)s);",
797 " if (%(var)s == NULL) {",
805 return TranslateList(code, {"var": varname, "value": value})
807 def GetVarLen(self, var):
808 return "strlen(%s)" % self.GetVarName(var)
811 def CodeMakeInitalize(varname):
812 return "%(varname)s = NULL;" % {"varname": varname}
814 def CodeAssign(self):
816 %(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
817 const %(ctype)s value)
819 if (msg->%(name)s_data != NULL)
820 free(msg->%(name)s_data);
821 if ((msg->%(name)s_data = strdup(value)) == NULL)
823 msg->%(name)s_set = 1;
826 self.GetTranslation()
829 return code.split("\n")
831 def CodeUnmarshal(self, buf, tag_name, var_name, _var_len):
833 "if (evtag_unmarshal_string(%(buf)s, %(tag)s, &%(var)s) == -1) {",
834 ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
838 code = "\n".join(code) % self.GetTranslation(
839 {"buf": buf, "tag": tag_name, "var": var_name}
841 return code.split("\n")
844 def CodeMarshal(buf, tag_name, var_name, _var_len):
845 code = ["evtag_marshal_string(%s, %s, %s);" % (buf, tag_name, var_name)]
848 def CodeClear(self, structname):
850 "if (%s->%s_set == 1) {" % (structname, self.Name()),
851 " free(%s->%s_data);" % (structname, self.Name()),
852 " %s->%s_data = NULL;" % (structname, self.Name()),
853 " %s->%s_set = 0;" % (structname, self.Name()),
859 def CodeInitialize(self, name):
860 code = ["%s->%s_data = NULL;" % (name, self._name)]
863 def CodeFree(self, name):
865 "if (%s->%s_data != NULL)" % (name, self._name),
866 " free (%s->%s_data);" % (name, self._name),
871 def Declaration(self):
872 dcl = ["char *%s_data;" % self._name]
877 class EntryStruct(Entry):
878 def __init__(self, ent_type, name, tag, refname):
880 super(EntryStruct, self).__init__(ent_type, name, tag)
882 self._optpointer = False
883 self._can_be_array = True
884 self._refname = refname
885 self._ctype = "struct %s*" % refname
886 self._optaddarg = False
888 def GetInitializer(self):
891 def GetVarLen(self, _var):
894 def CodeArrayAdd(self, varname, _value):
896 "%(varname)s = %(refname)s_new();",
897 "if (%(varname)s == NULL)",
901 return TranslateList(code, self.GetTranslation({"varname": varname}))
903 def CodeArrayFree(self, var):
904 code = ["%(refname)s_free(%(var)s);" % self.GetTranslation({"var": var})]
907 def CodeArrayAssign(self, var, srcvar):
909 "int had_error = 0;",
910 "struct evbuffer *tmp = NULL;",
911 "%(refname)s_clear(%(var)s);",
912 "if ((tmp = evbuffer_new()) == NULL) {",
913 ' event_warn("%%s: evbuffer_new()", __func__);',
917 "%(refname)s_marshal(tmp, %(srcvar)s);",
918 "if (%(refname)s_unmarshal(%(var)s, tmp) == -1) {",
919 ' event_warnx("%%s: %(refname)s_unmarshal", __func__);',
925 " evbuffer_free(tmp);",
927 " %(refname)s_clear(%(var)s);",
932 return TranslateList(code, self.GetTranslation({"var": var, "srcvar": srcvar}))
938 "%s_%s_get(struct %s *msg, %s *value)"
939 % (self._struct.Name(), name, self._struct.Name(), self._ctype),
941 " if (msg->%s_set != 1) {" % name,
942 " msg->%s_data = %s_new();" % (name, self._refname),
943 " if (msg->%s_data == NULL)" % name,
945 " msg->%s_set = 1;" % name,
947 " *value = msg->%s_data;" % name,
953 def CodeAssign(self):
956 %(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
957 const %(ctype)s value)
959 struct evbuffer *tmp = NULL;
960 if (msg->%(name)s_set) {
961 %(refname)s_clear(msg->%(name)s_data);
962 msg->%(name)s_set = 0;
964 msg->%(name)s_data = %(refname)s_new();
965 if (msg->%(name)s_data == NULL) {
966 event_warn("%%s: %(refname)s_new()", __func__);
970 if ((tmp = evbuffer_new()) == NULL) {
971 event_warn("%%s: evbuffer_new()", __func__);
974 %(refname)s_marshal(tmp, value);
975 if (%(refname)s_unmarshal(msg->%(name)s_data, tmp) == -1) {
976 event_warnx("%%s: %(refname)s_unmarshal", __func__);
979 msg->%(name)s_set = 1;
985 if (msg->%(name)s_data != NULL) {
986 %(refname)s_free(msg->%(name)s_data);
987 msg->%(name)s_data = NULL;
991 % self.GetTranslation()
993 return code.split("\n")
995 def CodeComplete(self, structname, var_name):
997 "if (%(structname)s->%(name)s_set && "
998 "%(refname)s_complete(%(var)s) == -1)",
1002 return TranslateList(
1003 code, self.GetTranslation({"structname": structname, "var": var_name})
1006 def CodeUnmarshal(self, buf, tag_name, var_name, _var_len):
1008 "%(var)s = %(refname)s_new();",
1009 "if (%(var)s == NULL)",
1011 "if (evtag_unmarshal_%(refname)s(%(buf)s, %(tag)s, ",
1012 " %(var)s) == -1) {",
1013 ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
1017 code = "\n".join(code) % self.GetTranslation(
1018 {"buf": buf, "tag": tag_name, "var": var_name}
1020 return code.split("\n")
1022 def CodeMarshal(self, buf, tag_name, var_name, _var_len):
1024 "evtag_marshal_%s(%s, %s, %s);" % (self._refname, buf, tag_name, var_name)
1028 def CodeClear(self, structname):
1030 "if (%s->%s_set == 1) {" % (structname, self.Name()),
1031 " %s_free(%s->%s_data);" % (self._refname, structname, self.Name()),
1032 " %s->%s_data = NULL;" % (structname, self.Name()),
1033 " %s->%s_set = 0;" % (structname, self.Name()),
1039 def CodeInitialize(self, name):
1040 code = ["%s->%s_data = NULL;" % (name, self._name)]
1043 def CodeFree(self, name):
1045 "if (%s->%s_data != NULL)" % (name, self._name),
1046 " %s_free(%s->%s_data);" % (self._refname, name, self._name),
1051 def Declaration(self):
1052 dcl = ["%s %s_data;" % (self._ctype, self._name)]
1057 class EntryVarBytes(Entry):
1058 def __init__(self, ent_type, name, tag):
1060 super(EntryVarBytes, self).__init__(ent_type, name, tag)
1062 self._ctype = "ev_uint8_t *"
1065 def GetInitializer():
1068 def GetVarLen(self, var):
1069 return "%(var)s->%(name)s_length" % self.GetTranslation({"var": var})
1072 def CodeArrayAdd(varname, _value):
1074 return ["%(varname)s = NULL;" % {"varname": varname}]
1076 def GetDeclaration(self, funcname):
1078 "int %s(struct %s *, %s *, ev_uint32_t *);"
1079 % (funcname, self._struct.Name(), self._ctype)
1083 def AssignDeclaration(self, funcname):
1085 "int %s(struct %s *, const %s, ev_uint32_t);"
1086 % (funcname, self._struct.Name(), self._ctype)
1090 def CodeAssign(self):
1094 "%s_%s_assign(struct %s *msg, "
1095 "const %s value, ev_uint32_t len)"
1096 % (self._struct.Name(), name, self._struct.Name(), self._ctype),
1098 " if (msg->%s_data != NULL)" % name,
1099 " free (msg->%s_data);" % name,
1100 " msg->%s_data = malloc(len);" % name,
1101 " if (msg->%s_data == NULL)" % name,
1103 " msg->%s_set = 1;" % name,
1104 " msg->%s_length = len;" % name,
1105 " memcpy(msg->%s_data, value, len);" % name,
1115 "%s_%s_get(struct %s *msg, %s *value, ev_uint32_t *plen)"
1116 % (self._struct.Name(), name, self._struct.Name(), self._ctype),
1118 " if (msg->%s_set != 1)" % name,
1120 " *value = msg->%s_data;" % name,
1121 " *plen = msg->%s_length;" % name,
1127 def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
1129 "if (evtag_payload_length(%(buf)s, &%(varlen)s) == -1)",
1131 # We do not want DoS opportunities
1132 "if (%(varlen)s > evbuffer_get_length(%(buf)s))",
1134 "if ((%(var)s = malloc(%(varlen)s)) == NULL)",
1136 "if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, %(var)s, "
1137 "%(varlen)s) == -1) {",
1138 ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
1142 code = "\n".join(code) % self.GetTranslation(
1143 {"buf": buf, "tag": tag_name, "var": var_name, "varlen": var_len}
1145 return code.split("\n")
1148 def CodeMarshal(buf, tag_name, var_name, var_len):
1149 code = ["evtag_marshal(%s, %s, %s, %s);" % (buf, tag_name, var_name, var_len)]
1152 def CodeClear(self, structname):
1154 "if (%s->%s_set == 1) {" % (structname, self.Name()),
1155 " free (%s->%s_data);" % (structname, self.Name()),
1156 " %s->%s_data = NULL;" % (structname, self.Name()),
1157 " %s->%s_length = 0;" % (structname, self.Name()),
1158 " %s->%s_set = 0;" % (structname, self.Name()),
1164 def CodeInitialize(self, name):
1166 "%s->%s_data = NULL;" % (name, self._name),
1167 "%s->%s_length = 0;" % (name, self._name),
1171 def CodeFree(self, name):
1173 "if (%s->%s_data != NULL)" % (name, self._name),
1174 " free(%s->%s_data);" % (name, self._name),
1179 def Declaration(self):
1181 "ev_uint8_t *%s_data;" % self._name,
1182 "ev_uint32_t %s_length;" % self._name,
1188 class EntryArray(Entry):
1191 def __init__(self, entry):
1193 super(EntryArray, self).__init__(entry._type, entry._name, entry._tag)
1196 self._refname = entry._refname
1197 self._ctype = self._entry._ctype
1198 self._optional = True
1199 self._optpointer = self._entry._optpointer
1200 self._optaddarg = self._entry._optaddarg
1202 # provide a new function for accessing the variable name
1203 def GetVarName(var_name):
1204 return "%(var)s->%(name)s_data[%(index)s]" % self._entry.GetTranslation(
1205 {"var": var_name, "index": self._index}
1208 self._entry.GetVarName = GetVarName
1210 def GetInitializer(self):
1213 def GetVarName(self, var):
1216 def GetVarLen(self, _var_name):
1219 def GetDeclaration(self, funcname):
1220 """Allows direct access to elements of the array."""
1222 "int %(funcname)s(struct %(parent_name)s *, int, %(ctype)s *);"
1223 % self.GetTranslation({"funcname": funcname})
1227 def AssignDeclaration(self, funcname):
1229 "int %s(struct %s *, int, const %s);"
1230 % (funcname, self._struct.Name(), self._ctype)
1234 def AddDeclaration(self, funcname):
1236 "%(ctype)s %(optpointer)s "
1237 "%(funcname)s(struct %(parent_name)s *msg%(optaddarg)s);"
1238 % self.GetTranslation({"funcname": funcname})
1244 %(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, int offset,
1247 if (!msg->%(name)s_set || offset < 0 || offset >= msg->%(name)s_length)
1249 *value = msg->%(name)s_data[offset];
1253 self.GetTranslation()
1256 return code.splitlines()
1258 def CodeAssign(self):
1261 "%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, int off,",
1262 " const %(ctype)s value)",
1264 " if (!msg->%(name)s_set || off < 0 || off >= msg->%(name)s_length)",
1269 code = TranslateList(code, self.GetTranslation())
1271 codearrayassign = self._entry.CodeArrayAssign(
1272 "msg->%(name)s_data[off]" % self.GetTranslation(), "value"
1274 code += [" " + x for x in codearrayassign]
1276 code += TranslateList([" }", " return (0);", "}"], self.GetTranslation())
1281 codearrayadd = self._entry.CodeArrayAdd(
1282 "msg->%(name)s_data[msg->%(name)s_length - 1]" % self.GetTranslation(),
1287 "%(parent_name)s_%(name)s_expand_to_hold_more("
1288 "struct %(parent_name)s *msg)",
1290 " int tobe_allocated = msg->%(name)s_num_allocated;",
1291 " %(ctype)s* new_data = NULL;",
1292 " tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;",
1293 " new_data = (%(ctype)s*) realloc(msg->%(name)s_data,",
1294 " tobe_allocated * sizeof(%(ctype)s));",
1295 " if (new_data == NULL)",
1297 " msg->%(name)s_data = new_data;",
1298 " msg->%(name)s_num_allocated = tobe_allocated;",
1302 "%(ctype)s %(optpointer)s",
1303 "%(parent_name)s_%(name)s_add(struct %(parent_name)s *msg%(optaddarg)s)",
1305 " if (++msg->%(name)s_length >= msg->%(name)s_num_allocated) {",
1306 " if (%(parent_name)s_%(name)s_expand_to_hold_more(msg)<0)",
1311 code = TranslateList(code, self.GetTranslation())
1313 code += [" " + x for x in codearrayadd]
1315 code += TranslateList(
1317 " msg->%(name)s_set = 1;",
1318 " return %(optreference)s(msg->%(name)s_data["
1319 "msg->%(name)s_length - 1]);",
1321 " --msg->%(name)s_length;",
1325 self.GetTranslation(),
1330 def CodeComplete(self, structname, var_name):
1332 tmp = self._entry.CodeComplete(structname, self._entry.GetVarName(var_name))
1333 # skip the whole loop if there is nothing to check
1337 translate = self.GetTranslation({"structname": structname})
1341 " for (i = 0; i < %(structname)s->%(name)s_length; ++i) {",
1344 code = TranslateList(code, translate)
1346 code += [" " + x for x in tmp]
1352 def CodeUnmarshal(self, buf, tag_name, var_name, _var_len):
1353 translate = self.GetTranslation(
1358 "init": self._entry.GetInitializer(),
1362 "if (%(var)s->%(name)s_length >= %(var)s->%(name)s_num_allocated &&",
1363 " %(parent_name)s_%(name)s_expand_to_hold_more(%(var)s) < 0) {",
1364 ' puts("HEY NOW");',
1369 # the unmarshal code directly returns
1370 code = TranslateList(code, translate)
1372 self._index = "%(var)s->%(name)s_length" % translate
1373 code += self._entry.CodeUnmarshal(
1376 self._entry.GetVarName(var_name),
1377 self._entry.GetVarLen(var_name),
1380 code += ["++%(var)s->%(name)s_length;" % translate]
1384 def CodeMarshal(self, buf, tag_name, var_name, _var_len):
1385 code = ["{", " int i;", " for (i = 0; i < %(var)s->%(name)s_length; ++i) {"]
1388 code += self._entry.CodeMarshal(
1391 self._entry.GetVarName(var_name),
1392 self._entry.GetVarLen(var_name),
1396 code = "\n".join(code) % self.GetTranslation({"var": var_name})
1398 return code.split("\n")
1400 def CodeClear(self, structname):
1401 translate = self.GetTranslation({"structname": structname})
1402 codearrayfree = self._entry.CodeArrayFree(
1403 "%(structname)s->%(name)s_data[i]"
1404 % self.GetTranslation({"structname": structname})
1407 code = ["if (%(structname)s->%(name)s_set == 1) {"]
1412 " for (i = 0; i < %(structname)s->%(name)s_length; ++i) {",
1415 code = TranslateList(code, translate)
1418 code += [" " + x for x in codearrayfree]
1421 code += TranslateList(
1423 " free(%(structname)s->%(name)s_data);",
1424 " %(structname)s->%(name)s_data = NULL;",
1425 " %(structname)s->%(name)s_set = 0;",
1426 " %(structname)s->%(name)s_length = 0;",
1427 " %(structname)s->%(name)s_num_allocated = 0;",
1435 def CodeInitialize(self, name):
1437 "%s->%s_data = NULL;" % (name, self._name),
1438 "%s->%s_length = 0;" % (name, self._name),
1439 "%s->%s_num_allocated = 0;" % (name, self._name),
1443 def CodeFree(self, structname):
1444 code = self.CodeClear(structname)
1446 code += TranslateList(
1447 ["free(%(structname)s->%(name)s_data);"],
1448 self.GetTranslation({"structname": structname}),
1453 def Declaration(self):
1455 "%s *%s_data;" % (self._ctype, self._name),
1456 "int %s_length;" % self._name,
1457 "int %s_num_allocated;" % self._name,
1463 def NormalizeLine(line):
1465 line = CPPCOMMENT_RE.sub("", line)
1467 line = WHITESPACE_RE.sub(" ", line)
1472 ENTRY_NAME_RE = re.compile(r"(?P<name>[^\[\]]+)(\[(?P<fixed_length>.*)\])?")
1473 ENTRY_TAG_NUMBER_RE = re.compile(r"(0x)?\d+", re.I)
1476 def ProcessOneEntry(factory, newstruct, entry):
1486 for token in entry.split(" "):
1488 if not optional and token == "optional":
1492 if not array and token == "array":
1501 res = ENTRY_NAME_RE.match(token)
1504 r"""Cannot parse name: "%s" around line %d""" % (entry, LINE_COUNT)
1506 name = res.group("name")
1507 fixed_length = res.group("fixed_length")
1512 if separator != "=":
1514 r'''Expected "=" after name "%s" got "%s"''' % (name, token)
1520 if not ENTRY_TAG_NUMBER_RE.match(token):
1521 raise RpcGenError(r'''Expected tag number: "%s"''' % (entry))
1525 raise RpcGenError(r'''Cannot parse "%s"''' % (entry))
1528 raise RpcGenError(r'''Need tag number: "%s"''' % (entry))
1530 # Create the right entry
1531 if entry_type == "bytes":
1533 newentry = factory.EntryBytes(entry_type, name, tag, fixed_length)
1535 newentry = factory.EntryVarBytes(entry_type, name, tag)
1536 elif entry_type == "int" and not fixed_length:
1537 newentry = factory.EntryInt(entry_type, name, tag)
1538 elif entry_type == "int64" and not fixed_length:
1539 newentry = factory.EntryInt(entry_type, name, tag, bits=64)
1540 elif entry_type == "string" and not fixed_length:
1541 newentry = factory.EntryString(entry_type, name, tag)
1543 res = STRUCT_REF_RE.match(entry_type)
1545 # References another struct defined in our file
1546 newentry = factory.EntryStruct(entry_type, name, tag, res.group("name"))
1548 raise RpcGenError('Bad type: "%s" in "%s"' % (entry_type, entry))
1553 newentry.MakeOptional()
1555 newentry.MakeArray()
1557 newentry.SetStruct(newstruct)
1558 newentry.SetLineCount(LINE_COUNT)
1562 # We need to encapsulate this entry into a struct
1563 newentry = factory.EntryArray(newentry)
1564 newentry.SetStruct(newstruct)
1565 newentry.SetLineCount(LINE_COUNT)
1566 newentry.MakeArray()
1568 newstruct.AddEntry(newentry)
1573 def ProcessStruct(factory, data):
1574 tokens = data.split(" ")
1576 # First three tokens are: 'struct' 'name' '{'
1577 newstruct = factory.Struct(tokens[1])
1579 inside = " ".join(tokens[3:-1])
1581 tokens = inside.split(";")
1585 for entry in tokens:
1586 entry = NormalizeLine(entry)
1590 # It's possible that new structs get defined in here
1591 structs.extend(ProcessOneEntry(factory, newstruct, entry))
1593 structs.append(newstruct)
1597 C_COMMENT_START = "/*"
1598 C_COMMENT_END = "*/"
1600 C_COMMENT_START_RE = re.compile(re.escape(C_COMMENT_START))
1601 C_COMMENT_END_RE = re.compile(re.escape(C_COMMENT_END))
1603 C_COMMENT_START_SUB_RE = re.compile(r"%s.*$" % (re.escape(C_COMMENT_START)))
1604 C_COMMENT_END_SUB_RE = re.compile(r"%s.*$" % (re.escape(C_COMMENT_END)))
1606 C_MULTILINE_COMMENT_SUB_RE = re.compile(
1607 r"%s.*?%s" % (re.escape(C_COMMENT_START), re.escape(C_COMMENT_END))
1609 CPP_CONDITIONAL_BLOCK_RE = re.compile(r"#(if( |def)|endif)")
1610 INCLUDE_RE = re.compile(r'#include (".+"|<.+>)')
1613 def GetNextStruct(filep):
1618 have_c_comment = False
1623 line = filep.readline()
1630 if not have_c_comment and C_COMMENT_START_RE.search(line):
1631 if C_MULTILINE_COMMENT_SUB_RE.search(line):
1632 line = C_MULTILINE_COMMENT_SUB_RE.sub("", line)
1634 line = C_COMMENT_START_SUB_RE.sub("", line)
1635 have_c_comment = True
1638 if not C_COMMENT_END_RE.search(line):
1640 have_c_comment = False
1641 line = C_COMMENT_END_SUB_RE.sub("", line)
1643 line = NormalizeLine(line)
1649 if INCLUDE_RE.match(line):
1650 CPP_DIRECT.append(line)
1651 elif CPP_CONDITIONAL_BLOCK_RE.match(line):
1652 CPP_DIRECT.append(line)
1653 elif PREPROCESSOR_DEF_RE.match(line):
1654 HEADER_DIRECT.append(line)
1655 elif not STRUCT_DEF_RE.match(line):
1656 raise RpcGenError("Missing struct on line %d: %s" % (LINE_COUNT, line))
1662 # We are inside the struct
1663 tokens = line.split("}")
1664 if len(tokens) == 1:
1669 raise RpcGenError("Trailing garbage after struct on line %d" % LINE_COUNT)
1671 # We found the end of the struct
1672 data += " %s}" % tokens[0]
1675 # Remove any comments, that might be in there
1676 data = re.sub(r"/\*.*\*/", "", data)
1681 def Parse(factory, filep):
1683 Parses the input file and returns C code and corresponding header file.
1689 # Just gets the whole struct nicely formatted
1690 data = GetNextStruct(filep)
1695 entities.extend(ProcessStruct(factory, data))
1700 class CCodeGenerator(object):
1705 def GuardName(name):
1706 # Use the complete provided path to the input file, with all
1707 # non-identifier characters replaced with underscores, to
1708 # reduce the chance of a collision between guard macros.
1709 return "EVENT_RPCOUT_%s_" % (NONIDENT_RE.sub("_", name).upper())
1711 def HeaderPreamble(self, name):
1712 guard = self.GuardName(name)
1715 * Automatically generated from %s
1728 for statement in HEADER_DIRECT:
1729 pre += "%s\n" % statement
1733 #include <event2/util.h> /* for ev_uint*_t */
1734 #include <event2/rpc.h>
1739 def HeaderPostamble(self, name):
1740 guard = self.GuardName(name)
1741 return "#endif /* %s */" % (guard)
1744 def BodyPreamble(name, header_file):
1748 slash = header_file.rfind("/")
1750 header_file = header_file[slash + 1 :]
1754 * Automatically generated from %(name)s
1755 * by %(script_name)s/%(script_version)s. DO NOT EDIT THIS FILE.
1761 #include <event2/event-config.h>
1762 #include <event2/event.h>
1763 #include <event2/buffer.h>
1764 #include <event2/tag.h>
1766 #if defined(EVENT__HAVE___func__)
1768 # define __func__ __func__
1770 #elif defined(EVENT__HAVE___FUNCTION__)
1771 # define __func__ __FUNCTION__
1773 # define __func__ __FILE__
1778 "script_name": _NAME,
1779 "script_version": _VERSION,
1782 for statement in CPP_DIRECT:
1783 pre += "%s\n" % statement
1785 pre += '\n#include "%s"\n\n' % header_file
1787 pre += "void event_warn(const char *fmt, ...);\n"
1788 pre += "void event_warnx(const char *fmt, ...);\n\n"
1793 def HeaderFilename(filename):
1794 return ".".join(filename.split(".")[:-1]) + ".h"
1797 def CodeFilename(filename):
1798 return ".".join(filename.split(".")[:-1]) + ".gen.c"
1802 return StructCCode(name)
1805 def EntryBytes(entry_type, name, tag, fixed_length):
1806 return EntryBytes(entry_type, name, tag, fixed_length)
1809 def EntryVarBytes(entry_type, name, tag):
1810 return EntryVarBytes(entry_type, name, tag)
1813 def EntryInt(entry_type, name, tag, bits=32):
1814 return EntryInt(entry_type, name, tag, bits)
1817 def EntryString(entry_type, name, tag):
1818 return EntryString(entry_type, name, tag)
1821 def EntryStruct(entry_type, name, tag, struct_name):
1822 return EntryStruct(entry_type, name, tag, struct_name)
1825 def EntryArray(entry):
1826 return EntryArray(entry)
1829 class CommandLine(object):
1830 def __init__(self, argv=None):
1831 """Initialize a command-line to launch event_rpcgen, as if
1832 from a command-line with CommandLine(sys.argv). If you're
1833 calling this directly, remember to provide a dummy value
1838 self.filename = None
1839 self.header_file = None
1840 self.impl_file = None
1841 self.factory = CCodeGenerator()
1843 parser = argparse.ArgumentParser(
1844 usage="%(prog)s [options] rpc-file [[h-file] c-file]"
1846 parser.add_argument("--quiet", action="store_true", default=False)
1847 parser.add_argument("rpc_file", type=argparse.FileType("r"))
1849 args, extra_args = parser.parse_known_args(args=argv)
1851 QUIETLY = args.quiet
1854 if len(extra_args) == 1:
1855 self.impl_file = extra_args[0].replace("\\", "/")
1856 elif len(extra_args) == 2:
1857 self.header_file = extra_args[0].replace("\\", "/")
1858 self.impl_file = extra_args[1].replace("\\", "/")
1860 parser.error("Spurious arguments provided")
1862 self.rpc_file = args.rpc_file
1864 if not self.impl_file:
1865 self.impl_file = self.factory.CodeFilename(self.rpc_file.name)
1867 if not self.header_file:
1868 self.header_file = self.factory.HeaderFilename(self.impl_file)
1870 if not self.impl_file.endswith(".c"):
1871 parser.error("can only generate C implementation files")
1872 if not self.header_file.endswith(".h"):
1873 parser.error("can only generate C header files")
1876 filename = self.rpc_file.name
1877 header_file = self.header_file
1878 impl_file = self.impl_file
1879 factory = self.factory
1881 declare('Reading "%s"' % filename)
1884 entities = Parse(factory, self.rpc_file)
1886 declare('... creating "%s"' % header_file)
1887 with open(header_file, "w") as header_fp:
1888 header_fp.write(factory.HeaderPreamble(filename))
1890 # Create forward declarations: allows other structs to reference
1892 for entry in entities:
1893 entry.PrintForwardDeclaration(header_fp)
1894 header_fp.write("\n")
1896 for entry in entities:
1897 entry.PrintTags(header_fp)
1898 entry.PrintDeclaration(header_fp)
1899 header_fp.write(factory.HeaderPostamble(filename))
1901 declare('... creating "%s"' % impl_file)
1902 with open(impl_file, "w") as impl_fp:
1903 impl_fp.write(factory.BodyPreamble(filename, header_file))
1904 for entry in entities:
1905 entry.PrintCode(impl_fp)
1908 def main(argv=None):
1910 CommandLine(argv=argv).run()
1912 except RpcGenError as e:
1914 except EnvironmentError as e:
1915 if e.filename and e.strerror:
1916 sys.stderr.write("%s: %s" % (e.filename, e.strerror))
1918 sys.stderr.write(e.strerror)
1924 if __name__ == "__main__":
1925 sys.exit(main(argv=sys.argv[1:]))