scripts/kernel-doc: Adding cross-reference links to html documentation.
authorDanilo Cesar Lemes de Paula <danilo.cesar@collabora.co.uk>
Tue, 28 Jul 2015 19:45:15 +0000 (16:45 -0300)
committerJonathan Corbet <corbet@lwn.net>
Mon, 17 Aug 2015 04:11:16 +0000 (22:11 -0600)
Functions, Structs and Parameters definitions on kernel documentation
are pure cosmetic, it only highlights the element.

To ease the navigation in the documentation we should use <links> inside
those tags so readers can easily jump between methods directly.

This was discussed in 2014[1] and is implemented by getting a list
of <refentries> from the DocBook XML to generate a database. Then it looks
for <function>,<structnames> and <paramdef> tags that matches the ones in
the database. As it only links existent references, no broken links are
added.

[1] - lists.freedesktop.org/archives/dri-devel/2014-August/065404.html

Signed-off-by: Danilo Cesar Lemes de Paula <danilo.cesar@collabora.co.uk>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Stephan Mueller <smueller@chronox.de>
Cc: Michal Marek <mmarek@suse.cz>
Cc: intel-gfx <intel-gfx@lists.freedesktop.org>
Cc: dri-devel <dri-devel@lists.freedesktop.org>
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
Documentation/DocBook/Makefile
scripts/kernel-doc-xml-ref [new file with mode: 0755]

index 5e9702194dfeca21f165f8d11a4c400da2334f08..b1d6c951ea290655c8ddbd49125c0ca037c56d7d 100644 (file)
@@ -66,8 +66,9 @@ installmandocs: mandocs
 
 ###
 #External programs used
-KERNELDOC = $(srctree)/scripts/kernel-doc
-DOCPROC   = $(objtree)/scripts/docproc
+KERNELDOCXMLREF = $(srctree)/scripts/kernel-doc-xml-ref
+KERNELDOC       = $(srctree)/scripts/kernel-doc
+DOCPROC         = $(objtree)/scripts/docproc
 
 XMLTOFLAGS = -m $(srctree)/$(src)/stylesheet.xsl
 XMLTOFLAGS += --skip-validation
@@ -91,7 +92,7 @@ define rule_docproc
         ) > $(dir $@).$(notdir $@).cmd
 endef
 
-%.xml: %.tmpl $(KERNELDOC) $(DOCPROC) FORCE
+%.xml: %.tmpl $(KERNELDOC) $(DOCPROC) $(KERNELDOCXMLREF) FORCE
        $(call if_changed_rule,docproc)
 
 # Tell kbuild to always build the programs
@@ -142,7 +143,20 @@ quiet_cmd_db2html = HTML    $@
                echo '<a HREF="$(patsubst %.html,%,$(notdir $@))/index.html"> \
                $(patsubst %.html,%,$(notdir $@))</a><p>' > $@
 
-%.html:        %.xml
+###
+# Rules to create an aux XML and .db, and use them to re-process the DocBook XML
+# to fill internal hyperlinks
+       gen_aux_xml = :
+ quiet_gen_aux_xml = echo '  XMLREF  $@'
+silent_gen_aux_xml = :
+%.aux.xml: %.xml
+       @$($(quiet)gen_aux_xml)
+       @rm -rf $@
+       @(cat $< | egrep "^<refentry id" | egrep -o "\".*\"" | cut -f 2 -d \" > $<.db)
+       @$(KERNELDOCXMLREF) -db $<.db $< > $@
+.PRECIOUS: %.aux.xml
+
+%.html:        %.aux.xml
        @(which xmlto > /dev/null 2>&1) || \
         (echo "*** You need to install xmlto ***"; \
          exit 1)
@@ -211,15 +225,18 @@ dochelp:
 ###
 # Temporary files left by various tools
 clean-files := $(DOCBOOKS) \
-       $(patsubst %.xml, %.dvi,  $(DOCBOOKS)) \
-       $(patsubst %.xml, %.aux,  $(DOCBOOKS)) \
-       $(patsubst %.xml, %.tex,  $(DOCBOOKS)) \
-       $(patsubst %.xml, %.log,  $(DOCBOOKS)) \
-       $(patsubst %.xml, %.out,  $(DOCBOOKS)) \
-       $(patsubst %.xml, %.ps,   $(DOCBOOKS)) \
-       $(patsubst %.xml, %.pdf,  $(DOCBOOKS)) \
-       $(patsubst %.xml, %.html, $(DOCBOOKS)) \
-       $(patsubst %.xml, %.9,    $(DOCBOOKS)) \
+       $(patsubst %.xml, %.dvi,     $(DOCBOOKS)) \
+       $(patsubst %.xml, %.aux,     $(DOCBOOKS)) \
+       $(patsubst %.xml, %.tex,     $(DOCBOOKS)) \
+       $(patsubst %.xml, %.log,     $(DOCBOOKS)) \
+       $(patsubst %.xml, %.out,     $(DOCBOOKS)) \
+       $(patsubst %.xml, %.ps,      $(DOCBOOKS)) \
+       $(patsubst %.xml, %.pdf,     $(DOCBOOKS)) \
+       $(patsubst %.xml, %.html,    $(DOCBOOKS)) \
+       $(patsubst %.xml, %.9,       $(DOCBOOKS)) \
+       $(patsubst %.xml, %.aux.xml, $(DOCBOOKS)) \
+       $(patsubst %.xml, %.xml.db,  $(DOCBOOKS)) \
+       $(patsubst %.xml, %.xml,     $(DOCBOOKS)) \
        $(index)
 
 clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS)) man
diff --git a/scripts/kernel-doc-xml-ref b/scripts/kernel-doc-xml-ref
new file mode 100755 (executable)
index 0000000..104a5a5
--- /dev/null
@@ -0,0 +1,198 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+## Copyright (C) 2015  Intel Corporation                         ##
+#                                                                ##
+## This software falls under the GNU General Public License.     ##
+## Please read the COPYING file for more information             ##
+#
+#
+# This software reads a XML file and a list of valid interal
+# references to replace Docbook tags with links.
+#
+# The list of "valid internal references" must be one-per-line in the following format:
+#      API-struct-foo
+#      API-enum-bar
+#      API-my-function
+#
+# The software walks over the XML file looking for xml tags representing possible references
+# to the Document. Each reference will be cross checked against the "Valid Internal Reference" list. If
+# the referece is found it replaces its content by a <link> tag.
+#
+# usage:
+# kernel-doc-xml-ref -db filename
+#                   xml filename > outputfile
+
+# read arguments
+if ($#ARGV != 2) {
+       usage();
+}
+
+#Holds the database filename
+my $databasefile;
+my @database;
+
+#holds the inputfile
+my $inputfile;
+my $errors = 0;
+
+my %highlights = (
+       "<function>(.*?)</function>",
+           "\"<function>\" . convert_function(\$1, \$line) . \"</function>\"",
+       "<structname>(.*?)</structname>",
+           "\"<structname>\" . convert_struct(\$1) . \"</structname>\"",
+       "<funcdef>(.*?)<function>(.*?)</function></funcdef>",
+           "\"<funcdef>\" . convert_param(\$1) . \"<function>\$2</function></funcdef>\"",
+       "<paramdef>(.*?)<parameter>(.*?)</parameter></paramdef>",
+           "\"<paramdef>\" . convert_param(\$1) . \"<parameter>\$2</parameter></paramdef>\"");
+
+while($ARGV[0] =~ m/^-(.*)/) {
+       my $cmd = shift @ARGV;
+       if ($cmd eq "-db") {
+               $databasefile = shift @ARGV
+       } else {
+               usage();
+       }
+}
+$inputfile = shift @ARGV;
+
+sub open_database {
+       open (my $handle, '<', $databasefile) or die "Cannot open $databasefile";
+       chomp(my @lines = <$handle>);
+       close $handle;
+
+       @database = @lines;
+}
+
+sub process_file {
+       open_database();
+
+       my $dohighlight;
+       foreach my $pattern (keys %highlights) {
+               $dohighlight .=  "\$line =~ s:$pattern:$highlights{$pattern}:eg;\n";
+       }
+
+       open(FILE, $inputfile) or die("Could not open $inputfile") or die ("Cannot open $inputfile");
+       foreach my $line (<FILE>)  {
+               eval $dohighlight;
+               print $line;
+       }
+}
+
+sub trim($_)
+{
+       my $str = $_[0];
+       $str =~ s/^\s+|\s+$//g;
+       return $str
+}
+
+sub has_key_defined($_)
+{
+       if ( grep( /^$_[0]$/, @database)) {
+               return 1;
+       }
+       return 0;
+}
+
+# Gets a <function> content and add it a hyperlink if possible.
+sub convert_function($_)
+{
+       my $arg = $_[0];
+       my $key = $_[0];
+
+       my $line = $_[1];
+
+       $key = trim($key);
+
+       $key =~ s/[^A-Za-z0-9]/-/g;
+       $key = "API-" . $key;
+
+       # We shouldn't add links to <funcdef> prototype
+       if (!has_key_defined($key) || $line =~ m/\s+<funcdef/i) {
+               return $arg;
+       }
+
+       my $head = $arg;
+       my $tail = "";
+       if ($arg =~ /(.*?)( ?)$/) {
+               $head = $1;
+               $tail = $2;
+       }
+       return "<link linkend=\"$key\">$head</link>$tail";
+}
+
+# Converting a struct text to link
+sub convert_struct($_)
+{
+       my $arg = $_[0];
+       my $key = $_[0];
+       $key =~ s/(struct )?(\w)/$2/g;
+       $key =~ s/[^A-Za-z0-9]/-/g;
+       $key = "API-struct-" . $key;
+
+       if (!has_key_defined($key)) {
+               return $arg;
+       }
+
+       my ($head, $tail) = split_pointer($arg);
+       return "<link linkend=\"$key\">$head</link>$tail";
+}
+
+# Identify "object *" elements
+sub split_pointer($_)
+{
+       my $arg = $_[0];
+       if ($arg =~ /(.*?)( ?\* ?)/) {
+               return ($1, $2);
+       }
+       return ($arg, "");
+}
+
+sub convert_param($_)
+{
+       my $type = $_[0];
+       my $keyname = convert_key_name($type);
+
+       if (!has_key_defined($keyname)) {
+               return $type;
+       }
+
+       my ($head, $tail) = split_pointer($type);
+       return "<link linkend=\"$keyname\">$head</link>$tail";
+
+}
+
+# DocBook links are in the API-<TYPE>-<STRUCT-NAME> format
+# This method gets an element and returns a valid DocBook reference for it.
+sub convert_key_name($_)
+{
+       #Pattern $2 is optional and might be uninitialized
+       no warnings 'uninitialized';
+
+       my $str = $_[0];
+       $str =~ s/(const|static)? ?(struct)? ?([a-zA-Z0-9_]+) ?(\*|&)?/$2 $3/g ;
+
+       # trim
+       $str =~ s/^\s+|\s+$//g;
+
+       # spaces and _ to -
+       $str =~ s/[^A-Za-z0-9]/-/g;
+
+       return "API-" . $str;
+}
+
+sub usage {
+       print "Usage: $0 -db database filename\n";
+       print "         xml source file(s) > outputfile\n";
+       exit 1;
+}
+
+# starting point
+process_file();
+
+if ($errors) {
+       print STDERR "$errors errors\n";
+}
+
+exit($errors);