#!/usr/bin/env perl# SPDX-License-Identifier: GPL-2.0# vim: softtabstop=4 use warnings;use strict; ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved #### Copyright (C) 2000, 1 Tim Waugh <twaugh@redhat.com> #### Copyright (C) 2001 Simon Huggins #### Copyright (C) 2005-2012 Randy Dunlap #### Copyright (C) 2012 Dan Luedtke #### #### #define enhancements by Armin Kuster <akuster@mvista.com> #### Copyright (c) 2000 MontaVista Software, Inc. #### Copyright (C) 2022 Tomasz Warniełło (POD) use Pod::Usage qw/pod2usage/; =head1 NAME kernel-doc - Print formatted kernel documentation to stdout =head1 SYNOPSIS kernel-doc [-h] [-v] [-Werror] [-Wall] [-Wreturn] [-Wshort-desc[ription]] [-Wcontents-before-sections] [ -man | -rst [-sphinx-version VERSION] [-enable-lineno] | -none ] [ -export | -internal | [-function NAME] ... | [-nosymbol NAME] ... ] [-no-doc-sections] [-export-file FILE] ... FILE ... Run `kernel-doc -h` for details. =head1 DESCRIPTION Read C language source or header FILEs, extract embedded documentation comments,and print formatted documentation to standard output. The documentation comments are identified by the "/**" opening comment mark. See Documentation/doc-guide/kernel-doc.rst for the documentation comment syntax. =cut # more perldoc at the end of the file ## init lots of data my $errors = 0;my $warnings = 0;my $anon_struct_union = 0; # match expressions used to find embedded type informationmy $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 paramsmy $type_fp_param2 = '\@(\w+->\S+)\(\)'; # Special RST handling for structs with func ptr paramsmy $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_member_func = $type_member . '\(\)'; # Output conversion substitutions.# One for each output format # these are pretty roughmy @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-modemy @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 argumentsif ($#ARGV == -1) { pod2usage( -message => "No arguments!\n", -exitval => 1, -verbose => 99, -sections => 'SYNOPSIS', -output => \*STDERR, );} my $kernelversion;my ($sphinx_major, $sphinx_minor, $sphinx_patch); my $dohighlight = ""; my $verbose = 0;my $Werror = 0;my $Wreturn = 0;my $Wshort_desc = 0;my $Wcontents_before_sections = 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'}) && $ENV{'KBUILD_VERBOSE'} =~ '1') { $verbose = 1;} if (defined($ENV{'KCFLAGS'})) { my $kcflags = "$ENV{'KCFLAGS'}"; if ($kcflags =~ /(\s|^)-Werror(\s|$)/) { $Werror = 1; }} # reading this variable is for backwards compat just in case# someone was calling it with the variable from outside the# kernel's build systemif (defined($ENV{'KDOC_WERROR'})) { $Werror = "$ENV{'KDOC_WERROR'}";}# other environment variables are converted to command-line# arguments in cmd_checkdoc in the build system # 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 statesuse 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 stateuse 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; # Name of the kernel-doc identifier for non-DOC markupsmy $identifier; 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# Specifically:# Match @word:# @...:# @{section-name}:# while trying to not match literal block starts like "example::"#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 $export_symbol_ns = '^\s*EXPORT_SYMBOL_NS(_GPL)?\s*\(\s*(\w+)\s*,\s*\w+\)\s*;';my $function_pointer = qr{([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)};my $attribute = qr{__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)}i; 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 sectionmy $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 "Wreturn") { $Wreturn = 1; } elsif ($cmd eq "Wshort-desc" or $cmd eq "Wshort-description") { $Wshort_desc = 1; } elsif ($cmd eq "Wcontents-before-sections") { $Wcontents_before_sections = 1; } elsif ($cmd eq "Wall") { $Wreturn = 1; $Wshort_desc = 1; $Wcontents_before_sections = 1; } elsif (($cmd eq "h") || ($cmd eq "help")) { pod2usage(-exitval => 0, -verbose => 2); } 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 pod2usage( -message => "Argument unknown!\n", -exitval => 1, -verbose => 99, -sections => 'SYNOPSIS', -output => \*STDERR, ); } if ($#ARGV < 0){ pod2usage( -message => "FILE argument missing\n", -exitval => 1, -verbose => 99, -sections => 'SYNOPSIS', -output => \*STDERR, ); }} # 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 envsub 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 ".. LINENO " . $lineno . "\n"; }} sub emit_warning { my $location = shift; my $msg = shift; print STDERR "$location: warning: $msg"; ++$warnings;}### 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) { emit_warning("${file}:$.", "duplicate section name '$name'\n"); } $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;Lines 1–500 of 2545. Load more
#!/usr/bin/env perl # SPDX-License-Identifier: GPL-2.0 # vim: softtabstop=4 use warnings; use strict; ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved ## ## Copyright (C) 2000, 1 Tim Waugh <twaugh@redhat.com> ## ## Copyright (C) 2001 Simon Huggins ## ## Copyright (C) 2005-2012 Randy Dunlap ## ## Copyright (C) 2012 Dan Luedtke ## ## ## ## #define enhancements by Armin Kuster <akuster@mvista.com> ## ## Copyright (c) 2000 MontaVista Software, Inc. ## # # Copyright (C) 2022 Tomasz Warniełło (POD) use Pod::Usage qw/pod2usage/; =head1 NAME kernel-doc - Print formatted kernel documentation to stdout =head1 SYNOPSIS kernel-doc [-h] [-v] [-Werror] [-Wall] [-Wreturn] [-Wshort-desc[ription]] [-Wcontents-before-sections] [ -man | -rst [-sphinx-version VERSION] [-enable-lineno] | -none ] [ -export | -internal | [-function NAME] ... | [-nosymbol NAME] ... ] [-no-doc-sections] [-export-file FILE] ... FILE ... Run `kernel-doc -h` for details. =head1 DESCRIPTION Read C language source or header FILEs, extract embedded documentation comments, and print formatted documentation to standard output. The documentation comments are identified by the "/**" opening comment mark. See Documentation/doc-guide/kernel-doc.rst for the documentation comment syntax. =cut # more perldoc at the end of the file ## 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 = '\&(typedef\s*([_\w]+))'; my $type_union = '\&(union\s*([_\w]+))'; my $type_member = '\&([_\w]+)(\.|->)([_\w]+)'; my $type_fallback = '\&([_\w]+)'; 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) { pod2usage( -message => "No arguments!\n", -exitval => 1, -verbose => 99, -sections => 'SYNOPSIS', -output => \*STDERR, ); } my $kernelversion; my ($sphinx_major, $sphinx_minor, $sphinx_patch); my $dohighlight = ""; my $verbose = 0; my $Werror = 0; my $Wreturn = 0; my $Wshort_desc = 0; my $Wcontents_before_sections = 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'}) && $ENV{'KBUILD_VERBOSE'} =~ '1') { $verbose = 1; } if (defined($ENV{'KCFLAGS'})) { my $kcflags = "$ENV{'KCFLAGS'}"; if ($kcflags =~ /(\s|^)-Werror(\s|$)/) { $Werror = 1; } } # reading this variable is for backwards compat just in case # someone was calling it with the variable from outside the # kernel's build system if (defined($ENV{'KDOC_WERROR'})) { $Werror = "$ENV{'KDOC_WERROR'}"; } # other environment variables are converted to command-line # arguments in cmd_checkdoc in the build system # 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; # Name of the kernel-doc identifier for non-DOC markups my $identifier; 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 # Specifically: # Match @word: # @...: # @{section-name}: # while trying to not match literal block starts like "example::" # 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 $export_symbol_ns = '^\s*EXPORT_SYMBOL_NS(_GPL)?\s*\(\s*(\w+)\s*,\s*\w+\)\s*;'; my $function_pointer = qr{([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)}; my $attribute = qr{__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)}i; 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 "Wreturn") { $Wreturn = 1; } elsif ($cmd eq "Wshort-desc" or $cmd eq "Wshort-description") { $Wshort_desc = 1; } elsif ($cmd eq "Wcontents-before-sections") { $Wcontents_before_sections = 1; } elsif ($cmd eq "Wall") { $Wreturn = 1; $Wshort_desc = 1; $Wcontents_before_sections = 1; } elsif (($cmd eq "h") || ($cmd eq "help")) { pod2usage(-exitval => 0, -verbose => 2); } 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 pod2usage( -message => "Argument unknown!\n", -exitval => 1, -verbose => 99, -sections => 'SYNOPSIS', -output => \*STDERR, ); } if ($#ARGV < 0){ pod2usage( -message => "FILE argument missing\n", -exitval => 1, -verbose => 99, -sections => 'SYNOPSIS', -output => \*STDERR, ); } } # 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 ".. LINENO " . $lineno . "\n"; } } sub emit_warning { my $location = shift; my $msg = shift; print STDERR "$location: warning: $msg"; ++$warnings; } ## # 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) { emit_warning("${file}:$.", "duplicate section name '$name'\n"); } $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;