doc: generate admin ref from the pod documentation
authorchas williams - CONTRACTOR <chas@cmf.nrl.navy.mil>
Sat, 13 Aug 2011 14:18:45 +0000 (10:18 -0400)
committerDerrick Brashear <shadow@dementix.org>
Tue, 23 Aug 2011 16:37:33 +0000 (09:37 -0700)
a bit convoluted but this generates docbook from the pod documentation and
from that pdf, epub and mobi versions.  we are using variablelist.as.block
since that looks prettier on smaller devices/screen.

Change-Id: I5cd51ef10448373960a0aeed15212bbcf6f44039
Change-Id: Ib222dbfa30e3af644b1dbc6738df1d39cc33c92f
Reviewed-on: http://gerrit.openafs.org/5255
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Derrick Brashear <shadow@dementix.org>

configure.ac
doc/xml/AdminRef/Makefile.in [new file with mode: 0644]
doc/xml/AdminRef/auarf000.png [new file with mode: 0644]
doc/xml/AdminRef/auarf000.xml [new file with mode: 0644]
doc/xml/AdminRef/generate-xml.pl [new file with mode: 0755]
doc/xml/AdminRef/pod2refentry [new file with mode: 0755]
doc/xml/AdminRef/preface.xml [new file with mode: 0644]

index 97ef417..56ee4c2 100644 (file)
@@ -102,6 +102,11 @@ if test -f 'doc/xml/UserGuide/Makefile.in' ; then
 else
    USERGUIDE_MAKEFILE=
 fi
+if test -f 'doc/xml/AdminRef/Makefile.in' ; then
+   ADMINREF_MAKEFILE="doc/xml/AdminRef/Makefile"
+else
+   ADMINREF_MAKEFILE=
+fi
 if test -f 'doc/xml/mobi-fixup.xsl.in' ; then
    MOBI_FIXUP_XSL="doc/xml/mobi-fixup.xsl"
 else
@@ -114,6 +119,7 @@ ${MAN_MAKEFILE} \
 ${ADMINGUIDE_MAKEFILE} \
 ${QSUNIX_MAKEFILE} \
 ${USERGUIDE_MAKEFILE} \
+${ADMINREF_MAKEFILE} \
 ${MOBI_FIXUP_XSL} \
 src/afs/Makefile \
 src/afsd/Makefile \
diff --git a/doc/xml/AdminRef/Makefile.in b/doc/xml/AdminRef/Makefile.in
new file mode 100644 (file)
index 0000000..50facc6
--- /dev/null
@@ -0,0 +1,43 @@
+# Makefile to build the AFS Reference Guide for Unix.
+
+BOOK = auarf000
+
+all: $(BOOK).pdf $(BOOK).epub $(BOOK).mobi
+
+include @TOP_OBJDIR@/src/config/Makefile.config
+VERSION=version
+include @TOP_OBJDIR@/src/config/Makefile.version
+
+SRCS     = $(BOOK).xml preface.xml $(VERSION).xml \
+          entities.dtd sect1.xml sect5.xml sect8.xml
+DOCBOOK_STYLESHEETS = @DOCBOOK_STYLESHEETS@
+XSLTPROC = @XSLTPROC@ --stringparam variablelist.as.blocks 1
+DOCBOOK2PDF = @DOCBOOK2PDF@
+DBTOEPUB = $(DOCBOOK_STYLESHEETS)/epub/bin/dbtoepub
+
+entities.dtd sect1.xml sect5.xml sect8.xml:
+       ./generate-xml.pl $(TOP_SRCDIR)
+
+$(BOOK).pdf: $(SRCS)
+       if test "x$(DOCBOOK2PDF)" = "xfop"; then \
+               $(XSLTPROC) $(DOCBOOK_STYLESHEETS)/fo/docbook.xsl $(BOOK).xml > $(BOOK).fo; \
+               $(DOCBOOK2PDF) $(BOOK).fo $(BOOK).pdf; \
+       else \
+               $(DOCBOOK2PDF) $(BOOK).xml; \
+       fi
+
+$(BOOK).epub: $(SRCS)
+       if test -x "$(DBTOEPUB)" ; then \
+               $(DBTOEPUB) -s $(TOP_SRCDIR)/../doc/xml/mobi-fixup.xsl $(BOOK).xml; \
+       fi
+
+$(BOOK).mobi: $(BOOK).epub
+       kindlegen $(BOOK).epub -o $(BOOK).mobi
+
+check:
+       xmllint --noout --valid $(BOOK).xml
+
+clean:
+       rm -f $(BOOK).pdf $(BOOK).mobi $(BOOK).epub $(BOOK).fo \
+               entities.dtd sect1.xml sect5.xml sect8.xml $(VERSION).xml
+       rm -rf sect1 sect5 sect8
diff --git a/doc/xml/AdminRef/auarf000.png b/doc/xml/AdminRef/auarf000.png
new file mode 100644 (file)
index 0000000..263dba0
Binary files /dev/null and b/doc/xml/AdminRef/auarf000.png differ
diff --git a/doc/xml/AdminRef/auarf000.xml b/doc/xml/AdminRef/auarf000.xml
new file mode 100644 (file)
index 0000000..6cbe7dc
--- /dev/null
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.3//EN"
+        "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
+<!ENTITY version SYSTEM "version.xml">
+<!ENTITY preface SYSTEM "preface.xml">
+<!ENTITY sect1 SYSTEM "sect1.xml">
+<!ENTITY sect5 SYSTEM "sect5.xml">
+<!ENTITY sect8 SYSTEM "sect8.xml">
+<!ENTITY % entities SYSTEM "entities.dtd">
+  %entities;
+]>
+
+<book>
+  <bookinfo>
+    <title>OpenAFS Administration Reference</title>
+
+    <mediaobject role="cover">
+      <imageobject>
+        <imagedata fileref="auarf000.png" />
+      </imageobject>
+    </mediaobject>
+
+    <copyright>
+      <year>2000</year>
+
+      <holder>IBM Corporation. All Rights Reserved</holder>
+    </copyright>
+
+    <revhistory>
+      &version;
+
+      <revision>
+        <revnumber>3.6</revnumber>
+
+       <date>April 2000</date>
+
+        <revremark>First IBM Edition, Document Number GC09-4563-00</revremark>
+      </revision>
+    </revhistory>
+
+    <abstract>
+      <para>
+        This reference manual details the syntax of each OpenAFS command
+        and is intended for the experienced AFS administrator, programmer,
+        or user.
+     </para>
+
+      <para>
+        In general, this document does not explain when to use a command
+        or its place in the sequence of commands that make up a
+        complete procedure. For that type of information, refer to the
+        <emphasis>OpenAFS Administration Guide</emphasis>.
+      </para>
+    </abstract>
+  </bookinfo>
+
+  &preface;
+
+  <reference>
+    <title>AFS Commands</title>
+    &sect1;
+  </reference>
+
+  <reference>
+    <title>AFS System Files</title>
+    &sect5;
+  </reference>
+
+  <reference>
+    <title>AFS System Commands</title>
+    &sect8;
+  </reference>
+  <index></index>
+</book>
diff --git a/doc/xml/AdminRef/generate-xml.pl b/doc/xml/AdminRef/generate-xml.pl
new file mode 100755 (executable)
index 0000000..f414bc6
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/perl
+    eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
+       if $running_under_some_shell;
+
+@sections = ('1', '5', '8');
+
+$TOP_SRCDIR = shift @ARGV;
+$doc_man_pages = sprintf "%s/../doc/man-pages", $TOP_SRCDIR;
+
+open(ENTITIES, ">entities.dtd") || die;
+
+foreach $section (@sections) {
+    printf "generating section %s...\n", $section;
+
+    mkdir(sprintf "sect%d", $section);
+    opendir($DIR, sprintf "%s/pod%d", $doc_man_pages, $section) || die;
+    open(SECT, sprintf ">sect%d.xml", $section) || die;
+    while ($podfile = readdir($DIR)) {
+       next unless $podfile =~ /\.pod$/;
+
+       ($xmlfile = $podfile) =~ s/\.pod$/.xml/;
+       ($entity = $xmlfile) =~ s/\.xml$//;
+
+       printf "pod2refentry < %s > %s\n", $podfile, $xmlfile;
+
+       system(sprintf "./pod2refentry --section=%d < %s/pod%d/%s > sect%d/%s",
+           $section, $doc_man_pages, $section, $podfile, $section, $xmlfile);
+
+       printf ENTITIES "<!ENTITY %s%s SYSTEM \"sect%d/%s\">\n",
+           $entity, $section, $section, $xmlfile;
+       printf SECT "&%s%s;\n", $entity, $section;
+    }
+    closedir($DIR);
+    close(SECT);
+}
+
+close(ENTITIES);
diff --git a/doc/xml/AdminRef/pod2refentry b/doc/xml/AdminRef/pod2refentry
new file mode 100755 (executable)
index 0000000..371c21e
--- /dev/null
@@ -0,0 +1,558 @@
+#!/usr/bin/perl
+    eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
+        if $running_under_some_shell;
+
+# Pod::RefEntry -- Convert POD data to DocBook RefEntry
+#
+# Copyright 2005, 2006 by Chas Williams <chas@cmf.nrl.navy.mil>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the same terms as Perl itself.
+#
+# based on:
+#
+# Pod::PlainText -- Convert POD data to formatted ASCII text.
+# $Id: Text.pm,v 2.1 1999/09/20 11:53:33 eagle Exp $
+#
+# Copyright 1999-2000 by Russ Allbery <rra@stanford.edu>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the same terms as Perl itself.
+
+package Pod::RefEntry;
+
+require 5.005;
+
+use Carp qw(carp);
+use Pod::Select ();
+
+use strict;
+use vars qw(@ISA %ESCAPES $VERSION);
+
+# We inherit from Pod::Select instead of Pod::Parser so that we can be used
+# by Pod::Usage.
+@ISA = qw(Pod::Select);
+
+$VERSION = '0.06';
+
+# This table is taken near verbatim from Pod::PlainText in Pod::Parser,
+# which got it near verbatim from the original Pod::Text.  It is therefore
+# credited to Tom Christiansen, and I'm glad I didn't have to write it.  :)
+%ESCAPES = (
+    'amp'       =>    '&amp;',      # ampersand
+    'lt'        =>    '&lt;',      # left chevron, less-than
+    'gt'        =>    '&gt;',      # right chevron, greater-than
+    'quot'      =>    '"',      # double quote
+);
+
+# Initialize the object.  Must be sure to call our parent initializer.
+sub initialize {
+    my $self = shift;
+
+    $$self{hlevel}   = 0  unless defined $$self{hlevel};
+    $$self{ltype}    = 0  unless defined $$self{ltype};
+    $$self{lopen}    = 0  unless defined $$self{lopen};
+    $$self{indent}   = 2  unless defined $$self{indent};
+    $$self{width}    = 76 unless defined $$self{width};
+    $$self{refnamediv} = 0;
+
+    $$self{LSTATE}   = [];
+    $$self{MARGIN}   = 0;               # Current left margin in spaces.
+
+    $self->SUPER::initialize;
+}
+
+sub begin_pod {
+    my $self = shift;
+
+    $self->output ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+}
+
+sub end_pod {
+    my $self = shift;
+    my $i;
+
+    for($i = 4; $i > 0; --$i) {
+       if ($$self{hlevel} >= $i) {
+           $self->{MARGIN} -= 2;
+            #$self->output ("</refsection>\n");
+            $self->output (sprintf "</refsect%d>\n", $i);
+       };
+    };
+
+    $self->{MARGIN} -= 2;
+    $self->output ("</refentry>\n");
+}
+
+# Called for each command paragraph.  Gets the command, the associated
+# paragraph, the line number, and a Pod::Paragraph object.  Just dispatches
+# the command to a method named the same as the command.  =cut is handled
+# internally by Pod::Parser.
+sub command {
+    my $self = shift;
+    my $command = shift;
+    return if $command eq 'pod';
+    return if ($$self{EXCLUDE} && $command ne 'end');
+    $self->item ("\n") if defined $$self{ITEM};
+    $command = 'cmd_' . $command;
+    $self->$command (@_);
+}
+
+# Called for a verbatim paragraph.  Gets the paragraph, the line number, and
+# a Pod::Paragraph object.  Just output it verbatim, but with tabs converted
+# to spaces.
+sub verbatim {
+    my $self = shift;
+    return if $$self{EXCLUDE};
+    $self->item if defined $$self{ITEM};
+    local $_ = shift;
+    return if /^\s*$/;
+    $$self{MARGIN} += 2;
+    s/&/&amp;/g;       # do &amp; first to avoid "fixing" the & in &lt;
+    s/</&lt;/g;
+    s/>/&gt;/g;
+    my $saved = $$self{MARGIN};
+    $$self{MARGIN} = 0;
+    $self->output ("<programlisting>\n");
+    $self->output ($_);
+    $self->output ("</programlisting>\n");
+    $$self{MARGIN} = $saved;
+}
+
+sub escapes {
+    (undef, local $_) = @_;
+    s/(&)/\&amp;/g;
+    s/(<)/\&lt;/g;
+    s/(>)/\&gt;/g;
+    $_;
+}
+
+# Called for interior sequences.  Gets a Pod::InteriorSequence object
+# and is expected to return the resulting text.
+sub sequence {
+    my ($self, $seq) = @_;
+
+    my $cmd_name = $seq->cmd_name;
+
+    $seq->left_delimiter( '' );
+    $seq->right_delimiter( '' );
+    $seq->cmd_name( '' );
+    $_ = $seq->raw_text;
+
+    if ($cmd_name eq 'B') {
+       $_ = sprintf "<emphasis role=\"bold\">%s</emphasis>", $_;
+    } elsif ($cmd_name eq 'C') {
+       $_ = sprintf "<computeroutput>%s</computeroutput>", $_;
+    } elsif ($cmd_name eq 'F') {
+       $_ = sprintf "<replaceable>%s</replaceable>", $_;
+    } elsif ($cmd_name eq 'I') {
+       $_ = sprintf "<emphasis>%s</emphasis>", $_;
+    } elsif ($cmd_name eq 'S') {
+       # perhaps translate ' ' to &nbsp;
+       $_ = sprintf "%s", $_;
+    } elsif ($cmd_name eq 'L') {
+       $_ = $self->seq_l ($seq);
+    } elsif ($cmd_name eq 'E') {
+       if (defined $ESCAPES{$_}) {
+            $_ = $ESCAPES{$_} if defined $ESCAPES{$_};
+       } else {
+            carp "Unknown escape: E<$_>";
+       }
+    } else {
+       carp "\nUnknown sequence $cmd_name<$_>\n";
+    }
+
+    my $parent = $seq->nested;
+    if (defined $parent) {
+
+        if ($parent->cmd_name eq 'B') {
+           $_ = sprintf "</emphasis>%s<emphasis role=\"bold\">", $_;
+       } elsif ($parent->cmd_name eq 'C') {
+           $_ = sprintf "</computeroutput>%s<computeroutput>", $_;
+       } elsif ($parent->cmd_name eq 'F') {
+           $_ = sprintf "</replaceable>%s<replaceable>", $_;
+       } elsif ($parent->cmd_name eq 'I') {
+           $_ = sprintf "</emphasis>%s<emphasis>", $_;
+       }
+    }
+
+    return $_;
+}
+
+# Called for a regular text block.  Gets the paragraph, the line number, and
+# a Pod::Paragraph object.  Perform parse_text and output the results.
+sub textblock {
+    my $self = shift;
+    return if $$self{EXCLUDE};
+    $self->output ($_[0]), return if $$self{VERBATIM};
+    local $_ = shift;
+    my $line = shift;
+    my $name;
+    my $purpose;
+
+#    /<http:.*>/ && do {
+#        s/<http:([^>]+)\>/<ulink url=\"http:\1\">http:\1<\/ulink>/;
+#    };
+#
+#    /<.*@.*>/ && do {
+#        s/<([^>]+@[^>]+)>/<email>\1<\/email>/g;
+#    };
+
+    $_ = $self->parse_text(
+       { -expand_text => q(escapes),
+         -expand_seq => q(sequence) },
+                                       $_, $line ) -> raw_text();
+
+    if (defined $$self{ITEM}) {
+        $self->item ($_ . "\n");
+    } elsif ($self->{refnamediv}) {
+       ($name, $purpose) = /(.+)\s+\-\s+(.+)/;
+       my $id = $name;
+       $id =~ s/,.*$//;                # only reference by first entry?
+       $id =~ s/[ \.,\(\)]/_/g;
+       if (defined $$self{section}) {
+           $id = sprintf "%s%d", $id, $$self{section};
+       }
+       $self->output ("<refentry id=\"$id\">\n");
+       $self->{MARGIN} += 2;
+       if (defined $$self{section}) {
+           $self->output ("<refmeta>\n");
+           $self->{MARGIN} += 2;
+           $self->output (sprintf "<refentrytitle>%s</refentrytitle>\n",  $name);
+           $self->output (sprintf "<manvolnum>%d</manvolnum>\n",  $$self{section});
+           $self->{MARGIN} -= 2;
+           $self->output ("</refmeta>\n");
+       }
+       $self->output ("<refnamediv>\n");
+       $self->{MARGIN} += 2;
+       $self->output ("<refname>$name</refname>\n");
+       $self->output ("<refpurpose>$purpose</refpurpose>\n");
+       $self->{MARGIN} -= 2;
+       $self->output ("</refnamediv>\n");
+       $self->{refnamediv} = 0;
+    } else {
+       s/\n+$//;
+       $self->output ("<para>" . $_ . "<\/para>" . "\n\n");
+    }
+}
+
+# Level headings.
+sub cmd_head {
+    my $self = shift;
+    local $_ = shift;
+    my $line = shift;
+    my $level = $self->{level};
+    my $i;
+
+    for($i = 4; $i > 0; --$i) {
+       if ($level <= $i) {
+           if ($$self{hlevel} >= $i) {
+               $$self{MARGIN} -= 2;
+               #$self->output (sprintf "</refsection>\n", $i);
+               $self->output (sprintf "</refsect%d>\n", $i);
+           }
+       }
+    }
+
+    # special, output next <para> as <refnamediv>
+    if ($level == 1 && $_ =~ /NAME/) {
+       $self->{refnamediv} = 1;
+       return;
+    }
+
+    #$self->output (sprintf "<refsection>\n", $level);
+    $self->output (sprintf "<refsect%d>\n", $level);
+    $$self{MARGIN} += 2;
+    s/\s+$//;
+    $_ = $self->parse_text(
+       { -expand_text => q(escapes),
+         -expand_seq => q(sequence) },
+                                       $_, $line ) -> raw_text();
+    if (/^[A-Z ]+$/) {
+       s/(\w+)/\u\L$1/g if $level == 1;        # kill capitalization
+    }
+    $self->output ("<title>" . $_ . "<\/title>" . "\n");
+    $$self{hlevel} = $level;
+}
+
+# First level heading.
+sub cmd_head1 {
+    my $self = shift;
+    $self->{level} = 1;
+    $self->cmd_head (@_);
+}
+
+# Second level heading.
+sub cmd_head2 {
+    my $self = shift;
+    $self->{level} = 2;
+    $self->cmd_head (@_);
+}
+
+# Third level heading.
+sub cmd_head3 {
+    my $self = shift;
+    $self->{level} = 3;
+    $self->cmd_head (@_);
+}
+
+sub cmd_head4 {
+    my $self = shift;
+    # <refsect4> doesnt exist -- we would use <refsection>
+    # when it becomes available in 4.4
+    printf STDERR "=head4 being rendered as <refsect3>\n";
+    $self->{level} = 3;
+    $self->cmd_head (@_);
+}
+
+# Start a list.
+sub cmd_over {
+    my $self = shift;
+    local $_ = shift;
+    unless (/^[-+]?\d+\s+$/) { $_ = $$self{indent} }
+    push (@{ $$self{LSTATE} }, $$self{lopen});
+    push (@{ $$self{LSTATE} }, $$self{ltype});
+    undef $self->{ltype};
+    $$self{lopen} = 0;
+}
+
+# End a list.
+sub cmd_back {
+    my $self = shift;
+    if ($self->{ltype} == 2) {
+       $self->{MARGIN} -= 2;
+        $self->output ("</listitem>\n");
+       $self->{MARGIN} -= 2;
+       $self->output ("</orderedlist>\n");
+    } elsif ($self->{ltype} == 1) {
+       $self->{MARGIN} -= 2;
+        $self->output ("</listitem>\n");
+       $self->{MARGIN} -= 2;
+       $self->output ("</itemizedlist>\n");
+    } else {
+       $self->{MARGIN} -= 2;
+        $self->output ("</listitem>\n");
+       $self->{MARGIN} -= 2;
+        $self->output ("</varlistentry>\n");
+       $self->{MARGIN} -= 2;
+       $self->output ("</variablelist>\n");
+    }
+    $$self{ltype} = pop @{ $$self{LSTATE} };
+    $$self{lopen} = pop @{ $$self{LSTATE} };
+    unless (defined $$self{LSTATE}) {
+        carp "Unmatched =back";
+        $$self{MARGIN} = $$self{indent};
+    }
+}
+
+# An individual list item.
+sub cmd_item {
+    my $self = shift;
+    if (defined $$self{ITEM}) { $self->item }
+    local $_ = shift;
+    my $line = shift;
+    s/\s+$//;
+    $$self{ITEM} = $self->parse_text(
+       { -expand_text => q(escapes),
+         -expand_seq => q(sequence) },
+                                       $_, $line ) -> raw_text();
+}
+
+# Begin a block for a particular translator.  Setting VERBATIM triggers
+# special handling in textblock().
+sub cmd_begin {
+    my $self = shift;
+    local $_ = shift;
+    my ($kind) = /^(\S+)/ or return;
+    if ($kind eq 'text') {
+        $$self{VERBATIM} = 1;
+    } else {
+        $$self{EXCLUDE} = 1;
+    }
+}
+
+# End a block for a particular translator.  We assume that all =begin/=end
+# pairs are properly closed.
+sub cmd_end {
+    my $self = shift;
+    $$self{EXCLUDE} = 0;
+    $$self{VERBATIM} = 0;
+}    
+
+# One paragraph for a particular translator.  Ignore it unless it's intended
+# for text, in which case we treat it as a verbatim text block.
+sub cmd_for {
+    my $self = shift;
+    local $_ = shift;
+    my $line = shift;
+    return unless s/^text\b[ \t]*\n?//;
+    $self->verbatim ($_, $line);
+}
+
+# The complicated one.  Handle links.  Since this is plain text, we can't
+# actually make any real links, so this is all to figure out what text we
+# print out.
+sub seq_l {
+    my ($self, $seq) = @_;
+
+    s/>$//;    # remove trailing >
+
+    # Smash whitespace in case we were split across multiple lines.
+    s/\s+/ /g;
+
+    # If we were given any explicit text, just output it.
+    if (/^([^|]+)\|/) { return $1 }
+
+    # Okay, leading and trailing whitespace isn't important; get rid of it.
+    s/^\s+//;
+    s/\s+$//;
+
+    # Default to using the whole content of the link entry as a section
+    # name.  Note that L<manpage/> forces a manpage interpretation, as does
+    # something looking like L<manpage(section)>.  The latter is an
+    # enhancement over the original Pod::Text.
+    my ($manpage, $section) = ('', $_);
+    if (/^(?:https?|ftp|news):/) {
+        # a URL
+        return $_;
+    } elsif (/^"\s*(.*?)\s*"$/) {
+        $section = '"' . $1 . '"';
+    } elsif (m/^[-:.\w]+(?:\(\S+\))?$/) {
+        ($manpage, $section) = ($_, '');
+    } elsif (m%/%) {
+        ($manpage, $section) = split (/\s*\/\s*/, $_, 2);
+    }
+
+    $seq->cmd_name("");
+
+    # Now build the actual output text.
+    if (length $section) {
+        $section =~ s/^\"\s*//;
+        $section =~ s/\s*\"$//;
+        $_ = $section;
+        $_ .= " in $manpage" if length $manpage;
+    }
+    if (length $manpage) {
+       my $linkend = $manpage;
+       $linkend =~ s/[\(\)]//g;
+       $linkend =~ s/[ ,\.]/_/g;       # this needs to match <refentry id=
+       $seq->prepend("<link linkend=\"$linkend\">");
+       $seq->append("</link>");
+       return $seq;
+    } else {
+       return $_;
+    }
+}
+
+# This method is called whenever an =item command is complete (in other
+# words, we've seen its associated paragraph or know for certain that it
+# doesn't have one).  It gets the paragraph associated with the item as an
+# argument.  If that argument is empty, just output the item tag; if it
+# contains a newline, output the item tag followed by the newline.
+# Otherwise, see if there's enough room for us to output the item tag in the
+# margin of the text or if we have to put it on a separate line.
+sub item {
+    my $self = shift;
+    local $_ = shift;
+    my $tag = $$self{ITEM};
+    unless (defined $tag) {
+        carp "item called without tag";
+        return;
+    }
+    undef $$self{ITEM};
+    if ($$self{lopen}) {
+        if ($self->{ltype} == 1 || $self->{ltype} == 2) {
+           $self->{MARGIN} -= 2;
+           $self->output ("</listitem>\n");
+        } else {
+           $self->{MARGIN} -= 2;
+           $self->output ("</listitem>\n");
+           $self->{MARGIN} -= 2;
+           $self->output ("</varlistentry>\n");
+       }
+    }
+    my $output = $_;
+    $output =~ s/\n*$/\n/;
+    if (!defined $self->{ltype}) {
+           if ($tag =~ /[0-9]+\./) {
+               $self->{ltype} = 2;
+               $self->output ("<orderedlist>\n");
+           } elsif ($tag =~ /^\*$/) {
+               $self->{ltype} = 1;
+               $self->output ("<itemizedlist>\n");
+           } else {
+               $self->{ltype} = 0;
+               $self->output ("<variablelist>\n");
+           }
+           $self->{MARGIN} += 2;
+    }
+    if ($self->{ltype} == 1 || $self->{ltype} == 2) {
+       $self->output ("<listitem>\n");
+       $self->{MARGIN} += 2;
+       s/\n+$//;
+       $self->output ("<para>" . $_ . "<\/para>" . "\n\n");
+    } else {
+       $self->output ("<varlistentry>\n");
+       $self->{MARGIN} += 2;
+       $self->output ("<term>" . $tag . "</term>" . "\n");
+       $self->output ("<listitem>\n");
+       $self->{MARGIN} += 2;
+       s/\n+$//;
+       $self->output ("<para>" . $_ . "<\/para>" . "\n\n");
+    }
+    $$self{lopen} = 1;
+}
+
+# Output text to the output device.
+sub output {
+    my $self = shift;
+    local $_ = shift;
+    s/^(\s*\S+)/(' ' x $$self{MARGIN}) . $1/gme;
+    print { $self->output_handle } $_;
+}
+
+1;
+
+
+# pod2refentry -- Convert POD data to DocBook RefEntry
+#
+# Copyright 2005, 2006 by Chas Williams <chas@cmf.nrl.navy.mil>
+#
+# This program is free software; you may redistribute it and/or modify it
+# under the same terms as Perl itself.
+#
+# based on:
+#
+# pod2text -- Convert POD data to formatted ASCII text.
+#
+# Copyright 1999, 2000, 2001 by Russ Allbery <rra@stanford.edu>
+#
+# This program is free software; you may redistribute it and/or modify it
+# under the same terms as Perl itself.
+
+package main;
+
+require 5.004;
+
+use Getopt::Long qw(GetOptions);
+use Pod::Usage qw(pod2usage);
+
+use strict;
+
+# Silence -w warnings.
+use vars qw($running_under_some_shell);
+
+# Insert -- into @ARGV before any single dash argument to hide it from
+# Getopt::Long; we want to interpret it as meaning stdin (which Pod::Parser
+# does correctly).
+my $stdin;
+@ARGV = map { $_ eq '-' && !$stdin++ ? ('--', $_) : $_ } @ARGV;
+
+# Parse our options.
+my %options;
+GetOptions (\%options, 'help|h', 'indent|i=i', 'section|s=i' ) or exit 1;
+pod2usage (1) if $options{help};
+
+# Initialize and run the formatter.
+my $parser = Pod::RefEntry->new (%options);
+$parser->parse_from_file (@ARGV);
diff --git a/doc/xml/AdminRef/preface.xml b/doc/xml/AdminRef/preface.xml
new file mode 100644 (file)
index 0000000..36aea80
--- /dev/null
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<preface id="Header_2">
+  <title>About This Manual</title>
+
+  <para>This chapter describes the purpose, organization, and conventions of this document.</para>
+
+  <sect1 id="HDRWQ1">
+    <title>Audience and Purpose</title>
+
+    <para>This reference manual details the syntax of each OpenAFS command and
+    is intended for the experienced AFS administrator, programmer, or user.</para>
+
+    <para>In general, this document does not explain when to use a command or its place in the sequence of commands that make up a
+    complete procedure. For that type of information, refer to the <emphasis>OpenAFS Administration Guide</emphasis>.</para>
+  </sect1>
+
+  <sect1 id="HDRWQ2">
+    <title>Organization</title>
+
+    <para>This document presents OpenAFS files and commands in separate sections, with the files or commands in alphabetical
+    order.</para>
+
+    <para>The following sections of each reference page provide the indicated type of information:</para>
+
+    <itemizedlist>
+      <listitem>
+        <para><emphasis role="bold">Purpose</emphasis> briefly describes the command's function.</para>
+      </listitem>
+
+      <listitem>
+        <para><emphasis role="bold">Synopsis</emphasis> displays the complete syntax statement for a command, which specifies the
+        required order for all options, using the same notation as the OpenAFS online help. If abbreviating the command name a nd option
+        names is acceptable, as it is for most commands, a second statement specifies the shortest acceptable abbreviation of each
+        name. If the command has an alias, it also appears in this section.</para>
+      </listitem>
+
+      <listitem>
+        <para><emphasis role="bold">Description</emphasis> describes the file or command's function in detail.</para>
+      </listitem>
+
+      <listitem>
+        <para><emphasis role="bold">Cautions</emphasis> describes restrictions, requirements, and potential complications in use of
+        the command. It appears only when necessary.</para>
+      </listitem>
+
+      <listitem>
+        <para><emphasis role="bold">Options</emphasis> describes the function and required form of each argument and flag.</para>
+      </listitem>
+
+      <listitem>
+        <para><emphasis role="bold">Output</emphasis> describes any output the command writes to the standard output stream. This
+        section does not appear if the command does not produce output or if the only output is a message confirming the command's
+        success.</para>
+      </listitem>
+
+      <listitem>
+        <para><emphasis role="bold">Examples</emphasis> provides one or more sample commands and resulting output.</para>
+      </listitem>
+
+      <listitem>
+        <para><emphasis role="bold">Privilege Required</emphasis> lists each privilege required to perform the command.</para>
+      </listitem>
+
+      <listitem>
+        <para><emphasis role="bold">Related Information</emphasis> lists related commands and files, if any.</para>
+      </listitem>
+    </itemizedlist>
+  </sect1>
+
+  <sect1 id="HDRWQ3">
+    <title>How to Use This Document</title>
+
+    <para>Refer to this document when you need detailed information about a specific command. For a description of all the steps in
+    a procedure, refer to the <emphasis>OpenAFS Administration Guide</emphasis>.</para>
+  </sect1>
+
+  <sect1 id="HDRWQ4">
+    <title>Related Documents</title>
+
+    <para>The following documents are included in the OpenAFS documentation set.</para>
+
+    <para><emphasis>OpenAFS Administration Guide</emphasis></para>
+
+    <para>This guide describes the concepts and procedures that a system administrator must know to manage an AFS cell. It assumes
+    familiarity with UNIX, but requires no previous knowledge of AFS.</para>
+
+    <para>The first chapters of the <emphasis>OpenAFS Administration Guide</emphasis> present basic concepts and guidelines.
+    Understanding them is crucial to successful administration of an AFS cell. The remaining chapters in the guide provide
+    step-by-step instructions for specific administrative tasks, along with discussions of the concepts important to that particular
+    task.</para>
+
+    <para><emphasis>OpenAFS Quick Beginnings</emphasis></para>
+
+    <para>This guide provides instructions for installing OpenAFS server and client machines. It is assumed that the installer is an
+    experienced UNIX<superscript><superscript>(R)</superscript></superscript> system administrator.</para>
+
+    <para>For predictable performance, machines must be installed and configured in accordance with the instructions in this
+    guide.</para>
+
+    <para><emphasis>OpenAFS Release Notes</emphasis></para>
+
+    <para>This document provides information specific to each release of OpenAFS, such as a list of new features and commands, a list of
+    requirements and limitations, and instructions for upgrading server and client machines.</para>
+
+    <para><emphasis>OpenAFS User Guide</emphasis></para>
+
+    <para>This guide presents the basic concepts and procedures necessary for using AFS effectively. It assumes that the reader has
+    some experience with UNIX, but does not require familiarity with networking or AFS.</para>
+
+    <para>The guide explains how to perform basic functions, including authenticating, changing a password, protecting AFS data,
+    creating groups, and troubleshooting. It provides illustrative examples for each function and describes some of the differences
+    between the UNIX file system and AFS.</para>
+  </sect1>
+
+  <sect1 id="HDRTYPO_CONV">
+    <title>Typographical Conventions</title>
+
+    <para>This document uses the following typographical conventions:</para>
+
+    <itemizedlist>
+      <listitem>
+        <para>Command and option names appear in <emphasis role="bold">bold type</emphasis> in syntax definitions, examples, and
+        running text. Names of directories, files, machines, partitions, volumes, and users also appear in <emphasis
+        role="bold">bold type</emphasis>.</para>
+      </listitem>
+
+      <listitem>
+        <para>Variable information appears in <emphasis>italic type</emphasis>. This includes user-supplied information on command
+        lines and the parts of prompts that differ depending on who issues the command. New terms also appear in <emphasis>italic
+        type</emphasis>.</para>
+      </listitem>
+
+      <listitem>
+        <para>Examples of screen output and file contents appear in <computeroutput>monospace type</computeroutput>.</para>
+      </listitem>
+    </itemizedlist>
+
+    <para>In addition, the following symbols appear in command syntax definitions, both in the documentation and in OpenAFS online help
+    statements. When issuing a command, do not type these symbols.</para>
+
+    <itemizedlist>
+      <listitem>
+        <para>Square brackets <emphasis role="bold">[ ]</emphasis> surround optional items.</para>
+      </listitem>
+
+      <listitem>
+        <para>Angle brackets <emphasis role="bold">&lt; &gt;</emphasis> surround user-supplied values in OpenAFS commands.</para>
+      </listitem>
+
+      <listitem>
+        <para>A superscripted plus sign <emphasis role="bold">+</emphasis> follows an argument that accepts more than one
+        value.</para>
+      </listitem>
+
+      <listitem>
+        <para>The percent sign <computeroutput>%</computeroutput> represents the regular command shell prompt. Some operating
+        systems possibly use a different character for this prompt.</para>
+      </listitem>
+
+      <listitem>
+        <para>The number sign <computeroutput>#</computeroutput> represents the command shell prompt for the local superuser
+        <emphasis role="bold">root</emphasis>. Some operating systems possibly use a different character for this prompt.</para>
+      </listitem>
+
+      <listitem>
+        <para>The pipe symbol <emphasis role="bold">|</emphasis> in a command syntax statement separates mutually exclusive values
+        for an argument.</para>
+      </listitem>
+    </itemizedlist>
+  </sect1>
+</preface>