So once upon a time I set out to fix the problem reported by Tobin wherein a literal block within a kerneldoc comment would be corrupted in processing. On the way, though, I got annoyed at the way I have to learn how kernel-doc works from the beginning every time I tear into it. As a result, seven of the following eight patches just get rid of some dead code and reorganize the rest - mostly turning the 500-line process_file() function into something a bit more rational. Sphinx output is unchanged after these are applied. Then, at the end, there's a tweak to stop messing with literal blocks. If anybody was unaware that I've not done any serious Perl since the 1990's, they will certainly understand that fact now.
Unified · Split
| @@ -1,4 +1,5 @@ | ||
| 1 | 1 | #!/usr/bin/env perl |
| 2 | +# SPDX-License-Identifier: GPL-2.0 | |
| 2 | 3 | |
| 3 | 4 | use warnings; |
| 4 | 5 | use strict; |
| @@ -328,13 +329,15 @@ my $lineprefix=""; · 323 unmodified lines | ||
| 328 | 329 | use constant { |
| 329 | 330 | STATE_NORMAL => 0, # normal code |
| 330 | 331 | STATE_NAME => 1, # looking for function name |
| 331 | − STATE_FIELD => 2, # scanning field start | |
| 332 | − STATE_PROTO => 3, # scanning prototype | |
| 333 | − STATE_DOCBLOCK => 4, # documentation block | |
| 334 | − STATE_INLINE => 5, # gathering documentation outside main block | |
| 332 | + STATE_BODY_MAYBE => 2, # body - or maybe more description | |
| 333 | + STATE_BODY => 3, # the body of the comment | |
| 334 | + STATE_PROTO => 4, # scanning prototype | |
| 335 | + STATE_DOCBLOCK => 5, # documentation block | |
| 336 | + STATE_INLINE => 6, # gathering documentation outside main block | |
| 335 | 337 | }; |
| 336 | 338 | my $state; |
| 337 | 339 | my $in_doc_sect; |
| 340 | +my $leading_space; | |
| 338 | 341 | |
| 339 | 342 | # Inline documentation state |
| 340 | 343 | use constant { |
| @@ -553,10 +556,9 @@ sub output_highlight { · 212 unmodified lines | ||
| 553 | 556 | } |
| 554 | 557 | if ($line eq ""){ |
| 555 | 558 | if (! $output_preformatted) { |
| 556 | − print $lineprefix, local_unescape($blankline); | |
| 559 | + print $lineprefix, $blankline; | |
| 557 | 560 | } |
| 558 | 561 | } else { |
| 559 | − $line =~ s/\\\\\\/\&/g; | |
| 560 | 562 | if ($output_mode eq "man" && substr($line, 0, 1) eq ".") { |
| 561 | 563 | print "\\&$line"; |
| 562 | 564 | } else { |
| @@ -747,17 +749,73 @@ sub output_blockhead_rst(%) { · 184 unmodified lines | ||
| 747 | 749 | } |
| 748 | 750 | } |
| 749 | 751 | |
| 750 | −sub output_highlight_rst { | |
| 751 | − my $contents = join "\n",@_; | |
| 752 | − my $line; | |
| 753 | − | |
| 754 | − # undo the evil effects of xml_escape() earlier | |
| 755 | − $contents = xml_unescape($contents); | |
| 756 | − | |
| 752 | +# | |
| 753 | +# Apply the RST highlights to a sub-block of text. | |
| 754 | +# | |
| 755 | +sub highlight_block($) { | |
| 756 | + # The dohighlight kludge requires the text be called $contents | |
| 757 | + my $contents = shift; | |
| 757 | 758 | eval $dohighlight; |
| 758 | 759 | die $@ if $@; |
| 760 | + return $contents; | |
| 761 | +} | |
| 759 | 762 | |
| 760 | − foreach $line (split "\n", $contents) { | |
| 763 | +# | |
| 764 | +# Regexes used only here. | |
| 765 | +# | |
| 766 | +my $sphinx_literal = '^[^.].*::$'; | |
| 767 | +my $sphinx_cblock = '^\.\.\ +code-block::'; | |
| 768 | + | |
| 769 | +sub output_highlight_rst { | |
| 770 | + my $input = join "\n",@_; | |
| 771 | + my $output = ""; | |
| 772 | + my $line; | |
| 773 | + my $in_literal = 0; | |
| 774 | + my $litprefix; | |
| 775 | + my $block = ""; | |
| 776 | + | |
| 777 | + foreach $line (split "\n",$input) { | |
| 778 | + # | |
| 779 | + # If we're in a literal block, see if we should drop out | |
| 780 | + # of it. Otherwise pass the line straight through unmunged. | |
| 781 | + # | |
| 782 | + if ($in_literal) { | |
| 783 | + if (! ($line =~ /^\s*$/)) { | |
| 784 | + # | |
| 785 | + # If this is the first non-blank line in a literal | |
| 786 | + # block we need to figure out what the proper indent is. | |
| 787 | + # | |
| 788 | + if ($litprefix eq "") { | |
| 789 | + $line =~ /^(\s*)/; | |
| 790 | + $litprefix = '^' . $1; | |
| 791 | + $output .= $line . "\n"; | |
| 792 | + } elsif (! ($line =~ /$litprefix/)) { | |
| 793 | + $in_literal = 0; | |
| 794 | + } else { | |
| 795 | + $output .= $line . "\n"; | |
| 796 | + } | |
| 797 | + } else { | |
| 798 | + $output .= $line . "\n"; | |
| 799 | + } | |
| 800 | + } | |
| 801 | + # | |
| 802 | + # Not in a literal block (or just dropped out) | |
| 803 | + # | |
| 804 | + if (! $in_literal) { | |
| 805 | + $block .= $line . "\n"; | |
| 806 | + if (($line =~ /$sphinx_literal/) || ($line =~ /$sphinx_cblock/)) { | |
| 807 | + $in_literal = 1; | |
| 808 | + $litprefix = ""; | |
| 809 | + $output .= highlight_block($block); | |
| 810 | + $block = "" | |
| 811 | + } | |
| 812 | + } | |
| 813 | + } | |
| 814 | + | |
| 815 | + if ($block) { | |
| 816 | + $output .= highlight_block($block); | |
| 817 | + } | |
| 818 | + foreach $line (split "\n", $output) { | |
| 761 | 819 | print $lineprefix . $line . "\n"; |
| 762 | 820 | } |
| 763 | 821 | } |
| @@ -1422,8 +1480,6 @@ sub push_parameter($$$$) { · 658 unmodified lines | ||
| 1422 | 1480 | } |
| 1423 | 1481 | } |
| 1424 | 1482 | |
| 1425 | − $param = xml_escape($param); | |
| 1426 | − | |
| 1427 | 1483 | # strip spaces from $param so that it is one continuous string |
| 1428 | 1484 | # on @parameterlist; |
| 1429 | 1485 | # this fixes a problem where check_sections() cannot find |
| @@ -1748,47 +1804,6 @@ sub process_proto_type($$) { · 318 unmodified lines | ||
| 1748 | 1804 | } |
| 1749 | 1805 | } |
| 1750 | 1806 | |
| 1751 | −# xml_escape: replace <, >, and & in the text stream; | |
| 1752 | −# | |
| 1753 | −# however, formatting controls that are generated internally/locally in the | |
| 1754 | −# kernel-doc script are not escaped here; instead, they begin life like | |
| 1755 | −# $blankline_html (4 of '\' followed by a mnemonic + ':'), then these strings | |
| 1756 | −# are converted to their mnemonic-expected output, without the 4 * '\' & ':', | |
| 1757 | −# just before actual output; (this is done by local_unescape()) | |
| 1758 | −sub xml_escape($) { | |
| 1759 | − my $text = shift; | |
| 1760 | − if ($output_mode eq "man") { | |
| 1761 | − return $text; | |
| 1762 | − } | |
| 1763 | − $text =~ s/\&/\\\\\\amp;/g; | |
| 1764 | − $text =~ s/\</\\\\\\lt;/g; | |
| 1765 | − $text =~ s/\>/\\\\\\gt;/g; | |
| 1766 | − return $text; | |
| 1767 | −} | |
| 1768 | − | |
| 1769 | −# xml_unescape: reverse the effects of xml_escape | |
| 1770 | −sub xml_unescape($) { | |
| 1771 | − my $text = shift; | |
| 1772 | − if ($output_mode eq "man") { | |
| 1773 | − return $text; | |
| 1774 | − } | |
| 1775 | − $text =~ s/\\\\\\amp;/\&/g; | |
| 1776 | − $text =~ s/\\\\\\lt;/</g; | |
| 1777 | − $text =~ s/\\\\\\gt;/>/g; | |
| 1778 | − return $text; | |
| 1779 | −} | |
| 1780 | − | |
| 1781 | −# convert local escape strings to html | |
| 1782 | −# local escape strings look like: '\\\\menmonic:' (that's 4 backslashes) | |
| 1783 | −sub local_unescape($) { | |
| 1784 | − my $text = shift; | |
| 1785 | − if ($output_mode eq "man") { | |
| 1786 | − return $text; | |
| 1787 | − } | |
| 1788 | − $text =~ s/\\\\\\\\lt:/</g; | |
| 1789 | − $text =~ s/\\\\\\\\gt:/>/g; | |
| 1790 | − return $text; | |
| 1791 | −} | |
| 1792 | 1807 | |
| 1793 | 1808 | sub map_filename($) { |
| 1794 | 1809 | my $file; |
| @@ -1826,15 +1841,291 @@ sub process_export_file($) { · 31 unmodified lines | ||
| 1826 | 1841 | close(IN); |
| 1827 | 1842 | } |
| 1828 | 1843 | |
| 1829 | −sub process_file($) { | |
| 1830 | − my $file; | |
| 1844 | +# | |
| 1845 | +# Parsers for the various processing states. | |
| 1846 | +# | |
| 1847 | +# STATE_NORMAL: looking for the /** to begin everything. | |
| 1848 | +# | |
| 1849 | +sub process_normal() { | |
| 1850 | + if (/$doc_start/o) { | |
| 1851 | + $state = STATE_NAME; # next line is always the function name | |
| 1852 | + $in_doc_sect = 0; | |
| 1853 | + $declaration_start_line = $. + 1; | |
| 1854 | + } | |
| 1855 | +} | |
| 1856 | + | |
| 1857 | +# | |
| 1858 | +# STATE_NAME: Looking for the "name - description" line | |
| 1859 | +# | |
| 1860 | +sub process_name($$) { | |
| 1861 | + my $file = shift; | |
| 1831 | 1862 | my $identifier; |
| 1832 | − my $func; | |
| 1833 | 1863 | my $descr; |
| 1834 | − my $in_purpose = 0; | |
| 1864 | + | |
| 1865 | + if (/$doc_block/o) { | |
| 1866 | + $state = STATE_DOCBLOCK; | |
| 1867 | + $contents = ""; | |
| 1868 | + $new_start_line = $. + 1; | |
| 1869 | + | |
| 1870 | + if ( $1 eq "" ) { | |
| 1871 | + $section = $section_intro; | |
| 1872 | + } else { | |
| 1873 | + $section = $1; | |
| 1874 | + } | |
| 1875 | + } | |
| 1876 | + elsif (/$doc_decl/o) { | |
| 1877 | + $identifier = $1; | |
| 1878 | + if (/\s*([\w\s]+?)(\(\))?\s*-/) { | |
| 1879 | + $identifier = $1; | |
| 1880 | + } | |
| 1881 | + | |
| 1882 | + $state = STATE_BODY; | |
| 1883 | + # if there's no @param blocks need to set up default section | |
| 1884 | + # here | |
| 1885 | + $contents = ""; | |
| 1886 | + $section = $section_default; | |
| 1887 | + $new_start_line = $. + 1; | |
| 1888 | + if (/-(.*)/) { | |
| 1889 | + # strip leading/trailing/multiple spaces | |
| 1890 | + $descr= $1; | |
| 1891 | + $descr =~ s/^\s*//; | |
| 1892 | + $descr =~ s/\s*$//; | |
| 1893 | + $descr =~ s/\s+/ /g; | |
| 1894 | + $declaration_purpose = $descr; | |
| 1895 | + $state = STATE_BODY_MAYBE; | |
| 1896 | + } else { | |
| 1897 | + $declaration_purpose = ""; | |
| 1898 | + } | |
| 1899 | + | |
| 1900 | + if (($declaration_purpose eq "") && $verbose) { | |
| 1901 | + print STDERR "${file}:$.: warning: missing initial short description on line:\n"; | |
| 1902 | + print STDERR $_; | |
| 1903 | + ++$warnings; | |
| 1904 | + } | |
| 1905 | + | |
| 1906 | + if ($identifier =~ m/^struct/) { | |
| 1907 | + $decl_type = 'struct'; | |
| 1908 | + } elsif ($identifier =~ m/^union/) { | |
| 1909 | + $decl_type = 'union'; | |
| 1910 | + } elsif ($identifier =~ m/^enum/) { | |
| 1911 | + $decl_type = 'enum'; | |
| 1912 | + } elsif ($identifier =~ m/^typedef/) { | |
| 1913 | + $decl_type = 'typedef'; | |
| 1914 | + } else { | |
| 1915 | + $decl_type = 'function'; | |
| 1916 | + } | |
| 1917 | + | |
| 1918 | + if ($verbose) { | |
| 1919 | + print STDERR "${file}:$.: info: Scanning doc for $identifier\n"; | |
| 1920 | + } | |
| 1921 | + } else { | |
| 1922 | + print STDERR "${file}:$.: warning: Cannot understand $_ on line $.", | |
| 1923 | + " - I thought it was a doc line\n"; | |
| 1924 | + ++$warnings; | |
| 1925 | + $state = STATE_NORMAL; | |
| 1926 | + } | |
| 1927 | +} | |
| 1928 | + | |
| 1929 | + | |
| 1930 | +# | |
| 1931 | +# STATE_BODY and STATE_BODY_MAYBE: the bulk of a kerneldoc comment. | |
| 1932 | +# | |
| 1933 | +sub process_body($$) { | |
| 1934 | + my $file = shift; | |
| 1935 | + | |
| 1936 | + if (/$doc_sect/i) { # case insensitive for supported section names | |
| 1937 | + $newsection = $1; | |
| 1938 | + $newcontents = $2; | |
| 1939 | + | |
| 1940 | + # map the supported section names to the canonical names | |
| 1941 | + if ($newsection =~ m/^description$/i) { | |
| 1942 | + $newsection = $section_default; | |
| 1943 | + } elsif ($newsection =~ m/^context$/i) { | |
| 1944 | + $newsection = $section_context; | |
| 1945 | + } elsif ($newsection =~ m/^returns?$/i) { | |
| 1946 | + $newsection = $section_return; | |
| 1947 | + } elsif ($newsection =~ m/^\@return$/) { | |
| 1948 | + # special: @return is a section, not a param description | |
| 1949 | + $newsection = $section_return; | |
| 1950 | + } | |
| 1951 | + | |
| 1952 | + if (($contents ne "") && ($contents ne "\n")) { | |
| 1953 | + if (!$in_doc_sect && $verbose) { | |
| 1954 | + print STDERR "${file}:$.: warning: contents before sections\n"; | |
| 1955 | + ++$warnings; | |
| 1956 | + } | |
| 1957 | + dump_section($file, $section, $contents); | |
| 1958 | + $section = $section_default; | |
| 1959 | + } | |
| 1960 | + | |
| 1961 | + $in_doc_sect = 1; | |
| 1962 | + $state = STATE_BODY; | |
| 1963 | + $contents = $newcontents; | |
| 1964 | + $new_start_line = $.; | |
| 1965 | + while (substr($contents, 0, 1) eq " ") { | |
| 1966 | + $contents = substr($contents, 1); | |
| 1967 | + } | |
| 1968 | + if ($contents ne "") { | |
| 1969 | + $contents .= "\n"; | |
| 1970 | + } | |
| 1971 | + $section = $newsection; | |
| 1972 | + $leading_space = undef; | |
| 1973 | + } elsif (/$doc_end/) { | |
| 1974 | + if (($contents ne "") && ($contents ne "\n")) { | |
| 1975 | + dump_section($file, $section, $contents); | |
| 1976 | + $section = $section_default; | |
| 1977 | + $contents = ""; | |
| 1978 | + } | |
| 1979 | + # look for doc_com + <text> + doc_end: | |
| 1980 | + if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') { | |
| 1981 | + print STDERR "${file}:$.: warning: suspicious ending line: $_"; | |
| 1982 | + ++$warnings; | |
| 1983 | + } | |
| 1984 | + | |
| 1985 | + $prototype = ""; | |
| 1986 | + $state = STATE_PROTO; | |
| 1987 | + $brcount = 0; | |
| 1988 | + } elsif (/$doc_content/) { | |
| 1989 | + # miguel-style comment kludge, look for blank lines after | |
| 1990 | + # @parameter line to signify start of description | |
| 1991 | + if ($1 eq "") { | |
| 1992 | + if ($section =~ m/^@/ || $section eq $section_context) { | |
| 1993 | + dump_section($file, $section, $contents); | |
| 1994 | + $section = $section_default; | |
| 1995 | + $contents = ""; | |
| 1996 | + $new_start_line = $.; | |
| 1997 | + } else { | |
| 1998 | + $contents .= "\n"; | |
| 1999 | + } | |
| 2000 | + $state = STATE_BODY; | |
| 2001 | + } elsif ($state == STATE_BODY_MAYBE) { | |
| 2002 | + # Continued declaration purpose | |
| 2003 | + chomp($declaration_purpose); | |
| 2004 | + $declaration_purpose .= " " . $1; | |
| 2005 | + $declaration_purpose =~ s/\s+/ /g; | |
| 2006 | + } else { | |
| 2007 | + my $cont = $1; | |
| 2008 | + if ($section =~ m/^@/ || $section eq $section_context) { | |
| 2009 | + if (!defined $leading_space) { | |
| 2010 | + if ($cont =~ m/^(\s+)/) { | |
| 2011 | + $leading_space = $1; | |
| 2012 | + } else { | |
| 2013 | + $leading_space = ""; | |
| 2014 | + } | |
| 2015 | + } | |
| 2016 | + $cont =~ s/^$leading_space//; | |
| 2017 | + } | |
| 2018 | + $contents .= $cont . "\n"; | |
| 2019 | + } | |
| 2020 | + } else { | |
| 2021 | + # i dont know - bad line? ignore. | |
| 2022 | + print STDERR "${file}:$.: warning: bad line: $_"; | |
| 2023 | + ++$warnings; | |
| 2024 | + } | |
| 2025 | +} | |
| 2026 | + | |
| 2027 | + | |
| 2028 | +# | |
| 2029 | +# STATE_PROTO: reading a function/whatever prototype. | |
| 2030 | +# | |
| 2031 | +sub process_proto($$) { | |
| 2032 | + my $file = shift; | |
| 2033 | + | |
| 2034 | + if (/$doc_inline_oneline/) { | |
| 2035 | + $section = $1; | |
| 2036 | + $contents = $2; | |
| 2037 | + if ($contents ne "") { | |
| 2038 | + $contents .= "\n"; | |
| 2039 | + dump_section($file, $section, $contents); | |
| 2040 | + $section = $section_default; | |
| 2041 | + $contents = ""; | |
| 2042 | + } | |
| 2043 | + } elsif (/$doc_inline_start/) { | |
| 2044 | + $state = STATE_INLINE; | |
| 2045 | + $inline_doc_state = STATE_INLINE_NAME; | |
| 2046 | + } elsif ($decl_type eq 'function') { | |
| 2047 | + process_proto_function($_, $file); | |
| 2048 | + } else { | |
| 2049 | + process_proto_type($_, $file); | |
| 2050 | + } | |
| 2051 | +} | |
| 2052 | + | |
| 2053 | +# | |
| 2054 | +# STATE_DOCBLOCK: within a DOC: block. | |
| 2055 | +# | |
| 2056 | +sub process_docblock($$) { | |
| 2057 | + my $file = shift; | |
| 2058 | + | |
| 2059 | + if (/$doc_end/) { | |
| 2060 | + dump_doc_section($file, $section, $contents); | |
| 2061 | + $section = $section_default; | |
| 2062 | + $contents = ""; | |
| 2063 | + $function = ""; | |
| 2064 | + %parameterdescs = (); | |
| 2065 | + %parametertypes = (); | |
| 2066 | + @parameterlist = (); | |
| 2067 | + %sections = (); | |
| 2068 | + @sectionlist = (); | |
| 2069 | + $prototype = ""; | |
| 2070 | + $state = STATE_NORMAL; | |
| 2071 | + } elsif (/$doc_content/) { | |
| 2072 | + if ( $1 eq "" ) { | |
| 2073 | + $contents .= $blankline; | |
| 2074 | + } else { | |
| 2075 | + $contents .= $1 . "\n"; | |
| 2076 | + } | |
| 2077 | + } | |
| 2078 | +} | |
| 2079 | + | |
| 2080 | +# | |
| 2081 | +# STATE_INLINE: docbook comments within a prototype. | |
| 2082 | +# | |
| 2083 | +sub process_inline($$) { | |
| 2084 | + my $file = shift; | |
| 2085 | + | |
| 2086 | + # First line (state 1) needs to be a @parameter | |
| 2087 | + if ($inline_doc_state == STATE_INLINE_NAME && /$doc_inline_sect/o) { | |
| 2088 | + $section = $1; | |
| 2089 | + $contents = $2; | |
| 2090 | + $new_start_line = $.; | |
| 2091 | + if ($contents ne "") { | |
| 2092 | + while (substr($contents, 0, 1) eq " ") { | |
| 2093 | + $contents = substr($contents, 1); | |
| 2094 | + } | |
| 2095 | + $contents .= "\n"; | |
| 2096 | + } | |
| 2097 | + $inline_doc_state = STATE_INLINE_TEXT; | |
| 2098 | + # Documentation block end */ | |
| 2099 | + } elsif (/$doc_inline_end/) { | |
| 2100 | + if (($contents ne "") && ($contents ne "\n")) { | |
| 2101 | + dump_section($file, $section, $contents); | |
| 2102 | + $section = $section_default; | |
| 2103 | + $contents = ""; | |
| 2104 | + } | |
| 2105 | + $state = STATE_PROTO; | |
| 2106 | + $inline_doc_state = STATE_INLINE_NA; | |
| 2107 | + # Regular text | |
| 2108 | + } elsif (/$doc_content/) { | |
| 2109 | + if ($inline_doc_state == STATE_INLINE_TEXT) { | |
| 2110 | + $contents .= $1 . "\n"; | |
| 2111 | + # nuke leading blank lines | |
| 2112 | + if ($contents =~ /^\s*$/) { | |
| 2113 | + $contents = ""; | |
| 2114 | + } | |
| 2115 | + } elsif ($inline_doc_state == STATE_INLINE_NAME) { | |
| 2116 | + $inline_doc_state = STATE_INLINE_ERROR; | |
| 2117 | + print STDERR "${file}:$.: warning: "; | |
| 2118 | + print STDERR "Incorrect use of kernel-doc format: $_"; | |
| 2119 | + ++$warnings; | |
| 2120 | + } | |
| 2121 | + } | |
| 2122 | +} | |
| 2123 | + | |
| 2124 | + | |
| 2125 | +sub process_file($) { | |
| 2126 | + my $file; | |
| 1835 | 2127 | my $initial_section_counter = $section_counter; |
| 1836 | 2128 | my ($orig_file) = @_; |
| 1837 | − my $leading_space; | |
| 1838 | 2129 | |
| 1839 | 2130 | $file = map_filename($orig_file); |
| 1840 | 2131 | |
| @@ -1853,250 +2144,23 @@ sub process_file($) { · 12 unmodified lines | ||
| 1853 | 2144 | } |
| 1854 | 2145 | # Replace tabs by spaces |
| 1855 | 2146 | while ($_ =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}; |
| 2147 | + # Hand this line to the appropriate state handler | |
| 1856 | 2148 | if ($state == STATE_NORMAL) { |
| 1857 | − if (/$doc_start/o) { | |
| 1858 | − $state = STATE_NAME; # next line is always the function name | |
| 1859 | − $in_doc_sect = 0; | |
| 1860 | − $declaration_start_line = $. + 1; | |
| 1861 | − } | |
| 1862 | − } elsif ($state == STATE_NAME) {# this line is the function name (always) | |
| 1863 | − if (/$doc_block/o) { | |
| 1864 | − $state = STATE_DOCBLOCK; | |
| 1865 | − $contents = ""; | |
| 1866 | − $new_start_line = $. + 1; | |
| 1867 | − | |
| 1868 | − if ( $1 eq "" ) { | |
| 1869 | − $section = $section_intro; | |
| 1870 | − } else { | |
| 1871 | − $section = $1; | |
| 1872 | − } | |
| 1873 | − } | |
| 1874 | − elsif (/$doc_decl/o) { | |
| 1875 | − $identifier = $1; | |
| 1876 | − if (/\s*([\w\s]+?)(\(\))?\s*-/) { | |
| 1877 | − $identifier = $1; | |
| 1878 | − } | |
| 1879 | − | |
| 1880 | − $state = STATE_FIELD; | |
| 1881 | − # if there's no @param blocks need to set up default section | |
| 1882 | − # here | |
| 1883 | − $contents = ""; | |
| 1884 | − $section = $section_default; | |
| 1885 | − $new_start_line = $. + 1; | |
| 1886 | − if (/-(.*)/) { | |
| 1887 | − # strip leading/trailing/multiple spaces | |
| 1888 | − $descr= $1; | |
| 1889 | − $descr =~ s/^\s*//; | |
| 1890 | − $descr =~ s/\s*$//; | |
| 1891 | − $descr =~ s/\s+/ /g; | |
| 1892 | − $declaration_purpose = xml_escape($descr); | |
| 1893 | − $in_purpose = 1; | |
| 1894 | − } else { | |
| 1895 | − $declaration_purpose = ""; | |
| 1896 | − } | |
| 1897 | − | |
| 1898 | − if (($declaration_purpose eq "") && $verbose) { | |
| 1899 | − print STDERR "${file}:$.: warning: missing initial short description on line:\n"; | |
| 1900 | − print STDERR $_; | |
| 1901 | − ++$warnings; | |
| 1902 | − } | |
| 1903 | − | |
| 1904 | − if ($identifier =~ m/^struct/) { | |
| 1905 | − $decl_type = 'struct'; | |
| 1906 | − } elsif ($identifier =~ m/^union/) { | |
| 1907 | − $decl_type = 'union'; | |
| 1908 | − } elsif ($identifier =~ m/^enum/) { | |
| 1909 | − $decl_type = 'enum'; | |
| 1910 | − } elsif ($identifier =~ m/^typedef/) { | |
| 1911 | − $decl_type = 'typedef'; | |
| 1912 | − } else { | |
| 1913 | − $decl_type = 'function'; | |
| 1914 | − } | |
| 1915 | − | |
| 1916 | − if ($verbose) { | |
| 1917 | − print STDERR "${file}:$.: info: Scanning doc for $identifier\n"; | |
| 1918 | − } | |
| 1919 | − } else { | |
| 1920 | − print STDERR "${file}:$.: warning: Cannot understand $_ on line $.", | |
| 1921 | − " - I thought it was a doc line\n"; | |
| 1922 | − ++$warnings; | |
| 1923 | − $state = STATE_NORMAL; | |
| 1924 | − } | |
| 1925 | − } elsif ($state == STATE_FIELD) { # look for head: lines, and include content | |
| 1926 | − if (/$doc_sect/i) { # case insensitive for supported section names | |
| 1927 | − $newsection = $1; | |
| 1928 | − $newcontents = $2; | |
| 1929 | − | |
| 1930 | − # map the supported section names to the canonical names | |
| 1931 | − if ($newsection =~ m/^description$/i) { | |
| 1932 | − $newsection = $section_default; | |
| 1933 | − } elsif ($newsection =~ m/^context$/i) { | |
| 1934 | − $newsection = $section_context; | |
| 1935 | − } elsif ($newsection =~ m/^returns?$/i) { | |
| 1936 | − $newsection = $section_return; | |
| 1937 | − } elsif ($newsection =~ m/^\@return$/) { | |
| 1938 | − # special: @return is a section, not a param description | |
| 1939 | − $newsection = $section_return; | |
| 1940 | − } | |
| 1941 | − | |
| 1942 | − if (($contents ne "") && ($contents ne "\n")) { | |
| 1943 | − if (!$in_doc_sect && $verbose) { | |
| 1944 | − print STDERR "${file}:$.: warning: contents before sections\n"; | |
| 1945 | − ++$warnings; | |
| 1946 | − } | |
| 1947 | − dump_section($file, $section, xml_escape($contents)); | |
| 1948 | − $section = $section_default; | |
| 1949 | − } | |
| 1950 | − | |
| 1951 | − $in_doc_sect = 1; | |
| 1952 | − $in_purpose = 0; | |
| 1953 | − $contents = $newcontents; | |
| 1954 | − $new_start_line = $.; | |
| 1955 | − while (substr($contents, 0, 1) eq " ") { | |
| 1956 | − $contents = substr($contents, 1); | |
| 1957 | − } | |
| 1958 | − if ($contents ne "") { | |
| 1959 | − $contents .= "\n"; | |
| 1960 | − } | |
| 1961 | − $section = $newsection; | |
| 1962 | − $leading_space = undef; | |
| 1963 | − } elsif (/$doc_end/) { | |
| 1964 | − if (($contents ne "") && ($contents ne "\n")) { | |
| 1965 | − dump_section($file, $section, xml_escape($contents)); | |
| 1966 | − $section = $section_default; | |
| 1967 | − $contents = ""; | |
| 1968 | − } | |
| 1969 | − # look for doc_com + <text> + doc_end: | |
| 1970 | − if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') { | |
| 1971 | − print STDERR "${file}:$.: warning: suspicious ending line: $_"; | |
| 1972 | − ++$warnings; | |
| 1973 | − } | |
| 1974 | − | |
| 1975 | − $prototype = ""; | |
| 1976 | − $state = STATE_PROTO; | |
| 1977 | − $brcount = 0; | |
| 1978 | −# print STDERR "end of doc comment, looking for prototype\n"; | |
| 1979 | − } elsif (/$doc_content/) { | |
| 1980 | − # miguel-style comment kludge, look for blank lines after | |
| 1981 | − # @parameter line to signify start of description | |
| 1982 | − if ($1 eq "") { | |
| 1983 | − if ($section =~ m/^@/ || $section eq $section_context) { | |
| 1984 | − dump_section($file, $section, xml_escape($contents)); | |
| 1985 | − $section = $section_default; | |
| 1986 | − $contents = ""; | |
| 1987 | − $new_start_line = $.; | |
| 1988 | − } else { | |
| 1989 | − $contents .= "\n"; | |
| 1990 | − } | |
| 1991 | − $in_purpose = 0; | |
| 1992 | − } elsif ($in_purpose == 1) { | |
| 1993 | − # Continued declaration purpose | |
| 1994 | − chomp($declaration_purpose); | |
| 1995 | − $declaration_purpose .= " " . xml_escape($1); | |
| 1996 | − $declaration_purpose =~ s/\s+/ /g; | |
| 1997 | − } else { | |
| 1998 | − my $cont = $1; | |
| 1999 | − if ($section =~ m/^@/ || $section eq $section_context) { | |
| 2000 | − if (!defined $leading_space) { | |
| 2001 | − if ($cont =~ m/^(\s+)/) { | |
| 2002 | − $leading_space = $1; | |
| 2003 | − } else { | |
| 2004 | − $leading_space = ""; | |
| 2005 | − } | |
| 2006 | − } | |
| 2007 | − | |
| 2008 | − $cont =~ s/^$leading_space//; | |
| 2009 | − } | |
| 2010 | − $contents .= $cont . "\n"; | |
| 2011 | − } | |
| 2012 | − } else { | |
| 2013 | − # i dont know - bad line? ignore. | |
| 2014 | − print STDERR "${file}:$.: warning: bad line: $_"; | |
| 2015 | − ++$warnings; | |
| 2016 | − } | |
| 2149 | + process_normal(); | |
| 2150 | + } elsif ($state == STATE_NAME) { | |
| 2151 | + process_name($file, $_); | |
| 2152 | + } elsif ($state == STATE_BODY || $state == STATE_BODY_MAYBE) { | |
| 2153 | + process_body($file, $_); | |
| 2017 | 2154 | } elsif ($state == STATE_INLINE) { # scanning for inline parameters |
| 2018 | − # First line (state 1) needs to be a @parameter | |
| 2019 | − if ($inline_doc_state == STATE_INLINE_NAME && /$doc_inline_sect/o) { | |
| 2020 | − $section = $1; | |
| 2021 | − $contents = $2; | |
| 2022 | − $new_start_line = $.; | |
| 2023 | − if ($contents ne "") { | |
| 2024 | − while (substr($contents, 0, 1) eq " ") { | |
| 2025 | − $contents = substr($contents, 1); | |
| 2026 | − } | |
| 2027 | − $contents .= "\n"; | |
| 2028 | − } | |
| 2029 | − $inline_doc_state = STATE_INLINE_TEXT; | |
| 2030 | − # Documentation block end */ | |
| 2031 | − } elsif (/$doc_inline_end/) { | |
| 2032 | − if (($contents ne "") && ($contents ne "\n")) { | |
| 2033 | − dump_section($file, $section, xml_escape($contents)); | |
| 2034 | − $section = $section_default; | |
| 2035 | − $contents = ""; | |
| 2036 | − } | |
| 2037 | − $state = STATE_PROTO; | |
| 2038 | − $inline_doc_state = STATE_INLINE_NA; | |
| 2039 | − # Regular text | |
| 2040 | − } elsif (/$doc_content/) { | |
| 2041 | − if ($inline_doc_state == STATE_INLINE_TEXT) { | |
| 2042 | − $contents .= $1 . "\n"; | |
| 2043 | − # nuke leading blank lines | |
| 2044 | − if ($contents =~ /^\s*$/) { | |
| 2045 | − $contents = ""; | |
| 2046 | − } | |
| 2047 | − } elsif ($inline_doc_state == STATE_INLINE_NAME) { | |
| 2048 | − $inline_doc_state = STATE_INLINE_ERROR; | |
| 2049 | − print STDERR "${file}:$.: warning: "; | |
| 2050 | − print STDERR "Incorrect use of kernel-doc format: $_"; | |
| 2051 | − ++$warnings; | |
| 2052 | − } | |
| 2053 | − } | |
| 2054 | − } elsif ($state == STATE_PROTO) { # scanning for function '{' (end of prototype) | |
| 2055 | − if (/$doc_inline_oneline/) { | |
| 2056 | − $section = $1; | |
| 2057 | − $contents = $2; | |
| 2058 | − if ($contents ne "") { | |
| 2059 | − $contents .= "\n"; | |
| 2060 | − dump_section($file, $section, xml_escape($contents)); | |
| 2061 | − $section = $section_default; | |
| 2062 | − $contents = ""; | |
| 2063 | − } | |
| 2064 | − } elsif (/$doc_inline_start/) { | |
| 2065 | − $state = STATE_INLINE; | |
| 2066 | − $inline_doc_state = STATE_INLINE_NAME; | |
| 2067 | − } elsif ($decl_type eq 'function') { | |
| 2068 | − process_proto_function($_, $file); | |
| 2069 | − } else { | |
| 2070 | − process_proto_type($_, $file); | |
| 2071 | − } | |
| 2155 | + process_inline($file, $_); | |
| 2156 | + } elsif ($state == STATE_PROTO) { | |
| 2157 | + process_proto($file, $_); | |
| 2072 | 2158 | } elsif ($state == STATE_DOCBLOCK) { |
| 2073 | − if (/$doc_end/) | |
| 2074 | − { | |
| 2075 | − dump_doc_section($file, $section, xml_escape($contents)); | |
| 2076 | − $section = $section_default; | |
| 2077 | − $contents = ""; | |
| 2078 | − $function = ""; | |
| 2079 | − %parameterdescs = (); | |
| 2080 | − %parametertypes = (); | |
| 2081 | − @parameterlist = (); | |
| 2082 | − %sections = (); | |
| 2083 | − @sectionlist = (); | |
| 2084 | − $prototype = ""; | |
| 2085 | − $state = STATE_NORMAL; | |
| 2086 | − } | |
| 2087 | − elsif (/$doc_content/) | |
| 2088 | − { | |
| 2089 | − if ( $1 eq "" ) | |
| 2090 | − { | |
| 2091 | − $contents .= $blankline; | |
| 2092 | − } | |
| 2093 | − else | |
| 2094 | − { | |
| 2095 | − $contents .= $1 . "\n"; | |
| 2096 | − } | |
| 2097 | − } | |
| 2159 | + process_docblock($file, $_); | |
| 2098 | 2160 | } |
| 2099 | 2161 | } |
| 2162 | + | |
| 2163 | + # Make sure we got something interesting. | |
| 2100 | 2164 | if ($initial_section_counter == $section_counter) { |
| 2101 | 2165 | if ($output_mode ne "none") { |
| 2102 | 2166 | print STDERR "${file}:1: warning: no structured comments found\n"; |