Em Thu, 14 Aug 2025 18:13:22 +0100 Peter Maydell <peter.mayd...@linaro.org> escreveu:
> We can now delete the old Perl kernel-doc script. For posterity, > this is a complete diff of the local changes that we were carrying > between the kernel's Perl script as of kernel commit 72b97d0b911872ba > (the last time we synced it) and our local copy: > > --- /tmp/kdoc 2025-08-14 10:42:47.620331939 +0100 > +++ scripts/kernel-doc 2025-02-17 10:44:34.528421457 +0000 > @@ -1,5 +1,5 @@ > #!/usr/bin/env perl > -# SPDX-License-Identifier: GPL-2.0 > +# SPDX-License-Identifier: GPL-2.0-only > > use warnings; > use strict; > @@ -224,12 +224,12 @@ > my $type_fp_param = '\@(\w+)\(\)'; # Special RST handling for func ptr > params > my $type_fp_param2 = '\@(\w+->\S+)\(\)'; # Special RST handling for structs > with func ptr params > my $type_env = '(\$\w+)'; > -my $type_enum = '\&(enum\s*([_\w]+))'; > -my $type_struct = '\&(struct\s*([_\w]+))'; > -my $type_typedef = '\&(typedef\s*([_\w]+))'; > -my $type_union = '\&(union\s*([_\w]+))'; > -my $type_member = '\&([_\w]+)(\.|->)([_\w]+)'; > -my $type_fallback = '\&([_\w]+)'; > +my $type_enum = '#(enum\s*([_\w]+))'; > +my $type_struct = '#(struct\s*([_\w]+))'; > +my $type_typedef = '#(([A-Z][_\w]*))'; > +my $type_union = '#(union\s*([_\w]+))'; > +my $type_member = '#([_\w]+)(\.|->)([_\w]+)'; > +my $type_fallback = '(?!)'; # this never matches > my $type_member_func = $type_member . '\(\)'; > > # Output conversion substitutions. > @@ -1745,6 +1745,9 @@ > )+ > \)\)\s+//x; > > + # Strip QEMU specific compiler annotations > + $prototype =~ s/QEMU_[A-Z_]+ +//; > + > # Yes, this truly is vile. We are looking for: > # 1. Return type (may be nothing if we're looking at a macro) > # 2. Function name > @@ -2057,7 +2060,7 @@ > } > elsif (/$doc_decl/o) { > $identifier = $1; > - if (/\s*([\w\s]+?)(\(\))?\s*-/) { > + if (/\s*([\w\s]+?)(\s*-|:)/) { > $identifier = $1; > } > > @@ -2067,7 +2070,7 @@ > $contents = ""; > $section = $section_default; > $new_start_line = $. + 1; > - if (/-(.*)/) { > + if (/[-:](.*)/) { > # strip leading/trailing/multiple spaces > $descr= $1; > $descr =~ s/^\s*//; > > These changes correspond to: > 06e2329636f license: Update deprecated SPDX tag GPL-2.0 to GPL-2.0-only > (a bulk change which we won't bother to re-apply to this third-party script) > b30df2751e5 scripts/kernel-doc: strip QEMU_ from function definitions > 4cf41794411 docs: tweak kernel-doc for QEMU coding standards > > We have already applied the equivalent of these changes to the > Python code in libs/kdoc/ in the preceding commits. > > Signed-off-by: Peter Maydell <peter.mayd...@linaro.org> LGTM. Reviewed-by: Mauro Carvalho Chehab <mchehab+hua...@kernel.org> > --- > .editorconfig | 2 +- > scripts/kernel-doc | 2442 -------------------------------------------- > 2 files changed, 1 insertion(+), 2443 deletions(-) > delete mode 100755 scripts/kernel-doc > > diff --git a/.editorconfig b/.editorconfig > index a04cb9054cb..258d41ab485 100644 > --- a/.editorconfig > +++ b/.editorconfig > @@ -55,7 +55,7 @@ indent_size = 4 > emacs_mode = perl > > # but user kernel "style" for imported scripts > -[scripts/{kernel-doc,get_maintainer.pl,checkpatch.pl}] > +[scripts/{get_maintainer.pl,checkpatch.pl}] > indent_style = tab > indent_size = 8 > emacs_mode = perl > diff --git a/scripts/kernel-doc b/scripts/kernel-doc > deleted file mode 100755 > index fec83f53eda..00000000000 > --- a/scripts/kernel-doc > +++ /dev/null > @@ -1,2442 +0,0 @@ > -#!/usr/bin/env perl > -# SPDX-License-Identifier: GPL-2.0-only > - > -use warnings; > -use strict; > - > -## Copyright (c) 1998 Michael Zucchi, All Rights Reserved ## > -## Copyright (C) 2000, 1 Tim Waugh <twa...@redhat.com> ## > -## Copyright (C) 2001 Simon Huggins ## > -## Copyright (C) 2005-2012 Randy Dunlap ## > -## Copyright (C) 2012 Dan Luedtke ## > -## ## > -## #define enhancements by Armin Kuster <akus...@mvista.com> ## > -## Copyright (c) 2000 MontaVista Software, Inc. ## > -## ## > -## This software falls under the GNU General Public License. ## > -## Please read the COPYING file for more information ## > - > -# 18/01/2001 - Cleanups > -# Functions prototyped as foo(void) same as foo() > -# Stop eval'ing where we don't need to. > -# -- hug...@earth.li > - > -# 27/06/2001 - Allowed whitespace after initial "/**" and > -# allowed comments before function declarations. > -# -- Christian Kreibich <c...@whoop.org> > - > -# Still to do: > -# - add perldoc documentation > -# - Look more closely at some of the scarier bits :) > - > -# 26/05/2001 - Support for separate source and object trees. > -# Return error code. > -# Keith Owens <k...@ocs.com.au> > - > -# 23/09/2001 - Added support for typedefs, structs, enums and unions > -# Support for Context section; can be terminated using empty > line > -# Small fixes (like spaces vs. \s in regex) > -# -- Tim Jansen <t...@tjansen.de> > - > -# 25/07/2012 - Added support for HTML5 > -# -- Dan Luedtke <m...@danrl.de> > - > -sub usage { > - my $message = <<"EOF"; > -Usage: $0 [OPTION ...] FILE ... > - > -Read C language source or header FILEs, extract embedded documentation > comments, > -and print formatted documentation to standard output. > - > -The documentation comments are identified by "/**" opening comment mark. See > -Documentation/doc-guide/kernel-doc.rst for the documentation comment syntax. > - > -Output format selection (mutually exclusive): > - -man Output troff manual page format. This is the > default. > - -rst Output reStructuredText format. > - -none Do not output documentation, only warnings. > - > -Output format selection modifier (affects only ReST output): > - > - -sphinx-version Use the ReST C domain dialect compatible with an > - specific Sphinx Version. > - If not specified, kernel-doc will auto-detect using > - the sphinx-build version found on PATH. > - > -Output selection (mutually exclusive): > - -export Only output documentation for symbols that have been > - exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL() > - in any input FILE or -export-file FILE. > - -internal Only output documentation for symbols that have NOT been > - exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL() > - in any input FILE or -export-file FILE. > - -function NAME Only output documentation for the given function(s) > - or DOC: section title(s). All other functions and DOC: > - sections are ignored. May be specified multiple times. > - -nosymbol NAME Exclude the specified symbols from the output > - documentation. May be specified multiple times. > - > -Output selection modifiers: > - -no-doc-sections Do not output DOC: sections. > - -enable-lineno Enable output of #define LINENO lines. Only works > with > - reStructuredText format. > - -export-file FILE Specify an additional FILE in which to look for > - EXPORT_SYMBOL() and EXPORT_SYMBOL_GPL(). To be used > with > - -export or -internal. May be specified multiple > times. > - > -Other parameters: > - -v Verbose output, more warnings and other information. > - -h Print this help. > - -Werror Treat warnings as errors. > - > -EOF > - print $message; > - exit 1; > -} > - > -# > -# format of comments. > -# In the following table, (...)? signifies optional structure. > -# (...)* signifies 0 or more structure elements > -# /** > -# * function_name(:)? (- short description)? > -# (* @parameterx: (description of parameter x)?)* > -# (* a blank line)? > -# * (Description:)? (Description of function)? > -# * (section header: (section description)? )* > -# (*)?*/ > -# > -# So .. the trivial example would be: > -# > -# /** > -# * my_function > -# */ > -# > -# If the Description: header tag is omitted, then there must be a blank line > -# after the last parameter specification. > -# e.g. > -# /** > -# * my_function - does my stuff > -# * @my_arg: its mine damnit > -# * > -# * Does my stuff explained. > -# */ > -# > -# or, could also use: > -# /** > -# * my_function - does my stuff > -# * @my_arg: its mine damnit > -# * Description: Does my stuff explained. > -# */ > -# etc. > -# > -# Besides functions you can also write documentation for structs, unions, > -# enums and typedefs. Instead of the function name you must write the name > -# of the declaration; the struct/union/enum/typedef must always precede > -# the name. Nesting of declarations is not supported. > -# Use the argument mechanism to document members or constants. > -# e.g. > -# /** > -# * struct my_struct - short description > -# * @a: first member > -# * @b: second member > -# * > -# * Longer description > -# */ > -# struct my_struct { > -# int a; > -# int b; > -# /* private: */ > -# int c; > -# }; > -# > -# All descriptions can be multiline, except the short function description. > -# > -# For really longs structs, you can also describe arguments inside the > -# body of the struct. > -# eg. > -# /** > -# * struct my_struct - short description > -# * @a: first member > -# * @b: second member > -# * > -# * Longer description > -# */ > -# struct my_struct { > -# int a; > -# int b; > -# /** > -# * @c: This is longer description of C > -# * > -# * You can use paragraphs to describe arguments > -# * using this method. > -# */ > -# int c; > -# }; > -# > -# This should be use only for struct/enum members. > -# > -# You can also add additional sections. When documenting kernel functions you > -# should document the "Context:" of the function, e.g. whether the functions > -# can be called form interrupts. Unlike other sections you can end it with an > -# empty line. > -# A non-void function should have a "Return:" section describing the return > -# value(s). > -# Example-sections should contain the string EXAMPLE so that they are marked > -# appropriately in DocBook. > -# > -# Example: > -# /** > -# * user_function - function that can only be called in user context > -# * @a: some argument > -# * Context: !in_interrupt() > -# * > -# * Some description > -# * Example: > -# * user_function(22); > -# */ > -# ... > -# > -# > -# All descriptive text is further processed, scanning for the following > special > -# patterns, which are highlighted appropriately. > -# > -# 'funcname()' - function > -# '$ENVVAR' - environmental variable > -# '&struct_name' - name of a structure (up to two words including 'struct') > -# '&struct_name.member' - name of a structure member > -# '@parameter' - name of a parameter > -# '%CONST' - name of a constant. > -# '``LITERAL``' - literal string without any spaces on it. > - > -## init lots of data > - > -my $errors = 0; > -my $warnings = 0; > -my $anon_struct_union = 0; > - > -# match expressions used to find embedded type information > -my $type_constant = '\b``([^\`]+)``\b'; > -my $type_constant2 = '\%([-_\w]+)'; > -my $type_func = '(\w+)\(\)'; > -my $type_param = '\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)'; > -my $type_param_ref = '([\!]?)\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)'; > -my $type_fp_param = '\@(\w+)\(\)'; # Special RST handling for func ptr > params > -my $type_fp_param2 = '\@(\w+->\S+)\(\)'; # Special RST handling for structs > with func ptr params > -my $type_env = '(\$\w+)'; > -my $type_enum = '#(enum\s*([_\w]+))'; > -my $type_struct = '#(struct\s*([_\w]+))'; > -my $type_typedef = '#(([A-Z][_\w]*))'; > -my $type_union = '#(union\s*([_\w]+))'; > -my $type_member = '#([_\w]+)(\.|->)([_\w]+)'; > -my $type_fallback = '(?!)'; # this never matches > -my $type_member_func = $type_member . '\(\)'; > - > -# Output conversion substitutions. > -# One for each output format > - > -# these are pretty rough > -my @highlights_man = ( > - [$type_constant, "\$1"], > - [$type_constant2, "\$1"], > - [$type_func, "\\\\fB\$1\\\\fP"], > - [$type_enum, "\\\\fI\$1\\\\fP"], > - [$type_struct, "\\\\fI\$1\\\\fP"], > - [$type_typedef, "\\\\fI\$1\\\\fP"], > - [$type_union, "\\\\fI\$1\\\\fP"], > - [$type_param, "\\\\fI\$1\\\\fP"], > - [$type_param_ref, "\\\\fI\$1\$2\\\\fP"], > - [$type_member, "\\\\fI\$1\$2\$3\\\\fP"], > - [$type_fallback, "\\\\fI\$1\\\\fP"] > - ); > -my $blankline_man = ""; > - > -# rst-mode > -my @highlights_rst = ( > - [$type_constant, "``\$1``"], > - [$type_constant2, "``\$1``"], > - # Note: need to escape () to avoid func matching later > - [$type_member_func, > "\\:c\\:type\\:`\$1\$2\$3\\\\(\\\\) <\$1>`"], > - [$type_member, "\\:c\\:type\\:`\$1\$2\$3 <\$1>`"], > - [$type_fp_param, "**\$1\\\\(\\\\)**"], > - [$type_fp_param2, "**\$1\\\\(\\\\)**"], > - [$type_func, "\$1()"], > - [$type_enum, "\\:c\\:type\\:`\$1 <\$2>`"], > - [$type_struct, "\\:c\\:type\\:`\$1 <\$2>`"], > - [$type_typedef, "\\:c\\:type\\:`\$1 <\$2>`"], > - [$type_union, "\\:c\\:type\\:`\$1 <\$2>`"], > - # in rst this can refer to any type > - [$type_fallback, "\\:c\\:type\\:`\$1`"], > - [$type_param_ref, "**\$1\$2**"] > - ); > -my $blankline_rst = "\n"; > - > -# read arguments > -if ($#ARGV == -1) { > - usage(); > -} > - > -my $kernelversion; > -my ($sphinx_major, $sphinx_minor, $sphinx_patch); > - > -my $dohighlight = ""; > - > -my $verbose = 0; > -my $Werror = 0; > -my $output_mode = "rst"; > -my $output_preformatted = 0; > -my $no_doc_sections = 0; > -my $enable_lineno = 0; > -my @highlights = @highlights_rst; > -my $blankline = $blankline_rst; > -my $modulename = "Kernel API"; > - > -use constant { > - OUTPUT_ALL => 0, # output all symbols and doc sections > - OUTPUT_INCLUDE => 1, # output only specified symbols > - OUTPUT_EXPORTED => 2, # output exported symbols > - OUTPUT_INTERNAL => 3, # output non-exported symbols > -}; > -my $output_selection = OUTPUT_ALL; > -my $show_not_found = 0; # No longer used > - > -my @export_file_list; > - > -my @build_time; > -if (defined($ENV{'KBUILD_BUILD_TIMESTAMP'}) && > - (my $seconds = `date -d"${ENV{'KBUILD_BUILD_TIMESTAMP'}}" +%s`) ne '') { > - @build_time = gmtime($seconds); > -} else { > - @build_time = localtime; > -} > - > -my $man_date = ('January', 'February', 'March', 'April', 'May', 'June', > - 'July', 'August', 'September', 'October', > - 'November', 'December')[$build_time[4]] . > - " " . ($build_time[5]+1900); > - > -# Essentially these are globals. > -# They probably want to be tidied up, made more localised or something. > -# CAVEAT EMPTOR! Some of the others I localised may not want to be, which > -# could cause "use of undefined value" or other bugs. > -my ($function, %function_table, %parametertypes, $declaration_purpose); > -my %nosymbol_table = (); > -my $declaration_start_line; > -my ($type, $declaration_name, $return_type); > -my ($newsection, $newcontents, $prototype, $brcount, %source_map); > - > -if (defined($ENV{'KBUILD_VERBOSE'})) { > - $verbose = "$ENV{'KBUILD_VERBOSE'}"; > -} > - > -if (defined($ENV{'KDOC_WERROR'})) { > - $Werror = "$ENV{'KDOC_WERROR'}"; > -} > - > -if (defined($ENV{'KCFLAGS'})) { > - my $kcflags = "$ENV{'KCFLAGS'}"; > - > - if ($kcflags =~ /Werror/) { > - $Werror = 1; > - } > -} > - > -# Generated docbook code is inserted in a template at a point where > -# docbook v3.1 requires a non-zero sequence of RefEntry's; see: > -# > https://www.oasis-open.org/docbook/documentation/reference/html/refentry.html > -# We keep track of number of generated entries and generate a dummy > -# if needs be to ensure the expanded template can be postprocessed > -# into html. > -my $section_counter = 0; > - > -my $lineprefix=""; > - > -# Parser states > -use constant { > - STATE_NORMAL => 0, # normal code > - STATE_NAME => 1, # looking for function name > - STATE_BODY_MAYBE => 2, # body - or maybe more description > - STATE_BODY => 3, # the body of the comment > - STATE_BODY_WITH_BLANK_LINE => 4, # the body, which has a blank line > - STATE_PROTO => 5, # scanning prototype > - STATE_DOCBLOCK => 6, # documentation block > - STATE_INLINE => 7, # gathering doc outside main block > -}; > -my $state; > -my $in_doc_sect; > -my $leading_space; > - > -# Inline documentation state > -use constant { > - STATE_INLINE_NA => 0, # not applicable ($state != STATE_INLINE) > - STATE_INLINE_NAME => 1, # looking for member name (@foo:) > - STATE_INLINE_TEXT => 2, # looking for member documentation > - STATE_INLINE_END => 3, # done > - STATE_INLINE_ERROR => 4, # error - Comment without header was found. > - # Spit a warning as it's not > - # proper kernel-doc and ignore the rest. > -}; > -my $inline_doc_state; > - > -#declaration types: can be > -# 'function', 'struct', 'union', 'enum', 'typedef' > -my $decl_type; > - > -my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start. > -my $doc_end = '\*/'; > -my $doc_com = '\s*\*\s*'; > -my $doc_com_body = '\s*\* ?'; > -my $doc_decl = $doc_com . '(\w+)'; > -# @params and a strictly limited set of supported section names > -my $doc_sect = $doc_com . > - > '\s*(\@[.\w]+|\@\.\.\.|description|context|returns?|notes?|examples?)\s*:(.*)'; > -my $doc_content = $doc_com_body . '(.*)'; > -my $doc_block = $doc_com . 'DOC:\s*(.*)?'; > -my $doc_inline_start = '^\s*/\*\*\s*$'; > -my $doc_inline_sect = '\s*\*\s*(@\s*[\w][\w\.]*\s*):(.*)'; > -my $doc_inline_end = '^\s*\*/\s*$'; > -my $doc_inline_oneline = '^\s*/\*\*\s*(@[\w\s]+):\s*(.*)\s*\*/\s*$'; > -my $export_symbol = '^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*;'; > - > -my %parameterdescs; > -my %parameterdesc_start_lines; > -my @parameterlist; > -my %sections; > -my @sectionlist; > -my %section_start_lines; > -my $sectcheck; > -my $struct_actual; > - > -my $contents = ""; > -my $new_start_line = 0; > - > -# the canonical section names. see also $doc_sect above. > -my $section_default = "Description"; # default section > -my $section_intro = "Introduction"; > -my $section = $section_default; > -my $section_context = "Context"; > -my $section_return = "Return"; > - > -my $undescribed = "-- undescribed --"; > - > -reset_state(); > - > -while ($ARGV[0] =~ m/^--?(.*)/) { > - my $cmd = $1; > - shift @ARGV; > - if ($cmd eq "man") { > - $output_mode = "man"; > - @highlights = @highlights_man; > - $blankline = $blankline_man; > - } elsif ($cmd eq "rst") { > - $output_mode = "rst"; > - @highlights = @highlights_rst; > - $blankline = $blankline_rst; > - } elsif ($cmd eq "none") { > - $output_mode = "none"; > - } elsif ($cmd eq "module") { # not needed for XML, inherits from calling > document > - $modulename = shift @ARGV; > - } elsif ($cmd eq "function") { # to only output specific functions > - $output_selection = OUTPUT_INCLUDE; > - $function = shift @ARGV; > - $function_table{$function} = 1; > - } elsif ($cmd eq "nosymbol") { # Exclude specific symbols > - my $symbol = shift @ARGV; > - $nosymbol_table{$symbol} = 1; > - } elsif ($cmd eq "export") { # only exported symbols > - $output_selection = OUTPUT_EXPORTED; > - %function_table = (); > - } elsif ($cmd eq "internal") { # only non-exported symbols > - $output_selection = OUTPUT_INTERNAL; > - %function_table = (); > - } elsif ($cmd eq "export-file") { > - my $file = shift @ARGV; > - push(@export_file_list, $file); > - } elsif ($cmd eq "v") { > - $verbose = 1; > - } elsif ($cmd eq "Werror") { > - $Werror = 1; > - } elsif (($cmd eq "h") || ($cmd eq "help")) { > - usage(); > - } elsif ($cmd eq 'no-doc-sections') { > - $no_doc_sections = 1; > - } elsif ($cmd eq 'enable-lineno') { > - $enable_lineno = 1; > - } elsif ($cmd eq 'show-not-found') { > - $show_not_found = 1; # A no-op but don't fail > - } elsif ($cmd eq "sphinx-version") { > - my $ver_string = shift @ARGV; > - if ($ver_string =~ m/^(\d+)(\.\d+)?(\.\d+)?/) { > - $sphinx_major = $1; > - if (defined($2)) { > - $sphinx_minor = substr($2,1); > - } else { > - $sphinx_minor = 0; > - } > - if (defined($3)) { > - $sphinx_patch = substr($3,1) > - } else { > - $sphinx_patch = 0; > - } > - } else { > - die "Sphinx version should either major.minor or major.minor.patch > format\n"; > - } > - } else { > - # Unknown argument > - usage(); > - } > -} > - > -# continue execution near EOF; > - > -# The C domain dialect changed on Sphinx 3. So, we need to check the > -# version in order to produce the right tags. > -sub findprog($) > -{ > - foreach(split(/:/, $ENV{PATH})) { > - return "$_/$_[0]" if(-x "$_/$_[0]"); > - } > -} > - > -sub get_sphinx_version() > -{ > - my $ver; > - > - my $cmd = "sphinx-build"; > - if (!findprog($cmd)) { > - my $cmd = "sphinx-build3"; > - if (!findprog($cmd)) { > - $sphinx_major = 1; > - $sphinx_minor = 2; > - $sphinx_patch = 0; > - printf STDERR "Warning: Sphinx version not found. Using > default (Sphinx version %d.%d.%d)\n", > - $sphinx_major, $sphinx_minor, $sphinx_patch; > - return; > - } > - } > - > - open IN, "$cmd --version 2>&1 |"; > - while (<IN>) { > - if (m/^\s*sphinx-build\s+([\d]+)\.([\d\.]+)(\+\/[\da-f]+)?$/) { > - $sphinx_major = $1; > - $sphinx_minor = $2; > - $sphinx_patch = $3; > - last; > - } > - # Sphinx 1.2.x uses a different format > - if (m/^\s*Sphinx.*\s+([\d]+)\.([\d\.]+)$/) { > - $sphinx_major = $1; > - $sphinx_minor = $2; > - $sphinx_patch = $3; > - last; > - } > - } > - close IN; > -} > - > -# get kernel version from env > -sub get_kernel_version() { > - my $version = 'unknown kernel version'; > - > - if (defined($ENV{'KERNELVERSION'})) { > - $version = $ENV{'KERNELVERSION'}; > - } > - return $version; > -} > - > -# > -sub print_lineno { > - my $lineno = shift; > - if ($enable_lineno && defined($lineno)) { > - print "#define LINENO " . $lineno . "\n"; > - } > -} > -## > -# dumps section contents to arrays/hashes intended for that purpose. > -# > -sub dump_section { > - my $file = shift; > - my $name = shift; > - my $contents = join "\n", @_; > - > - if ($name =~ m/$type_param/) { > - $name = $1; > - $parameterdescs{$name} = $contents; > - $sectcheck = $sectcheck . $name . " "; > - $parameterdesc_start_lines{$name} = $new_start_line; > - $new_start_line = 0; > - } elsif ($name eq "@\.\.\.") { > - $name = "..."; > - $parameterdescs{$name} = $contents; > - $sectcheck = $sectcheck . $name . " "; > - $parameterdesc_start_lines{$name} = $new_start_line; > - $new_start_line = 0; > - } else { > - if (defined($sections{$name}) && ($sections{$name} ne "")) { > - # Only warn on user specified duplicate section names. > - if ($name ne $section_default) { > - print STDERR "${file}:$.: warning: duplicate section name > '$name'\n"; > - ++$warnings; > - } > - $sections{$name} .= $contents; > - } else { > - $sections{$name} = $contents; > - push @sectionlist, $name; > - $section_start_lines{$name} = $new_start_line; > - $new_start_line = 0; > - } > - } > -} > - > -## > -# dump DOC: section after checking that it should go out > -# > -sub dump_doc_section { > - my $file = shift; > - my $name = shift; > - my $contents = join "\n", @_; > - > - if ($no_doc_sections) { > - return; > - } > - > - return if (defined($nosymbol_table{$name})); > - > - if (($output_selection == OUTPUT_ALL) || > - (($output_selection == OUTPUT_INCLUDE) && > - defined($function_table{$name}))) > - { > - dump_section($file, $name, $contents); > - output_blockhead({'sectionlist' => \@sectionlist, > - 'sections' => \%sections, > - 'module' => $modulename, > - 'content-only' => ($output_selection != OUTPUT_ALL), > }); > - } > -} > - > -## > -# output function > -# > -# parameterdescs, a hash. > -# function => "function name" > -# parameterlist => @list of parameters > -# parameterdescs => %parameter descriptions > -# sectionlist => @list of sections > -# sections => %section descriptions > -# > - > -sub output_highlight { > - my $contents = join "\n",@_; > - my $line; > - > -# DEBUG > -# if (!defined $contents) { > -# use Carp; > -# confess "output_highlight got called with no args?\n"; > -# } > - > -# print STDERR "contents b4:$contents\n"; > - eval $dohighlight; > - die $@ if $@; > -# print STDERR "contents af:$contents\n"; > - > - foreach $line (split "\n", $contents) { > - if (! $output_preformatted) { > - $line =~ s/^\s*//; > - } > - if ($line eq ""){ > - if (! $output_preformatted) { > - print $lineprefix, $blankline; > - } > - } else { > - if ($output_mode eq "man" && substr($line, 0, 1) eq ".") { > - print "\\&$line"; > - } else { > - print $lineprefix, $line; > - } > - } > - print "\n"; > - } > -} > - > -## > -# output function in man > -sub output_function_man(%) { > - my %args = %{$_[0]}; > - my ($parameter, $section); > - my $count; > - > - print ".TH \"$args{'function'}\" 9 \"$args{'function'}\" \"$man_date\" > \"Kernel Hacker's Manual\" LINUX\n"; > - > - print ".SH NAME\n"; > - print $args{'function'} . " \\- " . $args{'purpose'} . "\n"; > - > - print ".SH SYNOPSIS\n"; > - if ($args{'functiontype'} ne "") { > - print ".B \"" . $args{'functiontype'} . "\" " . $args{'function'} . > "\n"; > - } else { > - print ".B \"" . $args{'function'} . "\n"; > - } > - $count = 0; > - my $parenth = "("; > - my $post = ","; > - foreach my $parameter (@{$args{'parameterlist'}}) { > - if ($count == $#{$args{'parameterlist'}}) { > - $post = ");"; > - } > - $type = $args{'parametertypes'}{$parameter}; > - if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { > - # pointer-to-function > - print ".BI \"" . $parenth . $1 . "\" " . " \") (" . $2 . ")" . > $post . "\"\n"; > - } else { > - $type =~ s/([^\*])$/$1 /; > - print ".BI \"" . $parenth . $type . "\" " . " \"" . $post . "\"\n"; > - } > - $count++; > - $parenth = ""; > - } > - > - print ".SH ARGUMENTS\n"; > - foreach $parameter (@{$args{'parameterlist'}}) { > - my $parameter_name = $parameter; > - $parameter_name =~ s/\[.*//; > - > - print ".IP \"" . $parameter . "\" 12\n"; > - output_highlight($args{'parameterdescs'}{$parameter_name}); > - } > - foreach $section (@{$args{'sectionlist'}}) { > - print ".SH \"", uc $section, "\"\n"; > - output_highlight($args{'sections'}{$section}); > - } > -} > - > -## > -# output enum in man > -sub output_enum_man(%) { > - my %args = %{$_[0]}; > - my ($parameter, $section); > - my $count; > - > - print ".TH \"$args{'module'}\" 9 \"enum $args{'enum'}\" \"$man_date\" > \"API Manual\" LINUX\n"; > - > - print ".SH NAME\n"; > - print "enum " . $args{'enum'} . " \\- " . $args{'purpose'} . "\n"; > - > - print ".SH SYNOPSIS\n"; > - print "enum " . $args{'enum'} . " {\n"; > - $count = 0; > - foreach my $parameter (@{$args{'parameterlist'}}) { > - print ".br\n.BI \" $parameter\"\n"; > - if ($count == $#{$args{'parameterlist'}}) { > - print "\n};\n"; > - last; > - } > - else { > - print ", \n.br\n"; > - } > - $count++; > - } > - > - print ".SH Constants\n"; > - foreach $parameter (@{$args{'parameterlist'}}) { > - my $parameter_name = $parameter; > - $parameter_name =~ s/\[.*//; > - > - print ".IP \"" . $parameter . "\" 12\n"; > - output_highlight($args{'parameterdescs'}{$parameter_name}); > - } > - foreach $section (@{$args{'sectionlist'}}) { > - print ".SH \"$section\"\n"; > - output_highlight($args{'sections'}{$section}); > - } > -} > - > -## > -# output struct in man > -sub output_struct_man(%) { > - my %args = %{$_[0]}; > - my ($parameter, $section); > - > - print ".TH \"$args{'module'}\" 9 \"" . $args{'type'} . " " . > $args{'struct'} . "\" \"$man_date\" \"API Manual\" LINUX\n"; > - > - print ".SH NAME\n"; > - print $args{'type'} . " " . $args{'struct'} . " \\- " . $args{'purpose'} > . "\n"; > - > - my $declaration = $args{'definition'}; > - $declaration =~ s/\t/ /g; > - $declaration =~ s/\n/"\n.br\n.BI \"/g; > - print ".SH SYNOPSIS\n"; > - print $args{'type'} . " " . $args{'struct'} . " {\n.br\n"; > - print ".BI \"$declaration\n};\n.br\n\n"; > - > - print ".SH Members\n"; > - foreach $parameter (@{$args{'parameterlist'}}) { > - ($parameter =~ /^#/) && next; > - > - my $parameter_name = $parameter; > - $parameter_name =~ s/\[.*//; > - > - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; > - print ".IP \"" . $parameter . "\" 12\n"; > - output_highlight($args{'parameterdescs'}{$parameter_name}); > - } > - foreach $section (@{$args{'sectionlist'}}) { > - print ".SH \"$section\"\n"; > - output_highlight($args{'sections'}{$section}); > - } > -} > - > -## > -# output typedef in man > -sub output_typedef_man(%) { > - my %args = %{$_[0]}; > - my ($parameter, $section); > - > - print ".TH \"$args{'module'}\" 9 \"$args{'typedef'}\" \"$man_date\" > \"API Manual\" LINUX\n"; > - > - print ".SH NAME\n"; > - print "typedef " . $args{'typedef'} . " \\- " . $args{'purpose'} . "\n"; > - > - foreach $section (@{$args{'sectionlist'}}) { > - print ".SH \"$section\"\n"; > - output_highlight($args{'sections'}{$section}); > - } > -} > - > -sub output_blockhead_man(%) { > - my %args = %{$_[0]}; > - my ($parameter, $section); > - my $count; > - > - print ".TH \"$args{'module'}\" 9 \"$args{'module'}\" \"$man_date\" \"API > Manual\" LINUX\n"; > - > - foreach $section (@{$args{'sectionlist'}}) { > - print ".SH \"$section\"\n"; > - output_highlight($args{'sections'}{$section}); > - } > -} > - > -## > -# output in restructured text > -# > - > -# > -# This could use some work; it's used to output the DOC: sections, and > -# starts by putting out the name of the doc section itself, but that tends > -# to duplicate a header already in the template file. > -# > -sub output_blockhead_rst(%) { > - my %args = %{$_[0]}; > - my ($parameter, $section); > - > - foreach $section (@{$args{'sectionlist'}}) { > - next if (defined($nosymbol_table{$section})); > - > - if ($output_selection != OUTPUT_INCLUDE) { > - print "**$section**\n\n"; > - } > - print_lineno($section_start_lines{$section}); > - output_highlight_rst($args{'sections'}{$section}); > - print "\n"; > - } > -} > - > -# > -# Apply the RST highlights to a sub-block of text. > -# > -sub highlight_block($) { > - # The dohighlight kludge requires the text be called $contents > - my $contents = shift; > - eval $dohighlight; > - die $@ if $@; > - return $contents; > -} > - > -# > -# Regexes used only here. > -# > -my $sphinx_literal = '^[^.].*::$'; > -my $sphinx_cblock = '^\.\.\ +code-block::'; > - > -sub output_highlight_rst { > - my $input = join "\n",@_; > - my $output = ""; > - my $line; > - my $in_literal = 0; > - my $litprefix; > - my $block = ""; > - > - foreach $line (split "\n",$input) { > - # > - # If we're in a literal block, see if we should drop out > - # of it. Otherwise pass the line straight through unmunged. > - # > - if ($in_literal) { > - if (! ($line =~ /^\s*$/)) { > - # > - # If this is the first non-blank line in a literal > - # block we need to figure out what the proper indent is. > - # > - if ($litprefix eq "") { > - $line =~ /^(\s*)/; > - $litprefix = '^' . $1; > - $output .= $line . "\n"; > - } elsif (! ($line =~ /$litprefix/)) { > - $in_literal = 0; > - } else { > - $output .= $line . "\n"; > - } > - } else { > - $output .= $line . "\n"; > - } > - } > - # > - # Not in a literal block (or just dropped out) > - # > - if (! $in_literal) { > - $block .= $line . "\n"; > - if (($line =~ /$sphinx_literal/) || ($line =~ /$sphinx_cblock/)) { > - $in_literal = 1; > - $litprefix = ""; > - $output .= highlight_block($block); > - $block = "" > - } > - } > - } > - > - if ($block) { > - $output .= highlight_block($block); > - } > - foreach $line (split "\n", $output) { > - print $lineprefix . $line . "\n"; > - } > -} > - > -sub output_function_rst(%) { > - my %args = %{$_[0]}; > - my ($parameter, $section); > - my $oldprefix = $lineprefix; > - my $start = ""; > - my $is_macro = 0; > - > - if ($sphinx_major < 3) { > - if ($args{'typedef'}) { > - print ".. c:type:: ". $args{'function'} . "\n\n"; > - print_lineno($declaration_start_line); > - print " **Typedef**: "; > - $lineprefix = ""; > - output_highlight_rst($args{'purpose'}); > - $start = "\n\n**Syntax**\n\n ``"; > - $is_macro = 1; > - } else { > - print ".. c:function:: "; > - } > - } else { > - if ($args{'typedef'} || $args{'functiontype'} eq "") { > - $is_macro = 1; > - print ".. c:macro:: ". $args{'function'} . "\n\n"; > - } else { > - print ".. c:function:: "; > - } > - > - if ($args{'typedef'}) { > - print_lineno($declaration_start_line); > - print " **Typedef**: "; > - $lineprefix = ""; > - output_highlight_rst($args{'purpose'}); > - $start = "\n\n**Syntax**\n\n ``"; > - } else { > - print "``" if ($is_macro); > - } > - } > - if ($args{'functiontype'} ne "") { > - $start .= $args{'functiontype'} . " " . $args{'function'} . " ("; > - } else { > - $start .= $args{'function'} . " ("; > - } > - print $start; > - > - my $count = 0; > - foreach my $parameter (@{$args{'parameterlist'}}) { > - if ($count ne 0) { > - print ", "; > - } > - $count++; > - $type = $args{'parametertypes'}{$parameter}; > - > - if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { > - # pointer-to-function > - print $1 . $parameter . ") (" . $2 . ")"; > - } else { > - print $type; > - } > - } > - if ($is_macro) { > - print ")``\n\n"; > - } else { > - print ")\n\n"; > - } > - if (!$args{'typedef'}) { > - print_lineno($declaration_start_line); > - $lineprefix = " "; > - output_highlight_rst($args{'purpose'}); > - print "\n"; > - } > - > - print "**Parameters**\n\n"; > - $lineprefix = " "; > - foreach $parameter (@{$args{'parameterlist'}}) { > - my $parameter_name = $parameter; > - $parameter_name =~ s/\[.*//; > - $type = $args{'parametertypes'}{$parameter}; > - > - if ($type ne "") { > - print "``$type``\n"; > - } else { > - print "``$parameter``\n"; > - } > - > - print_lineno($parameterdesc_start_lines{$parameter_name}); > - > - if (defined($args{'parameterdescs'}{$parameter_name}) && > - $args{'parameterdescs'}{$parameter_name} ne $undescribed) { > - output_highlight_rst($args{'parameterdescs'}{$parameter_name}); > - } else { > - print " *undescribed*\n"; > - } > - print "\n"; > - } > - > - $lineprefix = $oldprefix; > - output_section_rst(@_); > -} > - > -sub output_section_rst(%) { > - my %args = %{$_[0]}; > - my $section; > - my $oldprefix = $lineprefix; > - $lineprefix = ""; > - > - foreach $section (@{$args{'sectionlist'}}) { > - print "**$section**\n\n"; > - print_lineno($section_start_lines{$section}); > - output_highlight_rst($args{'sections'}{$section}); > - print "\n"; > - } > - print "\n"; > - $lineprefix = $oldprefix; > -} > - > -sub output_enum_rst(%) { > - my %args = %{$_[0]}; > - my ($parameter); > - my $oldprefix = $lineprefix; > - my $count; > - > - if ($sphinx_major < 3) { > - my $name = "enum " . $args{'enum'}; > - print "\n\n.. c:type:: " . $name . "\n\n"; > - } else { > - my $name = $args{'enum'}; > - print "\n\n.. c:enum:: " . $name . "\n\n"; > - } > - print_lineno($declaration_start_line); > - $lineprefix = " "; > - output_highlight_rst($args{'purpose'}); > - print "\n"; > - > - print "**Constants**\n\n"; > - $lineprefix = " "; > - foreach $parameter (@{$args{'parameterlist'}}) { > - print "``$parameter``\n"; > - if ($args{'parameterdescs'}{$parameter} ne $undescribed) { > - output_highlight_rst($args{'parameterdescs'}{$parameter}); > - } else { > - print " *undescribed*\n"; > - } > - print "\n"; > - } > - > - $lineprefix = $oldprefix; > - output_section_rst(@_); > -} > - > -sub output_typedef_rst(%) { > - my %args = %{$_[0]}; > - my ($parameter); > - my $oldprefix = $lineprefix; > - my $name; > - > - if ($sphinx_major < 3) { > - $name = "typedef " . $args{'typedef'}; > - } else { > - $name = $args{'typedef'}; > - } > - print "\n\n.. c:type:: " . $name . "\n\n"; > - print_lineno($declaration_start_line); > - $lineprefix = " "; > - output_highlight_rst($args{'purpose'}); > - print "\n"; > - > - $lineprefix = $oldprefix; > - output_section_rst(@_); > -} > - > -sub output_struct_rst(%) { > - my %args = %{$_[0]}; > - my ($parameter); > - my $oldprefix = $lineprefix; > - > - if ($sphinx_major < 3) { > - my $name = $args{'type'} . " " . $args{'struct'}; > - print "\n\n.. c:type:: " . $name . "\n\n"; > - } else { > - my $name = $args{'struct'}; > - if ($args{'type'} eq 'union') { > - print "\n\n.. c:union:: " . $name . "\n\n"; > - } else { > - print "\n\n.. c:struct:: " . $name . "\n\n"; > - } > - } > - print_lineno($declaration_start_line); > - $lineprefix = " "; > - output_highlight_rst($args{'purpose'}); > - print "\n"; > - > - print "**Definition**\n\n"; > - print "::\n\n"; > - my $declaration = $args{'definition'}; > - $declaration =~ s/\t/ /g; > - print " " . $args{'type'} . " " . $args{'struct'} . " {\n$declaration > };\n\n"; > - > - print "**Members**\n\n"; > - $lineprefix = " "; > - foreach $parameter (@{$args{'parameterlist'}}) { > - ($parameter =~ /^#/) && next; > - > - my $parameter_name = $parameter; > - $parameter_name =~ s/\[.*//; > - > - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; > - $type = $args{'parametertypes'}{$parameter}; > - print_lineno($parameterdesc_start_lines{$parameter_name}); > - print "``" . $parameter . "``\n"; > - output_highlight_rst($args{'parameterdescs'}{$parameter_name}); > - print "\n"; > - } > - print "\n"; > - > - $lineprefix = $oldprefix; > - output_section_rst(@_); > -} > - > -## none mode output functions > - > -sub output_function_none(%) { > -} > - > -sub output_enum_none(%) { > -} > - > -sub output_typedef_none(%) { > -} > - > -sub output_struct_none(%) { > -} > - > -sub output_blockhead_none(%) { > -} > - > -## > -# generic output function for all types (function, struct/union, typedef, > enum); > -# calls the generated, variable output_ function name based on > -# functype and output_mode > -sub output_declaration { > - no strict 'refs'; > - my $name = shift; > - my $functype = shift; > - my $func = "output_${functype}_$output_mode"; > - > - return if (defined($nosymbol_table{$name})); > - > - if (($output_selection == OUTPUT_ALL) || > - (($output_selection == OUTPUT_INCLUDE || > - $output_selection == OUTPUT_EXPORTED) && > - defined($function_table{$name})) || > - ($output_selection == OUTPUT_INTERNAL && > - !($functype eq "function" && defined($function_table{$name})))) > - { > - &$func(@_); > - $section_counter++; > - } > -} > - > -## > -# generic output function - calls the right one based on current output mode. > -sub output_blockhead { > - no strict 'refs'; > - my $func = "output_blockhead_" . $output_mode; > - &$func(@_); > - $section_counter++; > -} > - > -## > -# takes a declaration (struct, union, enum, typedef) and > -# invokes the right handler. NOT called for functions. > -sub dump_declaration($$) { > - no strict 'refs'; > - my ($prototype, $file) = @_; > - my $func = "dump_" . $decl_type; > - &$func(@_); > -} > - > -sub dump_union($$) { > - dump_struct(@_); > -} > - > -sub dump_struct($$) { > - my $x = shift; > - my $file = shift; > - > - if ($x =~ > /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|____cacheline_aligned_in_smp|____cacheline_aligned|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*/) > { > - my $decl_type = $1; > - $declaration_name = $2; > - my $members = $3; > - > - # ignore members marked private: > - $members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gosi; > - $members =~ s/\/\*\s*private:.*//gosi; > - # strip comments: > - $members =~ s/\/\*.*?\*\///gos; > - # strip attributes > - $members =~ s/\s*__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)/ /gi; > - $members =~ s/\s*__aligned\s*\([^;]*\)/ /gos; > - $members =~ s/\s*__packed\s*/ /gos; > - $members =~ s/\s*CRYPTO_MINALIGN_ATTR/ /gos; > - $members =~ s/\s*____cacheline_aligned_in_smp/ /gos; > - $members =~ s/\s*____cacheline_aligned/ /gos; > - > - # replace DECLARE_BITMAP > - $members =~ > s/__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)/DECLARE_BITMAP($1, > __ETHTOOL_LINK_MODE_MASK_NBITS)/gos; > - $members =~ s/DECLARE_BITMAP\s*\(([^,)]+),\s*([^,)]+)\)/unsigned long > $1\[BITS_TO_LONGS($2)\]/gos; > - # replace DECLARE_HASHTABLE > - $members =~ s/DECLARE_HASHTABLE\s*\(([^,)]+),\s*([^,)]+)\)/unsigned > long $1\[1 << (($2) - 1)\]/gos; > - # replace DECLARE_KFIFO > - $members =~ s/DECLARE_KFIFO\s*\(([^,)]+),\s*([^,)]+),\s*([^,)]+)\)/$2 > \*$1/gos; > - # replace DECLARE_KFIFO_PTR > - $members =~ s/DECLARE_KFIFO_PTR\s*\(([^,)]+),\s*([^,)]+)\)/$2 \*$1/gos; > - > - my $declaration = $members; > - > - # Split nested struct/union elements as newer ones > - while ($members =~ > m/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/) { > - my $newmember; > - my $maintype = $1; > - my $ids = $4; > - my $content = $3; > - foreach my $id(split /,/, $ids) { > - $newmember .= "$maintype $id; "; > - > - $id =~ s/[:\[].*//; > - $id =~ s/^\s*\**(\S+)\s*/$1/; > - foreach my $arg (split /;/, $content) { > - next if ($arg =~ m/^\s*$/); > - if ($arg =~ > m/^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)/) { > - # pointer-to-function > - my $type = $1; > - my $name = $2; > - my $extra = $3; > - next if (!$name); > - if ($id =~ m/^\s*$/) { > - # anonymous struct/union > - $newmember .= > "$type$name$extra; "; > - } else { > - $newmember .= > "$type$id.$name$extra; "; > - } > - } else { > - my $type; > - my $names; > - $arg =~ s/^\s+//; > - $arg =~ s/\s+$//; > - # Handle bitmaps > - $arg =~ s/:\s*\d+\s*//g; > - # Handle arrays > - $arg =~ s/\[.*\]//g; > - # The type may have multiple words, > - # and multiple IDs can be defined, like: > - # const struct foo, *bar, foobar > - # So, we remove spaces when parsing the > - # names, in order to match just names > - # and commas for the names > - $arg =~ s/\s*,\s*/,/g; > - if ($arg =~ m/(.*)\s+([\S+,]+)/) { > - $type = $1; > - $names = $2; > - } else { > - $newmember .= "$arg; "; > - next; > - } > - foreach my $name (split /,/, $names) { > - $name =~ s/^\s*\**(\S+)\s*/$1/; > - next if (($name =~ m/^\s*$/)); > - if ($id =~ m/^\s*$/) { > - # anonymous struct/union > - $newmember .= "$type > $name; "; > - } else { > - $newmember .= "$type > $id.$name; "; > - } > - } > - } > - } > - } > - $members =~ > s/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/$newmember/; > - } > - > - # Ignore other nested elements, like enums > - $members =~ s/(\{[^\{\}]*\})//g; > - > - create_parameterlist($members, ';', $file, $declaration_name); > - check_sections($file, $declaration_name, $decl_type, $sectcheck, > $struct_actual); > - > - # Adjust declaration for better display > - $declaration =~ s/([\{;])/$1\n/g; > - $declaration =~ s/\}\s+;/};/g; > - # Better handle inlined enums > - do {} while ($declaration =~ s/(enum\s+\{[^\}]+),([^\n])/$1,\n$2/); > - > - my @def_args = split /\n/, $declaration; > - my $level = 1; > - $declaration = ""; > - foreach my $clause (@def_args) { > - $clause =~ s/^\s+//; > - $clause =~ s/\s+$//; > - $clause =~ s/\s+/ /; > - next if (!$clause); > - $level-- if ($clause =~ m/(\})/ && $level > 1); > - if (!($clause =~ m/^\s*#/)) { > - $declaration .= "\t" x $level; > - } > - $declaration .= "\t" . $clause . "\n"; > - $level++ if ($clause =~ m/(\{)/ && !($clause =~m/\}/)); > - } > - output_declaration($declaration_name, > - 'struct', > - {'struct' => $declaration_name, > - 'module' => $modulename, > - 'definition' => $declaration, > - 'parameterlist' => \@parameterlist, > - 'parameterdescs' => \%parameterdescs, > - 'parametertypes' => \%parametertypes, > - 'sectionlist' => \@sectionlist, > - 'sections' => \%sections, > - 'purpose' => $declaration_purpose, > - 'type' => $decl_type > - }); > - } > - else { > - print STDERR "${file}:$.: error: Cannot parse struct or union!\n"; > - ++$errors; > - } > -} > - > - > -sub show_warnings($$) { > - my $functype = shift; > - my $name = shift; > - > - return 0 if (defined($nosymbol_table{$name})); > - > - return 1 if ($output_selection == OUTPUT_ALL); > - > - if ($output_selection == OUTPUT_EXPORTED) { > - if (defined($function_table{$name})) { > - return 1; > - } else { > - return 0; > - } > - } > - if ($output_selection == OUTPUT_INTERNAL) { > - if (!($functype eq "function" && > defined($function_table{$name}))) { > - return 1; > - } else { > - return 0; > - } > - } > - if ($output_selection == OUTPUT_INCLUDE) { > - if (defined($function_table{$name})) { > - return 1; > - } else { > - return 0; > - } > - } > - die("Please add the new output type at show_warnings()"); > -} > - > -sub dump_enum($$) { > - my $x = shift; > - my $file = shift; > - my $members; > - > - > - $x =~ s@/\*.*?\*/@@gos; # strip comments. > - # strip #define macros inside enums > - $x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos; > - > - if ($x =~ /typedef\s+enum\s*\{(.*)\}\s*(\w*)\s*;/) { > - $declaration_name = $2; > - $members = $1; > - } elsif ($x =~ /enum\s+(\w*)\s*\{(.*)\}/) { > - $declaration_name = $1; > - $members = $2; > - } > - > - if ($declaration_name) { > - my %_members; > - > - $members =~ s/\s+$//; > - > - foreach my $arg (split ',', $members) { > - $arg =~ s/^\s*(\w+).*/$1/; > - push @parameterlist, $arg; > - if (!$parameterdescs{$arg}) { > - $parameterdescs{$arg} = $undescribed; > - if (show_warnings("enum", $declaration_name)) { > - print STDERR "${file}:$.: warning: Enum value '$arg' > not described in enum '$declaration_name'\n"; > - } > - } > - $_members{$arg} = 1; > - } > - > - while (my ($k, $v) = each %parameterdescs) { > - if (!exists($_members{$k})) { > - if (show_warnings("enum", $declaration_name)) { > - print STDERR "${file}:$.: warning: Excess enum value '$k' > description in '$declaration_name'\n"; > - } > - } > - } > - > - output_declaration($declaration_name, > - 'enum', > - {'enum' => $declaration_name, > - 'module' => $modulename, > - 'parameterlist' => \@parameterlist, > - 'parameterdescs' => \%parameterdescs, > - 'sectionlist' => \@sectionlist, > - 'sections' => \%sections, > - 'purpose' => $declaration_purpose > - }); > - } else { > - print STDERR "${file}:$.: error: Cannot parse enum!\n"; > - ++$errors; > - } > -} > - > -my $typedef_type = qr { ((?:\s+[\w\*]+){1,8})\s* }x; > -my $typedef_ident = qr { \*?\s*(\w\S+)\s* }x; > -my $typedef_args = qr { \s*\((.*)\); }x; > - > -my $typedef1 = qr { typedef$typedef_type\($typedef_ident\)$typedef_args }x; > -my $typedef2 = qr { typedef$typedef_type$typedef_ident$typedef_args }x; > - > -sub dump_typedef($$) { > - my $x = shift; > - my $file = shift; > - > - $x =~ s@/\*.*?\*/@@gos; # strip comments. > - > - # Parse function typedef prototypes > - if ($x =~ $typedef1 || $x =~ $typedef2) { > - $return_type = $1; > - $declaration_name = $2; > - my $args = $3; > - $return_type =~ s/^\s+//; > - > - create_parameterlist($args, ',', $file, $declaration_name); > - > - output_declaration($declaration_name, > - 'function', > - {'function' => $declaration_name, > - 'typedef' => 1, > - 'module' => $modulename, > - 'functiontype' => $return_type, > - 'parameterlist' => \@parameterlist, > - 'parameterdescs' => \%parameterdescs, > - 'parametertypes' => \%parametertypes, > - 'sectionlist' => \@sectionlist, > - 'sections' => \%sections, > - 'purpose' => $declaration_purpose > - }); > - return; > - } > - > - while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) { > - $x =~ s/\(*.\)\s*;$/;/; > - $x =~ s/\[*.\]\s*;$/;/; > - } > - > - if ($x =~ /typedef.*\s+(\w+)\s*;/) { > - $declaration_name = $1; > - > - output_declaration($declaration_name, > - 'typedef', > - {'typedef' => $declaration_name, > - 'module' => $modulename, > - 'sectionlist' => \@sectionlist, > - 'sections' => \%sections, > - 'purpose' => $declaration_purpose > - }); > - } > - else { > - print STDERR "${file}:$.: error: Cannot parse typedef!\n"; > - ++$errors; > - } > -} > - > -sub save_struct_actual($) { > - my $actual = shift; > - > - # strip all spaces from the actual param so that it looks like one > string item > - $actual =~ s/\s*//g; > - $struct_actual = $struct_actual . $actual . " "; > -} > - > -sub create_parameterlist($$$$) { > - my $args = shift; > - my $splitter = shift; > - my $file = shift; > - my $declaration_name = shift; > - my $type; > - my $param; > - > - # temporarily replace commas inside function pointer definition > - while ($args =~ /(\([^\),]+),/) { > - $args =~ s/(\([^\),]+),/$1#/g; > - } > - > - foreach my $arg (split($splitter, $args)) { > - # strip comments > - $arg =~ s/\/\*.*\*\///; > - # strip leading/trailing spaces > - $arg =~ s/^\s*//; > - $arg =~ s/\s*$//; > - $arg =~ s/\s+/ /; > - > - if ($arg =~ /^#/) { > - # Treat preprocessor directive as a typeless variable just to fill > - # corresponding data structures "correctly". Catch it later in > - # output_* subs. > - push_parameter($arg, "", "", $file); > - } elsif ($arg =~ m/\(.+\)\s*\(/) { > - # pointer-to-function > - $arg =~ tr/#/,/; > - $arg =~ m/[^\(]+\(\*?\s*([\w\.]*)\s*\)/; > - $param = $1; > - $type = $arg; > - $type =~ s/([^\(]+\(\*?)\s*$param/$1/; > - save_struct_actual($param); > - push_parameter($param, $type, $arg, $file, $declaration_name); > - } elsif ($arg) { > - $arg =~ s/\s*:\s*/:/g; > - $arg =~ s/\s*\[/\[/g; > - > - my @args = split('\s*,\s*', $arg); > - if ($args[0] =~ m/\*/) { > - $args[0] =~ s/(\*+)\s*/ $1/; > - } > - > - my @first_arg; > - if ($args[0] =~ /^(.*\s+)(.*?\[.*\].*)$/) { > - shift @args; > - push(@first_arg, split('\s+', $1)); > - push(@first_arg, $2); > - } else { > - @first_arg = split('\s+', shift @args); > - } > - > - unshift(@args, pop @first_arg); > - $type = join " ", @first_arg; > - > - foreach $param (@args) { > - if ($param =~ m/^(\*+)\s*(.*)/) { > - save_struct_actual($2); > - > - push_parameter($2, "$type $1", $arg, $file, > $declaration_name); > - } > - elsif ($param =~ m/(.*?):(\d+)/) { > - if ($type ne "") { # skip unnamed bit-fields > - save_struct_actual($1); > - push_parameter($1, "$type:$2", $arg, $file, > $declaration_name) > - } > - } > - else { > - save_struct_actual($param); > - push_parameter($param, $type, $arg, $file, > $declaration_name); > - } > - } > - } > - } > -} > - > -sub push_parameter($$$$$) { > - my $param = shift; > - my $type = shift; > - my $org_arg = shift; > - my $file = shift; > - my $declaration_name = shift; > - > - if (($anon_struct_union == 1) && ($type eq "") && > - ($param eq "}")) { > - return; # ignore the ending }; from anon. struct/union > - } > - > - $anon_struct_union = 0; > - $param =~ s/[\[\)].*//; > - > - if ($type eq "" && $param =~ /\.\.\.$/) > - { > - if (!$param =~ /\w\.\.\.$/) { > - # handles unnamed variable parameters > - $param = "..."; > - } > - elsif ($param =~ /\w\.\.\.$/) { > - # for named variable parameters of the form `x...`, remove the > dots > - $param =~ s/\.\.\.$//; > - } > - if (!defined $parameterdescs{$param} || $parameterdescs{$param} eq > "") { > - $parameterdescs{$param} = "variable arguments"; > - } > - } > - elsif ($type eq "" && ($param eq "" or $param eq "void")) > - { > - $param="void"; > - $parameterdescs{void} = "no arguments"; > - } > - elsif ($type eq "" && ($param eq "struct" or $param eq "union")) > - # handle unnamed (anonymous) union or struct: > - { > - $type = $param; > - $param = "{unnamed_" . $param . "}"; > - $parameterdescs{$param} = "anonymous\n"; > - $anon_struct_union = 1; > - } > - > - # warn if parameter has no description > - # (but ignore ones starting with # as these are not parameters > - # but inline preprocessor statements); > - # Note: It will also ignore void params and unnamed structs/unions > - if (!defined $parameterdescs{$param} && $param !~ /^#/) { > - $parameterdescs{$param} = $undescribed; > - > - if (show_warnings($type, $declaration_name) && $param !~ /\./) { > - print STDERR > - "${file}:$.: warning: Function parameter or > member '$param' not described in '$declaration_name'\n"; > - ++$warnings; > - } > - } > - > - # strip spaces from $param so that it is one continuous string > - # on @parameterlist; > - # this fixes a problem where check_sections() cannot find > - # a parameter like "addr[6 + 2]" because it actually appears > - # as "addr[6", "+", "2]" on the parameter list; > - # but it's better to maintain the param string unchanged for output, > - # so just weaken the string compare in check_sections() to ignore > - # "[blah" in a parameter string; > - ###$param =~ s/\s*//g; > - push @parameterlist, $param; > - $org_arg =~ s/\s\s+/ /g; > - $parametertypes{$param} = $org_arg; > -} > - > -sub check_sections($$$$$) { > - my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck) = @_; > - my @sects = split ' ', $sectcheck; > - my @prms = split ' ', $prmscheck; > - my $err; > - my ($px, $sx); > - my $prm_clean; # strip trailing "[array size]" and/or > beginning "*" > - > - foreach $sx (0 .. $#sects) { > - $err = 1; > - foreach $px (0 .. $#prms) { > - $prm_clean = $prms[$px]; > - $prm_clean =~ s/\[.*\]//; > - $prm_clean =~ > s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i; > - # ignore array size in a parameter string; > - # however, the original param string may contain > - # spaces, e.g.: addr[6 + 2] > - # and this appears in @prms as "addr[6" since the > - # parameter list is split at spaces; > - # hence just ignore "[..." for the sections check; > - $prm_clean =~ s/\[.*//; > - > - ##$prm_clean =~ s/^\**//; > - if ($prm_clean eq $sects[$sx]) { > - $err = 0; > - last; > - } > - } > - if ($err) { > - if ($decl_type eq "function") { > - print STDERR "${file}:$.: warning: " . > - "Excess function parameter " . > - "'$sects[$sx]' " . > - "description in '$decl_name'\n"; > - ++$warnings; > - } > - } > - } > -} > - > -## > -# Checks the section describing the return value of a function. > -sub check_return_section { > - my $file = shift; > - my $declaration_name = shift; > - my $return_type = shift; > - > - # Ignore an empty return type (It's a macro) > - # Ignore functions with a "void" return type. (But don't ignore > "void *") > - if (($return_type eq "") || ($return_type =~ /void\s*\w*\s*$/)) { > - return; > - } > - > - if (!defined($sections{$section_return}) || > - $sections{$section_return} eq "") { > - print STDERR "${file}:$.: warning: " . > - "No description found for return value of " . > - "'$declaration_name'\n"; > - ++$warnings; > - } > -} > - > -## > -# takes a function prototype and the name of the current file being > -# processed and spits out all the details stored in the global > -# arrays/hashes. > -sub dump_function($$) { > - my $prototype = shift; > - my $file = shift; > - my $noret = 0; > - > - print_lineno($new_start_line); > - > - $prototype =~ s/^static +//; > - $prototype =~ s/^extern +//; > - $prototype =~ s/^asmlinkage +//; > - $prototype =~ s/^inline +//; > - $prototype =~ s/^__inline__ +//; > - $prototype =~ s/^__inline +//; > - $prototype =~ s/^__always_inline +//; > - $prototype =~ s/^noinline +//; > - $prototype =~ s/__init +//; > - $prototype =~ s/__init_or_module +//; > - $prototype =~ s/__meminit +//; > - $prototype =~ s/__must_check +//; > - $prototype =~ s/__weak +//; > - $prototype =~ s/__sched +//; > - $prototype =~ s/__printf\s*\(\s*\d*\s*,\s*\d*\s*\) +//; > - my $define = $prototype =~ s/^#\s*define\s+//; #ak added > - $prototype =~ s/__attribute__\s*\(\( > - (?: > - [\w\s]++ # attribute name > - (?:\([^)]*+\))? # attribute arguments > - \s*+,? # optional comma at the end > - )+ > - \)\)\s+//x; > - > - # Strip QEMU specific compiler annotations > - $prototype =~ s/QEMU_[A-Z_]+ +//; > - > - # Yes, this truly is vile. We are looking for: > - # 1. Return type (may be nothing if we're looking at a macro) > - # 2. Function name > - # 3. Function parameters. > - # > - # All the while we have to watch out for function pointer parameters > - # (which IIRC is what the two sections are for), C types (these > - # regexps don't even start to express all the possibilities), and > - # so on. > - # > - # If you mess with these regexps, it's a good idea to check that > - # the following functions' documentation still comes out right: > - # - parport_register_device (function pointer parameters) > - # - atomic_set (macro) > - # - pci_match_device, __copy_to_user (long return type) > - > - if ($define && $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s+/) { > - # This is an object-like macro, it has no return type and no > parameter > - # list. > - # Function-like macros are not allowed to have spaces between > - # declaration_name and opening parenthesis (notice the \s+). > - $return_type = $1; > - $declaration_name = $2; > - $noret = 1; > - } elsif ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || > - $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || > - $prototype =~ m/^(\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || > - $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || > - $prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ > || > - $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ > || > - $prototype =~ > m/^(\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || > - $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || > - $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || > - $prototype =~ m/^(\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || > - $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || > - $prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ > || > - $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ > || > - $prototype =~ > m/^(\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || > - $prototype =~ > m/^(\w+\s+\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || > - $prototype =~ > m/^(\w+\s+\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || > - $prototype =~ > m/^(\w+\s+\w+\s*\*+\s*\w+\s*\*+\s*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/) { > - $return_type = $1; > - $declaration_name = $2; > - my $args = $3; > - > - create_parameterlist($args, ',', $file, $declaration_name); > - } else { > - print STDERR "${file}:$.: warning: cannot understand function > prototype: '$prototype'\n"; > - return; > - } > - > - my $prms = join " ", @parameterlist; > - check_sections($file, $declaration_name, "function", $sectcheck, $prms); > - > - # This check emits a lot of warnings at the moment, because many > - # functions don't have a 'Return' doc section. So until the number > - # of warnings goes sufficiently down, the check is only performed in > - # verbose mode. > - # TODO: always perform the check. > - if ($verbose && !$noret) { > - check_return_section($file, $declaration_name, $return_type); > - } > - > - # The function parser can be called with a typedef parameter. > - # Handle it. > - if ($return_type =~ /typedef/) { > - output_declaration($declaration_name, > - 'function', > - {'function' => $declaration_name, > - 'typedef' => 1, > - 'module' => $modulename, > - 'functiontype' => $return_type, > - 'parameterlist' => \@parameterlist, > - 'parameterdescs' => \%parameterdescs, > - 'parametertypes' => \%parametertypes, > - 'sectionlist' => \@sectionlist, > - 'sections' => \%sections, > - 'purpose' => $declaration_purpose > - }); > - } else { > - output_declaration($declaration_name, > - 'function', > - {'function' => $declaration_name, > - 'module' => $modulename, > - 'functiontype' => $return_type, > - 'parameterlist' => \@parameterlist, > - 'parameterdescs' => \%parameterdescs, > - 'parametertypes' => \%parametertypes, > - 'sectionlist' => \@sectionlist, > - 'sections' => \%sections, > - 'purpose' => $declaration_purpose > - }); > - } > -} > - > -sub reset_state { > - $function = ""; > - %parameterdescs = (); > - %parametertypes = (); > - @parameterlist = (); > - %sections = (); > - @sectionlist = (); > - $sectcheck = ""; > - $struct_actual = ""; > - $prototype = ""; > - > - $state = STATE_NORMAL; > - $inline_doc_state = STATE_INLINE_NA; > -} > - > -sub tracepoint_munge($) { > - my $file = shift; > - my $tracepointname = 0; > - my $tracepointargs = 0; > - > - if ($prototype =~ m/TRACE_EVENT\((.*?),/) { > - $tracepointname = $1; > - } > - if ($prototype =~ m/DEFINE_SINGLE_EVENT\((.*?),/) { > - $tracepointname = $1; > - } > - if ($prototype =~ m/DEFINE_EVENT\((.*?),(.*?),/) { > - $tracepointname = $2; > - } > - $tracepointname =~ s/^\s+//; #strip leading whitespace > - if ($prototype =~ m/TP_PROTO\((.*?)\)/) { > - $tracepointargs = $1; > - } > - if (($tracepointname eq 0) || ($tracepointargs eq 0)) { > - print STDERR "${file}:$.: warning: Unrecognized tracepoint > format: \n". > - "$prototype\n"; > - } else { > - $prototype = "static inline void > trace_$tracepointname($tracepointargs)"; > - } > -} > - > -sub syscall_munge() { > - my $void = 0; > - > - $prototype =~ s@[\r\n]+@ @gos; # strip newlines/CR's > -## if ($prototype =~ m/SYSCALL_DEFINE0\s*\(\s*(a-zA-Z0-9_)*\s*\)/) { > - if ($prototype =~ m/SYSCALL_DEFINE0/) { > - $void = 1; > -## $prototype = "long sys_$1(void)"; > - } > - > - $prototype =~ s/SYSCALL_DEFINE.*\(/long sys_/; # fix return type & func > name > - if ($prototype =~ m/long (sys_.*?),/) { > - $prototype =~ s/,/\(/; > - } elsif ($void) { > - $prototype =~ s/\)/\(void\)/; > - } > - > - # now delete all of the odd-number commas in $prototype > - # so that arg types & arg names don't have a comma between them > - my $count = 0; > - my $len = length($prototype); > - if ($void) { > - $len = 0; # skip the for-loop > - } > - for (my $ix = 0; $ix < $len; $ix++) { > - if (substr($prototype, $ix, 1) eq ',') { > - $count++; > - if ($count % 2 == 1) { > - substr($prototype, $ix, 1) = ' '; > - } > - } > - } > -} > - > -sub process_proto_function($$) { > - my $x = shift; > - my $file = shift; > - > - $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line > - > - if ($x =~ m#\s*/\*\s+MACDOC\s*#io || ($x =~ /^#/ && $x !~ > /^#\s*define/)) { > - # do nothing > - } > - elsif ($x =~ /([^\{]*)/) { > - $prototype .= $1; > - } > - > - if (($x =~ /\{/) || ($x =~ /\#\s*define/) || ($x =~ /;/)) { > - $prototype =~ s@/\*.*?\*/@@gos; # strip comments. > - $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's. > - $prototype =~ s@^\s+@@gos; # strip leading spaces > - > - # Handle prototypes for function pointers like: > - # int (*pcs_config)(struct foo) > - $prototype =~ s@^(\S+\s+)\(\s*\*(\S+)\)@$1$2@gos; > - > - if ($prototype =~ /SYSCALL_DEFINE/) { > - syscall_munge(); > - } > - if ($prototype =~ /TRACE_EVENT/ || $prototype =~ /DEFINE_EVENT/ || > - $prototype =~ /DEFINE_SINGLE_EVENT/) > - { > - tracepoint_munge($file); > - } > - dump_function($prototype, $file); > - reset_state(); > - } > -} > - > -sub process_proto_type($$) { > - my $x = shift; > - my $file = shift; > - > - $x =~ s@[\r\n]+@ @gos; # strip newlines/cr's. > - $x =~ s@^\s+@@gos; # strip leading spaces > - $x =~ s@\s+$@@gos; # strip trailing spaces > - $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line > - > - if ($x =~ /^#/) { > - # To distinguish preprocessor directive from regular declaration later. > - $x .= ";"; > - } > - > - while (1) { > - if ( $x =~ /([^\{\};]*)([\{\};])(.*)/ ) { > - if( length $prototype ) { > - $prototype .= " " > - } > - $prototype .= $1 . $2; > - ($2 eq '{') && $brcount++; > - ($2 eq '}') && $brcount--; > - if (($2 eq ';') && ($brcount == 0)) { > - dump_declaration($prototype, $file); > - reset_state(); > - last; > - } > - $x = $3; > - } else { > - $prototype .= $x; > - last; > - } > - } > -} > - > - > -sub map_filename($) { > - my $file; > - my ($orig_file) = @_; > - > - if (defined($ENV{'SRCTREE'})) { > - $file = "$ENV{'SRCTREE'}" . "/" . $orig_file; > - } else { > - $file = $orig_file; > - } > - > - if (defined($source_map{$file})) { > - $file = $source_map{$file}; > - } > - > - return $file; > -} > - > -sub process_export_file($) { > - my ($orig_file) = @_; > - my $file = map_filename($orig_file); > - > - if (!open(IN,"<$file")) { > - print STDERR "Error: Cannot open file $file\n"; > - ++$errors; > - return; > - } > - > - while (<IN>) { > - if (/$export_symbol/) { > - next if (defined($nosymbol_table{$2})); > - $function_table{$2} = 1; > - } > - } > - > - close(IN); > -} > - > -# > -# Parsers for the various processing states. > -# > -# STATE_NORMAL: looking for the /** to begin everything. > -# > -sub process_normal() { > - if (/$doc_start/o) { > - $state = STATE_NAME; # next line is always the function name > - $in_doc_sect = 0; > - $declaration_start_line = $. + 1; > - } > -} > - > -# > -# STATE_NAME: Looking for the "name - description" line > -# > -sub process_name($$) { > - my $file = shift; > - my $identifier; > - my $descr; > - > - if (/$doc_block/o) { > - $state = STATE_DOCBLOCK; > - $contents = ""; > - $new_start_line = $.; > - > - if ( $1 eq "" ) { > - $section = $section_intro; > - } else { > - $section = $1; > - } > - } > - elsif (/$doc_decl/o) { > - $identifier = $1; > - if (/\s*([\w\s]+?)(\s*-|:)/) { > - $identifier = $1; > - } > - > - $state = STATE_BODY; > - # if there's no @param blocks need to set up default section > - # here > - $contents = ""; > - $section = $section_default; > - $new_start_line = $. + 1; > - if (/[-:](.*)/) { > - # strip leading/trailing/multiple spaces > - $descr= $1; > - $descr =~ s/^\s*//; > - $descr =~ s/\s*$//; > - $descr =~ s/\s+/ /g; > - $declaration_purpose = $descr; > - $state = STATE_BODY_MAYBE; > - } else { > - $declaration_purpose = ""; > - } > - > - if (($declaration_purpose eq "") && $verbose) { > - print STDERR "${file}:$.: warning: missing initial short > description on line:\n"; > - print STDERR $_; > - ++$warnings; > - } > - > - if ($identifier =~ m/^struct\b/) { > - $decl_type = 'struct'; > - } elsif ($identifier =~ m/^union\b/) { > - $decl_type = 'union'; > - } elsif ($identifier =~ m/^enum\b/) { > - $decl_type = 'enum'; > - } elsif ($identifier =~ m/^typedef\b/) { > - $decl_type = 'typedef'; > - } else { > - $decl_type = 'function'; > - } > - > - if ($verbose) { > - print STDERR "${file}:$.: info: Scanning doc for $identifier\n"; > - } > - } else { > - print STDERR "${file}:$.: warning: Cannot understand $_ on line $.", > - " - I thought it was a doc line\n"; > - ++$warnings; > - $state = STATE_NORMAL; > - } > -} > - > - > -# > -# STATE_BODY and STATE_BODY_MAYBE: the bulk of a kerneldoc comment. > -# > -sub process_body($$) { > - my $file = shift; > - > - # Until all named variable macro parameters are > - # documented using the bare name (`x`) rather than with > - # dots (`x...`), strip the dots: > - if ($section =~ /\w\.\.\.$/) { > - $section =~ s/\.\.\.$//; > - > - if ($verbose) { > - print STDERR "${file}:$.: warning: Variable macro arguments should > be documented without dots\n"; > - ++$warnings; > - } > - } > - > - if ($state == STATE_BODY_WITH_BLANK_LINE && /^\s*\*\s?\S/) { > - dump_section($file, $section, $contents); > - $section = $section_default; > - $new_start_line = $.; > - $contents = ""; > - } > - > - if (/$doc_sect/i) { # case insensitive for supported section names > - $newsection = $1; > - $newcontents = $2; > - > - # map the supported section names to the canonical names > - if ($newsection =~ m/^description$/i) { > - $newsection = $section_default; > - } elsif ($newsection =~ m/^context$/i) { > - $newsection = $section_context; > - } elsif ($newsection =~ m/^returns?$/i) { > - $newsection = $section_return; > - } elsif ($newsection =~ m/^\@return$/) { > - # special: @return is a section, not a param description > - $newsection = $section_return; > - } > - > - if (($contents ne "") && ($contents ne "\n")) { > - if (!$in_doc_sect && $verbose) { > - print STDERR "${file}:$.: warning: contents before sections\n"; > - ++$warnings; > - } > - dump_section($file, $section, $contents); > - $section = $section_default; > - } > - > - $in_doc_sect = 1; > - $state = STATE_BODY; > - $contents = $newcontents; > - $new_start_line = $.; > - while (substr($contents, 0, 1) eq " ") { > - $contents = substr($contents, 1); > - } > - if ($contents ne "") { > - $contents .= "\n"; > - } > - $section = $newsection; > - $leading_space = undef; > - } elsif (/$doc_end/) { > - if (($contents ne "") && ($contents ne "\n")) { > - dump_section($file, $section, $contents); > - $section = $section_default; > - $contents = ""; > - } > - # look for doc_com + <text> + doc_end: > - if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') { > - print STDERR "${file}:$.: warning: suspicious ending line: $_"; > - ++$warnings; > - } > - > - $prototype = ""; > - $state = STATE_PROTO; > - $brcount = 0; > - $new_start_line = $. + 1; > - } elsif (/$doc_content/) { > - if ($1 eq "") { > - if ($section eq $section_context) { > - dump_section($file, $section, $contents); > - $section = $section_default; > - $contents = ""; > - $new_start_line = $.; > - $state = STATE_BODY; > - } else { > - if ($section ne $section_default) { > - $state = STATE_BODY_WITH_BLANK_LINE; > - } else { > - $state = STATE_BODY; > - } > - $contents .= "\n"; > - } > - } elsif ($state == STATE_BODY_MAYBE) { > - # Continued declaration purpose > - chomp($declaration_purpose); > - $declaration_purpose .= " " . $1; > - $declaration_purpose =~ s/\s+/ /g; > - } else { > - my $cont = $1; > - if ($section =~ m/^@/ || $section eq $section_context) { > - if (!defined $leading_space) { > - if ($cont =~ m/^(\s+)/) { > - $leading_space = $1; > - } else { > - $leading_space = ""; > - } > - } > - $cont =~ s/^$leading_space//; > - } > - $contents .= $cont . "\n"; > - } > - } else { > - # i dont know - bad line? ignore. > - print STDERR "${file}:$.: warning: bad line: $_"; > - ++$warnings; > - } > -} > - > - > -# > -# STATE_PROTO: reading a function/whatever prototype. > -# > -sub process_proto($$) { > - my $file = shift; > - > - if (/$doc_inline_oneline/) { > - $section = $1; > - $contents = $2; > - if ($contents ne "") { > - $contents .= "\n"; > - dump_section($file, $section, $contents); > - $section = $section_default; > - $contents = ""; > - } > - } elsif (/$doc_inline_start/) { > - $state = STATE_INLINE; > - $inline_doc_state = STATE_INLINE_NAME; > - } elsif ($decl_type eq 'function') { > - process_proto_function($_, $file); > - } else { > - process_proto_type($_, $file); > - } > -} > - > -# > -# STATE_DOCBLOCK: within a DOC: block. > -# > -sub process_docblock($$) { > - my $file = shift; > - > - if (/$doc_end/) { > - dump_doc_section($file, $section, $contents); > - $section = $section_default; > - $contents = ""; > - $function = ""; > - %parameterdescs = (); > - %parametertypes = (); > - @parameterlist = (); > - %sections = (); > - @sectionlist = (); > - $prototype = ""; > - $state = STATE_NORMAL; > - } elsif (/$doc_content/) { > - if ( $1 eq "" ) { > - $contents .= $blankline; > - } else { > - $contents .= $1 . "\n"; > - } > - } > -} > - > -# > -# STATE_INLINE: docbook comments within a prototype. > -# > -sub process_inline($$) { > - my $file = shift; > - > - # First line (state 1) needs to be a @parameter > - if ($inline_doc_state == STATE_INLINE_NAME && /$doc_inline_sect/o) { > - $section = $1; > - $contents = $2; > - $new_start_line = $.; > - if ($contents ne "") { > - while (substr($contents, 0, 1) eq " ") { > - $contents = substr($contents, 1); > - } > - $contents .= "\n"; > - } > - $inline_doc_state = STATE_INLINE_TEXT; > - # Documentation block end */ > - } elsif (/$doc_inline_end/) { > - if (($contents ne "") && ($contents ne "\n")) { > - dump_section($file, $section, $contents); > - $section = $section_default; > - $contents = ""; > - } > - $state = STATE_PROTO; > - $inline_doc_state = STATE_INLINE_NA; > - # Regular text > - } elsif (/$doc_content/) { > - if ($inline_doc_state == STATE_INLINE_TEXT) { > - $contents .= $1 . "\n"; > - # nuke leading blank lines > - if ($contents =~ /^\s*$/) { > - $contents = ""; > - } > - } elsif ($inline_doc_state == STATE_INLINE_NAME) { > - $inline_doc_state = STATE_INLINE_ERROR; > - print STDERR "${file}:$.: warning: "; > - print STDERR "Incorrect use of kernel-doc format: $_"; > - ++$warnings; > - } > - } > -} > - > - > -sub process_file($) { > - my $file; > - my $initial_section_counter = $section_counter; > - my ($orig_file) = @_; > - > - $file = map_filename($orig_file); > - > - if (!open(IN_FILE,"<$file")) { > - print STDERR "Error: Cannot open file $file\n"; > - ++$errors; > - return; > - } > - > - $. = 1; > - > - $section_counter = 0; > - while (<IN_FILE>) { > - while (s/\\\s*$//) { > - $_ .= <IN_FILE>; > - } > - # Replace tabs by spaces > - while ($_ =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}; > - # Hand this line to the appropriate state handler > - if ($state == STATE_NORMAL) { > - process_normal(); > - } elsif ($state == STATE_NAME) { > - process_name($file, $_); > - } elsif ($state == STATE_BODY || $state == STATE_BODY_MAYBE || > - $state == STATE_BODY_WITH_BLANK_LINE) { > - process_body($file, $_); > - } elsif ($state == STATE_INLINE) { # scanning for inline parameters > - process_inline($file, $_); > - } elsif ($state == STATE_PROTO) { > - process_proto($file, $_); > - } elsif ($state == STATE_DOCBLOCK) { > - process_docblock($file, $_); > - } > - } > - > - # Make sure we got something interesting. > - if ($initial_section_counter == $section_counter && $ > - output_mode ne "none") { > - if ($output_selection == OUTPUT_INCLUDE) { > - print STDERR "${file}:1: warning: '$_' not found\n" > - for keys %function_table; > - } > - else { > - print STDERR "${file}:1: warning: no structured comments found\n"; > - } > - } > - close IN_FILE; > -} > - > - > -if ($output_mode eq "rst") { > - get_sphinx_version() if (!$sphinx_major); > -} > - > -$kernelversion = get_kernel_version(); > - > -# generate a sequence of code that will splice in highlighting information > -# using the s// operator. > -for (my $k = 0; $k < @highlights; $k++) { > - my $pattern = $highlights[$k][0]; > - my $result = $highlights[$k][1]; > -# print STDERR "scanning pattern:$pattern, highlight:($result)\n"; > - $dohighlight .= "\$contents =~ s:$pattern:$result:gs;\n"; > -} > - > -# Read the file that maps relative names to absolute names for > -# separate source and object directories and for shadow trees. > -if (open(SOURCE_MAP, "<.tmp_filelist.txt")) { > - my ($relname, $absname); > - while(<SOURCE_MAP>) { > - chop(); > - ($relname, $absname) = (split())[0..1]; > - $relname =~ s:^/+::; > - $source_map{$relname} = $absname; > - } > - close(SOURCE_MAP); > -} > - > -if ($output_selection == OUTPUT_EXPORTED || > - $output_selection == OUTPUT_INTERNAL) { > - > - push(@export_file_list, @ARGV); > - > - foreach (@export_file_list) { > - chomp; > - process_export_file($_); > - } > -} > - > -foreach (@ARGV) { > - chomp; > - process_file($_); > -} > -if ($verbose && $errors) { > - print STDERR "$errors errors\n"; > -} > -if ($verbose && $warnings) { > - print STDERR "$warnings warnings\n"; > -} > - > -if ($Werror && $warnings) { > - print STDERR "$warnings warnings as Errors\n"; > - exit($warnings); > -} else { > - exit($output_mode eq "none" ? 0 : $errors) > -} Thanks, Mauro