| 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 |