From 445e84f517a14e0ec583de4928fbc421944d6d1b Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 29 Nov 2011 15:48:06 +0000 Subject: docs/html/: Initial cut of header documentation massager "xen-headers" generates HTML from header files. So far this generates just some type cross-references, if you say make -C docs html/hypercall/stamp An index page, proper wiring into the build system, and a few more annotations in the headers, and will be forthcoming. Signed-off-by: Ian Jackson Acked-by: Ian Campbell Committed-by: Ian Jackson --- docs/xen-headers | 292 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100755 docs/xen-headers (limited to 'docs/xen-headers') diff --git a/docs/xen-headers b/docs/xen-headers new file mode 100755 index 0000000000..3dde4575dc --- /dev/null +++ b/docs/xen-headers @@ -0,0 +1,292 @@ +#!/usr/bin/perl -w +# usage: xen-headers OPTIONS... BASE-DIR INPUT-SUB-DIR... +# INPUT-SUB-DIR must be a relative path, and is interpreted +# relative to BASE-DIR. Only files whose names end .h are processed +# options: +# -O HTML-DIR write html to this directory (mandatory) +# -T EXTRA-TITLE-HTML tail of title string (used in ) +# -X GLOB | -I GLOB include/exclude files matching; +# glob patterns matched against /INPUT-SUB-FILE +# first match wins; if no match, files included +# -D increase debug + +# Functionality: +# enum values --> selected function or struct +# type & function names, macro definitions --> definition +# function or struct selected by enum ++> ref to enum value + +# definitions must start in LH column +# extra syntax: +# /* ` <definition> } parse as if <definition> +# * ` <definition> } was not commented +# enum <name> { // <pattern>* => <func>() } cross-reference +# enum <name> { // <pattern>* => struct <s> } enum values +# + +# 1st pass: find where things are defined and what references are wanted +# 2rd pass: write out output + +use strict; +use warnings; + +use Getopt::Long; +use File::Find; +use IO::File; + +Getopt::Long::Configure('bundling'); + +our $outdir; +our $debug=0; +our $xtitle=''; +our @fglobs; + +sub includeexclude { + my ($yn, $optobj, $value) = @_; + push @fglobs, [ $value, $yn ]; +} + +GetOptions("O|output-dir=s" => \$outdir, + "D+" => \$debug, + "T=s" => \$xtitle, + "I=s" => sub { includeexclude(1, @_); }, + "X=s" => sub { includeexclude(0, @_); }) + or die; + +die unless defined $outdir; +@ARGV>=2 or die; + +my ($basedir,@indirs) = @ARGV; + +# general globals +our $pass; +our %sdef; +# $sdef{$type}{$name} => { +# DefLocs => { "$leaf_path:$lineno" => $leaf_opath ,... } +# Xrefs => { "$leaf_path,$lineno" => "$xref", ... } +# Used => 1 +# } +# $type might be Func Struct Union Enum EnumVal + +# provided by the find() function +our $leaf; +our $leaf_opath; + +# reset at the start of each file +our $o; +our $in_enum; +our @pending_xrefs; + +sub compile_fglobs () { + local ($_); + my $f = "sub file_wanted (\$) {\n local (\$_) = \"/\$leaf\";\n"; + foreach my $fglob (@fglobs) { + $_ = $fglob->[0]; + $_ = "**$_**" unless m/[?*]/; + s/\W/\\$&/g; + s,\\\*\\\*,.*,g; + s,\\\*,[^/]*,g; + s,\\\?,[^/],g; + $f .= " return $fglob->[1] if m,$_,o;\n"; + } + $f .= " return 1;\n}\n1;\n"; + debug(3, $f); + eval $f or die "$@ "; +} + +compile_fglobs(); + + +sub warning { + print STDERR "$leaf:$.: @_\n"; +} + +sub debug { + my $msglevel = scalar shift @_; + return unless $debug >= $msglevel; + print STDERR "DEBUG $pass $msglevel @_\n" or die $!; +} + +sub in_enum ($$$) { $in_enum = [ @_ ]; } # [ $enumvalpfx, RefType, $refnamepfx ] + +sub aelem ($$$) { + my ($ntext,$ytext,$hparams) = @_; + return $ntext unless $hparams =~ m/\S/; + return "<a $hparams>$ytext</a>"; +} + +sub defn ($$$;$) { + my ($text,$type,$name,$hparams) = @_; + $hparams='' if !defined $hparams; + debug(2,"DEFN $. $type $name $hparams"); + $sdef{$type}{$name}{DefLocs}{"$leaf:$."} = $leaf_opath; + my $xrefs = $sdef{$type}{$name}{Xrefs}; + push @pending_xrefs, values %$xrefs if $xrefs; + $hparams .= " name=\"${type}_$name\"" if $sdef{$type}{$name}{Used}; + return aelem($text, "<strong>$text</strong>", $hparams); +} + +sub norm ($) { + local ($_) = @_; + my $no = ''; + while (length) { + if (s/^(?:\s|^\W)+//) { + $no .= $&; + } elsif (s/^(struct|union|enum)\s+(\w+)\b//) { + $no .= ahref($&, (ucfirst $1), $2); + } elsif (s/^\w+\b//) { + $no .= ahref($&, 'Func', $&); + } else { + die "$_ ?"; + } + } + return $no; +} + +sub refhref ($$) { + my ($type,$name) = @_; + $sdef{$type}{$name}{Used} = 1; + my $locs = $sdef{$type}{$name}{DefLocs}; + return '' unless $locs; + if ((scalar keys %$locs) != 1 && !$sdef{$type}{$name}{MultiWarned}) { + warning("multiple definitions of $type $name: $_") + foreach keys %$locs; + $sdef{$type}{$name}{MultiWarned}=1; + } + my ($loc) = values %$locs; + return "href=\"$loc#${type}_$name\""; +} + +sub ahref ($$$) { + my ($text,$type,$name) = @_; + return aelem($text,$text, refhref($type,$name)); +} + +sub defmacro ($) { + my ($valname) = @_; + if (!$in_enum) { + return $valname; + } elsif (substr($valname, 0, (length $in_enum->[0])) ne $in_enum->[0]) { + warning("in enum expecting $in_enum->[0]* got $valname"); + return $valname; + } else { + my $reftype = $in_enum->[1]; + my $refname = $in_enum->[2].substr($valname, (length $in_enum->[0])); + $sdef{$reftype}{$refname}{Xrefs}{$leaf,$.} = + "[see <a href=\"$leaf_opath#EnumVal_$valname\">$valname</a>]"; + $sdef{EnumVal}{$valname}{Used} = 1; + return defn($valname,'EnumVal',$valname, refhref($reftype,$refname)); + } +} + +sub out_xrefs ($) { + my ($linemapfunc) = @_; + foreach my $xref (@pending_xrefs) { + $o .= $linemapfunc->($xref); + $o .= "\n"; + } + @pending_xrefs = (); +} + +sub write_file ($$) { + my ($opath, $odata) = @_; + my $out = new IO::File "$opath.new", '>' or die "$opath $!"; + print $out $odata or die $!; + rename "$opath.new", "$opath" or die "$opath $!"; +} + +sub process_file ($$) { + my ($infile, $outfile) = @_; + debug(1,"$pass $infile => $outfile"); + my $in = new IO::File "$infile", '<' or die "$infile $!"; + + $o = ''; + $in_enum = undef; + @pending_xrefs = (); + + $o .= "<html><head><title>$leaf - $xtitle
\n";
+    
+    while (<$in>) {
+	s/\&/\&/g;
+	s/\/\>/g;
+
+	if (m/^(.*\`)[ \t]*$/) {
+	    my $lhs = $1;
+	    out_xrefs(sub { "$1 $_[0]"; });
+	} elsif (m/^\s*$/) {
+	    out_xrefs(sub { sprintf "/* %70s */", $_[0]; });
+	}
+
+	# In case of comments, strip " /* ` " and " * ` ";
+	my $lstripped = s,^ \s* /? \* \s* \` \  ,,x ? $&: '';
+
+	# Strip trailing whitespace and perhaps trailing "*/" or "*"
+	s,(?: \s* \* /? )? \s* $,,x or die;
+	my $rstripped = $&;
+
+	# Now the actual functionality:
+
+	debug(3,"$. $_");
+
+	if (!m/^(?: __attribute__ | __pragma__ )\b/x &&
+	    s/^( (?: \w+\  )? ) (\w+[a-z]\w+) ( \( .*)$
+             / $1.defn($2,'Func',$2).norm($3) /xe) {
+	} elsif (s/^((struct|union|enum) \  (\w+)) ( \s+ \{ .* )$
+                  / defn($1,(ucfirst $2),$3).norm($4) /xe) {
+	    if ($2 eq 'enum') {
+		if (m,/[/*] (\w+)\* \=\>\; (\w+)\*\(\),) { 
+		    in_enum($1,'Func',$2)
+		} elsif (m,/[/*] (\w+)\* \=\>\; (struct) (\w+)\*,) { 
+		    in_enum($1,(ucfirst $2),$3);
+	        }
+	    }
+	} elsif (s/^( \s* \#define \s+ ) (\w+) ( \s+\S )
+                  / $1.defmacro($2).norm($3) /xe) {
+	} else {
+	    if (m/^\s*\}/) {
+		$in_enum = undef;
+	    }
+	    $_ = norm($_);
+	}
+
+	# Write the line out
+
+	if ($pass == 2) {
+	    $o .= $lstripped;
+	    $o .= $_;
+	    $o .= $rstripped;
+	}
+    }
+
+    warning("pending xrefs at end of file") if @pending_xrefs;
+
+    if ($pass == 2) {
+	$o .= "
"; + write_file($outfile, $o); + } +} + + +foreach $pass (qw(1 2)) { + find({ wanted => + sub { + return unless m/\.h$/; + lstat $File::Find::name or die "$File::Find::name $!"; + -f _ or die "$File::Find::name"; + substr($File::Find::name, 0, 1+length $basedir) + eq "$basedir/" + or die "$File::Find::name $basedir"; + $leaf = substr($File::Find::name, 1+length $basedir); + if (!file_wanted()) { + debug(1,"$pass $File::Find::name excluded"); + return; + } + $leaf_opath = $leaf; + $leaf_opath =~ s#/#,#g; + $leaf_opath .= ".html"; + process_file($File::Find::name, $outdir.'/'.$leaf_opath); + }, + no_chdir => 1, + }, + map { "$basedir/$_" } @indirs); +} -- cgit v1.2.3