## 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-2007 Randy Dunlap ##
## ##
## #define enhancements by Armin Kuster <akuster@mvista.com> ##
## Copyright (c) 2000 MontaVista Software, Inc. ##
# 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
#
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_xml = '\\\amp;((struct\s*)*[_\w]+)';
+my $type_struct_xml = '\\&((struct\s*)*[_\w]+)';
my $type_env = '(\$\w+)';
# Output conversion substitutions.
$type_struct_xml, "<i>\$1</i>",
$type_env, "<b><i>\$1</i></b>",
$type_param, "<tt><b>\$1</b></tt>" );
-my $blankline_html = "<p>";
+my $local_lt = "\\\\\\\\lt:";
+my $local_gt = "\\\\\\\\gt:";
+my $blankline_html = $local_lt . "p" . $local_gt; # was "<p>"
# XML, docbook format
my %highlights_xml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>",
$type_constant, "<constant>\$1</constant>",
$type_func, "<function>\$1</function>",
- $type_struct, "<structname>\$1</structname>",
+ $type_struct_xml, "<structname>\$1</structname>",
$type_env, "<envar>\$1</envar>",
$type_param, "<parameter>\$1</parameter>" );
-my $blankline_xml = "</para><para>\n";
+my $blankline_xml = $local_lt . "/para" . $local_gt . $local_lt . "para" . $local_gt . "\n";
# gnome, docbook format
my %highlights_gnome = ( $type_constant, "<replaceable class=\"option\">\$1</replaceable>",
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";
my $verbose = 0;
my $output_mode = "man";
+my $no_doc_sections = 0;
my %highlights = %highlights_man;
my $blankline = $blankline_man;
my $modulename = "Kernel API";
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;
+ 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.
}
}
+##
+# dump DOC: section after checking that it should go out
+#
+sub dump_doc_section {
+ 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 $name, $contents;
+ output_blockhead({'sectionlist' => \@sectionlist,
+ 'sections' => \%sections,
+ 'module' => $modulename,
+ 'content-only' => ($function_only != 0), });
+ }
+}
+
##
# output function
#
# 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 $@;
- if ($output_mode eq "html") {
- $contents =~ s/\\\\//;
- }
# print STDERR "contents af:$contents\n";
foreach $line (split "\n", $contents) {
if ($line eq ""){
- print $lineprefix, $blankline;
+ print $lineprefix, local_unescape($blankline);
} else {
$line =~ s/\\\\\\/\&/g;
- print $lineprefix, $line;
+ if ($output_mode eq "man" && substr($line, 0, 1) eq ".") {
+ print "\\&$line";
+ } else {
+ print $lineprefix, $line;
+ }
}
print "\n";
}
print "<hr>\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;
print "<refmeta>\n";
print " <refentrytitle><phrase>".$args{'function'}."</phrase></refentrytitle>\n";
print " <manvolnum>9</manvolnum>\n";
- print " <refmiscinfo class=\"version\">" . get_kernel_version() . "</refmiscinfo>\n";
+ print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
print "</refmeta>\n";
print "<refnamediv>\n";
print " <refname>".$args{'function'}."</refname>\n";
print "<refmeta>\n";
print " <refentrytitle><phrase>".$args{'type'}." ".$args{'struct'}."</phrase></refentrytitle>\n";
print " <manvolnum>9</manvolnum>\n";
- print " <refmiscinfo class=\"version\">" . get_kernel_version() . "</refmiscinfo>\n";
+ print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
print "</refmeta>\n";
print "<refnamediv>\n";
print " <refname>".$args{'type'}." ".$args{'struct'}."</refname>\n";
# pointer-to-function
print " $1 $parameter) ($2);\n";
} elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+ # bitfield
print " $1 $parameter$2;\n";
} else {
print " ".$type." ".$parameter.";\n";
print "<refmeta>\n";
print " <refentrytitle><phrase>enum ".$args{'enum'}."</phrase></refentrytitle>\n";
print " <manvolnum>9</manvolnum>\n";
- print " <refmiscinfo class=\"version\">" . get_kernel_version() . "</refmiscinfo>\n";
+ print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
print "</refmeta>\n";
print "<refnamediv>\n";
print " <refname>enum ".$args{'enum'}."</refname>\n";
}
# output in XML DocBook
-sub output_intro_xml(%) {
+sub output_blockhead_xml(%) {
my %args = %{$_[0]};
my ($parameter, $section);
my $count;
# print out each section
$lineprefix=" ";
foreach $section (@{$args{'sectionlist'}}) {
- print "<refsect1>\n <title>$section</title>\n <para>\n";
+ if (!$args{'content-only'}) {
+ print "<refsect1>\n <title>$section</title>\n";
+ }
if ($section =~ m/EXAMPLE/i) {
print "<example><para>\n";
+ } else {
+ print "<para>\n";
}
output_highlight($args{'sections'}{$section});
if ($section =~ m/EXAMPLE/i) {
print "</para></example>\n";
+ } else {
+ print "</para>";
+ }
+ if (!$args{'content-only'}) {
+ print "\n</refsect1>\n";
}
- print " </para>\n</refsect1>\n";
}
print "\n\n";
}
}
-sub output_intro_man(%) {
+sub output_blockhead_man(%) {
my %args = %{$_[0]};
my ($parameter, $section);
my $count;
# 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";
output_section_text(@_);
}
-sub output_intro_text(%) {
+sub output_blockhead_text(%) {
my %args = %{$_[0]};
my ($parameter, $section);
##
# 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++;
}
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/\[.*//;
# 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;
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 !~ /^#define/)) {
# do nothing
}
$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 .= ";";
}
}
-# 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")) {
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;
+ $text =~ s/\\\\\\\\gt:/>/g;
+ return $text;
+}
+
sub process_file($) {
my $file;
my $identifier;
$state = 2;
if (/-(.*)/) {
- # strip leading/trailing/multiple spaces #RDD:T:
+ # strip leading/trailing/multiple spaces
$descr= $1;
$descr =~ s/^\s*//;
$descr =~ s/\s*$//;
} elsif ($state == 4) {
# Documentation block
if (/$doc_block/) {
- dump_section($section, $contents);
- output_intro({'sectionlist' => \@sectionlist,
- 'sections' => \%sections });
+ dump_doc_section($section, xml_escape($contents));
$contents = "";
$function = "";
%constants = ();
}
elsif (/$doc_end/)
{
- dump_section($section, $contents);
- output_intro({'sectionlist' => \@sectionlist,
- 'sections' => \%sections });
+ dump_doc_section($section, xml_escape($contents));
$contents = "";
$function = "";
%constants = ();