Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'dump-struct' into docs-mw

In my ongoing effort to truly understand our new kernel-doc, I continue to
make changes to improve the code, and to try to make the understanding task
easier for the next person. These patches focus on dump_struct() in
particular, which starts out at nearly 300 lines long - to much to fit into
my little brain anyway. Hopefully the result is easier to manage.

There are no changes in the rendered docs.

+258 -241
+258 -241
scripts/lib/kdoc/kdoc_parser.py
··· 46 46 known_section_names = 'description|context|returns?|notes?|examples?' 47 47 known_sections = KernRe(known_section_names, flags = re.I) 48 48 doc_sect = doc_com + \ 49 - KernRe(r'\s*(\@[.\w]+|\@\.\.\.|' + known_section_names + r')\s*:([^:].*)?$', 49 + KernRe(r'\s*(@[.\w]+|@\.\.\.|' + known_section_names + r')\s*:([^:].*)?$', 50 50 flags=re.I, cache=False) 51 51 52 52 doc_content = doc_com_body + KernRe(r'(.*)', cache=False) ··· 54 54 doc_inline_sect = KernRe(r'\s*\*\s*(@\s*[\w][\w\.]*\s*):(.*)', cache=False) 55 55 doc_inline_end = KernRe(r'^\s*\*/\s*$', cache=False) 56 56 doc_inline_oneline = KernRe(r'^\s*/\*\*\s*(@[\w\s]+):\s*(.*)\s*\*/\s*$', cache=False) 57 - attribute = KernRe(r"__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)", 58 - flags=re.I | re.S, cache=False) 59 57 60 58 export_symbol = KernRe(r'^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*', cache=False) 61 59 export_symbol_ns = KernRe(r'^\s*EXPORT_SYMBOL_NS(_GPL)?\s*\(\s*(\w+)\s*,\s*"\S+"\)\s*', cache=False) 62 60 63 - type_param = KernRe(r"\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False) 61 + type_param = KernRe(r"@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False) 64 62 65 63 # 66 64 # Tests for the beginning of a kerneldoc block in its various forms. ··· 73 75 cache = False) 74 76 75 77 # 78 + # Here begins a long set of transformations to turn structure member prefixes 79 + # and macro invocations into something we can parse and generate kdoc for. 80 + # 81 + struct_attribute = KernRe(r"__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)", 82 + flags=re.I | re.S, cache=False) 83 + struct_args_pattern = r'([^,)]+)' 84 + 85 + struct_prefixes = [ 86 + # Strip attributes 87 + (struct_attribute, ' '), 88 + (KernRe(r'\s*__aligned\s*\([^;]*\)', re.S), ' '), 89 + (KernRe(r'\s*__counted_by\s*\([^;]*\)', re.S), ' '), 90 + (KernRe(r'\s*__counted_by_(le|be)\s*\([^;]*\)', re.S), ' '), 91 + (KernRe(r'\s*__packed\s*', re.S), ' '), 92 + (KernRe(r'\s*CRYPTO_MINALIGN_ATTR', re.S), ' '), 93 + (KernRe(r'\s*____cacheline_aligned_in_smp', re.S), ' '), 94 + (KernRe(r'\s*____cacheline_aligned', re.S), ' '), 95 + # 96 + # Unwrap struct_group macros based on this definition: 97 + # __struct_group(TAG, NAME, ATTRS, MEMBERS...) 98 + # which has variants like: struct_group(NAME, MEMBERS...) 99 + # Only MEMBERS arguments require documentation. 100 + # 101 + # Parsing them happens on two steps: 102 + # 103 + # 1. drop struct group arguments that aren't at MEMBERS, 104 + # storing them as STRUCT_GROUP(MEMBERS) 105 + # 106 + # 2. remove STRUCT_GROUP() ancillary macro. 107 + # 108 + # The original logic used to remove STRUCT_GROUP() using an 109 + # advanced regex: 110 + # 111 + # \bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*; 112 + # 113 + # with two patterns that are incompatible with 114 + # Python re module, as it has: 115 + # 116 + # - a recursive pattern: (?1) 117 + # - an atomic grouping: (?>...) 118 + # 119 + # I tried a simpler version: but it didn't work either: 120 + # \bSTRUCT_GROUP\(([^\)]+)\)[^;]*; 121 + # 122 + # As it doesn't properly match the end parenthesis on some cases. 123 + # 124 + # So, a better solution was crafted: there's now a NestedMatch 125 + # class that ensures that delimiters after a search are properly 126 + # matched. So, the implementation to drop STRUCT_GROUP() will be 127 + # handled in separate. 128 + # 129 + (KernRe(r'\bstruct_group\s*\(([^,]*,)', re.S), r'STRUCT_GROUP('), 130 + (KernRe(r'\bstruct_group_attr\s*\(([^,]*,){2}', re.S), r'STRUCT_GROUP('), 131 + (KernRe(r'\bstruct_group_tagged\s*\(([^,]*),([^,]*),', re.S), r'struct \1 \2; STRUCT_GROUP('), 132 + (KernRe(r'\b__struct_group\s*\(([^,]*,){3}', re.S), r'STRUCT_GROUP('), 133 + # 134 + # Replace macros 135 + # 136 + # TODO: use NestedMatch for FOO($1, $2, ...) matches 137 + # 138 + # it is better to also move those to the NestedMatch logic, 139 + # to ensure that parenthesis will be properly matched. 140 + # 141 + (KernRe(r'__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)', re.S), 142 + r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'), 143 + (KernRe(r'DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)', re.S), 144 + r'DECLARE_BITMAP(\1, PHY_INTERFACE_MODE_MAX)'), 145 + (KernRe(r'DECLARE_BITMAP\s*\(' + struct_args_pattern + r',\s*' + struct_args_pattern + r'\)', 146 + re.S), r'unsigned long \1[BITS_TO_LONGS(\2)]'), 147 + (KernRe(r'DECLARE_HASHTABLE\s*\(' + struct_args_pattern + r',\s*' + struct_args_pattern + r'\)', 148 + re.S), r'unsigned long \1[1 << ((\2) - 1)]'), 149 + (KernRe(r'DECLARE_KFIFO\s*\(' + struct_args_pattern + r',\s*' + struct_args_pattern + 150 + r',\s*' + struct_args_pattern + r'\)', re.S), r'\2 *\1'), 151 + (KernRe(r'DECLARE_KFIFO_PTR\s*\(' + struct_args_pattern + r',\s*' + 152 + struct_args_pattern + r'\)', re.S), r'\2 *\1'), 153 + (KernRe(r'(?:__)?DECLARE_FLEX_ARRAY\s*\(' + struct_args_pattern + r',\s*' + 154 + struct_args_pattern + r'\)', re.S), r'\1 \2[]'), 155 + (KernRe(r'DEFINE_DMA_UNMAP_ADDR\s*\(' + struct_args_pattern + r'\)', re.S), r'dma_addr_t \1'), 156 + (KernRe(r'DEFINE_DMA_UNMAP_LEN\s*\(' + struct_args_pattern + r'\)', re.S), r'__u32 \1'), 157 + ] 158 + # 159 + # Regexes here are guaranteed to have the end limiter matching 160 + # the start delimiter. Yet, right now, only one replace group 161 + # is allowed. 162 + # 163 + struct_nested_prefixes = [ 164 + (re.compile(r'\bSTRUCT_GROUP\('), r'\1'), 165 + ] 166 + 167 + 168 + # 76 169 # A little helper to get rid of excess white space 77 170 # 78 171 multi_space = KernRe(r'\s\s+') 79 172 def trim_whitespace(s): 80 173 return multi_space.sub(' ', s.strip()) 174 + 175 + # 176 + # Remove struct/enum members that have been marked "private". 177 + # 178 + def trim_private_members(text): 179 + # 180 + # First look for a "public:" block that ends a private region, then 181 + # handle the "private until the end" case. 182 + # 183 + text = KernRe(r'/\*\s*private:.*?/\*\s*public:.*?\*/', flags=re.S).sub('', text) 184 + text = KernRe(r'/\*\s*private:.*', flags=re.S).sub('', text) 185 + # 186 + # We needed the comments to do the above, but now we can take them out. 187 + # 188 + return KernRe(r'\s*/\*.*?\*/\s*', flags=re.S).sub('', text).strip() 81 189 82 190 class state: 83 191 """ ··· 494 390 495 391 for arg in args.split(splitter): 496 392 # Strip comments 497 - arg = KernRe(r'\/\*.*\*\/').sub('', arg) 393 + arg = KernRe(r'/\*.*\*/').sub('', arg) 498 394 499 395 # Ignore argument attributes 500 396 arg = KernRe(r'\sPOS0?\s').sub(' ', arg) ··· 517 413 518 414 arg = arg.replace('#', ',') 519 415 520 - r = KernRe(r'[^\(]+\(\*?\s*([\w\[\]\.]*)\s*\)') 416 + r = KernRe(r'[^\(]+\(\*?\s*([\w\[\].]*)\s*\)') 521 417 if r.match(arg): 522 418 param = r.group(1) 523 419 else: ··· 532 428 # Array-of-pointers 533 429 534 430 arg = arg.replace('#', ',') 535 - r = KernRe(r'[^\(]+\(\s*\*\s*([\w\[\]\.]*?)\s*(\s*\[\s*[\w]+\s*\]\s*)*\)') 431 + r = KernRe(r'[^\(]+\(\s*\*\s*([\w\[\].]*?)\s*(\s*\[\s*[\w]+\s*\]\s*)*\)') 536 432 if r.match(arg): 537 433 param = r.group(1) 538 434 else: ··· 624 520 self.emit_msg(ln, 625 521 f"No description found for return value of '{declaration_name}'") 626 522 627 - def dump_struct(self, ln, proto): 628 - """ 629 - Store an entry for an struct or union 630 - """ 631 - 523 + # 524 + # Split apart a structure prototype; returns (struct|union, name, members) or None 525 + # 526 + def split_struct_proto(self, proto): 632 527 type_pattern = r'(struct|union)' 633 - 634 528 qualifiers = [ 635 529 "__attribute__", 636 530 "__packed", ··· 636 534 "____cacheline_aligned_in_smp", 637 535 "____cacheline_aligned", 638 536 ] 639 - 640 537 definition_body = r'\{(.*)\}\s*' + "(?:" + '|'.join(qualifiers) + ")?" 641 - struct_members = KernRe(type_pattern + r'([^\{\};]+)(\{)([^\{\}]*)(\})([^\{\}\;]*)(\;)') 642 - 643 - # Extract struct/union definition 644 - members = None 645 - declaration_name = None 646 - decl_type = None 647 538 648 539 r = KernRe(type_pattern + r'\s+(\w+)\s*' + definition_body) 649 540 if r.search(proto): 650 - decl_type = r.group(1) 651 - declaration_name = r.group(2) 652 - members = r.group(3) 541 + return (r.group(1), r.group(2), r.group(3)) 653 542 else: 654 543 r = KernRe(r'typedef\s+' + type_pattern + r'\s*' + definition_body + r'\s*(\w+)\s*;') 655 - 656 544 if r.search(proto): 657 - decl_type = r.group(1) 658 - declaration_name = r.group(3) 659 - members = r.group(2) 660 - 661 - if not members: 662 - self.emit_msg(ln, f"{proto} error: Cannot parse struct or union!") 663 - return 664 - 665 - if self.entry.identifier != declaration_name: 666 - self.emit_msg(ln, 667 - f"expecting prototype for {decl_type} {self.entry.identifier}. Prototype was for {decl_type} {declaration_name} instead\n") 668 - return 669 - 670 - args_pattern = r'([^,)]+)' 671 - 672 - sub_prefixes = [ 673 - (KernRe(r'\/\*\s*private:.*?\/\*\s*public:.*?\*\/', re.S | re.I), ''), 674 - (KernRe(r'\/\*\s*private:.*', re.S | re.I), ''), 675 - 676 - # Strip comments 677 - (KernRe(r'\/\*.*?\*\/', re.S), ''), 678 - 679 - # Strip attributes 680 - (attribute, ' '), 681 - (KernRe(r'\s*__aligned\s*\([^;]*\)', re.S), ' '), 682 - (KernRe(r'\s*__counted_by\s*\([^;]*\)', re.S), ' '), 683 - (KernRe(r'\s*__counted_by_(le|be)\s*\([^;]*\)', re.S), ' '), 684 - (KernRe(r'\s*__packed\s*', re.S), ' '), 685 - (KernRe(r'\s*CRYPTO_MINALIGN_ATTR', re.S), ' '), 686 - (KernRe(r'\s*____cacheline_aligned_in_smp', re.S), ' '), 687 - (KernRe(r'\s*____cacheline_aligned', re.S), ' '), 688 - 689 - # Unwrap struct_group macros based on this definition: 690 - # __struct_group(TAG, NAME, ATTRS, MEMBERS...) 691 - # which has variants like: struct_group(NAME, MEMBERS...) 692 - # Only MEMBERS arguments require documentation. 693 - # 694 - # Parsing them happens on two steps: 695 - # 696 - # 1. drop struct group arguments that aren't at MEMBERS, 697 - # storing them as STRUCT_GROUP(MEMBERS) 698 - # 699 - # 2. remove STRUCT_GROUP() ancillary macro. 700 - # 701 - # The original logic used to remove STRUCT_GROUP() using an 702 - # advanced regex: 703 - # 704 - # \bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*; 705 - # 706 - # with two patterns that are incompatible with 707 - # Python re module, as it has: 708 - # 709 - # - a recursive pattern: (?1) 710 - # - an atomic grouping: (?>...) 711 - # 712 - # I tried a simpler version: but it didn't work either: 713 - # \bSTRUCT_GROUP\(([^\)]+)\)[^;]*; 714 - # 715 - # As it doesn't properly match the end parenthesis on some cases. 716 - # 717 - # So, a better solution was crafted: there's now a NestedMatch 718 - # class that ensures that delimiters after a search are properly 719 - # matched. So, the implementation to drop STRUCT_GROUP() will be 720 - # handled in separate. 721 - 722 - (KernRe(r'\bstruct_group\s*\(([^,]*,)', re.S), r'STRUCT_GROUP('), 723 - (KernRe(r'\bstruct_group_attr\s*\(([^,]*,){2}', re.S), r'STRUCT_GROUP('), 724 - (KernRe(r'\bstruct_group_tagged\s*\(([^,]*),([^,]*),', re.S), r'struct \1 \2; STRUCT_GROUP('), 725 - (KernRe(r'\b__struct_group\s*\(([^,]*,){3}', re.S), r'STRUCT_GROUP('), 726 - 727 - # Replace macros 728 - # 729 - # TODO: use NestedMatch for FOO($1, $2, ...) matches 730 - # 731 - # it is better to also move those to the NestedMatch logic, 732 - # to ensure that parenthesis will be properly matched. 733 - 734 - (KernRe(r'__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'), 735 - (KernRe(r'DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, PHY_INTERFACE_MODE_MAX)'), 736 - (KernRe(r'DECLARE_BITMAP\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[BITS_TO_LONGS(\2)]'), 737 - (KernRe(r'DECLARE_HASHTABLE\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[1 << ((\2) - 1)]'), 738 - (KernRe(r'DECLARE_KFIFO\s*\(' + args_pattern + r',\s*' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\2 *\1'), 739 - (KernRe(r'DECLARE_KFIFO_PTR\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\2 *\1'), 740 - (KernRe(r'(?:__)?DECLARE_FLEX_ARRAY\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\1 \2[]'), 741 - (KernRe(r'DEFINE_DMA_UNMAP_ADDR\s*\(' + args_pattern + r'\)', re.S), r'dma_addr_t \1'), 742 - (KernRe(r'DEFINE_DMA_UNMAP_LEN\s*\(' + args_pattern + r'\)', re.S), r'__u32 \1'), 743 - (KernRe(r'VIRTIO_DECLARE_FEATURES\s*\(' + args_pattern + r'\)', re.S), r'u64 \1; u64 \1_array[VIRTIO_FEATURES_DWORDS]'), 744 - ] 745 - 746 - # Regexes here are guaranteed to have the end limiter matching 747 - # the start delimiter. Yet, right now, only one replace group 748 - # is allowed. 749 - 750 - sub_nested_prefixes = [ 751 - (re.compile(r'\bSTRUCT_GROUP\('), r'\1'), 752 - ] 753 - 754 - for search, sub in sub_prefixes: 755 - members = search.sub(sub, members) 756 - 757 - nested = NestedMatch() 758 - 759 - for search, sub in sub_nested_prefixes: 760 - members = nested.sub(search, sub, members) 761 - 762 - # Keeps the original declaration as-is 763 - declaration = members 764 - 765 - # Split nested struct/union elements 545 + return (r.group(1), r.group(3), r.group(2)) 546 + return None 547 + # 548 + # Rewrite the members of a structure or union for easier formatting later on. 549 + # Among other things, this function will turn a member like: 550 + # 551 + # struct { inner_members; } foo; 552 + # 553 + # into: 554 + # 555 + # struct foo; inner_members; 556 + # 557 + def rewrite_struct_members(self, members): 766 558 # 767 - # This loop was simpler at the original kernel-doc perl version, as 768 - # while ($members =~ m/$struct_members/) { ... } 769 - # reads 'members' string on each interaction. 559 + # Process struct/union members from the most deeply nested outward. The 560 + # trick is in the ^{ below - it prevents a match of an outer struct/union 561 + # until the inner one has been munged (removing the "{" in the process). 770 562 # 771 - # Python behavior is different: it parses 'members' only once, 772 - # creating a list of tuples from the first interaction. 773 - # 774 - # On other words, this won't get nested structs. 775 - # 776 - # So, we need to have an extra loop on Python to override such 777 - # re limitation. 778 - 779 - while True: 780 - tuples = struct_members.findall(members) 781 - if not tuples: 782 - break 783 - 563 + struct_members = KernRe(r'(struct|union)' # 0: declaration type 564 + r'([^\{\};]+)' # 1: possible name 565 + r'(\{)' 566 + r'([^\{\}]*)' # 3: Contents of declaration 567 + r'(\})' 568 + r'([^\{\};]*)(;)') # 5: Remaining stuff after declaration 569 + tuples = struct_members.findall(members) 570 + while tuples: 784 571 for t in tuples: 785 572 newmember = "" 786 - maintype = t[0] 787 - s_ids = t[5] 788 - content = t[3] 789 - 790 - oldmember = "".join(t) 791 - 792 - for s_id in s_ids.split(','): 573 + oldmember = "".join(t) # Reconstruct the original formatting 574 + dtype, name, lbr, content, rbr, rest, semi = t 575 + # 576 + # Pass through each field name, normalizing the form and formatting. 577 + # 578 + for s_id in rest.split(','): 793 579 s_id = s_id.strip() 794 - 795 - newmember += f"{maintype} {s_id}; " 580 + newmember += f"{dtype} {s_id}; " 581 + # 582 + # Remove bitfield/array/pointer info, getting the bare name. 583 + # 796 584 s_id = KernRe(r'[:\[].*').sub('', s_id) 797 585 s_id = KernRe(r'^\s*\**(\S+)\s*').sub(r'\1', s_id) 798 - 586 + # 587 + # Pass through the members of this inner structure/union. 588 + # 799 589 for arg in content.split(';'): 800 590 arg = arg.strip() 801 - 802 - if not arg: 803 - continue 804 - 805 - r = KernRe(r'^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)') 591 + # 592 + # Look for (type)(*name)(args) - pointer to function 593 + # 594 + r = KernRe(r'^([^\(]+\(\*?\s*)([\w.]*)(\s*\).*)') 806 595 if r.match(arg): 596 + dtype, name, extra = r.group(1), r.group(2), r.group(3) 807 597 # Pointer-to-function 808 - dtype = r.group(1) 809 - name = r.group(2) 810 - extra = r.group(3) 811 - 812 - if not name: 813 - continue 814 - 815 598 if not s_id: 816 599 # Anonymous struct/union 817 600 newmember += f"{dtype}{name}{extra}; " 818 601 else: 819 602 newmember += f"{dtype}{s_id}.{name}{extra}; " 820 - 603 + # 604 + # Otherwise a non-function member. 605 + # 821 606 else: 822 - arg = arg.strip() 823 - # Handle bitmaps 607 + # 608 + # Remove bitmap and array portions and spaces around commas 609 + # 824 610 arg = KernRe(r':\s*\d+\s*').sub('', arg) 825 - 826 - # Handle arrays 827 611 arg = KernRe(r'\[.*\]').sub('', arg) 828 - 829 - # Handle multiple IDs 830 612 arg = KernRe(r'\s*,\s*').sub(',', arg) 831 - 613 + # 614 + # Look for a normal decl - "type name[,name...]" 615 + # 832 616 r = KernRe(r'(.*)\s+([\S+,]+)') 833 - 834 617 if r.search(arg): 835 - dtype = r.group(1) 836 - names = r.group(2) 618 + for name in r.group(2).split(','): 619 + name = KernRe(r'^\s*\**(\S+)\s*').sub(r'\1', name) 620 + if not s_id: 621 + # Anonymous struct/union 622 + newmember += f"{r.group(1)} {name}; " 623 + else: 624 + newmember += f"{r.group(1)} {s_id}.{name}; " 837 625 else: 838 626 newmember += f"{arg}; " 839 - continue 840 - 841 - for name in names.split(','): 842 - name = KernRe(r'^\s*\**(\S+)\s*').sub(r'\1', name).strip() 843 - 844 - if not name: 845 - continue 846 - 847 - if not s_id: 848 - # Anonymous struct/union 849 - newmember += f"{dtype} {name}; " 850 - else: 851 - newmember += f"{dtype} {s_id}.{name}; " 852 - 627 + # 628 + # At the end of the s_id loop, replace the original declaration with 629 + # the munged version. 630 + # 853 631 members = members.replace(oldmember, newmember) 632 + # 633 + # End of the tuple loop - search again and see if there are outer members 634 + # that now turn up. 635 + # 636 + tuples = struct_members.findall(members) 637 + return members 854 638 855 - # Ignore other nested elements, like enums 856 - members = re.sub(r'(\{[^\{\}]*\})', '', members) 857 - 858 - self.create_parameter_list(ln, decl_type, members, ';', 859 - declaration_name) 860 - self.check_sections(ln, declaration_name, decl_type) 861 - 862 - # Adjust declaration for better display 639 + # 640 + # Format the struct declaration into a standard form for inclusion in the 641 + # resulting docs. 642 + # 643 + def format_struct_decl(self, declaration): 644 + # 645 + # Insert newlines, get rid of extra spaces. 646 + # 863 647 declaration = KernRe(r'([\{;])').sub(r'\1\n', declaration) 864 648 declaration = KernRe(r'\}\s+;').sub('};', declaration) 865 - 866 - # Better handle inlined enums 867 - while True: 868 - r = KernRe(r'(enum\s+\{[^\}]+),([^\n])') 869 - if not r.search(declaration): 870 - break 871 - 649 + # 650 + # Format inline enums with each member on its own line. 651 + # 652 + r = KernRe(r'(enum\s+\{[^\}]+),([^\n])') 653 + while r.search(declaration): 872 654 declaration = r.sub(r'\1,\n\2', declaration) 873 - 655 + # 656 + # Now go through and supply the right number of tabs 657 + # for each line. 658 + # 874 659 def_args = declaration.split('\n') 875 660 level = 1 876 661 declaration = "" 877 662 for clause in def_args: 663 + clause = KernRe(r'\s+').sub(' ', clause.strip(), count=1) 664 + if clause: 665 + if '}' in clause and level > 1: 666 + level -= 1 667 + if not clause.startswith('#'): 668 + declaration += "\t" * level 669 + declaration += "\t" + clause + "\n" 670 + if "{" in clause and "}" not in clause: 671 + level += 1 672 + return declaration 878 673 879 - clause = clause.strip() 880 - clause = KernRe(r'\s+').sub(' ', clause, count=1) 881 674 882 - if not clause: 883 - continue 675 + def dump_struct(self, ln, proto): 676 + """ 677 + Store an entry for an struct or union 678 + """ 679 + # 680 + # Do the basic parse to get the pieces of the declaration. 681 + # 682 + struct_parts = self.split_struct_proto(proto) 683 + if not struct_parts: 684 + self.emit_msg(ln, f"{proto} error: Cannot parse struct or union!") 685 + return 686 + decl_type, declaration_name, members = struct_parts 884 687 885 - if '}' in clause and level > 1: 886 - level -= 1 688 + if self.entry.identifier != declaration_name: 689 + self.emit_msg(ln, f"expecting prototype for {decl_type} {self.entry.identifier}. " 690 + f"Prototype was for {decl_type} {declaration_name} instead\n") 691 + return 692 + # 693 + # Go through the list of members applying all of our transformations. 694 + # 695 + members = trim_private_members(members) 696 + for search, sub in struct_prefixes: 697 + members = search.sub(sub, members) 887 698 888 - if not KernRe(r'^\s*#').match(clause): 889 - declaration += "\t" * level 890 - 891 - declaration += "\t" + clause + "\n" 892 - if "{" in clause and "}" not in clause: 893 - level += 1 894 - 699 + nested = NestedMatch() 700 + for search, sub in struct_nested_prefixes: 701 + members = nested.sub(search, sub, members) 702 + # 703 + # Deal with embedded struct and union members, and drop enums entirely. 704 + # 705 + declaration = members 706 + members = self.rewrite_struct_members(members) 707 + members = re.sub(r'(\{[^\{\}]*\})', '', members) 708 + # 709 + # Output the result and we are done. 710 + # 711 + self.create_parameter_list(ln, decl_type, members, ';', 712 + declaration_name) 713 + self.check_sections(ln, declaration_name, decl_type) 895 714 self.output_declaration(decl_type, declaration_name, 896 - definition=declaration, 715 + definition=self.format_struct_decl(declaration), 897 716 purpose=self.entry.declaration_purpose) 898 717 899 718 def dump_enum(self, ln, proto): 900 719 """ 901 720 Stores an enum inside self.entries array. 902 721 """ 903 - 904 - # Ignore members marked private 905 - proto = KernRe(r'\/\*\s*private:.*?\/\*\s*public:.*?\*\/', flags=re.S).sub('', proto) 906 - proto = KernRe(r'\/\*\s*private:.*}', flags=re.S).sub('}', proto) 907 - 908 - # Strip comments 909 - proto = KernRe(r'\/\*.*?\*\/', flags=re.S).sub('', proto) 910 - 911 - # Strip #define macros inside enums 722 + # 723 + # Strip preprocessor directives. Note that this depends on the 724 + # trailing semicolon we added in process_proto_type(). 725 + # 912 726 proto = KernRe(r'#\s*((define|ifdef|if)\s+|endif)[^;]*;', flags=re.S).sub('', proto) 913 - 914 727 # 915 728 # Parse out the name and members of the enum. Typedef form first. 916 729 # 917 730 r = KernRe(r'typedef\s+enum\s*\{(.*)\}\s*(\w*)\s*;') 918 731 if r.search(proto): 919 732 declaration_name = r.group(2) 920 - members = r.group(1).rstrip() 733 + members = trim_private_members(r.group(1)) 921 734 # 922 735 # Failing that, look for a straight enum 923 736 # ··· 840 823 r = KernRe(r'enum\s+(\w*)\s*\{(.*)\}') 841 824 if r.match(proto): 842 825 declaration_name = r.group(1) 843 - members = r.group(2).rstrip() 826 + members = trim_private_members(r.group(2)) 844 827 # 845 828 # OK, this isn't going to work. 846 829 # ··· 1058 1041 Stores a typedef inside self.entries array. 1059 1042 """ 1060 1043 1061 - typedef_type = r'((?:\s+[\w\*]+\b){0,7}\s+(?:\w+\b|\*+))\s*' 1044 + typedef_type = r'((?:\s+[\w*]+\b){0,7}\s+(?:\w+\b|\*+))\s*' 1062 1045 typedef_ident = r'\*?\s*(\w\S+)\s*' 1063 1046 typedef_args = r'\s*\((.*)\);' 1064 1047 ··· 1279 1262 self.dump_section() 1280 1263 1281 1264 # Look for doc_com + <text> + doc_end: 1282 - r = KernRe(r'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') 1265 + r = KernRe(r'\s*\*\s*[a-zA-Z_0-9:.]+\*/') 1283 1266 if r.match(line): 1284 1267 self.emit_msg(ln, f"suspicious ending line: {line}") 1285 1268 ··· 1490 1473 """Ancillary routine to process a function prototype""" 1491 1474 1492 1475 # strip C99-style comments to end of line 1493 - line = KernRe(r"\/\/.*$", re.S).sub('', line) 1476 + line = KernRe(r"//.*$", re.S).sub('', line) 1494 1477 # 1495 1478 # Soak up the line's worth of prototype text, stopping at { or ; if present. 1496 1479 #