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