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