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