blob: 0911ca253c5d8eb81ef8283addcc5dfcc10d74e5 [file] [log] [blame]
Haibo Huangb2279672019-05-31 16:12:39 -07001#!/usr/bin/env python
Christopher Wileye8679812015-07-01 13:36:18 -07002#
3# Copyright (c) 2005-2007 Niels Provos <provos@citi.umich.edu>
4# Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
5# All rights reserved.
6#
7# Generates marshaling code based on libevent.
8
9# TODO:
10# 1) use optparse to allow the strategy shell to parse options, and
11# to allow the instantiated factory (for the specific output language)
12# to parse remaining options
13# 2) move the globals into a class that manages execution (including the
14# progress outputs that space stderr at the moment)
15# 3) emit other languages
16
17import sys
18import re
19
20_NAME = "event_rpcgen.py"
21_VERSION = "0.1"
22
23# Globals
24line_count = 0
25
26white = re.compile(r'\s+')
27cppcomment = re.compile(r'\/\/.*$')
28nonident = re.compile(r'[^a-zA-Z0-9_]')
29structref = re.compile(r'^struct\[([a-zA-Z_][a-zA-Z0-9_]*)\]$')
30structdef = re.compile(r'^struct +[a-zA-Z_][a-zA-Z0-9_]* *{$')
31
32headerdirect = []
33cppdirect = []
34
Narayan Kamathfc74cb42017-09-13 12:53:52 +010035QUIETLY = 0
36
37def declare(s):
38 if not QUIETLY:
Haibo Huangb2279672019-05-31 16:12:39 -070039 print(s)
Narayan Kamathfc74cb42017-09-13 12:53:52 +010040
Christopher Wileye8679812015-07-01 13:36:18 -070041def TranslateList(mylist, mydict):
Haibo Huangb2279672019-05-31 16:12:39 -070042 return [x % mydict for x in mylist]
Christopher Wileye8679812015-07-01 13:36:18 -070043
44# Exception class for parse errors
45class RpcGenError(Exception):
46 def __init__(self, why):
47 self.why = why
48 def __str__(self):
49 return str(self.why)
50
51# Holds everything that makes a struct
52class Struct:
53 def __init__(self, name):
54 self._name = name
55 self._entries = []
56 self._tags = {}
Narayan Kamathfc74cb42017-09-13 12:53:52 +010057 declare(' Created struct: %s' % name)
Christopher Wileye8679812015-07-01 13:36:18 -070058
59 def AddEntry(self, entry):
Haibo Huangb2279672019-05-31 16:12:39 -070060 if entry.Tag() in self._tags:
Christopher Wileye8679812015-07-01 13:36:18 -070061 raise RpcGenError(
62 'Entry "%s" duplicates tag number %d from "%s" '
63 'around line %d' % (entry.Name(), entry.Tag(),
64 self._tags[entry.Tag()], line_count))
65 self._entries.append(entry)
66 self._tags[entry.Tag()] = entry.Name()
Narayan Kamathfc74cb42017-09-13 12:53:52 +010067 declare(' Added entry: %s' % entry.Name())
Christopher Wileye8679812015-07-01 13:36:18 -070068
69 def Name(self):
70 return self._name
71
72 def EntryTagName(self, entry):
73 """Creates the name inside an enumeration for distinguishing data
74 types."""
75 name = "%s_%s" % (self._name, entry.Name())
76 return name.upper()
77
78 def PrintIndented(self, file, ident, code):
79 """Takes an array, add indentation to each entry and prints it."""
80 for entry in code:
Haibo Huangb2279672019-05-31 16:12:39 -070081 file.write('%s%s\n' % (ident, entry))
Christopher Wileye8679812015-07-01 13:36:18 -070082
83class StructCCode(Struct):
84 """ Knows how to generate C code for a struct """
85
86 def __init__(self, name):
87 Struct.__init__(self, name)
88
89 def PrintTags(self, file):
90 """Prints the tag definitions for a structure."""
Haibo Huangb2279672019-05-31 16:12:39 -070091 file.write('/* Tag definition for %s */\n' % self._name)
92 file.write('enum %s_ {\n' % self._name.lower())
Christopher Wileye8679812015-07-01 13:36:18 -070093 for entry in self._entries:
Haibo Huangb2279672019-05-31 16:12:39 -070094 file.write(' %s=%d,\n' % (self.EntryTagName(entry), entry.Tag()))
95 file.write(' %s_MAX_TAGS\n' % (self._name.upper()))
96 file.write('};\n\n')
Christopher Wileye8679812015-07-01 13:36:18 -070097
98 def PrintForwardDeclaration(self, file):
Haibo Huangb2279672019-05-31 16:12:39 -070099 file.write('struct %s;\n' % self._name)
Christopher Wileye8679812015-07-01 13:36:18 -0700100
101 def PrintDeclaration(self, file):
Haibo Huangb2279672019-05-31 16:12:39 -0700102 file.write('/* Structure declaration for %s */\n' % self._name)
103 file.write('struct %s_access_ {\n' % self._name)
Christopher Wileye8679812015-07-01 13:36:18 -0700104 for entry in self._entries:
105 dcl = entry.AssignDeclaration('(*%s_assign)' % entry.Name())
106 dcl.extend(
107 entry.GetDeclaration('(*%s_get)' % entry.Name()))
108 if entry.Array():
109 dcl.extend(
110 entry.AddDeclaration('(*%s_add)' % entry.Name()))
111 self.PrintIndented(file, ' ', dcl)
Haibo Huangb2279672019-05-31 16:12:39 -0700112 file.write('};\n\n')
Christopher Wileye8679812015-07-01 13:36:18 -0700113
Haibo Huangb2279672019-05-31 16:12:39 -0700114 file.write('struct %s {\n' % self._name)
115 file.write(' struct %s_access_ *base;\n\n' % self._name)
Christopher Wileye8679812015-07-01 13:36:18 -0700116 for entry in self._entries:
117 dcl = entry.Declaration()
118 self.PrintIndented(file, ' ', dcl)
Haibo Huangb2279672019-05-31 16:12:39 -0700119 file.write('\n')
Christopher Wileye8679812015-07-01 13:36:18 -0700120 for entry in self._entries:
Haibo Huangb2279672019-05-31 16:12:39 -0700121 file.write(' ev_uint8_t %s_set;\n' % entry.Name())
122 file.write('};\n\n')
Christopher Wileye8679812015-07-01 13:36:18 -0700123
Haibo Huangb2279672019-05-31 16:12:39 -0700124 file.write("""struct %(name)s *%(name)s_new(void);
Christopher Wileye8679812015-07-01 13:36:18 -0700125struct %(name)s *%(name)s_new_with_arg(void *);
126void %(name)s_free(struct %(name)s *);
127void %(name)s_clear(struct %(name)s *);
128void %(name)s_marshal(struct evbuffer *, const struct %(name)s *);
129int %(name)s_unmarshal(struct %(name)s *, struct evbuffer *);
130int %(name)s_complete(struct %(name)s *);
131void evtag_marshal_%(name)s(struct evbuffer *, ev_uint32_t,
132 const struct %(name)s *);
133int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
Haibo Huangb2279672019-05-31 16:12:39 -0700134 struct %(name)s *);\n""" % { 'name' : self._name })
Christopher Wileye8679812015-07-01 13:36:18 -0700135
136
137 # Write a setting function of every variable
138 for entry in self._entries:
139 self.PrintIndented(file, '', entry.AssignDeclaration(
140 entry.AssignFuncName()))
141 self.PrintIndented(file, '', entry.GetDeclaration(
142 entry.GetFuncName()))
143 if entry.Array():
144 self.PrintIndented(file, '', entry.AddDeclaration(
145 entry.AddFuncName()))
146
Haibo Huangb2279672019-05-31 16:12:39 -0700147 file.write('/* --- %s done --- */\n\n' % self._name)
Christopher Wileye8679812015-07-01 13:36:18 -0700148
149 def PrintCode(self, file):
Haibo Huangb2279672019-05-31 16:12:39 -0700150 file.write(('/*\n'
Christopher Wileye8679812015-07-01 13:36:18 -0700151 ' * Implementation of %s\n'
Haibo Huangb2279672019-05-31 16:12:39 -0700152 ' */\n\n') % self._name)
Christopher Wileye8679812015-07-01 13:36:18 -0700153
Haibo Huangb2279672019-05-31 16:12:39 -0700154 file.write('static struct %(name)s_access_ %(name)s_base__ = {\n' % \
155 { 'name' : self._name })
Christopher Wileye8679812015-07-01 13:36:18 -0700156 for entry in self._entries:
157 self.PrintIndented(file, ' ', entry.CodeBase())
Haibo Huangb2279672019-05-31 16:12:39 -0700158 file.write('};\n\n')
Christopher Wileye8679812015-07-01 13:36:18 -0700159
160 # Creation
Haibo Huangb2279672019-05-31 16:12:39 -0700161 file.write((
Christopher Wileye8679812015-07-01 13:36:18 -0700162 'struct %(name)s *\n'
163 '%(name)s_new(void)\n'
164 '{\n'
165 ' return %(name)s_new_with_arg(NULL);\n'
166 '}\n'
167 '\n'
168 'struct %(name)s *\n'
169 '%(name)s_new_with_arg(void *unused)\n'
170 '{\n'
171 ' struct %(name)s *tmp;\n'
172 ' if ((tmp = malloc(sizeof(struct %(name)s))) == NULL) {\n'
173 ' event_warn("%%s: malloc", __func__);\n'
174 ' return (NULL);\n'
175 ' }\n'
Haibo Huangb2279672019-05-31 16:12:39 -0700176 ' tmp->base = &%(name)s_base__;\n\n') % { 'name' : self._name })
Christopher Wileye8679812015-07-01 13:36:18 -0700177
178 for entry in self._entries:
179 self.PrintIndented(file, ' ', entry.CodeInitialize('tmp'))
Haibo Huangb2279672019-05-31 16:12:39 -0700180 file.write(' tmp->%s_set = 0;\n\n' % entry.Name())
Christopher Wileye8679812015-07-01 13:36:18 -0700181
Haibo Huangb2279672019-05-31 16:12:39 -0700182 file.write((
Christopher Wileye8679812015-07-01 13:36:18 -0700183 ' return (tmp);\n'
Haibo Huangb2279672019-05-31 16:12:39 -0700184 '}\n\n'))
Christopher Wileye8679812015-07-01 13:36:18 -0700185
186 # Adding
187 for entry in self._entries:
188 if entry.Array():
189 self.PrintIndented(file, '', entry.CodeAdd())
Haibo Huangb2279672019-05-31 16:12:39 -0700190 file.write('\n')
Christopher Wileye8679812015-07-01 13:36:18 -0700191
192 # Assigning
193 for entry in self._entries:
194 self.PrintIndented(file, '', entry.CodeAssign())
Haibo Huangb2279672019-05-31 16:12:39 -0700195 file.write('\n')
Christopher Wileye8679812015-07-01 13:36:18 -0700196
197 # Getting
198 for entry in self._entries:
199 self.PrintIndented(file, '', entry.CodeGet())
Haibo Huangb2279672019-05-31 16:12:39 -0700200 file.write('\n')
Christopher Wileye8679812015-07-01 13:36:18 -0700201
202 # Clearing
Haibo Huangb2279672019-05-31 16:12:39 -0700203 file.write(( 'void\n'
Christopher Wileye8679812015-07-01 13:36:18 -0700204 '%(name)s_clear(struct %(name)s *tmp)\n'
205 '{'
Haibo Huangb2279672019-05-31 16:12:39 -0700206 '\n') % { 'name' : self._name })
Christopher Wileye8679812015-07-01 13:36:18 -0700207 for entry in self._entries:
208 self.PrintIndented(file, ' ', entry.CodeClear('tmp'))
209
Haibo Huangb2279672019-05-31 16:12:39 -0700210 file.write('}\n\n')
Christopher Wileye8679812015-07-01 13:36:18 -0700211
212 # Freeing
Haibo Huangb2279672019-05-31 16:12:39 -0700213 file.write(( 'void\n'
Christopher Wileye8679812015-07-01 13:36:18 -0700214 '%(name)s_free(struct %(name)s *tmp)\n'
215 '{'
Haibo Huangb2279672019-05-31 16:12:39 -0700216 '\n') % { 'name' : self._name })
Christopher Wileye8679812015-07-01 13:36:18 -0700217
218 for entry in self._entries:
219 self.PrintIndented(file, ' ', entry.CodeFree('tmp'))
220
Haibo Huangb2279672019-05-31 16:12:39 -0700221 file.write((' free(tmp);\n'
222 '}\n\n'))
Christopher Wileye8679812015-07-01 13:36:18 -0700223
224 # Marshaling
Haibo Huangb2279672019-05-31 16:12:39 -0700225 file.write(('void\n'
Christopher Wileye8679812015-07-01 13:36:18 -0700226 '%(name)s_marshal(struct evbuffer *evbuf, '
227 'const struct %(name)s *tmp)'
Haibo Huangb2279672019-05-31 16:12:39 -0700228 '{\n') % { 'name' : self._name })
Christopher Wileye8679812015-07-01 13:36:18 -0700229 for entry in self._entries:
230 indent = ' '
231 # Optional entries do not have to be set
232 if entry.Optional():
233 indent += ' '
Haibo Huangb2279672019-05-31 16:12:39 -0700234 file.write(' if (tmp->%s_set) {\n' % entry.Name())
Christopher Wileye8679812015-07-01 13:36:18 -0700235 self.PrintIndented(
236 file, indent,
237 entry.CodeMarshal('evbuf', self.EntryTagName(entry),
238 entry.GetVarName('tmp'),
239 entry.GetVarLen('tmp')))
240 if entry.Optional():
Haibo Huangb2279672019-05-31 16:12:39 -0700241 file.write(' }\n')
Christopher Wileye8679812015-07-01 13:36:18 -0700242
Haibo Huangb2279672019-05-31 16:12:39 -0700243 file.write('}\n\n')
Christopher Wileye8679812015-07-01 13:36:18 -0700244
245 # Unmarshaling
Haibo Huangb2279672019-05-31 16:12:39 -0700246 file.write(('int\n'
Christopher Wileye8679812015-07-01 13:36:18 -0700247 '%(name)s_unmarshal(struct %(name)s *tmp, '
248 ' struct evbuffer *evbuf)\n'
249 '{\n'
250 ' ev_uint32_t tag;\n'
251 ' while (evbuffer_get_length(evbuf) > 0) {\n'
252 ' if (evtag_peek(evbuf, &tag) == -1)\n'
253 ' return (-1);\n'
254 ' switch (tag) {\n'
Haibo Huangb2279672019-05-31 16:12:39 -0700255 '\n') % { 'name' : self._name })
Christopher Wileye8679812015-07-01 13:36:18 -0700256 for entry in self._entries:
Haibo Huangb2279672019-05-31 16:12:39 -0700257 file.write(' case %s:\n' % self.EntryTagName(entry))
Christopher Wileye8679812015-07-01 13:36:18 -0700258 if not entry.Array():
Haibo Huangb2279672019-05-31 16:12:39 -0700259 file.write((
Christopher Wileye8679812015-07-01 13:36:18 -0700260 ' if (tmp->%s_set)\n'
261 ' return (-1);'
Haibo Huangb2279672019-05-31 16:12:39 -0700262 '\n') % (entry.Name()))
Christopher Wileye8679812015-07-01 13:36:18 -0700263
264 self.PrintIndented(
265 file, ' ',
266 entry.CodeUnmarshal('evbuf',
267 self.EntryTagName(entry),
268 entry.GetVarName('tmp'),
269 entry.GetVarLen('tmp')))
270
Haibo Huangb2279672019-05-31 16:12:39 -0700271 file.write(( ' tmp->%s_set = 1;\n' % entry.Name() +
272 ' break;\n' ))
273 file.write(( ' default:\n'
Christopher Wileye8679812015-07-01 13:36:18 -0700274 ' return -1;\n'
275 ' }\n'
Haibo Huangb2279672019-05-31 16:12:39 -0700276 ' }\n\n' ))
Christopher Wileye8679812015-07-01 13:36:18 -0700277 # Check if it was decoded completely
Haibo Huangb2279672019-05-31 16:12:39 -0700278 file.write(( ' if (%(name)s_complete(tmp) == -1)\n'
Christopher Wileye8679812015-07-01 13:36:18 -0700279 ' return (-1);'
Haibo Huangb2279672019-05-31 16:12:39 -0700280 '\n') % { 'name' : self._name })
Christopher Wileye8679812015-07-01 13:36:18 -0700281
282 # Successfully decoded
Haibo Huangb2279672019-05-31 16:12:39 -0700283 file.write(( ' return (0);\n'
284 '}\n\n'))
Christopher Wileye8679812015-07-01 13:36:18 -0700285
286 # Checking if a structure has all the required data
Haibo Huangb2279672019-05-31 16:12:39 -0700287 file.write((
Christopher Wileye8679812015-07-01 13:36:18 -0700288 'int\n'
289 '%(name)s_complete(struct %(name)s *msg)\n'
Haibo Huangb2279672019-05-31 16:12:39 -0700290 '{\n' ) % { 'name' : self._name })
Christopher Wileye8679812015-07-01 13:36:18 -0700291 for entry in self._entries:
292 if not entry.Optional():
293 code = [
294 'if (!msg->%(name)s_set)',
295 ' return (-1);' ]
296 code = TranslateList(code, entry.GetTranslation())
297 self.PrintIndented(
298 file, ' ', code)
299
300 self.PrintIndented(
301 file, ' ',
302 entry.CodeComplete('msg', entry.GetVarName('msg')))
Haibo Huangb2279672019-05-31 16:12:39 -0700303 file.write((
Christopher Wileye8679812015-07-01 13:36:18 -0700304 ' return (0);\n'
Haibo Huangb2279672019-05-31 16:12:39 -0700305 '}\n\n' ))
Christopher Wileye8679812015-07-01 13:36:18 -0700306
307 # Complete message unmarshaling
Haibo Huangb2279672019-05-31 16:12:39 -0700308 file.write((
Christopher Wileye8679812015-07-01 13:36:18 -0700309 'int\n'
310 'evtag_unmarshal_%(name)s(struct evbuffer *evbuf, '
311 'ev_uint32_t need_tag, struct %(name)s *msg)\n'
312 '{\n'
313 ' ev_uint32_t tag;\n'
314 ' int res = -1;\n'
315 '\n'
316 ' struct evbuffer *tmp = evbuffer_new();\n'
317 '\n'
318 ' if (evtag_unmarshal(evbuf, &tag, tmp) == -1'
319 ' || tag != need_tag)\n'
320 ' goto error;\n'
321 '\n'
322 ' if (%(name)s_unmarshal(msg, tmp) == -1)\n'
323 ' goto error;\n'
324 '\n'
325 ' res = 0;\n'
326 '\n'
327 ' error:\n'
328 ' evbuffer_free(tmp);\n'
329 ' return (res);\n'
Haibo Huangb2279672019-05-31 16:12:39 -0700330 '}\n\n' ) % { 'name' : self._name })
Christopher Wileye8679812015-07-01 13:36:18 -0700331
332 # Complete message marshaling
Haibo Huangb2279672019-05-31 16:12:39 -0700333 file.write((
Christopher Wileye8679812015-07-01 13:36:18 -0700334 'void\n'
335 'evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag, '
336 'const struct %(name)s *msg)\n'
337 '{\n'
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100338 ' struct evbuffer *buf_ = evbuffer_new();\n'
339 ' assert(buf_ != NULL);\n'
340 ' %(name)s_marshal(buf_, msg);\n'
341 ' evtag_marshal_buffer(evbuf, tag, buf_);\n '
342 ' evbuffer_free(buf_);\n'
Haibo Huangb2279672019-05-31 16:12:39 -0700343 '}\n\n' ) % { 'name' : self._name })
Christopher Wileye8679812015-07-01 13:36:18 -0700344
345class Entry:
346 def __init__(self, type, name, tag):
347 self._type = type
348 self._name = name
349 self._tag = int(tag)
350 self._ctype = type
351 self._optional = 0
352 self._can_be_array = 0
353 self._array = 0
354 self._line_count = -1
355 self._struct = None
356 self._refname = None
357
358 self._optpointer = True
359 self._optaddarg = True
360
361 def GetInitializer(self):
362 assert 0, "Entry does not provide initializer"
363
364 def SetStruct(self, struct):
365 self._struct = struct
366
367 def LineCount(self):
368 assert self._line_count != -1
369 return self._line_count
370
371 def SetLineCount(self, number):
372 self._line_count = number
373
374 def Array(self):
375 return self._array
376
377 def Optional(self):
378 return self._optional
379
380 def Tag(self):
381 return self._tag
382
383 def Name(self):
384 return self._name
385
386 def Type(self):
387 return self._type
388
389 def MakeArray(self, yes=1):
390 self._array = yes
391
392 def MakeOptional(self):
393 self._optional = 1
394
395 def Verify(self):
396 if self.Array() and not self._can_be_array:
397 raise RpcGenError(
398 'Entry "%s" cannot be created as an array '
399 'around line %d' % (self._name, self.LineCount()))
400 if not self._struct:
401 raise RpcGenError(
402 'Entry "%s" does not know which struct it belongs to '
403 'around line %d' % (self._name, self.LineCount()))
404 if self._optional and self._array:
405 raise RpcGenError(
406 'Entry "%s" has illegal combination of optional and array '
407 'around line %d' % (self._name, self.LineCount()))
408
409 def GetTranslation(self, extradict = {}):
410 mapping = {
411 "parent_name" : self._struct.Name(),
412 "name" : self._name,
413 "ctype" : self._ctype,
414 "refname" : self._refname,
415 "optpointer" : self._optpointer and "*" or "",
416 "optreference" : self._optpointer and "&" or "",
417 "optaddarg" :
418 self._optaddarg and ", const %s value" % self._ctype or ""
419 }
Haibo Huangb2279672019-05-31 16:12:39 -0700420 for (k, v) in list(extradict.items()):
Christopher Wileye8679812015-07-01 13:36:18 -0700421 mapping[k] = v
422
423 return mapping
424
425 def GetVarName(self, var):
426 return '%(var)s->%(name)s_data' % self.GetTranslation({ 'var' : var })
427
428 def GetVarLen(self, var):
429 return 'sizeof(%s)' % self._ctype
430
431 def GetFuncName(self):
432 return '%s_%s_get' % (self._struct.Name(), self._name)
433
434 def GetDeclaration(self, funcname):
435 code = [ 'int %s(struct %s *, %s *);' % (
436 funcname, self._struct.Name(), self._ctype ) ]
437 return code
438
439 def CodeGet(self):
440 code = (
441 'int',
442 '%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, '
443 '%(ctype)s *value)',
444 '{',
445 ' if (msg->%(name)s_set != 1)',
446 ' return (-1);',
447 ' *value = msg->%(name)s_data;',
448 ' return (0);',
449 '}' )
450 code = '\n'.join(code)
451 code = code % self.GetTranslation()
452 return code.split('\n')
453
454 def AssignFuncName(self):
455 return '%s_%s_assign' % (self._struct.Name(), self._name)
456
457 def AddFuncName(self):
458 return '%s_%s_add' % (self._struct.Name(), self._name)
459
460 def AssignDeclaration(self, funcname):
461 code = [ 'int %s(struct %s *, const %s);' % (
462 funcname, self._struct.Name(), self._ctype ) ]
463 return code
464
465 def CodeAssign(self):
466 code = [ 'int',
467 '%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,'
468 ' const %(ctype)s value)',
469 '{',
470 ' msg->%(name)s_set = 1;',
471 ' msg->%(name)s_data = value;',
472 ' return (0);',
473 '}' ]
474 code = '\n'.join(code)
475 code = code % self.GetTranslation()
476 return code.split('\n')
477
478 def CodeClear(self, structname):
479 code = [ '%s->%s_set = 0;' % (structname, self.Name()) ]
480
481 return code
482
483 def CodeComplete(self, structname, var_name):
484 return []
485
486 def CodeFree(self, name):
487 return []
488
489 def CodeBase(self):
490 code = [
491 '%(parent_name)s_%(name)s_assign,',
492 '%(parent_name)s_%(name)s_get,'
493 ]
494 if self.Array():
495 code.append('%(parent_name)s_%(name)s_add,')
496
497 code = '\n'.join(code)
498 code = code % self.GetTranslation()
499 return code.split('\n')
500
501class EntryBytes(Entry):
502 def __init__(self, type, name, tag, length):
503 # Init base class
504 Entry.__init__(self, type, name, tag)
505
506 self._length = length
507 self._ctype = 'ev_uint8_t'
508
509 def GetInitializer(self):
510 return "NULL"
511
512 def GetVarLen(self, var):
513 return '(%s)' % self._length
514
515 def CodeArrayAdd(self, varname, value):
516 # XXX: copy here
517 return [ '%(varname)s = NULL;' % { 'varname' : varname } ]
518
519 def GetDeclaration(self, funcname):
520 code = [ 'int %s(struct %s *, %s **);' % (
521 funcname, self._struct.Name(), self._ctype ) ]
522 return code
523
524 def AssignDeclaration(self, funcname):
525 code = [ 'int %s(struct %s *, const %s *);' % (
526 funcname, self._struct.Name(), self._ctype ) ]
527 return code
528
529 def Declaration(self):
530 dcl = ['ev_uint8_t %s_data[%s];' % (self._name, self._length)]
531
532 return dcl
533
534 def CodeGet(self):
535 name = self._name
536 code = [ 'int',
537 '%s_%s_get(struct %s *msg, %s **value)' % (
538 self._struct.Name(), name,
539 self._struct.Name(), self._ctype),
540 '{',
541 ' if (msg->%s_set != 1)' % name,
542 ' return (-1);',
543 ' *value = msg->%s_data;' % name,
544 ' return (0);',
545 '}' ]
546 return code
547
548 def CodeAssign(self):
549 name = self._name
550 code = [ 'int',
551 '%s_%s_assign(struct %s *msg, const %s *value)' % (
552 self._struct.Name(), name,
553 self._struct.Name(), self._ctype),
554 '{',
555 ' msg->%s_set = 1;' % name,
556 ' memcpy(msg->%s_data, value, %s);' % (
557 name, self._length),
558 ' return (0);',
559 '}' ]
560 return code
561
562 def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
563 code = [ 'if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, '
564 '%(var)s, %(varlen)s) == -1) {',
565 ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
566 ' return (-1);',
567 '}'
568 ]
569 return TranslateList(code,
570 self.GetTranslation({
571 'var' : var_name,
572 'varlen' : var_len,
573 'buf' : buf,
574 'tag' : tag_name }))
575
576 def CodeMarshal(self, buf, tag_name, var_name, var_len):
577 code = ['evtag_marshal(%s, %s, %s, %s);' % (
578 buf, tag_name, var_name, var_len)]
579 return code
580
581 def CodeClear(self, structname):
582 code = [ '%s->%s_set = 0;' % (structname, self.Name()),
583 'memset(%s->%s_data, 0, sizeof(%s->%s_data));' % (
584 structname, self._name, structname, self._name)]
585
586 return code
587
588 def CodeInitialize(self, name):
589 code = ['memset(%s->%s_data, 0, sizeof(%s->%s_data));' % (
590 name, self._name, name, self._name)]
591 return code
592
593 def Verify(self):
594 if not self._length:
595 raise RpcGenError(
596 'Entry "%s" needs a length '
597 'around line %d' % (self._name, self.LineCount()))
598
599 Entry.Verify(self)
600
601class EntryInt(Entry):
602 def __init__(self, type, name, tag, bits=32):
603 # Init base class
604 Entry.__init__(self, type, name, tag)
605
606 self._can_be_array = 1
607 if bits == 32:
608 self._ctype = 'ev_uint32_t'
609 self._marshal_type = 'int'
610 if bits == 64:
611 self._ctype = 'ev_uint64_t'
612 self._marshal_type = 'int64'
613
614 def GetInitializer(self):
615 return "0"
616
617 def CodeArrayFree(self, var):
618 return []
619
620 def CodeArrayAssign(self, varname, srcvar):
621 return [ '%(varname)s = %(srcvar)s;' % { 'varname' : varname,
622 'srcvar' : srcvar } ]
623
624 def CodeArrayAdd(self, varname, value):
625 """Returns a new entry of this type."""
626 return [ '%(varname)s = %(value)s;' % { 'varname' : varname,
627 'value' : value } ]
628
629 def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
630 code = [
631 'if (evtag_unmarshal_%(ma)s(%(buf)s, %(tag)s, &%(var)s) == -1) {',
632 ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
633 ' return (-1);',
634 '}' ]
635 code = '\n'.join(code) % self.GetTranslation({
636 'ma' : self._marshal_type,
637 'buf' : buf,
638 'tag' : tag_name,
639 'var' : var_name })
640 return code.split('\n')
641
642 def CodeMarshal(self, buf, tag_name, var_name, var_len):
643 code = [
644 'evtag_marshal_%s(%s, %s, %s);' % (
645 self._marshal_type, buf, tag_name, var_name)]
646 return code
647
648 def Declaration(self):
649 dcl = ['%s %s_data;' % (self._ctype, self._name)]
650
651 return dcl
652
653 def CodeInitialize(self, name):
654 code = ['%s->%s_data = 0;' % (name, self._name)]
655 return code
656
657class EntryString(Entry):
658 def __init__(self, type, name, tag):
659 # Init base class
660 Entry.__init__(self, type, name, tag)
661
662 self._can_be_array = 1
663 self._ctype = 'char *'
664
665 def GetInitializer(self):
666 return "NULL"
667
668 def CodeArrayFree(self, varname):
669 code = [
670 'if (%(var)s != NULL) free(%(var)s);' ]
671
672 return TranslateList(code, { 'var' : varname })
673
674 def CodeArrayAssign(self, varname, srcvar):
675 code = [
676 'if (%(var)s != NULL)',
677 ' free(%(var)s);',
678 '%(var)s = strdup(%(srcvar)s);',
679 'if (%(var)s == NULL) {',
680 ' event_warnx("%%s: strdup", __func__);',
681 ' return (-1);',
682 '}' ]
683
684 return TranslateList(code, { 'var' : varname,
685 'srcvar' : srcvar })
686
687 def CodeArrayAdd(self, varname, value):
688 code = [
689 'if (%(value)s != NULL) {',
690 ' %(var)s = strdup(%(value)s);',
691 ' if (%(var)s == NULL) {',
692 ' goto error;',
693 ' }',
694 '} else {',
695 ' %(var)s = NULL;',
696 '}' ]
697
698 return TranslateList(code, { 'var' : varname,
699 'value' : value })
700
701 def GetVarLen(self, var):
702 return 'strlen(%s)' % self.GetVarName(var)
703
704 def CodeMakeInitalize(self, varname):
705 return '%(varname)s = NULL;' % { 'varname' : varname }
706
707 def CodeAssign(self):
708 name = self._name
709 code = """int
710%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
711 const %(ctype)s value)
712{
713 if (msg->%(name)s_data != NULL)
714 free(msg->%(name)s_data);
715 if ((msg->%(name)s_data = strdup(value)) == NULL)
716 return (-1);
717 msg->%(name)s_set = 1;
718 return (0);
719}""" % self.GetTranslation()
720
721 return code.split('\n')
722
723 def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
724 code = ['if (evtag_unmarshal_string(%(buf)s, %(tag)s, &%(var)s) == -1) {',
725 ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
726 ' return (-1);',
727 '}'
728 ]
729 code = '\n'.join(code) % self.GetTranslation({
730 'buf' : buf,
731 'tag' : tag_name,
732 'var' : var_name })
733 return code.split('\n')
734
735 def CodeMarshal(self, buf, tag_name, var_name, var_len):
736 code = ['evtag_marshal_string(%s, %s, %s);' % (
737 buf, tag_name, var_name)]
738 return code
739
740 def CodeClear(self, structname):
741 code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
742 ' free(%s->%s_data);' % (structname, self.Name()),
743 ' %s->%s_data = NULL;' % (structname, self.Name()),
744 ' %s->%s_set = 0;' % (structname, self.Name()),
745 '}'
746 ]
747
748 return code
749
750 def CodeInitialize(self, name):
751 code = ['%s->%s_data = NULL;' % (name, self._name)]
752 return code
753
754 def CodeFree(self, name):
755 code = ['if (%s->%s_data != NULL)' % (name, self._name),
756 ' free (%s->%s_data);' % (name, self._name)]
757
758 return code
759
760 def Declaration(self):
761 dcl = ['char *%s_data;' % self._name]
762
763 return dcl
764
765class EntryStruct(Entry):
766 def __init__(self, type, name, tag, refname):
767 # Init base class
768 Entry.__init__(self, type, name, tag)
769
770 self._optpointer = False
771 self._can_be_array = 1
772 self._refname = refname
773 self._ctype = 'struct %s*' % refname
774 self._optaddarg = False
775
776 def GetInitializer(self):
777 return "NULL"
778
779 def GetVarLen(self, var):
780 return '-1'
781
782 def CodeArrayAdd(self, varname, value):
783 code = [
784 '%(varname)s = %(refname)s_new();',
785 'if (%(varname)s == NULL)',
786 ' goto error;' ]
787
788 return TranslateList(code, self.GetTranslation({ 'varname' : varname }))
789
790 def CodeArrayFree(self, var):
791 code = [ '%(refname)s_free(%(var)s);' % self.GetTranslation(
792 { 'var' : var }) ]
793 return code
794
795 def CodeArrayAssign(self, var, srcvar):
796 code = [
797 'int had_error = 0;',
798 'struct evbuffer *tmp = NULL;',
799 '%(refname)s_clear(%(var)s);',
800 'if ((tmp = evbuffer_new()) == NULL) {',
801 ' event_warn("%%s: evbuffer_new()", __func__);',
802 ' had_error = 1;',
803 ' goto done;',
804 '}',
805 '%(refname)s_marshal(tmp, %(srcvar)s);',
806 'if (%(refname)s_unmarshal(%(var)s, tmp) == -1) {',
807 ' event_warnx("%%s: %(refname)s_unmarshal", __func__);',
808 ' had_error = 1;',
809 ' goto done;',
810 '}',
811 'done:'
812 'if (tmp != NULL)',
813 ' evbuffer_free(tmp);',
814 'if (had_error) {',
815 ' %(refname)s_clear(%(var)s);',
816 ' return (-1);',
817 '}' ]
818
819 return TranslateList(code, self.GetTranslation({
820 'var' : var,
821 'srcvar' : srcvar}))
822
823 def CodeGet(self):
824 name = self._name
825 code = [ 'int',
826 '%s_%s_get(struct %s *msg, %s *value)' % (
827 self._struct.Name(), name,
828 self._struct.Name(), self._ctype),
829 '{',
830 ' if (msg->%s_set != 1) {' % name,
831 ' msg->%s_data = %s_new();' % (name, self._refname),
832 ' if (msg->%s_data == NULL)' % name,
833 ' return (-1);',
834 ' msg->%s_set = 1;' % name,
835 ' }',
836 ' *value = msg->%s_data;' % name,
837 ' return (0);',
838 '}' ]
839 return code
840
841 def CodeAssign(self):
842 name = self._name
843 code = """int
844%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
845 const %(ctype)s value)
846{
847 struct evbuffer *tmp = NULL;
848 if (msg->%(name)s_set) {
849 %(refname)s_clear(msg->%(name)s_data);
850 msg->%(name)s_set = 0;
851 } else {
852 msg->%(name)s_data = %(refname)s_new();
853 if (msg->%(name)s_data == NULL) {
854 event_warn("%%s: %(refname)s_new()", __func__);
855 goto error;
856 }
857 }
858 if ((tmp = evbuffer_new()) == NULL) {
859 event_warn("%%s: evbuffer_new()", __func__);
860 goto error;
861 }
862 %(refname)s_marshal(tmp, value);
863 if (%(refname)s_unmarshal(msg->%(name)s_data, tmp) == -1) {
864 event_warnx("%%s: %(refname)s_unmarshal", __func__);
865 goto error;
866 }
867 msg->%(name)s_set = 1;
868 evbuffer_free(tmp);
869 return (0);
870 error:
871 if (tmp != NULL)
872 evbuffer_free(tmp);
873 if (msg->%(name)s_data != NULL) {
874 %(refname)s_free(msg->%(name)s_data);
875 msg->%(name)s_data = NULL;
876 }
877 return (-1);
878}""" % self.GetTranslation()
879 return code.split('\n')
880
881 def CodeComplete(self, structname, var_name):
882 code = [ 'if (%(structname)s->%(name)s_set && '
883 '%(refname)s_complete(%(var)s) == -1)',
884 ' return (-1);' ]
885
886 return TranslateList(code, self.GetTranslation({
887 'structname' : structname,
888 'var' : var_name }))
889
890 def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
891 code = ['%(var)s = %(refname)s_new();',
892 'if (%(var)s == NULL)',
893 ' return (-1);',
894 'if (evtag_unmarshal_%(refname)s(%(buf)s, %(tag)s, '
895 '%(var)s) == -1) {',
896 ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
897 ' return (-1);',
898 '}'
899 ]
900 code = '\n'.join(code) % self.GetTranslation({
901 'buf' : buf,
902 'tag' : tag_name,
903 'var' : var_name })
904 return code.split('\n')
905
906 def CodeMarshal(self, buf, tag_name, var_name, var_len):
907 code = ['evtag_marshal_%s(%s, %s, %s);' % (
908 self._refname, buf, tag_name, var_name)]
909 return code
910
911 def CodeClear(self, structname):
912 code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
913 ' %s_free(%s->%s_data);' % (
914 self._refname, structname, self.Name()),
915 ' %s->%s_data = NULL;' % (structname, self.Name()),
916 ' %s->%s_set = 0;' % (structname, self.Name()),
917 '}'
918 ]
919
920 return code
921
922 def CodeInitialize(self, name):
923 code = ['%s->%s_data = NULL;' % (name, self._name)]
924 return code
925
926 def CodeFree(self, name):
927 code = ['if (%s->%s_data != NULL)' % (name, self._name),
928 ' %s_free(%s->%s_data);' % (
929 self._refname, name, self._name)]
930
931 return code
932
933 def Declaration(self):
934 dcl = ['%s %s_data;' % (self._ctype, self._name)]
935
936 return dcl
937
938class EntryVarBytes(Entry):
939 def __init__(self, type, name, tag):
940 # Init base class
941 Entry.__init__(self, type, name, tag)
942
943 self._ctype = 'ev_uint8_t *'
944
945 def GetInitializer(self):
946 return "NULL"
947
948 def GetVarLen(self, var):
949 return '%(var)s->%(name)s_length' % self.GetTranslation({ 'var' : var })
950
951 def CodeArrayAdd(self, varname, value):
952 # xxx: copy
953 return [ '%(varname)s = NULL;' % { 'varname' : varname } ]
954
955 def GetDeclaration(self, funcname):
956 code = [ 'int %s(struct %s *, %s *, ev_uint32_t *);' % (
957 funcname, self._struct.Name(), self._ctype ) ]
958 return code
959
960 def AssignDeclaration(self, funcname):
961 code = [ 'int %s(struct %s *, const %s, ev_uint32_t);' % (
962 funcname, self._struct.Name(), self._ctype ) ]
963 return code
964
965 def CodeAssign(self):
966 name = self._name
967 code = [ 'int',
968 '%s_%s_assign(struct %s *msg, '
969 'const %s value, ev_uint32_t len)' % (
970 self._struct.Name(), name,
971 self._struct.Name(), self._ctype),
972 '{',
973 ' if (msg->%s_data != NULL)' % name,
974 ' free (msg->%s_data);' % name,
975 ' msg->%s_data = malloc(len);' % name,
976 ' if (msg->%s_data == NULL)' % name,
977 ' return (-1);',
978 ' msg->%s_set = 1;' % name,
979 ' msg->%s_length = len;' % name,
980 ' memcpy(msg->%s_data, value, len);' % name,
981 ' return (0);',
982 '}' ]
983 return code
984
985 def CodeGet(self):
986 name = self._name
987 code = [ 'int',
988 '%s_%s_get(struct %s *msg, %s *value, ev_uint32_t *plen)' % (
989 self._struct.Name(), name,
990 self._struct.Name(), self._ctype),
991 '{',
992 ' if (msg->%s_set != 1)' % name,
993 ' return (-1);',
994 ' *value = msg->%s_data;' % name,
995 ' *plen = msg->%s_length;' % name,
996 ' return (0);',
997 '}' ]
998 return code
999
1000 def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
1001 code = ['if (evtag_payload_length(%(buf)s, &%(varlen)s) == -1)',
1002 ' return (-1);',
1003 # We do not want DoS opportunities
1004 'if (%(varlen)s > evbuffer_get_length(%(buf)s))',
1005 ' return (-1);',
1006 'if ((%(var)s = malloc(%(varlen)s)) == NULL)',
1007 ' return (-1);',
1008 'if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, %(var)s, '
1009 '%(varlen)s) == -1) {',
1010 ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
1011 ' return (-1);',
1012 '}'
1013 ]
1014 code = '\n'.join(code) % self.GetTranslation({
1015 'buf' : buf,
1016 'tag' : tag_name,
1017 'var' : var_name,
1018 'varlen' : var_len })
1019 return code.split('\n')
1020
1021 def CodeMarshal(self, buf, tag_name, var_name, var_len):
1022 code = ['evtag_marshal(%s, %s, %s, %s);' % (
1023 buf, tag_name, var_name, var_len)]
1024 return code
1025
1026 def CodeClear(self, structname):
1027 code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
1028 ' free (%s->%s_data);' % (structname, self.Name()),
1029 ' %s->%s_data = NULL;' % (structname, self.Name()),
1030 ' %s->%s_length = 0;' % (structname, self.Name()),
1031 ' %s->%s_set = 0;' % (structname, self.Name()),
1032 '}'
1033 ]
1034
1035 return code
1036
1037 def CodeInitialize(self, name):
1038 code = ['%s->%s_data = NULL;' % (name, self._name),
1039 '%s->%s_length = 0;' % (name, self._name) ]
1040 return code
1041
1042 def CodeFree(self, name):
1043 code = ['if (%s->%s_data != NULL)' % (name, self._name),
1044 ' free(%s->%s_data);' % (name, self._name)]
1045
1046 return code
1047
1048 def Declaration(self):
1049 dcl = ['ev_uint8_t *%s_data;' % self._name,
1050 'ev_uint32_t %s_length;' % self._name]
1051
1052 return dcl
1053
1054class EntryArray(Entry):
1055 def __init__(self, entry):
1056 # Init base class
1057 Entry.__init__(self, entry._type, entry._name, entry._tag)
1058
1059 self._entry = entry
1060 self._refname = entry._refname
1061 self._ctype = self._entry._ctype
1062 self._optional = True
1063 self._optpointer = self._entry._optpointer
1064 self._optaddarg = self._entry._optaddarg
1065
1066 # provide a new function for accessing the variable name
1067 def GetVarName(var_name):
1068 return '%(var)s->%(name)s_data[%(index)s]' % \
1069 self._entry.GetTranslation({'var' : var_name,
1070 'index' : self._index})
1071 self._entry.GetVarName = GetVarName
1072
1073 def GetInitializer(self):
1074 return "NULL"
1075
1076 def GetVarName(self, var_name):
1077 return var_name
1078
1079 def GetVarLen(self, var_name):
1080 return '-1'
1081
1082 def GetDeclaration(self, funcname):
1083 """Allows direct access to elements of the array."""
1084 code = [
1085 'int %(funcname)s(struct %(parent_name)s *, int, %(ctype)s *);' %
1086 self.GetTranslation({ 'funcname' : funcname }) ]
1087 return code
1088
1089 def AssignDeclaration(self, funcname):
1090 code = [ 'int %s(struct %s *, int, const %s);' % (
1091 funcname, self._struct.Name(), self._ctype ) ]
1092 return code
1093
1094 def AddDeclaration(self, funcname):
1095 code = [
1096 '%(ctype)s %(optpointer)s '
1097 '%(funcname)s(struct %(parent_name)s *msg%(optaddarg)s);' % \
1098 self.GetTranslation({ 'funcname' : funcname }) ]
1099 return code
1100
1101 def CodeGet(self):
1102 code = """int
1103%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, int offset,
1104 %(ctype)s *value)
1105{
1106 if (!msg->%(name)s_set || offset < 0 || offset >= msg->%(name)s_length)
1107 return (-1);
1108 *value = msg->%(name)s_data[offset];
1109 return (0);
1110}""" % self.GetTranslation()
1111
1112 return code.split('\n')
1113
1114 def CodeAssign(self):
1115 code = [
1116 'int',
1117 '%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, int off,',
1118 ' const %(ctype)s value)',
1119 '{',
1120 ' if (!msg->%(name)s_set || off < 0 || off >= msg->%(name)s_length)',
1121 ' return (-1);\n',
1122 ' {' ]
1123 code = TranslateList(code, self.GetTranslation())
1124
1125 codearrayassign = self._entry.CodeArrayAssign(
1126 'msg->%(name)s_data[off]' % self.GetTranslation(), 'value')
Haibo Huangb2279672019-05-31 16:12:39 -07001127 code += [' ' + x for x in codearrayassign]
Christopher Wileye8679812015-07-01 13:36:18 -07001128
1129 code += TranslateList([
1130 ' }',
1131 ' return (0);',
1132 '}' ], self.GetTranslation())
1133
1134 return code
1135
1136 def CodeAdd(self):
1137 codearrayadd = self._entry.CodeArrayAdd(
1138 'msg->%(name)s_data[msg->%(name)s_length - 1]' % self.GetTranslation(),
1139 'value')
1140 code = [
1141 'static int',
1142 '%(parent_name)s_%(name)s_expand_to_hold_more('
1143 'struct %(parent_name)s *msg)',
1144 '{',
1145 ' int tobe_allocated = msg->%(name)s_num_allocated;',
1146 ' %(ctype)s* new_data = NULL;',
1147 ' tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;',
1148 ' new_data = (%(ctype)s*) realloc(msg->%(name)s_data,',
1149 ' tobe_allocated * sizeof(%(ctype)s));',
1150 ' if (new_data == NULL)',
1151 ' return -1;',
1152 ' msg->%(name)s_data = new_data;',
1153 ' msg->%(name)s_num_allocated = tobe_allocated;',
1154 ' return 0;'
1155 '}',
1156 '',
1157 '%(ctype)s %(optpointer)s',
1158 '%(parent_name)s_%(name)s_add('
1159 'struct %(parent_name)s *msg%(optaddarg)s)',
1160 '{',
1161 ' if (++msg->%(name)s_length >= msg->%(name)s_num_allocated) {',
1162 ' if (%(parent_name)s_%(name)s_expand_to_hold_more(msg)<0)',
1163 ' goto error;',
1164 ' }' ]
1165
1166 code = TranslateList(code, self.GetTranslation())
1167
Haibo Huangb2279672019-05-31 16:12:39 -07001168 code += [' ' + x for x in codearrayadd]
Christopher Wileye8679812015-07-01 13:36:18 -07001169
1170 code += TranslateList([
1171 ' msg->%(name)s_set = 1;',
1172 ' return %(optreference)s(msg->%(name)s_data['
1173 'msg->%(name)s_length - 1]);',
1174 'error:',
1175 ' --msg->%(name)s_length;',
1176 ' return (NULL);',
1177 '}' ], self.GetTranslation())
1178
1179 return code
1180
1181 def CodeComplete(self, structname, var_name):
1182 self._index = 'i'
1183 tmp = self._entry.CodeComplete(structname, self._entry.GetVarName(var_name))
1184 # skip the whole loop if there is nothing to check
1185 if not tmp:
1186 return []
1187
1188 translate = self.GetTranslation({ 'structname' : structname })
1189 code = [
1190 '{',
1191 ' int i;',
1192 ' for (i = 0; i < %(structname)s->%(name)s_length; ++i) {' ]
1193
1194 code = TranslateList(code, translate)
1195
Haibo Huangb2279672019-05-31 16:12:39 -07001196 code += [' ' + x for x in tmp]
Christopher Wileye8679812015-07-01 13:36:18 -07001197
1198 code += [
1199 ' }',
1200 '}' ]
1201
1202 return code
1203
1204 def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
1205 translate = self.GetTranslation({ 'var' : var_name,
1206 'buf' : buf,
1207 'tag' : tag_name,
1208 'init' : self._entry.GetInitializer()})
1209 code = [
1210 'if (%(var)s->%(name)s_length >= %(var)s->%(name)s_num_allocated &&',
1211 ' %(parent_name)s_%(name)s_expand_to_hold_more(%(var)s) < 0) {',
1212 ' puts("HEY NOW");',
1213 ' return (-1);',
1214 '}']
1215
1216 # the unmarshal code directly returns
1217 code = TranslateList(code, translate)
1218
1219 self._index = '%(var)s->%(name)s_length' % translate
1220 code += self._entry.CodeUnmarshal(buf, tag_name,
1221 self._entry.GetVarName(var_name),
1222 self._entry.GetVarLen(var_name))
1223
1224 code += [ '++%(var)s->%(name)s_length;' % translate ]
1225
1226 return code
1227
1228 def CodeMarshal(self, buf, tag_name, var_name, var_len):
1229 code = ['{',
1230 ' int i;',
1231 ' for (i = 0; i < %(var)s->%(name)s_length; ++i) {' ]
1232
1233 self._index = 'i'
1234 code += self._entry.CodeMarshal(buf, tag_name,
1235 self._entry.GetVarName(var_name),
1236 self._entry.GetVarLen(var_name))
1237 code += [' }',
1238 '}'
1239 ]
1240
1241 code = "\n".join(code) % self.GetTranslation({ 'var' : var_name })
1242
1243 return code.split('\n')
1244
1245 def CodeClear(self, structname):
1246 translate = self.GetTranslation({ 'structname' : structname })
1247 codearrayfree = self._entry.CodeArrayFree(
1248 '%(structname)s->%(name)s_data[i]' % self.GetTranslation(
1249 { 'structname' : structname } ))
1250
1251 code = [ 'if (%(structname)s->%(name)s_set == 1) {' ]
1252
1253 if codearrayfree:
1254 code += [
1255 ' int i;',
1256 ' for (i = 0; i < %(structname)s->%(name)s_length; ++i) {' ]
1257
1258 code = TranslateList(code, translate)
1259
1260 if codearrayfree:
Haibo Huangb2279672019-05-31 16:12:39 -07001261 code += [' ' + x for x in codearrayfree]
Christopher Wileye8679812015-07-01 13:36:18 -07001262 code += [
1263 ' }' ]
1264
1265 code += TranslateList([
1266 ' free(%(structname)s->%(name)s_data);',
1267 ' %(structname)s->%(name)s_data = NULL;',
1268 ' %(structname)s->%(name)s_set = 0;',
1269 ' %(structname)s->%(name)s_length = 0;',
1270 ' %(structname)s->%(name)s_num_allocated = 0;',
1271 '}'
1272 ], translate)
1273
1274 return code
1275
1276 def CodeInitialize(self, name):
1277 code = ['%s->%s_data = NULL;' % (name, self._name),
1278 '%s->%s_length = 0;' % (name, self._name),
1279 '%s->%s_num_allocated = 0;' % (name, self._name)]
1280 return code
1281
1282 def CodeFree(self, structname):
1283 code = self.CodeClear(structname);
1284
1285 code += TranslateList([
1286 'free(%(structname)s->%(name)s_data);' ],
1287 self.GetTranslation({'structname' : structname }))
1288
1289 return code
1290
1291 def Declaration(self):
1292 dcl = ['%s *%s_data;' % (self._ctype, self._name),
1293 'int %s_length;' % self._name,
1294 'int %s_num_allocated;' % self._name ]
1295
1296 return dcl
1297
1298def NormalizeLine(line):
1299 global white
1300 global cppcomment
1301
1302 line = cppcomment.sub('', line)
1303 line = line.strip()
1304 line = white.sub(' ', line)
1305
1306 return line
1307
1308def ProcessOneEntry(factory, newstruct, entry):
1309 optional = 0
1310 array = 0
1311 entry_type = ''
1312 name = ''
1313 tag = ''
1314 tag_set = None
1315 separator = ''
1316 fixed_length = ''
1317
1318 tokens = entry.split(' ')
1319 while tokens:
1320 token = tokens[0]
1321 tokens = tokens[1:]
1322
1323 if not entry_type:
1324 if not optional and token == 'optional':
1325 optional = 1
1326 continue
1327
1328 if not array and token == 'array':
1329 array = 1
1330 continue
1331
1332 if not entry_type:
1333 entry_type = token
1334 continue
1335
1336 if not name:
1337 res = re.match(r'^([^\[\]]+)(\[.*\])?$', token)
1338 if not res:
1339 raise RpcGenError(
1340 'Cannot parse name: \"%s\" '
1341 'around line %d' % (entry, line_count))
1342 name = res.group(1)
1343 fixed_length = res.group(2)
1344 if fixed_length:
1345 fixed_length = fixed_length[1:-1]
1346 continue
1347
1348 if not separator:
1349 separator = token
1350 if separator != '=':
1351 raise RpcGenError('Expected "=" after name \"%s\" got %s'
1352 % (name, token))
1353 continue
1354
1355 if not tag_set:
1356 tag_set = 1
1357 if not re.match(r'^(0x)?[0-9]+$', token):
1358 raise RpcGenError('Expected tag number: \"%s\"' % entry)
1359 tag = int(token, 0)
1360 continue
1361
1362 raise RpcGenError('Cannot parse \"%s\"' % entry)
1363
1364 if not tag_set:
1365 raise RpcGenError('Need tag number: \"%s\"' % entry)
1366
1367 # Create the right entry
1368 if entry_type == 'bytes':
1369 if fixed_length:
1370 newentry = factory.EntryBytes(entry_type, name, tag, fixed_length)
1371 else:
1372 newentry = factory.EntryVarBytes(entry_type, name, tag)
1373 elif entry_type == 'int' and not fixed_length:
1374 newentry = factory.EntryInt(entry_type, name, tag)
1375 elif entry_type == 'int64' and not fixed_length:
1376 newentry = factory.EntryInt(entry_type, name, tag, bits=64)
1377 elif entry_type == 'string' and not fixed_length:
1378 newentry = factory.EntryString(entry_type, name, tag)
1379 else:
1380 res = structref.match(entry_type)
1381 if res:
1382 # References another struct defined in our file
1383 newentry = factory.EntryStruct(entry_type, name, tag, res.group(1))
1384 else:
1385 raise RpcGenError('Bad type: "%s" in "%s"' % (entry_type, entry))
1386
1387 structs = []
1388
1389 if optional:
1390 newentry.MakeOptional()
1391 if array:
1392 newentry.MakeArray()
1393
1394 newentry.SetStruct(newstruct)
1395 newentry.SetLineCount(line_count)
1396 newentry.Verify()
1397
1398 if array:
1399 # We need to encapsulate this entry into a struct
1400 newname = newentry.Name()+ '_array'
1401
1402 # Now borgify the new entry.
1403 newentry = factory.EntryArray(newentry)
1404 newentry.SetStruct(newstruct)
1405 newentry.SetLineCount(line_count)
1406 newentry.MakeArray()
1407
1408 newstruct.AddEntry(newentry)
1409
1410 return structs
1411
1412def ProcessStruct(factory, data):
1413 tokens = data.split(' ')
1414
1415 # First three tokens are: 'struct' 'name' '{'
1416 newstruct = factory.Struct(tokens[1])
1417
1418 inside = ' '.join(tokens[3:-1])
1419
1420 tokens = inside.split(';')
1421
1422 structs = []
1423
1424 for entry in tokens:
1425 entry = NormalizeLine(entry)
1426 if not entry:
1427 continue
1428
1429 # It's possible that new structs get defined in here
1430 structs.extend(ProcessOneEntry(factory, newstruct, entry))
1431
1432 structs.append(newstruct)
1433 return structs
1434
1435def GetNextStruct(file):
1436 global line_count
1437 global cppdirect
1438
1439 got_struct = 0
1440
1441 processed_lines = []
1442
1443 have_c_comment = 0
1444 data = ''
1445 while 1:
1446 line = file.readline()
1447 if not line:
1448 break
1449
1450 line_count += 1
1451 line = line[:-1]
1452
1453 if not have_c_comment and re.search(r'/\*', line):
1454 if re.search(r'/\*.*?\*/', line):
1455 line = re.sub(r'/\*.*?\*/', '', line)
1456 else:
1457 line = re.sub(r'/\*.*$', '', line)
1458 have_c_comment = 1
1459
1460 if have_c_comment:
1461 if not re.search(r'\*/', line):
1462 continue
1463 have_c_comment = 0
1464 line = re.sub(r'^.*\*/', '', line)
1465
1466 line = NormalizeLine(line)
1467
1468 if not line:
1469 continue
1470
1471 if not got_struct:
1472 if re.match(r'#include ["<].*[>"]', line):
1473 cppdirect.append(line)
1474 continue
1475
1476 if re.match(r'^#(if( |def)|endif)', line):
1477 cppdirect.append(line)
1478 continue
1479
1480 if re.match(r'^#define', line):
1481 headerdirect.append(line)
1482 continue
1483
1484 if not structdef.match(line):
1485 raise RpcGenError('Missing struct on line %d: %s'
1486 % (line_count, line))
1487 else:
1488 got_struct = 1
1489 data += line
1490 continue
1491
1492 # We are inside the struct
1493 tokens = line.split('}')
1494 if len(tokens) == 1:
1495 data += ' ' + line
1496 continue
1497
1498 if len(tokens[1]):
1499 raise RpcGenError('Trailing garbage after struct on line %d'
1500 % line_count)
1501
1502 # We found the end of the struct
1503 data += ' %s}' % tokens[0]
1504 break
1505
1506 # Remove any comments, that might be in there
1507 data = re.sub(r'/\*.*\*/', '', data)
1508
1509 return data
1510
1511
1512def Parse(factory, file):
1513 """
1514 Parses the input file and returns C code and corresponding header file.
1515 """
1516
1517 entities = []
1518
1519 while 1:
1520 # Just gets the whole struct nicely formatted
1521 data = GetNextStruct(file)
1522
1523 if not data:
1524 break
1525
1526 entities.extend(ProcessStruct(factory, data))
1527
1528 return entities
1529
1530class CCodeGenerator:
1531 def __init__(self):
1532 pass
1533
1534 def GuardName(self, name):
1535 # Use the complete provided path to the input file, with all
1536 # non-identifier characters replaced with underscores, to
1537 # reduce the chance of a collision between guard macros.
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001538 return 'EVENT_RPCOUT_' + nonident.sub('_', name).upper() + '_'
Christopher Wileye8679812015-07-01 13:36:18 -07001539
1540 def HeaderPreamble(self, name):
1541 guard = self.GuardName(name)
1542 pre = (
1543 '/*\n'
1544 ' * Automatically generated from %s\n'
1545 ' */\n\n'
1546 '#ifndef %s\n'
1547 '#define %s\n\n' ) % (
1548 name, guard, guard)
1549
1550 for statement in headerdirect:
1551 pre += '%s\n' % statement
1552 if headerdirect:
1553 pre += '\n'
1554
1555 pre += (
1556 '#include <event2/util.h> /* for ev_uint*_t */\n'
1557 '#include <event2/rpc.h>\n'
1558 )
1559
1560 return pre
1561
1562 def HeaderPostamble(self, name):
1563 guard = self.GuardName(name)
1564 return '#endif /* %s */' % guard
1565
1566 def BodyPreamble(self, name, header_file):
1567 global _NAME
1568 global _VERSION
1569
1570 slash = header_file.rfind('/')
1571 if slash != -1:
1572 header_file = header_file[slash+1:]
1573
1574 pre = ( '/*\n'
1575 ' * Automatically generated from %s\n'
1576 ' * by %s/%s. DO NOT EDIT THIS FILE.\n'
1577 ' */\n\n' ) % (name, _NAME, _VERSION)
1578 pre += ( '#include <stdlib.h>\n'
1579 '#include <string.h>\n'
1580 '#include <assert.h>\n'
1581 '#include <event2/event-config.h>\n'
1582 '#include <event2/event.h>\n'
1583 '#include <event2/buffer.h>\n'
1584 '#include <event2/tag.h>\n\n'
Haibo Huangb2279672019-05-31 16:12:39 -07001585 '#if defined(EVENT__HAVE___func__)\n'
1586 '# ifndef __func__\n'
1587 '# define __func__ __func__\n'
1588 '# endif\n'
1589 '#elif defined(EVENT__HAVE___FUNCTION__)\n'
1590 '# define __func__ __FUNCTION__\n'
1591 '#else\n'
1592 '# define __func__ __FILE__\n'
Christopher Wileye8679812015-07-01 13:36:18 -07001593 '#endif\n\n'
1594 )
1595
1596 for statement in cppdirect:
1597 pre += '%s\n' % statement
1598
1599 pre += '\n#include "%s"\n\n' % header_file
1600
1601 pre += 'void event_warn(const char *fmt, ...);\n'
1602 pre += 'void event_warnx(const char *fmt, ...);\n\n'
1603
1604 return pre
1605
1606 def HeaderFilename(self, filename):
1607 return '.'.join(filename.split('.')[:-1]) + '.h'
1608
1609 def CodeFilename(self, filename):
1610 return '.'.join(filename.split('.')[:-1]) + '.gen.c'
1611
1612 def Struct(self, name):
1613 return StructCCode(name)
1614
1615 def EntryBytes(self, entry_type, name, tag, fixed_length):
1616 return EntryBytes(entry_type, name, tag, fixed_length)
1617
1618 def EntryVarBytes(self, entry_type, name, tag):
1619 return EntryVarBytes(entry_type, name, tag)
1620
1621 def EntryInt(self, entry_type, name, tag, bits=32):
1622 return EntryInt(entry_type, name, tag, bits)
1623
1624 def EntryString(self, entry_type, name, tag):
1625 return EntryString(entry_type, name, tag)
1626
1627 def EntryStruct(self, entry_type, name, tag, struct_name):
1628 return EntryStruct(entry_type, name, tag, struct_name)
1629
1630 def EntryArray(self, entry):
1631 return EntryArray(entry)
1632
1633class Usage(RpcGenError):
1634 def __init__(self, argv0):
1635 RpcGenError.__init__("usage: %s input.rpc [[output.h] output.c]"
1636 % argv0)
1637
1638class CommandLine:
1639 def __init__(self, argv):
1640 """Initialize a command-line to launch event_rpcgen, as if
1641 from a command-line with CommandLine(sys.argv). If you're
1642 calling this directly, remember to provide a dummy value
1643 for sys.argv[0]
1644 """
1645 self.filename = None
1646 self.header_file = None
1647 self.impl_file = None
1648 self.factory = CCodeGenerator()
1649
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001650 if len(argv) >= 2 and argv[1] == '--quiet':
1651 global QUIETLY
1652 QUIETLY = 1
1653 del argv[1]
1654
Christopher Wileye8679812015-07-01 13:36:18 -07001655 if len(argv) < 2 or len(argv) > 4:
1656 raise Usage(argv[0])
1657
1658 self.filename = argv[1].replace('\\', '/')
1659 if len(argv) == 3:
1660 self.impl_file = argv[2].replace('\\', '/')
1661 if len(argv) == 4:
1662 self.header_file = argv[2].replace('\\', '/')
1663 self.impl_file = argv[3].replace('\\', '/')
1664
1665 if not self.filename:
1666 raise Usage(argv[0])
1667
1668 if not self.impl_file:
1669 self.impl_file = self.factory.CodeFilename(self.filename)
1670
1671 if not self.header_file:
1672 self.header_file = self.factory.HeaderFilename(self.impl_file)
1673
1674 if not self.impl_file.endswith('.c'):
1675 raise RpcGenError("can only generate C implementation files")
1676 if not self.header_file.endswith('.h'):
1677 raise RpcGenError("can only generate C header files")
1678
1679 def run(self):
1680 filename = self.filename
1681 header_file = self.header_file
1682 impl_file = self.impl_file
1683 factory = self.factory
1684
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001685 declare('Reading \"%s\"' % filename)
Christopher Wileye8679812015-07-01 13:36:18 -07001686
1687 fp = open(filename, 'r')
1688 entities = Parse(factory, fp)
1689 fp.close()
1690
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001691 declare('... creating "%s"' % header_file)
Christopher Wileye8679812015-07-01 13:36:18 -07001692 header_fp = open(header_file, 'w')
Haibo Huangb2279672019-05-31 16:12:39 -07001693 header_fp.write(factory.HeaderPreamble(filename))
Christopher Wileye8679812015-07-01 13:36:18 -07001694
1695 # Create forward declarations: allows other structs to reference
1696 # each other
1697 for entry in entities:
1698 entry.PrintForwardDeclaration(header_fp)
Haibo Huangb2279672019-05-31 16:12:39 -07001699 header_fp.write('\n')
Christopher Wileye8679812015-07-01 13:36:18 -07001700
1701 for entry in entities:
1702 entry.PrintTags(header_fp)
1703 entry.PrintDeclaration(header_fp)
Haibo Huangb2279672019-05-31 16:12:39 -07001704 header_fp.write(factory.HeaderPostamble(filename))
Christopher Wileye8679812015-07-01 13:36:18 -07001705 header_fp.close()
1706
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001707 declare('... creating "%s"' % impl_file)
Christopher Wileye8679812015-07-01 13:36:18 -07001708 impl_fp = open(impl_file, 'w')
Haibo Huangb2279672019-05-31 16:12:39 -07001709 impl_fp.write(factory.BodyPreamble(filename, header_file))
Christopher Wileye8679812015-07-01 13:36:18 -07001710 for entry in entities:
1711 entry.PrintCode(impl_fp)
1712 impl_fp.close()
1713
1714if __name__ == '__main__':
1715 try:
1716 CommandLine(sys.argv).run()
1717 sys.exit(0)
1718
Haibo Huangb2279672019-05-31 16:12:39 -07001719 except RpcGenError as e:
1720 sys.stderr.write(e)
Christopher Wileye8679812015-07-01 13:36:18 -07001721 sys.exit(1)
1722
Haibo Huangb2279672019-05-31 16:12:39 -07001723 except EnvironmentError as e:
Christopher Wileye8679812015-07-01 13:36:18 -07001724 if e.filename and e.strerror:
Haibo Huangb2279672019-05-31 16:12:39 -07001725 sys.stderr.write("%s: %s" % (e.filename, e.strerror))
Christopher Wileye8679812015-07-01 13:36:18 -07001726 sys.exit(1)
1727 elif e.strerror:
Haibo Huangb2279672019-05-31 16:12:39 -07001728 sys.stderr.write(e.strerror)
Christopher Wileye8679812015-07-01 13:36:18 -07001729 sys.exit(1)
1730 else:
1731 raise