[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 1/4] 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 <ian.jackson@xxxxxxxxxxxxx> --- docs/Makefile | 8 ++ docs/xen-headers | 292 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 300 insertions(+), 0 deletions(-) create mode 100755 docs/xen-headers diff --git a/docs/Makefile b/docs/Makefile index 2054541..ad315cf 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -129,6 +129,14 @@ html/%.html: %.markdown $(MARKDOWN) $< > $@.tmp ; \ $(call move-if-changed,$@.tmp,$@) ; fi +html/hypercall/stamp: + @$(INSTALL_DIR) $(@D) + ./xen-headers -O $(@D) \ + -T 'arch-x86_64 - Xen public headers' \ + -X arch-ia64 -X arch-x86_32 -X xen-x86_32 \ + ../xen include/public + touch $@ + txt/%.txt: %.txt $(INSTALL_DIR) $(@D) cp $< $@.tmp diff --git a/docs/xen-headers b/docs/xen-headers new file mode 100755 index 0000000..e893f91 --- /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 <title>) +# -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</title></head><body><pre>\n"; + + while (<$in>) { + s/\&/\&/g; + 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 .= "</pre></body></html>"; + 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); +} -- 1.7.2.5 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |