X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=scripts%2Fkernel-doc;h=3208a3a7e7fe5e3f9ad07a20a5bb9827d099d5ae;hb=7eef4091a653c243a87e5375c54504cc03bec4d8;hp=35d7fd9a1e657af651fc5e14fc7fec741487085f;hpb=891dcd2f7ab15e2aaad07f6925b3a53fd8d5c02f;p=safe%2Fjmp%2Flinux-2.6 diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 35d7fd9..3208a3a 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -5,6 +5,7 @@ use strict; ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved ## ## Copyright (C) 2000, 1 Tim Waugh ## ## Copyright (C) 2001 Simon Huggins ## +## Copyright (C) 2005-2008 Randy Dunlap ## ## ## ## #define enhancements by Armin Kuster ## ## Copyright (c) 2000 MontaVista Software, Inc. ## @@ -45,21 +46,24 @@ use strict; # Note: This only supports 'c'. # usage: -# kernel-doc [ -docbook | -html | -text | -man ] +# kernel-doc [ -docbook | -html | -text | -man ] [ -no-doc-sections ] # [ -function funcname [ -function funcname ...] ] c file(s)s > outputfile # or # [ -nofunction funcname [ -function funcname ...] ] c file(s)s > outputfile # # Set output format using one of -docbook -html -text or -man. Default is man. # +# -no-doc-sections +# Do not output DOC: sections +# # -function funcname -# If set, then only generate documentation for the given function(s). All -# other functions are ignored. +# If set, then only generate documentation for the given function(s) or +# DOC: section titles. All other functions and DOC: sections are ignored. # # -nofunction funcname -# If set, then only generate documentation for the other function(s). -# Cannot be used together with -function -# (yes, that's a bug -- perl hackers can fix it 8)) +# If set, then only generate documentation for the other function(s)/DOC: +# sections. Cannot be used together with -function (yes, that's a bug -- +# perl hackers can fix it 8)) # # c files - list of 'c' files to process # @@ -154,12 +158,14 @@ use strict; my $errors = 0; my $warnings = 0; +my $anon_struct_union = 0; # match expressions used to find embedded type information my $type_constant = '\%([-_\w]+)'; my $type_func = '(\w+)\(\)'; my $type_param = '\@(\w+)'; -my $type_struct = '\&((struct\s*)?[_\w]+)'; +my $type_struct = '\&((struct\s*)*[_\w]+)'; +my $type_struct_xml = '\\&((struct\s*)*[_\w]+)'; my $type_env = '(\$\w+)'; # Output conversion substitutions. @@ -168,18 +174,21 @@ my $type_env = '(\$\w+)'; # these work fairly well my %highlights_html = ( $type_constant, "\$1", $type_func, "\$1", - $type_struct, "\$1", + $type_struct_xml, "\$1", + $type_env, "\$1", $type_param, "\$1" ); -my $blankline_html = "

"; +my $local_lt = "\\\\\\\\lt:"; +my $local_gt = "\\\\\\\\gt:"; +my $blankline_html = $local_lt . "p" . $local_gt; # was "

" # XML, docbook format my %highlights_xml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1\$2", $type_constant, "\$1", $type_func, "\$1", - $type_struct, "\$1", + $type_struct_xml, "\$1", $type_env, "\$1", $type_param, "\$1" ); -my $blankline_xml = "\n"; +my $blankline_xml = $local_lt . "/para" . $local_gt . $local_lt . "para" . $local_gt . "\n"; # gnome, docbook format my %highlights_gnome = ( $type_constant, "\$1", @@ -205,10 +214,11 @@ my $blankline_text = ""; sub usage { - print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man ]\n"; + print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man ] [ -no-doc-sections ]\n"; print " [ -function funcname [ -function funcname ...] ]\n"; print " [ -nofunction funcname [ -nofunction funcname ...] ]\n"; print " c source file(s) > outputfile\n"; + print " -v : verbose output, more warnings & other info listed\n"; exit 1; } @@ -219,6 +229,7 @@ if ($#ARGV==-1) { my $verbose = 0; my $output_mode = "man"; +my $no_doc_sections = 0; my %highlights = %highlights_man; my $blankline = $blankline_man; my $modulename = "Kernel API"; @@ -236,6 +247,10 @@ my ($function, %function_table,%parametertypes,$declaration_purpose); my ($type,$declaration_name,$return_type); my ($newsection,$newcontents,$prototype,$filelist, $brcount, %source_map); +if (defined($ENV{'KBUILD_VERBOSE'})) { + $verbose = "$ENV{'KBUILD_VERBOSE'}"; +} + # Generated docbook code is inserted in a template at a point where # docbook v3.1 requires a non-zero sequence of RefEntry's; see: # http://www.oasis-open.org/docbook/documentation/reference/html/refentry.html @@ -274,6 +289,8 @@ my %parameterdescs; my @parameterlist; my %sections; my @sectionlist; +my $sectcheck; +my $struct_actual; my $contents = ""; my $section_default = "Description"; # default section @@ -323,15 +340,27 @@ while ($ARGV[0] =~ m/^-(.*)/) { usage(); } elsif ($cmd eq '-filelist') { $filelist = shift @ARGV; + } elsif ($cmd eq '-no-doc-sections') { + $no_doc_sections = 1; } } +# get kernel version from env +sub get_kernel_version() { + my $version = 'unknown kernel version'; + + if (defined($ENV{'KERNELVERSION'})) { + $version = $ENV{'KERNELVERSION'}; + } + return $version; +} +my $kernelversion = get_kernel_version(); # generate a sequence of code that will splice in highlighting information # using the s// operator. my $dohighlight = ""; foreach my $pattern (keys %highlights) { -# print "scanning pattern $pattern ($highlights{$pattern})\n"; +# print STDERR "scanning pattern:$pattern, highlight:($highlights{$pattern})\n"; $dohighlight .= "\$contents =~ s:$pattern:$highlights{$pattern}:gs;\n"; } @@ -339,6 +368,7 @@ foreach my $pattern (keys %highlights) { # dumps section contents to arrays/hashes intended for that purpose. # sub dump_section { + my $file = shift; my $name = shift; my $contents = join "\n", @_; @@ -350,14 +380,48 @@ sub dump_section { # print STDERR "parameter def '$1' = '$contents'\n"; $name = $1; $parameterdescs{$name} = $contents; + $sectcheck = $sectcheck . $name . " "; + } elsif ($name eq "@\.\.\.") { +# print STDERR "parameter def '...' = '$contents'\n"; + $name = "..."; + $parameterdescs{$name} = $contents; + $sectcheck = $sectcheck . $name . " "; } else { # print STDERR "other section '$name' = '$contents'\n"; + if (defined($sections{$name}) && ($sections{$name} ne "")) { + print STDERR "Error(${file}:$.): duplicate section name '$name'\n"; + ++$errors; + } $sections{$name} = $contents; push @sectionlist, $name; } } ## +# 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; + } + + if (($function_only == 0) || + ( $function_only == 1 && defined($function_table{$name})) || + ( $function_only == 2 && !defined($function_table{$name}))) + { + dump_section($file, $name, $contents); + output_blockhead({'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'module' => $modulename, + 'content-only' => ($function_only != 0), }); + } +} + +## # output function # # parameterdescs, a hash. @@ -365,7 +429,7 @@ sub dump_section { # parameterlist => @list of parameters # parameterdescs => %parameter descriptions # sectionlist => @list of sections -# sections => %descriont descriptions +# sections => %section descriptions # sub output_highlight { @@ -378,14 +442,26 @@ sub output_highlight { # confess "output_highlight got called with no args?\n"; # } + if ($output_mode eq "html" || $output_mode eq "xml") { + $contents = local_unescape($contents); + # convert data read & converted thru xml_escape() into &xyz; format: + $contents =~ s/\\\\\\/&/g; + } +# print STDERR "contents b4:$contents\n"; eval $dohighlight; die $@ if $@; +# print STDERR "contents af:$contents\n"; + foreach $line (split "\n", $contents) { - if ($line eq ""){ - print $lineprefix, $blankline; + if ($line eq ""){ + print $lineprefix, local_unescape($blankline); } else { - $line =~ s/\\\\\\/\&/g; - print $lineprefix, $line; + $line =~ s/\\\\\\/\&/g; + if ($output_mode eq "man" && substr($line, 0, 1) eq ".") { + print "\\&$line"; + } else { + print $lineprefix, $line; + } } print "\n"; } @@ -414,7 +490,7 @@ sub output_enum_html(%) { print "enum ".$args{'enum'}." {
\n"; $count = 0; foreach $parameter (@{$args{'parameterlist'}}) { - print " ".$parameter.""; + print " ".$parameter.""; if ($count != $#{$args{'parameterlist'}}) { $count++; print ",\n"; @@ -452,7 +528,7 @@ sub output_struct_html(%) { my %args = %{$_[0]}; my ($parameter); - print "

".$args{'type'}." ".$args{'struct'}."

\n"; + print "

".$args{'type'}." ".$args{'struct'}. " - " .$args{'purpose'}."

\n"; print "".$args{'type'}." ".$args{'struct'}." {
\n"; foreach $parameter (@{$args{'parameterlist'}}) { if ($parameter =~ /^#/) { @@ -462,15 +538,16 @@ sub output_struct_html(%) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function - print " $1$parameter) ($2);
\n"; + print "    $1$parameter) ($2);
\n"; } elsif ($type =~ m/^(.*?)\s*(:.*)/) { - print " $1 $parameter$2;
\n"; + # bitfield + print "    $1 $parameter$2;
\n"; } else { - print " $type $parameter;
\n"; + print "    $type $parameter;
\n"; } } print "};
\n"; @@ -483,7 +560,7 @@ sub output_struct_html(%) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; print "
".$parameter."\n"; print "
"; output_highlight($args{'parameterdescs'}{$parameter_name}); @@ -498,8 +575,8 @@ sub output_function_html(%) { my %args = %{$_[0]}; my ($parameter, $section); my $count; - print "

Function

\n"; + print "

" .$args{'function'}." - ".$args{'purpose'}."

\n"; print "".$args{'functiontype'}."\n"; print "".$args{'function'}."\n"; print "("; @@ -525,7 +602,7 @@ sub output_function_html(%) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; print "
".$parameter."\n"; print "
"; output_highlight($args{'parameterdescs'}{$parameter_name}); @@ -535,8 +612,8 @@ sub output_function_html(%) { print "
\n"; } -# output intro in html -sub output_intro_html(%) { +# output DOC: block header in html +sub output_blockhead_html(%) { my %args = %{$_[0]}; my ($parameter, $section); my $count; @@ -592,6 +669,7 @@ sub output_function_xml(%) { print "\n"; print " ".$args{'function'}."\n"; print " 9\n"; + print " " . $kernelversion . "\n"; print "\n"; print "\n"; print " ".$args{'function'}."\n"; @@ -668,6 +746,7 @@ sub output_struct_xml(%) { print "\n"; print " ".$args{'type'}." ".$args{'struct'}."\n"; print " 9\n"; + print " " . $kernelversion . "\n"; print "\n"; print "\n"; print " ".$args{'type'}." ".$args{'struct'}."\n"; @@ -691,12 +770,13 @@ sub output_struct_xml(%) { $parameter_name =~ s/\[.*//; defined($args{'parameterdescs'}{$parameter_name}) || next; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function print " $1 $parameter) ($2);\n"; } elsif ($type =~ m/^(.*?)\s*(:.*)/) { + # bitfield print " $1 $parameter$2;\n"; } else { print " ".$type." ".$parameter.";\n"; @@ -709,6 +789,7 @@ sub output_struct_xml(%) { print " \n"; print " Members\n"; + if ($#{$args{'parameterlist'}} >= 0) { print " \n"; foreach $parameter (@{$args{'parameterlist'}}) { ($parameter =~ /^#/) && next; @@ -726,6 +807,9 @@ sub output_struct_xml(%) { print " \n"; } print " \n"; + } else { + print " \n None\n \n"; + } print " \n"; output_section_xml(@_); @@ -752,6 +836,7 @@ sub output_enum_xml(%) { print "\n"; print " enum ".$args{'enum'}."\n"; print " 9\n"; + print " " . $kernelversion . "\n"; print "\n"; print "\n"; print " enum ".$args{'enum'}."\n"; @@ -767,11 +852,11 @@ sub output_enum_xml(%) { print "enum ".$args{'enum'}." {\n"; $count = 0; foreach $parameter (@{$args{'parameterlist'}}) { - print " $parameter"; - if ($count != $#{$args{'parameterlist'}}) { + print " $parameter"; + if ($count != $#{$args{'parameterlist'}}) { $count++; print ","; - } + } print "\n"; } print "};"; @@ -838,7 +923,7 @@ sub output_typedef_xml(%) { } # output in XML DocBook -sub output_intro_xml(%) { +sub output_blockhead_xml(%) { my %args = %{$_[0]}; my ($parameter, $section); my $count; @@ -849,15 +934,23 @@ sub output_intro_xml(%) { # print out each section $lineprefix=" "; foreach $section (@{$args{'sectionlist'}}) { - print "\n $section\n \n"; + if (!$args{'content-only'}) { + print "\n $section\n"; + } if ($section =~ m/EXAMPLE/i) { print "\n"; + } else { + print "\n"; } output_highlight($args{'sections'}{$section}); if ($section =~ m/EXAMPLE/i) { print "\n"; + } else { + print ""; + } + if (!$args{'content-only'}) { + print "\n\n"; } - print " \n\n"; } print "\n\n"; @@ -953,7 +1046,11 @@ sub output_function_man(%) { print $args{'function'}." \\- ".$args{'purpose'}."\n"; print ".SH SYNOPSIS\n"; - print ".B \"".$args{'functiontype'}."\" ".$args{'function'}."\n"; + if ($args{'functiontype'} ne "") { + print ".B \"".$args{'functiontype'}."\" ".$args{'function'}."\n"; + } else { + print ".B \"".$args{'function'}."\n"; + } $count = 0; my $parenth = "("; my $post = ","; @@ -1003,7 +1100,7 @@ sub output_enum_man(%) { print "enum ".$args{'enum'}." {\n"; $count = 0; foreach my $parameter (@{$args{'parameterlist'}}) { - print ".br\n.BI \" $parameter\"\n"; + print ".br\n.BI \" $parameter\"\n"; if ($count == $#{$args{'parameterlist'}}) { print "\n};\n"; last; @@ -1050,7 +1147,7 @@ sub output_struct_man(%) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function @@ -1073,7 +1170,7 @@ sub output_struct_man(%) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; print ".IP \"".$parameter."\" 12\n"; output_highlight($args{'parameterdescs'}{$parameter_name}); } @@ -1100,7 +1197,7 @@ sub output_typedef_man(%) { } } -sub output_intro_man(%) { +sub output_blockhead_man(%) { my %args = %{$_[0]}; my ($parameter, $section); my $count; @@ -1118,13 +1215,19 @@ sub output_intro_man(%) { sub output_function_text(%) { my %args = %{$_[0]}; my ($parameter, $section); + my $start; print "Name:\n\n"; print $args{'function'}." - ".$args{'purpose'}."\n"; print "\nSynopsis:\n\n"; - my $start=$args{'functiontype'}." ".$args{'function'}." ("; + if ($args{'functiontype'} ne "") { + $start = $args{'functiontype'}." ".$args{'function'}." ("; + } else { + $start = $args{'function'}." ("; + } print $start; + my $count = 0; foreach my $parameter (@{$args{'parameterlist'}}) { $type = $args{'parametertypes'}{$parameter}; @@ -1177,7 +1280,7 @@ sub output_enum_text(%) { print "enum ".$args{'enum'}." {\n"; $count = 0; foreach $parameter (@{$args{'parameterlist'}}) { - print "\t$parameter"; + print "\t$parameter"; if ($count != $#{$args{'parameterlist'}}) { $count++; print ","; @@ -1222,12 +1325,13 @@ sub output_struct_text(%) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function print "\t$1 $parameter) ($2);\n"; } elsif ($type =~ m/^(.*?)\s*(:.*)/) { + # bitfield print "\t$1 $parameter$2;\n"; } else { print "\t".$type." ".$parameter.";\n"; @@ -1242,7 +1346,7 @@ sub output_struct_text(%) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; print "$parameter\n\t"; print $args{'parameterdescs'}{$parameter_name}."\n"; } @@ -1250,7 +1354,7 @@ sub output_struct_text(%) { output_section_text(@_); } -sub output_intro_text(%) { +sub output_blockhead_text(%) { my %args = %{$_[0]}; my ($parameter, $section); @@ -1274,16 +1378,16 @@ sub output_declaration { ( $function_only == 1 && defined($function_table{$name})) || ( $function_only == 2 && !defined($function_table{$name}))) { - &$func(@_); + &$func(@_); $section_counter++; } } ## # generic output function - calls the right one based on current output mode. -sub output_intro { +sub output_blockhead { no strict 'refs'; - my $func = "output_intro_".$output_mode; + my $func = "output_blockhead_".$output_mode; &$func(@_); $section_counter++; } @@ -1305,21 +1409,26 @@ sub dump_union($$) { sub dump_struct($$) { my $x = shift; my $file = shift; + my $nested; - if ($x =~/(struct|union)\s+(\w+)\s*{(.*)}/) { - $declaration_name = $2; - my $members = $3; + if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) { + #my $decl_type = $1; + $declaration_name = $2; + my $members = $3; # ignore embedded structs or unions - $members =~ s/{.*?}//g; + $members =~ s/({.*})//g; + $nested = $1; # ignore members marked private: - $members =~ s/\/\*.*?private:.*?public:.*?\*\///gos; - $members =~ s/\/\*.*?private:.*//gos; + $members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gos; + $members =~ s/\/\*\s*private:.*//gos; # strip comments: $members =~ s/\/\*.*?\*\///gos; + $nested =~ s/\/\*.*?\*\///gos; create_parameterlist($members, ';', $file); + check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested); output_declaration($declaration_name, 'struct', @@ -1335,7 +1444,7 @@ sub dump_struct($$) { }); } else { - print STDERR "Error(${file}:$.): Cannot parse struct or union!\n"; + print STDERR "Error(${file}:$.): Cannot parse struct or union!\n"; ++$errors; } } @@ -1346,15 +1455,15 @@ sub dump_enum($$) { $x =~ s@/\*.*?\*/@@gos; # strip comments. if ($x =~ /enum\s+(\w+)\s*{(.*)}/) { - $declaration_name = $1; - my $members = $2; + $declaration_name = $1; + my $members = $2; foreach my $arg (split ',', $members) { $arg =~ s/^\s*(\w+).*/$1/; push @parameterlist, $arg; if (!$parameterdescs{$arg}) { - $parameterdescs{$arg} = $undescribed; - print STDERR "Warning(${file}:$.): Enum value '$arg' ". + $parameterdescs{$arg} = $undescribed; + print STDERR "Warning(${file}:$.): Enum value '$arg' ". "not described in enum '$declaration_name'\n"; } @@ -1372,7 +1481,7 @@ sub dump_enum($$) { }); } else { - print STDERR "Error(${file}:$.): Cannot parse enum!\n"; + print STDERR "Error(${file}:$.): Cannot parse enum!\n"; ++$errors; } } @@ -1383,12 +1492,12 @@ sub dump_typedef($$) { $x =~ s@/\*.*?\*/@@gos; # strip comments. while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) { - $x =~ s/\(*.\)\s*;$/;/; + $x =~ s/\(*.\)\s*;$/;/; $x =~ s/\[*.\]\s*;$/;/; } if ($x =~ /typedef.*\s+(\w+)\s*;/) { - $declaration_name = $1; + $declaration_name = $1; output_declaration($declaration_name, 'typedef', @@ -1400,11 +1509,19 @@ sub dump_typedef($$) { }); } else { - print STDERR "Error(${file}:$.): Cannot parse typedef!\n"; + print STDERR "Error(${file}:$.): 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; @@ -1414,14 +1531,14 @@ sub create_parameterlist($$$) { # temporarily replace commas inside function pointer definition while ($args =~ /(\([^\),]+),/) { - $args =~ s/(\([^\),]+),/$1#/g; + $args =~ s/(\([^\),]+),/$1#/g; } foreach my $arg (split($splitter, $args)) { # strip comments $arg =~ s/\/\*.*\*\///; - # strip leading/trailing spaces - $arg =~ s/^\s*//; + # strip leading/trailing spaces + $arg =~ s/^\s*//; $arg =~ s/\s*$//; $arg =~ s/\s+/ /; @@ -1430,13 +1547,14 @@ sub create_parameterlist($$$) { # corresponding data structures "correctly". Catch it later in # output_* subs. push_parameter($arg, "", $file); - } elsif ($arg =~ m/\(.*\*/) { + } elsif ($arg =~ m/\(.+\)\s*\(/) { # pointer-to-function $arg =~ tr/#/,/; - $arg =~ m/[^\(]+\(\*([^\)]+)\)/; + $arg =~ m/[^\(]+\(\*?\s*(\w*)\s*\)/; $param = $1; $type = $arg; - $type =~ s/([^\(]+\(\*)$param/$1/; + $type =~ s/([^\(]+\(\*?)\s*$param/$1/; + save_struct_actual($param); push_parameter($param, $type, $file); } elsif ($arg) { $arg =~ s/\s*:\s*/:/g; @@ -1446,18 +1564,32 @@ sub create_parameterlist($$$) { if ($args[0] =~ m/\*/) { $args[0] =~ s/(\*+)\s*/ $1/; } - my @first_arg = split('\s+', shift @args); + + 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", $file); } elsif ($param =~ m/(.*?):(\d+)/) { - push_parameter($1, "$type:$2", $file) + if ($type ne "") { # skip unnamed bit-fields + save_struct_actual($1); + push_parameter($1, "$type:$2", $file) + } } else { + save_struct_actual($param); push_parameter($param, $type, $file); } } @@ -1469,19 +1601,24 @@ sub push_parameter($$$) { my $param = shift; my $type = shift; my $file = shift; - my $anon = 0; + if (($anon_struct_union == 1) && ($type eq "") && + ($param eq "}")) { + return; # ignore the ending }; from anon. struct/union + } + + $anon_struct_union = 0; my $param_name = $param; $param_name =~ s/\[.*//; if ($type eq "" && $param =~ /\.\.\.$/) { - $type=""; - $parameterdescs{$param} = "variable arguments"; + if (!defined $parameterdescs{$param} || $parameterdescs{$param} eq "") { + $parameterdescs{$param} = "variable arguments"; + } } elsif ($type eq "" && ($param eq "" or $param eq "void")) { - $type=""; $param="void"; $parameterdescs{void} = "no arguments"; } @@ -1489,35 +1626,75 @@ sub push_parameter($$$) { # handle unnamed (anonymous) union or struct: { $type = $param; - $param = "{unnamed_" . $param. "}"; + $param = "{unnamed_" . $param . "}"; $parameterdescs{$param} = "anonymous\n"; - $anon = 1; + $anon_struct_union = 1; } # warn if parameter has no description # (but ignore ones starting with # as these are not parameters # but inline preprocessor statements); # also ignore unnamed structs/unions; - if (!$anon) { + if (!$anon_struct_union) { if (!defined $parameterdescs{$param_name} && $param_name !~ /^#/) { $parameterdescs{$param_name} = $undescribed; if (($type eq 'function') || ($type eq 'enum')) { - print STDERR "Warning(${file}:$.): Function parameter ". + print STDERR "Warning(${file}:$.): Function parameter ". "or member '$param' not " . "described in '$declaration_name'\n"; } print STDERR "Warning(${file}:$.):". - " No description found for parameter '$param'\n"; + " No description found for parameter '$param'\n"; ++$warnings; - } - } + } + } push @parameterlist, $param; $parametertypes{$param} = $type; } +sub check_sections($$$$$$) { + my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck, $nested) = @_; + 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\(\)]*\)\)//; + ##$prm_clean =~ s/^\**//; + if ($prm_clean eq $sects[$sx]) { + $err = 0; + last; + } + } + if ($err) { + if ($decl_type eq "function") { + print STDERR "Warning(${file}:$.): " . + "Excess function parameter " . + "'$sects[$sx]' " . + "description in '$decl_name'\n"; + ++$warnings; + } else { + if ($nested !~ m/\Q$sects[$sx]\E/) { + print STDERR "Warning(${file}:$.): " . + "Excess struct/union/enum/typedef member " . + "'$sects[$sx]' " . + "description in '$decl_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 @@ -1528,7 +1705,6 @@ sub dump_function($$) { $prototype =~ s/^static +//; $prototype =~ s/^extern +//; - $prototype =~ s/^fastcall +//; $prototype =~ s/^asmlinkage +//; $prototype =~ s/^inline +//; $prototype =~ s/^__inline__ +//; @@ -1536,8 +1712,9 @@ sub dump_function($$) { $prototype =~ s/^__always_inline +//; $prototype =~ s/^noinline +//; $prototype =~ s/__devinit +//; - $prototype =~ s/^#define +//; #ak added - $prototype =~ s/__attribute__ \(\([a-z,]*\)\)//; + $prototype =~ s/__init +//; + $prototype =~ s/^#\s*define\s+//; #ak added + $prototype =~ s/__attribute__\s*\(\([a-z,]*\)\)//; # Yes, this truly is vile. We are looking for: # 1. Return type (may be nothing if we're looking at a macro) @@ -1559,7 +1736,7 @@ sub dump_function($$) { $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*\*+)\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*\(([^\{]*)\)/ || @@ -1570,7 +1747,8 @@ sub dump_function($$) { $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+\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; @@ -1582,6 +1760,9 @@ sub dump_function($$) { return; } + my $prms = join " ", @parameterlist; + check_sections($file, $declaration_name, "function", $sectcheck, $prms, ""); + output_declaration($declaration_name, 'function', {'function' => $declaration_name, @@ -1640,26 +1821,68 @@ sub reset_state { @parameterlist = (); %sections = (); @sectionlist = (); + $sectcheck = ""; + $struct_actual = ""; $prototype = ""; $state = 0; } +sub syscall_munge() { + my $void = 0; + + $prototype =~ s@[\r\n\t]+@ @gos; # strip newlines/CR's/tabs +## 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_state3_function($$) { my $x = shift; my $file = shift; - if ($x =~ m#\s*/\*\s+MACDOC\s*#io || ($x =~ /^#/ && $x !~ /^#define/)) { + $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; + $prototype .= $1; } - if (($x =~ /\{/) || ($x =~ /\#define/) || ($x =~ /;/)) { - $prototype =~ s@/\*.*?\*/@@gos; # strip comments. + + 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 - dump_function($prototype,$file); + if ($prototype =~ /SYSCALL_DEFINE/) { + syscall_munge(); + } + dump_function($prototype, $file); reset_state(); } } @@ -1671,30 +1894,38 @@ sub process_state3_type($$) { $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 ( $x =~ /([^{};]*)([{};])(.*)/ ) { $prototype .= $1 . $2; ($2 eq '{') && $brcount++; ($2 eq '}') && $brcount--; if (($2 eq ';') && ($brcount == 0)) { - dump_declaration($prototype,$file); + dump_declaration($prototype,$file); reset_state(); - last; + last; } $x = $3; - } else { + } else { $prototype .= $x; last; } } } -# replace <, >, and & +# xml_escape: replace <, >, and & in the text stream; +# +# however, formatting controls that are generated internally/locally in the +# kernel-doc script are not escaped here; instead, they begin life like +# $blankline_html (4 of '\' followed by a mnemonic + ':'), then these strings +# are converted to their mnemonic-expected output, without the 4 * '\' & ':', +# just before actual output; (this is done by local_unescape()) sub xml_escape($) { my $text = shift; if (($output_mode eq "text") || ($output_mode eq "man")) { @@ -1706,10 +1937,23 @@ sub xml_escape($) { return $text; } +# convert local escape strings to html +# local escape strings look like: '\\\\menmonic:' (that's 4 backslashes) +sub local_unescape($) { + my $text = shift; + if (($output_mode eq "text") || ($output_mode eq "man")) { + return $text; + } + $text =~ s/\\\\\\\\lt://g; + return $text; +} + sub process_file($) { my $file; my $identifier; my $func; + my $descr; my $initial_section_counter = $section_counter; if (defined($ENV{'SRCTREE'})) { @@ -1744,7 +1988,7 @@ sub process_file($) { } else { $section = $1; } - } + } elsif (/$doc_decl/o) { $identifier = $1; if (/\s*([\w\s]+?)\s*-/) { @@ -1753,10 +1997,22 @@ sub process_file($) { $state = 2; if (/-(.*)/) { - $declaration_purpose = xml_escape($1); + # strip leading/trailing/multiple spaces + $descr= $1; + $descr =~ s/^\s*//; + $descr =~ s/\s*$//; + $descr =~ s/\s+/ /; + $declaration_purpose = xml_escape($descr); } else { $declaration_purpose = ""; } + + if (($declaration_purpose eq "") && $verbose) { + print STDERR "Warning(${file}:$.): missing initial short description on line:\n"; + print STDERR $_; + ++$warnings; + } + if ($identifier =~ m/^struct/) { $decl_type = 'struct'; } elsif ($identifier =~ m/^union/) { @@ -1783,12 +2039,12 @@ sub process_file($) { $newsection = $1; $newcontents = $2; - if ($contents ne "") { + if (($contents ne "") && ($contents ne "\n")) { if (!$in_doc_sect && $verbose) { print STDERR "Warning(${file}:$.): contents before sections\n"; ++$warnings; } - dump_section($section, xml_escape($contents)); + dump_section($file, $section, xml_escape($contents)); $section = $section_default; } @@ -1805,10 +2061,15 @@ sub process_file($) { } elsif (/$doc_end/) { if ($contents ne "") { - dump_section($section, xml_escape($contents)); + dump_section($file, $section, xml_escape($contents)); $section = $section_default; $contents = ""; } + # look for doc_com + + doc_end: + if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') { + print STDERR "Warning(${file}:$.): suspicious ending line: $_"; + ++$warnings; + } $prototype = ""; $state = 3; @@ -1819,7 +2080,7 @@ sub process_file($) { # @parameter line to signify start of description if ($1 eq "" && ($section =~ m/^@/ || $section eq $section_context)) { - dump_section($section, xml_escape($contents)); + dump_section($file, $section, xml_escape($contents)); $section = $section_default; $contents = ""; } else { @@ -1832,16 +2093,14 @@ sub process_file($) { } } elsif ($state == 3) { # scanning for function '{' (end of prototype) if ($decl_type eq 'function') { - process_state3_function($_, $file); + process_state3_function($_, $file); } else { - process_state3_type($_, $file); + process_state3_type($_, $file); } } elsif ($state == 4) { # Documentation block - if (/$doc_block/) { - dump_section($section, $contents); - output_intro({'sectionlist' => \@sectionlist, - 'sections' => \%sections }); + if (/$doc_block/) { + dump_doc_section($file, $section, xml_escape($contents)); $contents = ""; $function = ""; %constants = (); @@ -1856,12 +2115,10 @@ sub process_file($) { } else { $section = $1; } - } + } elsif (/$doc_end/) { - dump_section($section, $contents); - output_intro({'sectionlist' => \@sectionlist, - 'sections' => \%sections }); + dump_doc_section($file, $section, xml_escape($contents)); $contents = ""; $function = ""; %constants = (); @@ -1883,8 +2140,8 @@ sub process_file($) { { $contents .= $1 . "\n"; } - } - } + } + } } if ($initial_section_counter == $section_counter) { print STDERR "Warning(${file}): no structured comments found\n";