Add new -asciidoc option to produce asciidoc output from kernel-doc. The output is formatted internally, with no dependencies on external tools. Any asciidoc formatting present in kernel-doc will naturally be present in the resulting asciidoc as well. Highlighting of functions(), &struct structures, &enum enumerations, @parameters, etc. will be done by means of asciidoc. Anchors and cross-references are added as well, providing hyperlinking support in the result processed by asciidoc(1). This support is non-conflicting and orthogonal to the patches adding asciidoc support to the kernel-doc DocBook output [1]. Those patches bolt on to the current document generation pipeline; there is currently none for native asciidoc in the kernel (though ideas have been discussed [2]). At this time, this patch should be considered a worthwhile standalone improvement to kernel-doc, independent of the rest. [1] http://mid.gmane.org/1448471279-19748-1-git-send-email-daniel.vetter@xxxxxxxx [2] http://mid.gmane.org/20160114131823.2ff43a0c@xxxxxxx Cc: Jonathan Corbet <corbet@xxxxxxx> Cc: Daniel Vetter <daniel@xxxxxxxx> Signed-off-by: Jani Nikula <jani.nikula@xxxxxxxxx> --- WARNING: I do not know perl. This was all cargo-culted over a couple of evenings. I tested this mostly on drm/i915. I had to drop a few totally bogus kernel-doc comments for everything to work cleanly, series at http://patchwork.freedesktop.org/series/2581/. With those out of the way, IMHO the result is astonishing for the amount of time invested. With default installs and templates and stylesheets of asciidoc and asciidoctor on debian: $ scripts/kernel-doc -asciidoc drivers/gpu/drm/i915/*.[ch] | asciidoc - > i915-asciidoc.html See http://people.freedesktop.org/~jani/i915-asciidoc.html $ scripts/kernel-doc -asciidoc drivers/gpu/drm/i915/*.[ch] | asciidoctor - > i915-asciidoctor.html See http://people.freedesktop.org/~jani/i915-asciidoctor.html At this point, running kernel-doc on *.[ch] is of course just a random collection of glorified comments. For proper documentation, this will need a high level asciidoc and a way to include named sections and functions etc. I'll be giving that some thought next, but again, I think this is worthwhile on its own. BR, Jani. --- scripts/kernel-doc | 237 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 638a38e1b419..a9a38374cb49 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -201,6 +201,8 @@ my $type_param = '\@(\w+)'; my $type_struct = '\&((struct\s*)*[_\w]+)'; my $type_struct_xml = '\\&((struct\s*)*[_\w]+)'; my $type_env = '(\$\w+)'; +my $type_enum_full = '\&(enum)\s*([_\w]+)'; +my $type_struct_full = '\&(struct)\s*([_\w]+)'; # Output conversion substitutions. # One for each output format @@ -266,6 +268,17 @@ my @highlights_text = ( ); my $blankline_text = ""; +# asciidoc-mode +my @highlights_asciidoc = ( + [$type_constant, "`\$1`"], + [$type_func, "<<func_\$1,`\$1()`>>"], + [$type_struct_full, "<<\$1_\$2,`\$1 \$2`>>"], + [$type_enum_full, "<<\$1_\$2,`\$1 \$2`>>"], + [$type_struct, "<<struct_\$1,`\$1`>>"], + [$type_param, "*\$1*"] + ); +my $blankline_asciidoc = "\n"; + # list mode my @highlights_list = ( [$type_constant, "\$1"], @@ -402,6 +415,10 @@ while ($ARGV[0] =~ m/^-(.*)/) { $output_mode = "text"; @highlights = @highlights_text; $blankline = $blankline_text; + } elsif ($cmd eq "-asciidoc") { + $output_mode = "asciidoc"; + @highlights = @highlights_asciidoc; + $blankline = $blankline_asciidoc; } elsif ($cmd eq "-docbook") { $output_mode = "xml"; @highlights = @highlights_xml; @@ -1713,6 +1730,214 @@ sub output_blockhead_text(%) { } } +## +# output in asciidoc +sub output_highlight_asciidoc { + my $contents = join "\n",@_; + my $line; + + # undo the evil effects of xml_escape() earlier + $contents = xml_unescape($contents); + + eval $dohighlight; + die $@ if $@; + + foreach $line (split "\n", $contents) { + if ($line eq "") { + print $lineprefix, $blankline; + } else { + $line =~ s/\\\\\\/\&/g; + print $lineprefix, $line; + } + print "\n"; + } +} + +sub output_function_asciidoc(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $start; + + print "[[func_$args{'function'}]]\n"; + print "=== " . $args{'function'} . " ===\n"; + print $args{'purpose'} . "\n\n"; + + print "----------\n"; + 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}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { + # pointer-to-function + print $1 . $parameter . ") (" . $2; + } else { + print $type . " " . $parameter; + } + if ($count != $#{$args{'parameterlist'}}) { + $count++; + print ",\n"; + print " " x length($start); + } else { + print ");\n\n"; + } + } + print "----------\n"; + + print ".Parameters\n"; + print "[horizontal]\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + $type = $args{'parametertypes'}{$parameter}; + + print "`$type $parameter`::\n"; + if ($args{'parameterdescs'}{$parameter_name} ne $undescribed) { + $blankline = "+"; + output_highlight_asciidoc($args{'parameterdescs'}{$parameter_name}); + $blankline = "\n"; + } else { + print "_undescribed_\n"; + } + print "\n"; + } + output_section_asciidoc(@_); +} + +sub output_section_asciidoc(%) { + my %args = %{$_[0]}; + my $section; + + foreach $section (@{$args{'sectionlist'}}) { + print ".$section\n\n"; + output_highlight_asciidoc($args{'sections'}{$section}); + print "\n"; + } + print "\n"; +} + +sub output_enum_asciidoc(%) { + my %args = %{$_[0]}; + my ($parameter); + my $count; + + print "[[enum_$args{'enum'}]]\n"; + print "=== enum " . $args{'enum'} . " ===\n"; + print $args{'purpose'} . "\n\n"; + + print "----------\n"; + print "enum " . $args{'enum'} . " {\n"; + $count = 0; + foreach $parameter (@{$args{'parameterlist'}}) { + print "\t$parameter"; + if ($count != $#{$args{'parameterlist'}}) { + $count++; + print ","; + } + print "\n"; + } + print "};\n"; + print "----------\n"; + + print ".Constants\n"; + print "[horizontal]\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + print "`$parameter`::\n"; + if ($args{'parameterdescs'}{$parameter} ne $undescribed) { + $blankline = "+"; + output_highlight_asciidoc($args{'parameterdescs'}{$parameter}); + $blankline = "\n"; + } else { + print "_undescribed_\n"; + } + print "\n"; + } + + output_section_asciidoc(@_); +} + +sub output_typedef_asciidoc(%) { + my %args = %{$_[0]}; + my ($parameter); + my $count; + + print "[[$args{'typedef'}]]\n"; + print "=== typedef " . $args{'typedef'} . " ===\n"; + print $args{'purpose'} . "\n\n"; + + output_section_asciidoc(@_); +} + +sub output_struct_asciidoc(%) { + my %args = %{$_[0]}; + my ($parameter); + + print "[[$args{'type'}_$args{'struct'}]]\n"; + print "=== " . $args{'type'} . " " . $args{'struct'} . " ===\n"; + print $args{'purpose'} . "\n\n"; + + print "----------\n"; + print $args{'type'} . " " . $args{'struct'} . " {\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + if ($parameter =~ /^#/) { + print "$parameter\n"; + next; + } + + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($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"; + } + } + print "};\n"; + print "----------\n"; + + print ".Members\n"; + print "[horizontal]\n"; + 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 "`$type $parameter`" . "::\n"; + $blankline = "+"; + output_highlight_asciidoc($args{'parameterdescs'}{$parameter_name}); + $blankline = "\n"; + print "\n"; + } + print "\n"; + output_section_asciidoc(@_); +} + +sub output_blockhead_asciidoc(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + + foreach $section (@{$args{'sectionlist'}}) { + print "=== $section ===\n"; + output_highlight_asciidoc($args{'sections'}{$section}); + print "\n"; + } +} + ## list mode output functions sub output_function_list(%) { @@ -2411,6 +2636,18 @@ sub xml_escape($) { return $text; } +# xml_unescape: reverse the effects of xml_escape +sub xml_unescape($) { + my $text = shift; + if (($output_mode eq "text") || ($output_mode eq "man")) { + return $text; + } + $text =~ s/\\\\\\amp;/\&/g; + $text =~ s/\\\\\\lt;/</g; + $text =~ s/\\\\\\gt;/>/g; + return $text; +} + # convert local escape strings to html # local escape strings look like: '\\\\menmonic:' (that's 4 backslashes) sub local_unescape($) { -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-doc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html