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