OLD | NEW |
| (Empty) |
1 #!/usr/bin/env python | |
2 # | |
3 # Copyright (c) 2005 Niels Provos <provos@citi.umich.edu> | |
4 # All rights reserved. | |
5 # | |
6 # Generates marshaling code based on libevent. | |
7 | |
8 import sys | |
9 import re | |
10 | |
11 # | |
12 _NAME = "event_rpcgen.py" | |
13 _VERSION = "0.1" | |
14 _STRUCT_RE = '[a-z][a-z_0-9]*' | |
15 | |
16 # Globals | |
17 line_count = 0 | |
18 | |
19 white = re.compile(r'^\s+') | |
20 cppcomment = re.compile(r'\/\/.*$') | |
21 headerdirect = [] | |
22 cppdirect = [] | |
23 | |
24 # Holds everything that makes a struct | |
25 class Struct: | |
26 def __init__(self, name): | |
27 self._name = name | |
28 self._entries = [] | |
29 self._tags = {} | |
30 print >>sys.stderr, ' Created struct: %s' % name | |
31 | |
32 def AddEntry(self, entry): | |
33 if self._tags.has_key(entry.Tag()): | |
34 print >>sys.stderr, ( 'Entry "%s" duplicates tag number ' | |
35 '%d from "%s" around line %d' ) % ( | |
36 entry.Name(), entry.Tag(), | |
37 self._tags[entry.Tag()], line_count) | |
38 sys.exit(1) | |
39 self._entries.append(entry) | |
40 self._tags[entry.Tag()] = entry.Name() | |
41 print >>sys.stderr, ' Added entry: %s' % entry.Name() | |
42 | |
43 def Name(self): | |
44 return self._name | |
45 | |
46 def EntryTagName(self, entry): | |
47 """Creates the name inside an enumeration for distinguishing data | |
48 types.""" | |
49 name = "%s_%s" % (self._name, entry.Name()) | |
50 return name.upper() | |
51 | |
52 def PrintIdented(self, file, ident, code): | |
53 """Takes an array, add indentation to each entry and prints it.""" | |
54 for entry in code: | |
55 print >>file, '%s%s' % (ident, entry) | |
56 | |
57 def PrintTags(self, file): | |
58 """Prints the tag definitions for a structure.""" | |
59 print >>file, '/* Tag definition for %s */' % self._name | |
60 print >>file, 'enum %s_ {' % self._name.lower() | |
61 for entry in self._entries: | |
62 print >>file, ' %s=%d,' % (self.EntryTagName(entry), | |
63 entry.Tag()) | |
64 print >>file, ' %s_MAX_TAGS' % (self._name.upper()) | |
65 print >>file, '};\n' | |
66 | |
67 def PrintForwardDeclaration(self, file): | |
68 print >>file, 'struct %s;' % self._name | |
69 | |
70 def PrintDeclaration(self, file): | |
71 print >>file, '/* Structure declaration for %s */' % self._name | |
72 print >>file, 'struct %s_access_ {' % self._name | |
73 for entry in self._entries: | |
74 dcl = entry.AssignDeclaration('(*%s_assign)' % entry.Name()) | |
75 dcl.extend( | |
76 entry.GetDeclaration('(*%s_get)' % entry.Name())) | |
77 if entry.Array(): | |
78 dcl.extend( | |
79 entry.AddDeclaration('(*%s_add)' % entry.Name())) | |
80 self.PrintIdented(file, ' ', dcl) | |
81 print >>file, '};\n' | |
82 | |
83 print >>file, 'struct %s {' % self._name | |
84 print >>file, ' struct %s_access_ *base;\n' % self._name | |
85 for entry in self._entries: | |
86 dcl = entry.Declaration() | |
87 self.PrintIdented(file, ' ', dcl) | |
88 print >>file, '' | |
89 for entry in self._entries: | |
90 print >>file, ' ev_uint8_t %s_set;' % entry.Name() | |
91 print >>file, '};\n' | |
92 | |
93 print >>file, \ | |
94 """struct %(name)s *%(name)s_new(void); | |
95 void %(name)s_free(struct %(name)s *); | |
96 void %(name)s_clear(struct %(name)s *); | |
97 void %(name)s_marshal(struct evbuffer *, const struct %(name)s *); | |
98 int %(name)s_unmarshal(struct %(name)s *, struct evbuffer *); | |
99 int %(name)s_complete(struct %(name)s *); | |
100 void evtag_marshal_%(name)s(struct evbuffer *, ev_uint32_t, | |
101 const struct %(name)s *); | |
102 int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t, | |
103 struct %(name)s *);""" % { 'name' : self._name } | |
104 | |
105 | |
106 # Write a setting function of every variable | |
107 for entry in self._entries: | |
108 self.PrintIdented(file, '', entry.AssignDeclaration( | |
109 entry.AssignFuncName())) | |
110 self.PrintIdented(file, '', entry.GetDeclaration( | |
111 entry.GetFuncName())) | |
112 if entry.Array(): | |
113 self.PrintIdented(file, '', entry.AddDeclaration( | |
114 entry.AddFuncName())) | |
115 | |
116 print >>file, '/* --- %s done --- */\n' % self._name | |
117 | |
118 def PrintCode(self, file): | |
119 print >>file, ('/*\n' | |
120 ' * Implementation of %s\n' | |
121 ' */\n') % self._name | |
122 | |
123 print >>file, \ | |
124 'static struct %(name)s_access_ __%(name)s_base = {' % \ | |
125 { 'name' : self._name } | |
126 for entry in self._entries: | |
127 self.PrintIdented(file, ' ', entry.CodeBase()) | |
128 print >>file, '};\n' | |
129 | |
130 # Creation | |
131 print >>file, ( | |
132 'struct %(name)s *\n' | |
133 '%(name)s_new(void)\n' | |
134 '{\n' | |
135 ' struct %(name)s *tmp;\n' | |
136 ' if ((tmp = malloc(sizeof(struct %(name)s))) == NULL) {\n' | |
137 ' event_warn("%%s: malloc", __func__);\n' | |
138 ' return (NULL);\n' | |
139 ' }\n' | |
140 ' tmp->base = &__%(name)s_base;\n') % { 'name' : self._name } | |
141 | |
142 for entry in self._entries: | |
143 self.PrintIdented(file, ' ', entry.CodeNew('tmp')) | |
144 print >>file, ' tmp->%s_set = 0;\n' % entry.Name() | |
145 | |
146 print >>file, ( | |
147 ' return (tmp);\n' | |
148 '}\n') | |
149 | |
150 # Adding | |
151 for entry in self._entries: | |
152 if entry.Array(): | |
153 self.PrintIdented(file, '', entry.CodeAdd()) | |
154 print >>file, '' | |
155 | |
156 # Assigning | |
157 for entry in self._entries: | |
158 self.PrintIdented(file, '', entry.CodeAssign()) | |
159 print >>file, '' | |
160 | |
161 # Getting | |
162 for entry in self._entries: | |
163 self.PrintIdented(file, '', entry.CodeGet()) | |
164 print >>file, '' | |
165 | |
166 # Clearing | |
167 print >>file, ( 'void\n' | |
168 '%(name)s_clear(struct %(name)s *tmp)\n' | |
169 '{' | |
170 ) % { 'name' : self._name } | |
171 for entry in self._entries: | |
172 self.PrintIdented(file, ' ', entry.CodeClear('tmp')) | |
173 | |
174 print >>file, '}\n' | |
175 | |
176 # Freeing | |
177 print >>file, ( 'void\n' | |
178 '%(name)s_free(struct %(name)s *tmp)\n' | |
179 '{' | |
180 ) % { 'name' : self._name } | |
181 | |
182 for entry in self._entries: | |
183 self.PrintIdented(file, ' ', entry.CodeFree('tmp')) | |
184 | |
185 print >>file, (' free(tmp);\n' | |
186 '}\n') | |
187 | |
188 # Marshaling | |
189 print >>file, ('void\n' | |
190 '%(name)s_marshal(struct evbuffer *evbuf, ' | |
191 'const struct %(name)s *tmp)' | |
192 '{') % { 'name' : self._name } | |
193 for entry in self._entries: | |
194 indent = ' ' | |
195 # Optional entries do not have to be set | |
196 if entry.Optional(): | |
197 indent += ' ' | |
198 print >>file, ' if (tmp->%s_set) {' % entry.Name() | |
199 self.PrintIdented( | |
200 file, indent, | |
201 entry.CodeMarshal('evbuf', self.EntryTagName(entry), 'tmp')) | |
202 if entry.Optional(): | |
203 print >>file, ' }' | |
204 | |
205 print >>file, '}\n' | |
206 | |
207 # Unmarshaling | |
208 print >>file, ('int\n' | |
209 '%(name)s_unmarshal(struct %(name)s *tmp, ' | |
210 ' struct evbuffer *evbuf)\n' | |
211 '{\n' | |
212 ' ev_uint32_t tag;\n' | |
213 ' while (EVBUFFER_LENGTH(evbuf) > 0) {\n' | |
214 ' if (evtag_peek(evbuf, &tag) == -1)\n' | |
215 ' return (-1);\n' | |
216 ' switch (tag) {\n' | |
217 ) % { 'name' : self._name } | |
218 for entry in self._entries: | |
219 print >>file, ' case %s:\n' % self.EntryTagName(entry) | |
220 if not entry.Array(): | |
221 print >>file, ( | |
222 ' if (tmp->%s_set)\n' | |
223 ' return (-1);' | |
224 ) % (entry.Name()) | |
225 | |
226 self.PrintIdented( | |
227 file, ' ', | |
228 entry.CodeUnmarshal('evbuf', | |
229 self.EntryTagName(entry), 'tmp')) | |
230 | |
231 print >>file, ( ' tmp->%s_set = 1;\n' % entry.Name() + | |
232 ' break;\n' ) | |
233 print >>file, ( ' default:\n' | |
234 ' return -1;\n' | |
235 ' }\n' | |
236 ' }\n' ) | |
237 # Check if it was decoded completely | |
238 print >>file, ( ' if (%(name)s_complete(tmp) == -1)\n' | |
239 ' return (-1);' | |
240 ) % { 'name' : self._name } | |
241 | |
242 # Successfully decoded | |
243 print >>file, ( ' return (0);\n' | |
244 '}\n') | |
245 | |
246 # Checking if a structure has all the required data | |
247 print >>file, ( | |
248 'int\n' | |
249 '%(name)s_complete(struct %(name)s *msg)\n' | |
250 '{' ) % { 'name' : self._name } | |
251 for entry in self._entries: | |
252 self.PrintIdented( | |
253 file, ' ', | |
254 entry.CodeComplete('msg')) | |
255 print >>file, ( | |
256 ' return (0);\n' | |
257 '}\n' ) | |
258 | |
259 # Complete message unmarshaling | |
260 print >>file, ( | |
261 'int\n' | |
262 'evtag_unmarshal_%(name)s(struct evbuffer *evbuf, ' | |
263 'ev_uint32_t need_tag, struct %(name)s *msg)\n' | |
264 '{\n' | |
265 ' ev_uint32_t tag;\n' | |
266 ' int res = -1;\n' | |
267 '\n' | |
268 ' struct evbuffer *tmp = evbuffer_new();\n' | |
269 '\n' | |
270 ' if (evtag_unmarshal(evbuf, &tag, tmp) == -1' | |
271 ' || tag != need_tag)\n' | |
272 ' goto error;\n' | |
273 '\n' | |
274 ' if (%(name)s_unmarshal(msg, tmp) == -1)\n' | |
275 ' goto error;\n' | |
276 '\n' | |
277 ' res = 0;\n' | |
278 '\n' | |
279 ' error:\n' | |
280 ' evbuffer_free(tmp);\n' | |
281 ' return (res);\n' | |
282 '}\n' ) % { 'name' : self._name } | |
283 | |
284 # Complete message marshaling | |
285 print >>file, ( | |
286 'void\n' | |
287 'evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag, ' | |
288 'const struct %(name)s *msg)\n' | |
289 '{\n' | |
290 ' struct evbuffer *_buf = evbuffer_new();\n' | |
291 ' assert(_buf != NULL);\n' | |
292 ' evbuffer_drain(_buf, -1);\n' | |
293 ' %(name)s_marshal(_buf, msg);\n' | |
294 ' evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf), ' | |
295 'EVBUFFER_LENGTH(_buf));\n' | |
296 ' evbuffer_free(_buf);\n' | |
297 '}\n' ) % { 'name' : self._name } | |
298 | |
299 class Entry: | |
300 def __init__(self, type, name, tag): | |
301 self._type = type | |
302 self._name = name | |
303 self._tag = int(tag) | |
304 self._ctype = type | |
305 self._optional = 0 | |
306 self._can_be_array = 0 | |
307 self._array = 0 | |
308 self._line_count = -1 | |
309 self._struct = None | |
310 self._refname = None | |
311 | |
312 def GetTranslation(self): | |
313 return { "parent_name" : self._struct.Name(), | |
314 "name" : self._name, | |
315 "ctype" : self._ctype, | |
316 "refname" : self._refname | |
317 } | |
318 | |
319 def SetStruct(self, struct): | |
320 self._struct = struct | |
321 | |
322 def LineCount(self): | |
323 assert self._line_count != -1 | |
324 return self._line_count | |
325 | |
326 def SetLineCount(self, number): | |
327 self._line_count = number | |
328 | |
329 def Array(self): | |
330 return self._array | |
331 | |
332 def Optional(self): | |
333 return self._optional | |
334 | |
335 def Tag(self): | |
336 return self._tag | |
337 | |
338 def Name(self): | |
339 return self._name | |
340 | |
341 def Type(self): | |
342 return self._type | |
343 | |
344 def MakeArray(self, yes=1): | |
345 self._array = yes | |
346 | |
347 def MakeOptional(self): | |
348 self._optional = 1 | |
349 | |
350 def GetFuncName(self): | |
351 return '%s_%s_get' % (self._struct.Name(), self._name) | |
352 | |
353 def GetDeclaration(self, funcname): | |
354 code = [ 'int %s(struct %s *, %s *);' % ( | |
355 funcname, self._struct.Name(), self._ctype ) ] | |
356 return code | |
357 | |
358 def CodeGet(self): | |
359 code = ( | |
360 'int', | |
361 '%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, ' | |
362 '%(ctype)s *value)', | |
363 '{', | |
364 ' if (msg->%(name)s_set != 1)', | |
365 ' return (-1);', | |
366 ' *value = msg->%(name)s_data;', | |
367 ' return (0);', | |
368 '}' ) | |
369 code = '\n'.join(code) | |
370 code = code % self.GetTranslation() | |
371 return code.split('\n') | |
372 | |
373 def AssignFuncName(self): | |
374 return '%s_%s_assign' % (self._struct.Name(), self._name) | |
375 | |
376 def AddFuncName(self): | |
377 return '%s_%s_add' % (self._struct.Name(), self._name) | |
378 | |
379 def AssignDeclaration(self, funcname): | |
380 code = [ 'int %s(struct %s *, const %s);' % ( | |
381 funcname, self._struct.Name(), self._ctype ) ] | |
382 return code | |
383 | |
384 def CodeAssign(self): | |
385 code = [ 'int', | |
386 '%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,' | |
387 ' const %(ctype)s value)', | |
388 '{', | |
389 ' msg->%(name)s_set = 1;', | |
390 ' msg->%(name)s_data = value;', | |
391 ' return (0);', | |
392 '}' ] | |
393 code = '\n'.join(code) | |
394 code = code % self.GetTranslation() | |
395 return code.split('\n') | |
396 | |
397 def CodeClear(self, structname): | |
398 code = [ '%s->%s_set = 0;' % (structname, self.Name()) ] | |
399 | |
400 return code | |
401 | |
402 def CodeComplete(self, structname): | |
403 if self.Optional(): | |
404 return [] | |
405 | |
406 code = [ 'if (!%s->%s_set)' % (structname, self.Name()), | |
407 ' return (-1);' ] | |
408 | |
409 return code | |
410 | |
411 def CodeFree(self, name): | |
412 return [] | |
413 | |
414 def CodeBase(self): | |
415 code = [ | |
416 '%(parent_name)s_%(name)s_assign,', | |
417 '%(parent_name)s_%(name)s_get,' | |
418 ] | |
419 if self.Array(): | |
420 code.append('%(parent_name)s_%(name)s_add,') | |
421 | |
422 code = '\n'.join(code) | |
423 code = code % self.GetTranslation() | |
424 return code.split('\n') | |
425 | |
426 def Verify(self): | |
427 if self.Array() and not self._can_be_array: | |
428 print >>sys.stderr, ( | |
429 'Entry "%s" cannot be created as an array ' | |
430 'around line %d' ) % (self._name, self.LineCount()) | |
431 sys.exit(1) | |
432 if not self._struct: | |
433 print >>sys.stderr, ( | |
434 'Entry "%s" does not know which struct it belongs to ' | |
435 'around line %d' ) % (self._name, self.LineCount()) | |
436 sys.exit(1) | |
437 if self._optional and self._array: | |
438 print >>sys.stderr, ( 'Entry "%s" has illegal combination of ' | |
439 'optional and array around line %d' ) % ( | |
440 self._name, self.LineCount() ) | |
441 sys.exit(1) | |
442 | |
443 class EntryBytes(Entry): | |
444 def __init__(self, type, name, tag, length): | |
445 # Init base class | |
446 Entry.__init__(self, type, name, tag) | |
447 | |
448 self._length = length | |
449 self._ctype = 'ev_uint8_t' | |
450 | |
451 def GetDeclaration(self, funcname): | |
452 code = [ 'int %s(struct %s *, %s **);' % ( | |
453 funcname, self._struct.Name(), self._ctype ) ] | |
454 return code | |
455 | |
456 def AssignDeclaration(self, funcname): | |
457 code = [ 'int %s(struct %s *, const %s *);' % ( | |
458 funcname, self._struct.Name(), self._ctype ) ] | |
459 return code | |
460 | |
461 def Declaration(self): | |
462 dcl = ['ev_uint8_t %s_data[%s];' % (self._name, self._length)] | |
463 | |
464 return dcl | |
465 | |
466 def CodeGet(self): | |
467 name = self._name | |
468 code = [ 'int', | |
469 '%s_%s_get(struct %s *msg, %s **value)' % ( | |
470 self._struct.Name(), name, | |
471 self._struct.Name(), self._ctype), | |
472 '{', | |
473 ' if (msg->%s_set != 1)' % name, | |
474 ' return (-1);', | |
475 ' *value = msg->%s_data;' % name, | |
476 ' return (0);', | |
477 '}' ] | |
478 return code | |
479 | |
480 def CodeAssign(self): | |
481 name = self._name | |
482 code = [ 'int', | |
483 '%s_%s_assign(struct %s *msg, const %s *value)' % ( | |
484 self._struct.Name(), name, | |
485 self._struct.Name(), self._ctype), | |
486 '{', | |
487 ' msg->%s_set = 1;' % name, | |
488 ' memcpy(msg->%s_data, value, %s);' % ( | |
489 name, self._length), | |
490 ' return (0);', | |
491 '}' ] | |
492 return code | |
493 | |
494 def CodeUnmarshal(self, buf, tag_name, var_name): | |
495 code = [ 'if (evtag_unmarshal_fixed(%s, %s, ' % (buf, tag_name) + | |
496 '%s->%s_data, ' % (var_name, self._name) + | |
497 'sizeof(%s->%s_data)) == -1) {' % ( | |
498 var_name, self._name), | |
499 ' event_warnx("%%s: failed to unmarshal %s", __func__);' % ( | |
500 self._name ), | |
501 ' return (-1);', | |
502 '}' | |
503 ] | |
504 return code | |
505 | |
506 def CodeMarshal(self, buf, tag_name, var_name): | |
507 code = ['evtag_marshal(%s, %s, %s->%s_data, sizeof(%s->%s_data));' % ( | |
508 buf, tag_name, var_name, self._name, var_name, self._name )] | |
509 return code | |
510 | |
511 def CodeClear(self, structname): | |
512 code = [ '%s->%s_set = 0;' % (structname, self.Name()), | |
513 'memset(%s->%s_data, 0, sizeof(%s->%s_data));' % ( | |
514 structname, self._name, structname, self._name)] | |
515 | |
516 return code | |
517 | |
518 def CodeNew(self, name): | |
519 code = ['memset(%s->%s_data, 0, sizeof(%s->%s_data));' % ( | |
520 name, self._name, name, self._name)] | |
521 return code | |
522 | |
523 def Verify(self): | |
524 if not self._length: | |
525 print >>sys.stderr, 'Entry "%s" needs a length around line %d' % ( | |
526 self._name, self.LineCount() ) | |
527 sys.exit(1) | |
528 | |
529 Entry.Verify(self) | |
530 | |
531 class EntryInt(Entry): | |
532 def __init__(self, type, name, tag): | |
533 # Init base class | |
534 Entry.__init__(self, type, name, tag) | |
535 | |
536 self._ctype = 'ev_uint32_t' | |
537 | |
538 def CodeUnmarshal(self, buf, tag_name, var_name): | |
539 code = ['if (evtag_unmarshal_int(%s, %s, &%s->%s_data) == -1) {' % ( | |
540 buf, tag_name, var_name, self._name), | |
541 ' event_warnx("%%s: failed to unmarshal %s", __func__);' % ( | |
542 self._name ), | |
543 ' return (-1);', | |
544 '}' ] | |
545 return code | |
546 | |
547 def CodeMarshal(self, buf, tag_name, var_name): | |
548 code = ['evtag_marshal_int(%s, %s, %s->%s_data);' % ( | |
549 buf, tag_name, var_name, self._name)] | |
550 return code | |
551 | |
552 def Declaration(self): | |
553 dcl = ['ev_uint32_t %s_data;' % self._name] | |
554 | |
555 return dcl | |
556 | |
557 def CodeNew(self, name): | |
558 code = ['%s->%s_data = 0;' % (name, self._name)] | |
559 return code | |
560 | |
561 class EntryString(Entry): | |
562 def __init__(self, type, name, tag): | |
563 # Init base class | |
564 Entry.__init__(self, type, name, tag) | |
565 | |
566 self._ctype = 'char *' | |
567 | |
568 def CodeAssign(self): | |
569 name = self._name | |
570 code = """int | |
571 %(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, | |
572 const %(ctype)s value) | |
573 { | |
574 if (msg->%(name)s_data != NULL) | |
575 free(msg->%(name)s_data); | |
576 if ((msg->%(name)s_data = strdup(value)) == NULL) | |
577 return (-1); | |
578 msg->%(name)s_set = 1; | |
579 return (0); | |
580 }""" % self.GetTranslation() | |
581 | |
582 return code.split('\n') | |
583 | |
584 def CodeUnmarshal(self, buf, tag_name, var_name): | |
585 code = ['if (evtag_unmarshal_string(%s, %s, &%s->%s_data) == -1) {' % ( | |
586 buf, tag_name, var_name, self._name), | |
587 ' event_warnx("%%s: failed to unmarshal %s", __func__);' % ( | |
588 self._name ), | |
589 ' return (-1);', | |
590 '}' | |
591 ] | |
592 return code | |
593 | |
594 def CodeMarshal(self, buf, tag_name, var_name): | |
595 code = ['evtag_marshal_string(%s, %s, %s->%s_data);' % ( | |
596 buf, tag_name, var_name, self._name)] | |
597 return code | |
598 | |
599 def CodeClear(self, structname): | |
600 code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()), | |
601 ' free (%s->%s_data);' % (structname, self.Name()), | |
602 ' %s->%s_data = NULL;' % (structname, self.Name()), | |
603 ' %s->%s_set = 0;' % (structname, self.Name()), | |
604 '}' | |
605 ] | |
606 | |
607 return code | |
608 | |
609 def CodeNew(self, name): | |
610 code = ['%s->%s_data = NULL;' % (name, self._name)] | |
611 return code | |
612 | |
613 def CodeFree(self, name): | |
614 code = ['if (%s->%s_data != NULL)' % (name, self._name), | |
615 ' free (%s->%s_data); ' % (name, self._name)] | |
616 | |
617 return code | |
618 | |
619 def Declaration(self): | |
620 dcl = ['char *%s_data;' % self._name] | |
621 | |
622 return dcl | |
623 | |
624 class EntryStruct(Entry): | |
625 def __init__(self, type, name, tag, refname): | |
626 # Init base class | |
627 Entry.__init__(self, type, name, tag) | |
628 | |
629 self._can_be_array = 1 | |
630 self._refname = refname | |
631 self._ctype = 'struct %s*' % refname | |
632 | |
633 def CodeGet(self): | |
634 name = self._name | |
635 code = [ 'int', | |
636 '%s_%s_get(struct %s *msg, %s *value)' % ( | |
637 self._struct.Name(), name, | |
638 self._struct.Name(), self._ctype), | |
639 '{', | |
640 ' if (msg->%s_set != 1) {' % name, | |
641 ' msg->%s_data = %s_new();' % (name, self._refname), | |
642 ' if (msg->%s_data == NULL)' % name, | |
643 ' return (-1);', | |
644 ' msg->%s_set = 1;' % name, | |
645 ' }', | |
646 ' *value = msg->%s_data;' % name, | |
647 ' return (0);', | |
648 '}' ] | |
649 return code | |
650 | |
651 def CodeAssign(self): | |
652 name = self._name | |
653 code = """int | |
654 %(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, | |
655 const %(ctype)s value) | |
656 { | |
657 struct evbuffer *tmp = NULL; | |
658 if (msg->%(name)s_set) { | |
659 %(refname)s_clear(msg->%(name)s_data); | |
660 msg->%(name)s_set = 0; | |
661 } else { | |
662 msg->%(name)s_data = %(refname)s_new(); | |
663 if (msg->%(name)s_data == NULL) { | |
664 event_warn("%%s: %(refname)s_new()", __func__); | |
665 goto error; | |
666 } | |
667 } | |
668 if ((tmp = evbuffer_new()) == NULL) { | |
669 event_warn("%%s: evbuffer_new()", __func__); | |
670 goto error; | |
671 } | |
672 %(refname)s_marshal(tmp, value); | |
673 if (%(refname)s_unmarshal(msg->%(name)s_data, tmp) == -1) { | |
674 event_warnx("%%s: %(refname)s_unmarshal", __func__); | |
675 goto error; | |
676 } | |
677 msg->%(name)s_set = 1; | |
678 evbuffer_free(tmp); | |
679 return (0); | |
680 error: | |
681 if (tmp != NULL) | |
682 evbuffer_free(tmp); | |
683 if (msg->%(name)s_data != NULL) { | |
684 %(refname)s_free(msg->%(name)s_data); | |
685 msg->%(name)s_data = NULL; | |
686 } | |
687 return (-1); | |
688 }""" % self.GetTranslation() | |
689 return code.split('\n') | |
690 | |
691 def CodeComplete(self, structname): | |
692 if self.Optional(): | |
693 code = [ 'if (%s->%s_set && %s_complete(%s->%s_data) == -1)' % ( | |
694 structname, self.Name(), | |
695 self._refname, structname, self.Name()), | |
696 ' return (-1);' ] | |
697 else: | |
698 code = [ 'if (%s_complete(%s->%s_data) == -1)' % ( | |
699 self._refname, structname, self.Name()), | |
700 ' return (-1);' ] | |
701 | |
702 return code | |
703 | |
704 def CodeUnmarshal(self, buf, tag_name, var_name): | |
705 code = ['%s->%s_data = %s_new();' % ( | |
706 var_name, self._name, self._refname), | |
707 'if (%s->%s_data == NULL)' % (var_name, self._name), | |
708 ' return (-1);', | |
709 'if (evtag_unmarshal_%s(%s, %s, %s->%s_data) == -1) {' % ( | |
710 self._refname, buf, tag_name, var_name, self._name), | |
711 ' event_warnx("%%s: failed to unmarshal %s", __func__);' % ( | |
712 self._name ), | |
713 ' return (-1);', | |
714 '}' | |
715 ] | |
716 return code | |
717 | |
718 def CodeMarshal(self, buf, tag_name, var_name): | |
719 code = ['evtag_marshal_%s(%s, %s, %s->%s_data);' % ( | |
720 self._refname, buf, tag_name, var_name, self._name)] | |
721 return code | |
722 | |
723 def CodeClear(self, structname): | |
724 code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()), | |
725 ' %s_free(%s->%s_data);' % ( | |
726 self._refname, structname, self.Name()), | |
727 ' %s->%s_data = NULL;' % (structname, self.Name()), | |
728 ' %s->%s_set = 0;' % (structname, self.Name()), | |
729 '}' | |
730 ] | |
731 | |
732 return code | |
733 | |
734 def CodeNew(self, name): | |
735 code = ['%s->%s_data = NULL;' % (name, self._name)] | |
736 return code | |
737 | |
738 def CodeFree(self, name): | |
739 code = ['if (%s->%s_data != NULL)' % (name, self._name), | |
740 ' %s_free(%s->%s_data); ' % ( | |
741 self._refname, name, self._name)] | |
742 | |
743 return code | |
744 | |
745 def Declaration(self): | |
746 dcl = ['%s %s_data;' % (self._ctype, self._name)] | |
747 | |
748 return dcl | |
749 | |
750 class EntryVarBytes(Entry): | |
751 def __init__(self, type, name, tag): | |
752 # Init base class | |
753 Entry.__init__(self, type, name, tag) | |
754 | |
755 self._ctype = 'ev_uint8_t *' | |
756 | |
757 def GetDeclaration(self, funcname): | |
758 code = [ 'int %s(struct %s *, %s *, ev_uint32_t *);' % ( | |
759 funcname, self._struct.Name(), self._ctype ) ] | |
760 return code | |
761 | |
762 def AssignDeclaration(self, funcname): | |
763 code = [ 'int %s(struct %s *, const %s, ev_uint32_t);' % ( | |
764 funcname, self._struct.Name(), self._ctype ) ] | |
765 return code | |
766 | |
767 def CodeAssign(self): | |
768 name = self._name | |
769 code = [ 'int', | |
770 '%s_%s_assign(struct %s *msg, ' | |
771 'const %s value, ev_uint32_t len)' % ( | |
772 self._struct.Name(), name, | |
773 self._struct.Name(), self._ctype), | |
774 '{', | |
775 ' if (msg->%s_data != NULL)' % name, | |
776 ' free (msg->%s_data);' % name, | |
777 ' msg->%s_data = malloc(len);' % name, | |
778 ' if (msg->%s_data == NULL)' % name, | |
779 ' return (-1);', | |
780 ' msg->%s_set = 1;' % name, | |
781 ' msg->%s_length = len;' % name, | |
782 ' memcpy(msg->%s_data, value, len);' % name, | |
783 ' return (0);', | |
784 '}' ] | |
785 return code | |
786 | |
787 def CodeGet(self): | |
788 name = self._name | |
789 code = [ 'int', | |
790 '%s_%s_get(struct %s *msg, %s *value, ev_uint32_t *plen)' % ( | |
791 self._struct.Name(), name, | |
792 self._struct.Name(), self._ctype), | |
793 '{', | |
794 ' if (msg->%s_set != 1)' % name, | |
795 ' return (-1);', | |
796 ' *value = msg->%s_data;' % name, | |
797 ' *plen = msg->%s_length;' % name, | |
798 ' return (0);', | |
799 '}' ] | |
800 return code | |
801 | |
802 def CodeUnmarshal(self, buf, tag_name, var_name): | |
803 code = ['if (evtag_payload_length(%s, &%s->%s_length) == -1)' % ( | |
804 buf, var_name, self._name), | |
805 ' return (-1);', | |
806 # We do not want DoS opportunities | |
807 'if (%s->%s_length > EVBUFFER_LENGTH(%s))' % ( | |
808 var_name, self._name, buf), | |
809 ' return (-1);', | |
810 'if ((%s->%s_data = malloc(%s->%s_length)) == NULL)' % ( | |
811 var_name, self._name, var_name, self._name), | |
812 ' return (-1);', | |
813 'if (evtag_unmarshal_fixed(%s, %s, %s->%s_data, ' | |
814 '%s->%s_length) == -1) {' % ( | |
815 buf, tag_name, var_name, self._name, var_name, self._name), | |
816 ' event_warnx("%%s: failed to unmarshal %s", __func__);' % ( | |
817 self._name ), | |
818 ' return (-1);', | |
819 '}' | |
820 ] | |
821 return code | |
822 | |
823 def CodeMarshal(self, buf, tag_name, var_name): | |
824 code = ['evtag_marshal(%s, %s, %s->%s_data, %s->%s_length);' % ( | |
825 buf, tag_name, var_name, self._name, var_name, self._name)] | |
826 return code | |
827 | |
828 def CodeClear(self, structname): | |
829 code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()), | |
830 ' free (%s->%s_data);' % (structname, self.Name()), | |
831 ' %s->%s_data = NULL;' % (structname, self.Name()), | |
832 ' %s->%s_length = 0;' % (structname, self.Name()), | |
833 ' %s->%s_set = 0;' % (structname, self.Name()), | |
834 '}' | |
835 ] | |
836 | |
837 return code | |
838 | |
839 def CodeNew(self, name): | |
840 code = ['%s->%s_data = NULL;' % (name, self._name), | |
841 '%s->%s_length = 0;' % (name, self._name) ] | |
842 return code | |
843 | |
844 def CodeFree(self, name): | |
845 code = ['if (%s->%s_data != NULL)' % (name, self._name), | |
846 ' free (%s->%s_data); ' % (name, self._name)] | |
847 | |
848 return code | |
849 | |
850 def Declaration(self): | |
851 dcl = ['ev_uint8_t *%s_data;' % self._name, | |
852 'ev_uint32_t %s_length;' % self._name] | |
853 | |
854 return dcl | |
855 | |
856 class EntryArray(Entry): | |
857 def __init__(self, entry): | |
858 # Init base class | |
859 Entry.__init__(self, entry._type, entry._name, entry._tag) | |
860 | |
861 self._entry = entry | |
862 self._refname = entry._refname | |
863 self._ctype = 'struct %s *' % self._refname | |
864 | |
865 def GetDeclaration(self, funcname): | |
866 """Allows direct access to elements of the array.""" | |
867 translate = self.GetTranslation() | |
868 translate["funcname"] = funcname | |
869 code = [ | |
870 'int %(funcname)s(struct %(parent_name)s *, int, %(ctype)s *);' % | |
871 translate ] | |
872 return code | |
873 | |
874 def AssignDeclaration(self, funcname): | |
875 code = [ 'int %s(struct %s *, int, const %s);' % ( | |
876 funcname, self._struct.Name(), self._ctype ) ] | |
877 return code | |
878 | |
879 def AddDeclaration(self, funcname): | |
880 code = [ '%s %s(struct %s *);' % ( | |
881 self._ctype, funcname, self._struct.Name() ) ] | |
882 return code | |
883 | |
884 def CodeGet(self): | |
885 code = """int | |
886 %(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, int offset, | |
887 %(ctype)s *value) | |
888 { | |
889 if (!msg->%(name)s_set || offset < 0 || offset >= msg->%(name)s_length) | |
890 return (-1); | |
891 *value = msg->%(name)s_data[offset]; | |
892 return (0); | |
893 }""" % self.GetTranslation() | |
894 | |
895 return code.split('\n') | |
896 | |
897 def CodeAssign(self): | |
898 code = """int | |
899 %(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, int off, | |
900 const %(ctype)s value) | |
901 { | |
902 struct evbuffer *tmp = NULL; | |
903 if (!msg->%(name)s_set || off < 0 || off >= msg->%(name)s_length) | |
904 return (-1); | |
905 %(refname)s_clear(msg->%(name)s_data[off]); | |
906 if ((tmp = evbuffer_new()) == NULL) { | |
907 event_warn("%%s: evbuffer_new()", __func__); | |
908 goto error; | |
909 } | |
910 %(refname)s_marshal(tmp, value); | |
911 if (%(refname)s_unmarshal(msg->%(name)s_data[off], tmp) == -1) { | |
912 event_warnx("%%s: %(refname)s_unmarshal", __func__); | |
913 goto error; | |
914 } | |
915 evbuffer_free(tmp); | |
916 return (0); | |
917 error: | |
918 if (tmp != NULL) | |
919 evbuffer_free(tmp); | |
920 %(refname)s_clear(msg->%(name)s_data[off]); | |
921 return (-1); | |
922 }""" % self.GetTranslation() | |
923 | |
924 return code.split('\n') | |
925 | |
926 def CodeAdd(self): | |
927 code = \ | |
928 """%(ctype)s | |
929 %(parent_name)s_%(name)s_add(struct %(parent_name)s *msg) | |
930 { | |
931 if (++msg->%(name)s_length >= msg->%(name)s_num_allocated) { | |
932 int tobe_allocated = msg->%(name)s_num_allocated; | |
933 %(ctype)s* new_data = NULL; | |
934 tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1; | |
935 new_data = (%(ctype)s*) realloc(msg->%(name)s_data, | |
936 tobe_allocated * sizeof(%(ctype)s)); | |
937 if (new_data == NULL) | |
938 goto error; | |
939 msg->%(name)s_data = new_data; | |
940 msg->%(name)s_num_allocated = tobe_allocated; | |
941 } | |
942 msg->%(name)s_data[msg->%(name)s_length - 1] = %(refname)s_new(); | |
943 if (msg->%(name)s_data[msg->%(name)s_length - 1] == NULL) | |
944 goto error; | |
945 msg->%(name)s_set = 1; | |
946 return (msg->%(name)s_data[msg->%(name)s_length - 1]); | |
947 error: | |
948 --msg->%(name)s_length; | |
949 return (NULL); | |
950 } | |
951 """ % self.GetTranslation() | |
952 | |
953 return code.split('\n') | |
954 | |
955 def CodeComplete(self, structname): | |
956 code = [] | |
957 translate = self.GetTranslation() | |
958 | |
959 if self.Optional(): | |
960 code.append( 'if (%(structname)s->%(name)s_set)' % translate) | |
961 | |
962 translate["structname"] = structname | |
963 tmp = """{ | |
964 int i; | |
965 for (i = 0; i < %(structname)s->%(name)s_length; ++i) { | |
966 if (%(refname)s_complete(%(structname)s->%(name)s_data[i]) == -1) | |
967 return (-1); | |
968 } | |
969 }""" % translate | |
970 code.extend(tmp.split('\n')) | |
971 | |
972 return code | |
973 | |
974 def CodeUnmarshal(self, buf, tag_name, var_name): | |
975 translate = self.GetTranslation() | |
976 translate["var_name"] = var_name | |
977 translate["buf"] = buf | |
978 translate["tag_name"] = tag_name | |
979 code = """if (%(parent_name)s_%(name)s_add(%(var_name)s) == NULL) | |
980 return (-1); | |
981 if (evtag_unmarshal_%(refname)s(%(buf)s, %(tag_name)s, | |
982 %(var_name)s->%(name)s_data[%(var_name)s->%(name)s_length - 1]) == -1) { | |
983 --%(var_name)s->%(name)s_length; | |
984 event_warnx("%%s: failed to unmarshal %(name)s", __func__); | |
985 return (-1); | |
986 }""" % translate | |
987 | |
988 return code.split('\n') | |
989 | |
990 def CodeMarshal(self, buf, tag_name, var_name): | |
991 code = ['{', | |
992 ' int i;', | |
993 ' for (i = 0; i < %s->%s_length; ++i) {' % ( | |
994 var_name, self._name), | |
995 ' evtag_marshal_%s(%s, %s, %s->%s_data[i]);' % ( | |
996 self._refname, buf, tag_name, var_name, self._name), | |
997 ' }', | |
998 '}' | |
999 ] | |
1000 return code | |
1001 | |
1002 def CodeClear(self, structname): | |
1003 code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()), | |
1004 ' int i;', | |
1005 ' for (i = 0; i < %s->%s_length; ++i) {' % ( | |
1006 structname, self.Name()), | |
1007 ' %s_free(%s->%s_data[i]);' % ( | |
1008 self._refname, structname, self.Name()), | |
1009 ' }', | |
1010 ' free(%s->%s_data);' % (structname, self.Name()), | |
1011 ' %s->%s_data = NULL;' % (structname, self.Name()), | |
1012 ' %s->%s_set = 0;' % (structname, self.Name()), | |
1013 ' %s->%s_length = 0;' % (structname, self.Name()), | |
1014 ' %s->%s_num_allocated = 0;' % (structname, self.Name()), | |
1015 '}' | |
1016 ] | |
1017 | |
1018 return code | |
1019 | |
1020 def CodeNew(self, name): | |
1021 code = ['%s->%s_data = NULL;' % (name, self._name), | |
1022 '%s->%s_length = 0;' % (name, self._name), | |
1023 '%s->%s_num_allocated = 0;' % (name, self._name)] | |
1024 return code | |
1025 | |
1026 def CodeFree(self, name): | |
1027 code = ['if (%s->%s_data != NULL) {' % (name, self._name), | |
1028 ' int i;', | |
1029 ' for (i = 0; i < %s->%s_length; ++i) {' % ( | |
1030 name, self._name), | |
1031 ' %s_free(%s->%s_data[i]); ' % ( | |
1032 self._refname, name, self._name), | |
1033 ' %s->%s_data[i] = NULL;' % (name, self._name), | |
1034 ' }', | |
1035 ' free(%s->%s_data);' % (name, self._name), | |
1036 ' %s->%s_data = NULL;' % (name, self._name), | |
1037 ' %s->%s_length = 0;' % (name, self._name), | |
1038 ' %s->%s_num_allocated = 0;' % (name, self._name), | |
1039 '}' | |
1040 ] | |
1041 | |
1042 return code | |
1043 | |
1044 def Declaration(self): | |
1045 dcl = ['struct %s **%s_data;' % (self._refname, self._name), | |
1046 'int %s_length;' % self._name, | |
1047 'int %s_num_allocated;' % self._name ] | |
1048 | |
1049 return dcl | |
1050 | |
1051 def NormalizeLine(line): | |
1052 global white | |
1053 global cppcomment | |
1054 | |
1055 line = cppcomment.sub('', line) | |
1056 line = line.strip() | |
1057 line = white.sub(' ', line) | |
1058 | |
1059 return line | |
1060 | |
1061 def ProcessOneEntry(newstruct, entry): | |
1062 optional = 0 | |
1063 array = 0 | |
1064 entry_type = '' | |
1065 name = '' | |
1066 tag = '' | |
1067 tag_set = None | |
1068 separator = '' | |
1069 fixed_length = '' | |
1070 | |
1071 tokens = entry.split(' ') | |
1072 while tokens: | |
1073 token = tokens[0] | |
1074 tokens = tokens[1:] | |
1075 | |
1076 if not entry_type: | |
1077 if not optional and token == 'optional': | |
1078 optional = 1 | |
1079 continue | |
1080 | |
1081 if not array and token == 'array': | |
1082 array = 1 | |
1083 continue | |
1084 | |
1085 if not entry_type: | |
1086 entry_type = token | |
1087 continue | |
1088 | |
1089 if not name: | |
1090 res = re.match(r'^([^\[\]]+)(\[.*\])?$', token) | |
1091 if not res: | |
1092 print >>sys.stderr, 'Cannot parse name: \"%s\" around %d' % ( | |
1093 entry, line_count) | |
1094 sys.exit(1) | |
1095 name = res.group(1) | |
1096 fixed_length = res.group(2) | |
1097 if fixed_length: | |
1098 fixed_length = fixed_length[1:-1] | |
1099 continue | |
1100 | |
1101 if not separator: | |
1102 separator = token | |
1103 if separator != '=': | |
1104 print >>sys.stderr, 'Expected "=" after name \"%s\" got %s' % ( | |
1105 name, token) | |
1106 sys.exit(1) | |
1107 continue | |
1108 | |
1109 if not tag_set: | |
1110 tag_set = 1 | |
1111 if not re.match(r'^(0x)?[0-9]+$', token): | |
1112 print >>sys.stderr, 'Expected tag number: \"%s\"' % entry | |
1113 sys.exit(1) | |
1114 tag = int(token, 0) | |
1115 continue | |
1116 | |
1117 print >>sys.stderr, 'Cannot parse \"%s\"' % entry | |
1118 sys.exit(1) | |
1119 | |
1120 if not tag_set: | |
1121 print >>sys.stderr, 'Need tag number: \"%s\"' % entry | |
1122 sys.exit(1) | |
1123 | |
1124 # Create the right entry | |
1125 if entry_type == 'bytes': | |
1126 if fixed_length: | |
1127 newentry = EntryBytes(entry_type, name, tag, fixed_length) | |
1128 else: | |
1129 newentry = EntryVarBytes(entry_type, name, tag) | |
1130 elif entry_type == 'int' and not fixed_length: | |
1131 newentry = EntryInt(entry_type, name, tag) | |
1132 elif entry_type == 'string' and not fixed_length: | |
1133 newentry = EntryString(entry_type, name, tag) | |
1134 else: | |
1135 res = re.match(r'^struct\[(%s)\]$' % _STRUCT_RE, | |
1136 entry_type, re.IGNORECASE) | |
1137 if res: | |
1138 # References another struct defined in our file | |
1139 newentry = EntryStruct(entry_type, name, tag, res.group(1)) | |
1140 else: | |
1141 print >>sys.stderr, 'Bad type: "%s" in "%s"' % (entry_type, entry) | |
1142 sys.exit(1) | |
1143 | |
1144 structs = [] | |
1145 | |
1146 if optional: | |
1147 newentry.MakeOptional() | |
1148 if array: | |
1149 newentry.MakeArray() | |
1150 | |
1151 newentry.SetStruct(newstruct) | |
1152 newentry.SetLineCount(line_count) | |
1153 newentry.Verify() | |
1154 | |
1155 if array: | |
1156 # We need to encapsulate this entry into a struct | |
1157 newname = newentry.Name()+ '_array' | |
1158 | |
1159 # Now borgify the new entry. | |
1160 newentry = EntryArray(newentry) | |
1161 newentry.SetStruct(newstruct) | |
1162 newentry.SetLineCount(line_count) | |
1163 newentry.MakeArray() | |
1164 | |
1165 newstruct.AddEntry(newentry) | |
1166 | |
1167 return structs | |
1168 | |
1169 def ProcessStruct(data): | |
1170 tokens = data.split(' ') | |
1171 | |
1172 # First three tokens are: 'struct' 'name' '{' | |
1173 newstruct = Struct(tokens[1]) | |
1174 | |
1175 inside = ' '.join(tokens[3:-1]) | |
1176 | |
1177 tokens = inside.split(';') | |
1178 | |
1179 structs = [] | |
1180 | |
1181 for entry in tokens: | |
1182 entry = NormalizeLine(entry) | |
1183 if not entry: | |
1184 continue | |
1185 | |
1186 # It's possible that new structs get defined in here | |
1187 structs.extend(ProcessOneEntry(newstruct, entry)) | |
1188 | |
1189 structs.append(newstruct) | |
1190 return structs | |
1191 | |
1192 def GetNextStruct(file): | |
1193 global line_count | |
1194 global cppdirect | |
1195 | |
1196 got_struct = 0 | |
1197 | |
1198 processed_lines = [] | |
1199 | |
1200 have_c_comment = 0 | |
1201 data = '' | |
1202 while 1: | |
1203 line = file.readline() | |
1204 if not line: | |
1205 break | |
1206 | |
1207 line_count += 1 | |
1208 line = line[:-1] | |
1209 | |
1210 if not have_c_comment and re.search(r'/\*', line): | |
1211 if re.search(r'/\*.*\*/', line): | |
1212 line = re.sub(r'/\*.*\*/', '', line) | |
1213 else: | |
1214 line = re.sub(r'/\*.*$', '', line) | |
1215 have_c_comment = 1 | |
1216 | |
1217 if have_c_comment: | |
1218 if not re.search(r'\*/', line): | |
1219 continue | |
1220 have_c_comment = 0 | |
1221 line = re.sub(r'^.*\*/', '', line) | |
1222 | |
1223 line = NormalizeLine(line) | |
1224 | |
1225 if not line: | |
1226 continue | |
1227 | |
1228 if not got_struct: | |
1229 if re.match(r'#include ["<].*[>"]', line): | |
1230 cppdirect.append(line) | |
1231 continue | |
1232 | |
1233 if re.match(r'^#(if( |def)|endif)', line): | |
1234 cppdirect.append(line) | |
1235 continue | |
1236 | |
1237 if re.match(r'^#define', line): | |
1238 headerdirect.append(line) | |
1239 continue | |
1240 | |
1241 if not re.match(r'^struct %s {$' % _STRUCT_RE, | |
1242 line, re.IGNORECASE): | |
1243 print >>sys.stderr, 'Missing struct on line %d: %s' % ( | |
1244 line_count, line) | |
1245 sys.exit(1) | |
1246 else: | |
1247 got_struct = 1 | |
1248 data += line | |
1249 continue | |
1250 | |
1251 # We are inside the struct | |
1252 tokens = line.split('}') | |
1253 if len(tokens) == 1: | |
1254 data += ' ' + line | |
1255 continue | |
1256 | |
1257 if len(tokens[1]): | |
1258 print >>sys.stderr, 'Trailing garbage after struct on line %d' % ( | |
1259 line_count ) | |
1260 sys.exit(1) | |
1261 | |
1262 # We found the end of the struct | |
1263 data += ' %s}' % tokens[0] | |
1264 break | |
1265 | |
1266 # Remove any comments, that might be in there | |
1267 data = re.sub(r'/\*.*\*/', '', data) | |
1268 | |
1269 return data | |
1270 | |
1271 | |
1272 def Parse(file): | |
1273 """ | |
1274 Parses the input file and returns C code and corresponding header file. | |
1275 """ | |
1276 | |
1277 entities = [] | |
1278 | |
1279 while 1: | |
1280 # Just gets the whole struct nicely formatted | |
1281 data = GetNextStruct(file) | |
1282 | |
1283 if not data: | |
1284 break | |
1285 | |
1286 entities.extend(ProcessStruct(data)) | |
1287 | |
1288 return entities | |
1289 | |
1290 def GuardName(name): | |
1291 name = '_'.join(name.split('.')) | |
1292 name = '_'.join(name.split('/')) | |
1293 guard = '_'+name.upper()+'_' | |
1294 | |
1295 return guard | |
1296 | |
1297 def HeaderPreamble(name): | |
1298 guard = GuardName(name) | |
1299 pre = ( | |
1300 '/*\n' | |
1301 ' * Automatically generated from %s\n' | |
1302 ' */\n\n' | |
1303 '#ifndef %s\n' | |
1304 '#define %s\n\n' ) % ( | |
1305 name, guard, guard) | |
1306 | |
1307 # insert stdint.h - let's hope everyone has it | |
1308 pre += ( | |
1309 '#include <event-config.h>\n' | |
1310 '#ifdef _EVENT_HAVE_STDINT_H\n' | |
1311 '#include <stdint.h>\n' | |
1312 '#endif\n' ) | |
1313 | |
1314 for statement in headerdirect: | |
1315 pre += '%s\n' % statement | |
1316 if headerdirect: | |
1317 pre += '\n' | |
1318 | |
1319 pre += ( | |
1320 '#define EVTAG_HAS(msg, member) ((msg)->member##_set == 1)\n' | |
1321 '#ifdef __GNUC__\n' | |
1322 '#define EVTAG_ASSIGN(msg, member, args...) ' | |
1323 '(*(msg)->base->member##_assign)(msg, ## args)\n' | |
1324 '#define EVTAG_GET(msg, member, args...) ' | |
1325 '(*(msg)->base->member##_get)(msg, ## args)\n' | |
1326 '#else\n' | |
1327 '#define EVTAG_ASSIGN(msg, member, ...) ' | |
1328 '(*(msg)->base->member##_assign)(msg, ## __VA_ARGS__)\n' | |
1329 '#define EVTAG_GET(msg, member, ...) ' | |
1330 '(*(msg)->base->member##_get)(msg, ## __VA_ARGS__)\n' | |
1331 '#endif\n' | |
1332 '#define EVTAG_ADD(msg, member) (*(msg)->base->member##_add)(msg)\n' | |
1333 '#define EVTAG_LEN(msg, member) ((msg)->member##_length)\n' | |
1334 ) | |
1335 | |
1336 return pre | |
1337 | |
1338 | |
1339 def HeaderPostamble(name): | |
1340 guard = GuardName(name) | |
1341 return '#endif /* %s */' % guard | |
1342 | |
1343 def BodyPreamble(name): | |
1344 global _NAME | |
1345 global _VERSION | |
1346 | |
1347 header_file = '.'.join(name.split('.')[:-1]) + '.gen.h' | |
1348 | |
1349 pre = ( '/*\n' | |
1350 ' * Automatically generated from %s\n' | |
1351 ' * by %s/%s. DO NOT EDIT THIS FILE.\n' | |
1352 ' */\n\n' ) % (name, _NAME, _VERSION) | |
1353 pre += ( '#include <sys/types.h>\n' | |
1354 '#ifdef _EVENT_HAVE_SYS_TIME_H\n' | |
1355 '#include <sys/time.h>\n' | |
1356 '#endif\n' | |
1357 '#include <stdlib.h>\n' | |
1358 '#include <string.h>\n' | |
1359 '#include <assert.h>\n' | |
1360 '#define EVENT_NO_STRUCT\n' | |
1361 '#include <event.h>\n\n' | |
1362 '#ifdef _EVENT___func__\n' | |
1363 '#define __func__ _EVENT___func__\n' | |
1364 '#endif\n' ) | |
1365 | |
1366 for statement in cppdirect: | |
1367 pre += '%s\n' % statement | |
1368 | |
1369 pre += '\n#include "%s"\n\n' % header_file | |
1370 | |
1371 pre += 'void event_err(int eval, const char *fmt, ...);\n' | |
1372 pre += 'void event_warn(const char *fmt, ...);\n' | |
1373 pre += 'void event_errx(int eval, const char *fmt, ...);\n' | |
1374 pre += 'void event_warnx(const char *fmt, ...);\n\n' | |
1375 | |
1376 return pre | |
1377 | |
1378 def main(argv): | |
1379 if len(argv) < 2 or not argv[1]: | |
1380 print >>sys.stderr, 'Need RPC description file as first argument.' | |
1381 sys.exit(1) | |
1382 | |
1383 filename = argv[1] | |
1384 | |
1385 ext = filename.split('.')[-1] | |
1386 if ext != 'rpc': | |
1387 print >>sys.stderr, 'Unrecognized file extension: %s' % ext | |
1388 sys.exit(1) | |
1389 | |
1390 print >>sys.stderr, 'Reading \"%s\"' % filename | |
1391 | |
1392 fp = open(filename, 'r') | |
1393 entities = Parse(fp) | |
1394 fp.close() | |
1395 | |
1396 header_file = '.'.join(filename.split('.')[:-1]) + '.gen.h' | |
1397 impl_file = '.'.join(filename.split('.')[:-1]) + '.gen.c' | |
1398 | |
1399 print >>sys.stderr, '... creating "%s"' % header_file | |
1400 header_fp = open(header_file, 'w') | |
1401 print >>header_fp, HeaderPreamble(filename) | |
1402 | |
1403 # Create forward declarations: allows other structs to reference | |
1404 # each other | |
1405 for entry in entities: | |
1406 entry.PrintForwardDeclaration(header_fp) | |
1407 print >>header_fp, '' | |
1408 | |
1409 for entry in entities: | |
1410 entry.PrintTags(header_fp) | |
1411 entry.PrintDeclaration(header_fp) | |
1412 print >>header_fp, HeaderPostamble(filename) | |
1413 header_fp.close() | |
1414 | |
1415 print >>sys.stderr, '... creating "%s"' % impl_file | |
1416 impl_fp = open(impl_file, 'w') | |
1417 print >>impl_fp, BodyPreamble(filename) | |
1418 for entry in entities: | |
1419 entry.PrintCode(impl_fp) | |
1420 impl_fp.close() | |
1421 | |
1422 if __name__ == '__main__': | |
1423 main(sys.argv) | |
OLD | NEW |