[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # |
| 3 | # Copyright (c) 2005 Niels Provos <[email protected]> |
| 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: |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 90 | print >>file, ' ev_uint8_t %s_set;' % entry.Name() |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 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 *); |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 100 | void evtag_marshal_%(name)s(struct evbuffer *, ev_uint32_t, |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 101 | const struct %(name)s *); |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 102 | int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t, |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 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' |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 212 | ' ev_uint32_t tag;\n' |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 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, ' |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 263 | 'ev_uint32_t need_tag, struct %(name)s *msg)\n' |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 264 | '{\n' |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 265 | ' ev_uint32_t tag;\n' |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 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' |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 287 | 'evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag, ' |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 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 |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 449 | self._ctype = 'ev_uint8_t' |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 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): |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 462 | dcl = ['ev_uint8_t %s_data[%s];' % (self._name, self._length)] |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 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 | |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 536 | self._ctype = 'ev_uint32_t' |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 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): |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 553 | dcl = ['ev_uint32_t %s_data;' % self._name] |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 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 | |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 755 | self._ctype = 'ev_uint8_t *' |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 756 | |
| 757 | def GetDeclaration(self, funcname): |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 758 | code = [ 'int %s(struct %s *, %s *, ev_uint32_t *);' % ( |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 759 | funcname, self._struct.Name(), self._ctype ) ] |
| 760 | return code |
| 761 | |
| 762 | def AssignDeclaration(self, funcname): |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 763 | code = [ 'int %s(struct %s *, const %s, ev_uint32_t);' % ( |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 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, ' |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 771 | 'const %s value, ev_uint32_t len)' % ( |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 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', |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 790 | '%s_%s_get(struct %s *msg, %s *value, ev_uint32_t *plen)' % ( |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 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): |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 851 | dcl = ['ev_uint8_t *%s_data;' % self._name, |
| 852 | 'ev_uint32_t %s_length;' % self._name] |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 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' |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 1321 | '#ifdef __GNUC__\n' |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 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' |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 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' |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 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' |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 1354 | '#ifdef _EVENT_HAVE_SYS_TIME_H\n' |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 1355 | '#include <sys/time.h>\n' |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 1356 | '#endif\n' |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 1357 | '#include <stdlib.h>\n' |
| 1358 | '#include <string.h>\n' |
| 1359 | '#include <assert.h>\n' |
[email protected] | 78d4429 | 2009-11-20 20:23:54 | [diff] [blame] | 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' ) |
[email protected] | 0fe41ae | 2008-09-18 00:08:57 | [diff] [blame] | 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) |