The Answer to All Man's Problems (part 3 of 6)
Tom Christiansen
tchrist at convex.COM
Tue Jan 8 09:19:54 AEST 1991
X }
X }
X printf STDERR " pathcheck returns $section\n" if $debug & 8;
X $return;
X}
X
X#---------------------------------------------------------------------------
X
Xsub flush {
X $| = 1;
X print '';
X $| = 0;
X}
X
Xsub has_meta {
X $_[0] =~ /[[*?]/;
X}
X
Xsub macro {
X @_[0] =~ /^\\\*\(/;
X}
X
Xsub really {
X local($was,$is) = @_;
X print " really in $was($is)\n";
X}
X
Xsub usage {
X die "usage: $iam [-d debug-level] [-s sub-sections] [-p manpath]
X [-x xrefpath] [pattern ...] \n";
X}
X
Xsub glob {
X local($expr) = @_;
X local(@retlist) = ();
X local(*METADIR); # paranoia
X
X die "glob: null expr" unless $expr; # assert
X
X if ($expr =~ /\//) {
X warn "glob: \"$expr\" has slashes, punting...";
X return <${expr}>;
X }
X
X $expr =~ s/\*/.*/g;
X $expr =~ s/\?/./g;
X
X unless (opendir(METADIR, '.')) {
X warn "glob: can't opendir ".": $!\n";
X } else {
X @retlist = sort grep(/$expr/o, grep(!/^\./, readdir(METADIR)));
X closedir METADIR;
X }
X return @retlist;
X}
X
Xsub dbmopen {
X local($tree) = $_[0];
X # globals: %dbmopened, %warned
X return 1 if $dbmopened{$tree};
X
X unless (-f "
X
X}
SHAR_EOF
if test 10347 -ne "`wc -c < 'cfman'`"
then
echo shar: "error transmitting 'cfman'" '(should have been 10347 characters)'
fi
chmod 775 'cfman'
fi
echo shar: "extracting 'cfman.8l'" '(6219 characters)'
if test -f 'cfman.8l'
then
echo shar: "will not over-write existing file 'cfman.8l'"
else
sed 's/^ X//' << \SHAR_EOF > 'cfman.8l'
X.TH CFMAN 8L "" "15 November 1989"
X.de Sh
X.br
X.PP
X.ne 4
X.ti -.5i
X\fB\\$1\fR
X.PP
X..
X.de LB \" little and bold
X.ft B
X.if !"\\$1"" \&\s-1\\$1\s+1 \\$2 \\$3 \\$4 \\$5 \\$6
X.ft R
X..
X.de Sp
X.if t .sp .5v
X.if n .sp
X..
X.ds lq \&"\"
X.ds rq \&"\"
X.if t \
X. ds lq ``
X.if t \
X. ds rq ''
X.de Q
X\*(lq\\$1\*(rq\\$2
X..
X.Sh NAME
Xcfman \- cross-reference man pages for internal consistency
X.Sh SYNOPSIS
X.B cfman
X[
X.B \-d
Xlevel
X]
X[
X.B \-s
Xsections
X]
X[
X.B \-p
Xmanpath
X]
X[
X.B \-x
Xxrefpath
X]
X[ pattern | pathname ] ...
X.br
X.Sh DESCRIPTION
X.I
XCfman
Xis a
X.I perl
Xprogram that checks that man page sources
Xare mutually consistent in their
X.LB "SEE ALSO"
Xreferences.
XIt will also report any
X.LB ".TH"
Xline that claims the
Xman page is in a different place than
X.I cfman
Xfound it.
X.PP
XWhen supplied with no arguments,
X.I cfman
Xwill check all files (matching *.*) it finds in each man directory in
Xyour colon-delimited
X.LB "$MANPATH"
Xenvariable if set, or in
X.I /usr/man
Xotherwise. It first verifies that the
X.LB ".TH"
Xsays
Xthe man page is really where it should be, e.g. if the
Xline is
X.br
X.in +.5i
X.nf
X\f(TA
X\&.TH\ \ WIDGET\ \ 4
X.in -.5i
X\fR
X.fi
X.br
Xthen \fIwidget.8\fP should be the filename currently
Xbeing examined. All upper-case will map to all lower-case,
Xbut mixed case will be preserved for compatibility with
Xthe
X.LB X11
Xman pages.
X.PP
X.I Cfman
Xthen skips ahead to the
X.LB "SEE ALSO"
Xsection and retrieves
Xall comma-delimited entries of the general
Xform \fIpagename(section)\fP. It first looks in the file
X\&../man\fIsection/pagename.section\fP. If this fails
Xand the current file ended in one of \fB[npl]\fP, but the
X.I section
Xreferenced is either
X\fB1\fP or \fB8\fP, then it will check in
X.I ../man8.
XFailing this,
X.I cfman
Xchecks to see whether the referenced man page has been
Xinstalled stripped of its subsection, e.g. \fIuucp\fP(1c)
Xhas found its way into \fIuucp\fP(1). It then checks
Xto see whether something in section \fB1\fP has been mis-installed
Xin section \fB8\fP, or vice versa, or either one in section \fBl\fP
Xmis-installed in the
Xin section \fB8\fP and vice-versa. If all else fails,
X.I cfman
Xwill guess that a man page is referenced without its
Xproper subsection, as in a reference to \fIrcp(1)\fP
Xthat should really have been to \fIrcp(1c)\fP. If it finds
Xthe misplaced man page, it reports where the reference
Xthought it was and where it really was. Otherwise it
Xreports the man page as missing.
X.PP
XThe
X.LB $MANPATH
Xvariable may be overridden by
Xthe \fB-p\fP option.
XAll checks will
Xbe performed across each subtree specified in the manpath
X(either from the environment of the command line),
Xunless altered with the \fB-x\fP option. As a short-cut,
Xthe \fIxrefpath\fP may have a leading colon to indicate
Xthat it is to be concatenation of the \fImanpath\fP
Xand the supplied \fIxrefpath\fP.
X.PP
XYou can restrict the sections checked with the \fB-s\fP
Xswitch. By default, sections 1 through 8 will be examined.
XThe section may be a shell metacharacter expression,
Xlike
X.Q ?
Xor
X.Q [18lpn] .
X.PP
XYou may restrict the individual man pages cross-referenced
Xby specifying which ones you're interested in on the command
Xline. These may be full pathnames, simple names like
X.Q tty ,
Xor a shell metacharacter expression like
X.Q *net .
XIf
Xno period occurs in the simple name, it is assumed to mean that
Xthe name may have any extension. If you list specific
Xman pages on the command line and
X.I cfman
Xfinds none matching your specification, it will report this fact.
XSee the
X.LB "EXAMPLES"
Xsection.
X.PP
XMan pages that are linked by placing a \fB.so\fP directive
Xon the first line will be correctly followed, and no man page
Xin the same subtree. Very limited support for alternate
Xman macros is provided: the
X.I "\fIRand MH Message Handling System\fP" 's
Xman macro set are recognized, as is Larry Wall's
X.LB .Sh
Xreplacement for
X.LB .SH.
X.Sh DIAGNOSTICS
XRequires
X.I perl
Xto be at least version 3.0, patchlevel 1 to run. The
Xprogram will abort if you try to run it with an
Xearlier version of perl
X.PP
XFive different tracing levels can be specified with the \fB-d\fP
Xoption. If any debugging is turned on, the walk through
Xthe different components of the manpath are traced.
XDebug values are numeric and additive, and are interpreted
Xthis way:
X.Sp
X.in +.5i
X.nf
X.ne 5
X 1 Trace each man page examined
X 2 Trace each cross reference examined
X 4 Trace each \s-1\fB.TH\s+1\fP check
X 8 Trace each file-existence test
X 16 Trace each line
X'in -.5i
X.fi
X.Sp
XTracing information and other warnings are printed to
X\fIstderr\fP, but normal messages about bad cross references
Xare printed to \fIstdout\fP as that is \fIcfman\fP's principle
Xtask.
X.PP
XEmbedded
X.I troff
Xstring macros starting \e*( cannot be resolved, and they
Xwill trigger a warning message if found in the
X.LB .TH
Xor
X.LB "SEE ALSO"
Xsections.
X.Sh EXAMPLES
X.nf
X\f(TA
Xcfman # do all in $MANPATH
Xcfman -p /export/exec/sun3/share/man # sun man pages
Xcfman -p $HOME/man:/usr/local/mh/man:/usr/local/man:/usr/man
Xcfman -p /usr/local/man -x :/usr/man # xref also in /usr/man
Xcfman -s 18nlp # only these sections
Xcfman '*tty*' fubar # check for *tty*.* and fubar.*
Xcfman `pwd`/*.[1-8] # just check these files
Xcfman -s 23 'sys*' # sys*.* files in sections 2,3
Xcfman -s 1 -p /export/exec/sun3/share/man
X.fi
X\fR
X.PP
XThe last command produced this output on my machine:
X.nf
X\f(TA
Xbanner.1v: thinks it's in banner(1)
Xfoption.1: skyversion(8) missing
Xfrom.1: prmail(1) missing
Xmake.1: rstat(8c) missing
Xman.1: apropos(1) missing
Xold-perfmon.1: missing .TH
Xoldperfmon.1: missing .TH
Xoldsetkeys.1: thinks it's in setkeys(1)
Xorganizer.1: restore(1v) really in restore(8)
Xsunview.1: traffic(1) really in traffic(1c)
Xsort.1v: thinks it's in sort(1)
Xsum.1v: thinks it's in sum(1)
X.fi
X\fR
X.Sh ENVIRONMENT
XThe default manpath will be taken from
X.LB $MANPATH
Xif set.
X.Sh "SEE ALSO"
Xman(1), troff(1), perl(1), man(7).
X.Sh BUGS
XDue to the current implentation of globbing in
X.I perl,
Xyou can get
X.Q "Arguments too long"
Xerrors. The workaround is to run
X.I cfman
Xfirst on
X.Q [a-m]* ,
Xand then on
X.Q [n-z]* .
X.Sh AUTHOR
XTom Christiansen, \s-1CONVEX\s+1 Computer Corporation.
SHAR_EOF
if test 6219 -ne "`wc -c < 'cfman.8l'`"
then
echo shar: "error transmitting 'cfman.8l'" '(should have been 6219 characters)'
fi
chmod 664 'cfman.8l'
fi
echo shar: "extracting 'makewhatis'" '(11184 characters)'
if test -f 'makewhatis'
then
echo shar: "will not over-write existing file 'makewhatis'"
else
sed 's/^ X//' << \SHAR_EOF > 'makewhatis'
X#!/usr/local/bin/perl
X#
X# makewhatis: perl rewrite for makewhatis
X# author: tom christiansen <tchrist at convex.com>
X#
X# Copyright 1990 Convex Computer Corporation.
X# All rights reserved.
X
Xeval "exec /usr/bin/perl -S $0 $*" # some bozo called us with 'sh foo'
X if $running_under_some_shell; # 'catman -w' likes to do this; sigh
X
X
X&source('stat.pl');
X
X($program = $0) =~ s,.*/,,;
X
X$UNCOMPRESS = "uncompress";
X
X$MAXWHATISLEN = 300;
X$MAXDATUM = 1024; # DBM is such a pain
X
Xumask 022;
X
X&source('getopts.pl');
X
Xdo Getopts('ynvdP:M:') || &usage;
X
X$opt_P = shift if $#ARGV >= 0;
X
X&usage if $#ARGV > -1;
X
Xsub usage { die "usage: $program [-n] [-y] [-v] [[-M] manpath]\n"; }
X
X$nflag = $opt_n;
X$yflag = $opt_y;
X
X$manpath = $opt_M if $opt_M;
X$manpath = $opt_P if $opt_P; # backwards contemptibility
X$manpath = "/usr/man" unless $manpath;
X at manpath = split(/:/,$manpath);
X
X$| = $debug = ($opt_d || $opt_v);
X
X$SIG{'INT'} = 'CLEANUP';
X$SIG{'TERM'} = 'CLEANUP';
X
X$SIG{'HUP'} = 'INGORE';
X
Xchop($cwd = `pwd`);
X
X$WHATIS = "whatis";
X
X# ---------------------------------------------------------------------------
X# main loop
X#
X# chdir to each root in man path. save mtime of dbase for later compares
X# with files in case of nflag or yflag.
X# ---------------------------------------------------------------------------
X
Xforeach $root ( @manpath ) {
X local($dbtime, $filecount, $entries);
X
X $root = "$cwd/$root" if $root !~ m:^/:; # normalize to fullpathname
X chdir $root || die "can't chdir to $root: $!";
X
X print "root to $root\n" if $debug;
X
X if ($nflag || $yflag) {
X unless (&Stat('whatis.pag')) {
X print "couldn't stat $root/whatis DBM file\n" if $debug;
X &rebuild(0, 0) if $yflag;
X next;
X }
X $dbtime = $st_mtime;
X }
X &rebuild($nflag, $yflag);
X}
X
Xexit $status;
X
X# ---------------------------------------------------------------------------
X# rebuild -- open a new whatis database, store all references in files in
X# this root to it. if dont_touch or test_stale parms set, just
X# do the checks. if test_stale, recurse on a real rebuild.
X# ---------------------------------------------------------------------------
X
Xsub rebuild {
X local($dont_touch, $test_stale) = @_;
X
X local(%seen); # {dev,ino} pairs of files seen
X local(%so); # the .so references seen
X local(@WHATIS); # whatis list
X local($entries, $filecount) = (0,0);
X
X unless ($dont_touch || $test_stale) {
X if (!open (WHATIS, "> $WHATIS.$$")) {
X warn "can't open $root/$WHATIS.$$: $!\n";
X $status = 1;
X return;;
X }
X if (!dbmopen(WHATIS, "$WHATIS.$$", 0644)) {
X warn "can't dbmopen $root/$WHATIS: $!\n";
X $status = 1;
X return;
X }
X }
X
X foreach $mandir ( <man?*> ) {
X next if $mandir =~ /man0.*/;
X next if $mandir =~ /\.(old|bak)$/i;
X next if $mandir =~ /~$/;
X next unless -d $mandir;
X
X if (!chdir $mandir) {
X warn "can't chdir to $root/$mandir: $!\n";
X next;
X }
X
X ($dirext) = $mandir =~ /man(.*)$/;
X $dirext =~ s/\.Z$//;
X
X print "subdir is $mandir\n" if $debug;
X
X if (!opendir(mandir,'.')) {
X warn "can't opendir('$root/$mandir'): $!\n";
X next;
X }
X
X # read each file in directory. use readdir not globbing
X # because we don't want to blow up on huge directories
XFILE: while ($FILE = readdir(mandir)) {
X $compressed = $mandir =~ m:.*\.Z:;
X next FILE if $FILE =~ /^\.{1,2}/;
X
X if ($FILE !~ /\S\.\S/) {
X print STDERR "Skipping non-man file: $FILE\n";
X next FILE;
X }
X
X # this will be optimized into a case statement
X if ($FILE =~ /\.old$/i) {
X next;
X } elsif ($FILE =~ /\.bak$/i) {
X next;
X } elsif ($FILE =~ /\.out$/i) {
X next;
X } elsif ($FILE =~ /~$/) {
X next;
X }
X
X ($tmpfile = $FILE) =~ s/\.Z$//;
X
X ($filenam, $filext) =
X $tmpfile =~ /^(\S+)\.([^.]+)$/;
X
X #if ($filext eq '.Z') {
X #($filenam, $filext) = $filenam =~ /^(\S+)\.([^.]+)(\.Z)?$/;
X #}
X
X if ($filext !~ /^${dirext}.*/ && $mandir ne 'mano') {
X print STDERR "$FILE has a funny extension ($filext) to be in $mandir\n";
X }
X
X unless (&Stat($FILE)) {
X warn "can't stat $root/$mandir/$FILE: $!\n";
X next FILE;
X }
X
X if ($dont_touch || $test_stale) {
X next unless $st_mtime > $dbtime;
X print "$root/$mandir/$FILE newer than its dbm whatis file\n";
X closedir mandir;
X chdir $root;
X &rebuild(0,0) if $test_stale;
X return;
X }
X
X if ($apage = $seen{$st_dev,$st_ino}) {
X printf "already saw %s, linked to %s\n", $FILE, $apage
X if $debug;
X &chopext($page = $FILE);
X unless ($WHATIS{$page}) {
X print "forgot $page\n" if $debug;
X &store_indirect($page, $apage);
X }
X next FILE;
X }
X $seen{$st_dev,$st_ino} = $FILE;
X
X $compressed |= $FILE =~ /\.Z$/;
X
X if (!open(FILE, $compressed ? "$UNCOMPRESS < $FILE |" : $FILE)) {
X warn "can't open $FILE: $!\n";
X next FILE;
X }
X
X $filecount++;
X print "opened $root/$mandir/$FILE\n" if $debug;
X
X &extract_names;
X }
X closedir mandir;
X chdir $root || die "can't chdir back to $root: $!";
X }
X
X unless ($dont_touch || $test_stale) {
X $, = "\n";
X print WHATIS (sort @WHATIS),'';
X $, = '';
X close WHATIS || warn "can't close $WHATIS.$$: $!";
X rename ("$WHATIS.$$", $WHATIS)
X || warn "can't rename $WHATIS.$$ to $WHATIS: $!";
X &check_sos();
X dbmclose(WHATIS) || warn "can't dbmclose $WHATIS: $!";
X for $ext ( 'pag', 'dir' ) {
X unlink "$WHATIS.$ext";
X rename("$WHATIS.$$.$ext", "$WHATIS.$ext")
X || warn "can't rename $WHATIS.$$.$ext: $!";
X }
X print "$program: $root: found $entries entries in $filecount files\n";
X }
X}
X
X
X# in case we get interrupted
X#
Xsub CLEANUP {
X print stderr "<<INTERRUPTED>> reading $FILE\n";
X chdir $root;
X unlink "$WHATIS.$$", "$WHATIS.$$.pag", "$WHATIS.$$.dir";
X exit 1;
X}
X
X# get next line from FILE, honoring escaped newlines
X#
Xsub getline {
X local ($_);
X
X $_ = <FILE>;
X {
X chop;
X if (/\\$/) {
X chop;
X $_ .= ' ';
X $_ .= <FILE>;
X redo;
X }
X }
X $_;
X}
X
Xsub extract_names {
X local($_);
X local($needcmdlist) = 0;
X local($foundname) = 0;
X local(@lines);
X local($page, $page2, $indirect, $foundname, @lines, $nameline);
X local($cmdlist, $ocmdlist, $tmpfile, $section);
X local($prototype, $seenpage);
X
X unless (-T FILE) {
X print STDERR "$FILE: not a text file\n";
X next;
X }
X
X
X $_ = <FILE>; # first check for leading .so reference
X if (/^\.so\s+(man.+\/\S+)/) {
X local($indirect, $indirect2);
X $indirect = $1;
X ($page) = $FILE =~ m:([^.]+)\.[^.]*$:;
X ($page2) = $indirect =~ m:.*/([^/]+)$:;
X ($indirect2 = $indirect) =~ s!/!.Z/!;
X if (-e "../$indirect" || -e "../$indirect.Z" || -e $indirect2) {
X $so{$page} = $page2;
X print "$FILE: .so alias for $indirect\n" if $debug;
X } else {
X print STDERR "$FILE .so references non-existent $indirect\n";
X }
X return;
X } else {
X /^\.TH\s+(\S*)\s+(\S+)/ && &doTH($1, $2);
X }
X
XLINE: while (<FILE>) {
X /^\.TH\s+(\S*)\s+(\S+)/ && &doTH($1, $2);
X next LINE unless /^\.SH\s+"?NAME"?/i || /^\.NA\s?/;
X $foundname = 1;
X @lines = ();
X $nameline = '';
XNAME: while ($_ = &getline()) {
X last NAME if /^\.(S[hHYS])\s?/; # MH support
X if ( $_ eq '.br' ) {
X push(@lines, $nameline) if $nameline;
X $nameline = '';
X next NAME;
X }
X s/^\.[IB]\b//; # Kill Bold and Italics
X next if /^\./;
X $nameline .= ' ' if $nameline;
X $nameline .= $_;
X }
X
X push(@lines, $nameline);
X
X for ( @lines ) {
X next unless ord;
X s/\\f([PBIR]|\(..)//g; # kill font changes
X s/\\s[+-]?\d+//g; # kill point changes
X s/\\&//g; # and \&
X s/\\\((ru|ul)/_/g; # xlate to '_'
X s/\\\((mi|hy|em)/-/g; # xlate to '-'
X s/\\\*\(..//g && # no troff strings
X print STDERR "trimmed troff string macro in NAME section of $FILE\n";
X s/\\//g; # kill all remaining backslashes
X s/^\.\\"\s*//; # comments
X if (!/\s+-+\s+/) {
X # ^ otherwise L-devices would be L
X printf STDERR "$FILE: no separated dash in \"%s\"\n", $_;
X $needcmdlist = 1; # forgive their braindamage
X s/.*-//;
X $desc = $_;
X } else {
X ($cmdlist, $desc) = ( $`, $' );
X $cmdlist =~ s/^\s+//;
X }
X
X # need this for two reasons: sprintf might blow up and so
X # might the dbm store due to 1k limit
X #
X $ocmdlist = $cmdlist; # before truncation
X if (length($cmdlist) > $MAXWHATISLEN) {
X printf STDERR "$FILE: truncating cmdlist from %d to %d bytes for DBM's sake\n",
X length($cmdlist), $MAXWHATISLEN;
X $cmdlist = substr($cmdlist,0,$MAXWHATISLEN) . "...";
X }
X
X ($tmpfile = $FILE) =~ s/\.Z$//;
X ($page, $section) = $tmpfile =~ /^(\S+)\.(\S+)$/;
X $cmdlist = $page if $needcmdlist;
X
X $prototype = ''; $seenpage = 0;
X
X foreach $cmd (split(/[\s,]+/,$ocmdlist)) {
X next unless $cmd;
X $seenpage |= ($cmd eq $page);
X if (! $prototype) {
X &store_direct($cmd, $cmdlist, $tmpfile, $dirext, $desc);
X $prototype = $cmd;
X } else {
X &store_indirect($cmd, "$prototype.$filext");
X }
X }
X unless ($seenpage) {
X print "$FILE: forgot my own name!\n" if $debug;
X if ($prototype) {
X &store_indirect($page, "$prototype.$filext");
X } else {
X &store_direct($page, $page, $FILE, $dirext, '');
X }
X }
X }
X }
X unless ($foundname) {
X print STDERR "$FILE: no NAME lines, so has no whatis description!\n";
X ($tmpfile = $FILE) =~ s/\.Z$//;
X ($page, $section) = $tmpfile =~ /^(\S+)\.(\S+)$/;
X &store_direct($page, $page, $tmpfile, $dirext, 'NO DESCRIPTION');
X }
X}
X
X# --------------------------------------------------------------------------
Xsub source {
X local($file) = @_;
X local($return) = 0;
X
X
X $return = do $file;
X die "couldn't parse \"$file\": $@" if $@;
X die "couldn't do \"$file\": $!" unless defined $return;
X warn "couldn't run \"$file\"" unless $return;
X}
X
X
Xsub chopext {
X $_[0] =~ s/\.[^.]+$//;
X}
X
Xsub check_sos {
X local($key);
X
X foreach $key (keys %so) {
X unless (defined $WHATIS{$key}) {
X printf STDERR
X "%s was a .so alias for %s, but %s's NAME section doesn't know it!\n",
X $key, $so{$key}, $so{$key};
X &store_indirect($key, $so{$key});
X }
X }
X}
X
Xsub store_direct {
X local($cmd, $list, $page, $section, $desc) = @_;
X local($datum);
X
X push(@WHATIS,sprintf("%-20s - %s", "$list ($filext)", $desc));
X
X $datum = join("\001", $list, $page, $section, $desc);
X
X if (defined $WHATIS{$cmd}) {
X if (length($WHATIS{$cmd}) + length($datum) + 1 > $MAXDATUM) {
X print STDERR "can't store $page -- would break DBM\n";
X return;
X }
X $WHATIS{$cmd} .= "\002";
X }
X
X print "storing $cmd\n" if $debug;
X $WHATIS{$cmd} .= $datum;
X $entries++;
X}
X
Xsub store_indirect {
X local($indirect, $real) = @_;
X
X print "storing $indirect as reference to $real\n"
X if $debug;
X
X $WHATIS{$indirect} .= "\002" if $WHATIS{$indirect};
X $WHATIS{$indirect} .= $real;
X $entries++;
X}
X
Xsub doTH {
X local($THname, $THext) = @_;
X local($int_name, $ext_name);
X
X ($int_name = "$THname.$THext") =~ tr/A-Z/a-z/;
X ($ext_name = "$filenam.$filext") =~ tr/A-Z/a-z/;
X
X if ($int_name ne $ext_name && $debug) {
X print STDERR "${FILE}'s .TH thinks it's in $int_name\n";
X }
X}
SHAR_EOF
if test 11184 -ne "`wc -c < 'makewhatis'`"
then
echo shar: "error transmitting 'makewhatis'" '(should have been 11184 characters)'
fi
chmod 755 'makewhatis'
fi
echo shar: "extracting 'straycats'" '(476 characters)'
if test -f 'straycats'
then
echo shar: "will not over-write existing file 'straycats'"
else
sed 's/^ X//' << \SHAR_EOF > 'straycats'
X#!/usr/local/bin/perl
X
X$manpath = shift || $ENV{'MANPATH'} || '/usr/man/';
X
Xfor $root (split(/:/, $manpath)) {
X
X chdir($root) || die "can't chdir to $root: $!\n";
X
X foreach $catdir ( <cat*> ) {
X opendir (catdir, $catdir) || die "can't opendir $dir: $!";
X ($mandir = $catdir) =~ s/cat/man/;
X foreach $file ( readdir(catdir) ) {
X next if $file eq '.' || $file eq '..';
X next if -e "$mandir/$file";
X print "no man page for $root/$catdir/$file\n";
X }
X }
X
X}
SHAR_EOF
if test 476 -ne "`wc -c < 'straycats'`"
then
echo shar: "error transmitting 'straycats'" '(should have been 476 characters)'
fi
chmod 775 'straycats'
fi
echo shar: "extracting 'man.ms'" '(34978 characters)'
if test -f 'man.ms'
then
echo shar: "will not over-write existing file 'man.ms'"
else
sed 's/^ X//' << \SHAR_EOF > 'man.ms'
X.\" --------------------------------------------------------
X.de CW \" macro to begin constant-width font
X\" I like TA better, but whatever looks nicest should be used
X.ft TA
X..
X.\" --------------------------------------------------------
X.de CE \" macro to end constant-width font
X.ft R \" maybe should really be .ft P?
X..
X.\" --------------------------------------------------------
X.de M \" man page reference
X\\fI\\$1\\fR\\|(\\$2\)\\$3
X..
X.\" --------------------------------------------------------
X.\" Here begins a mostly successful attempt at
X.\" defining a macro to output a boxed, centered
X.\" figure that includes an auto-increment figure #N
X.\" line using -ms macros.
X.\" It doesn't actually do the centering. sigh.
X.nr FN 0 1
X.de BF \" begin figure
X.ds FN \\$1
X.KF
X.nf
X.na
X.sp
X.B1
X.CW
X..
X.\" --------------------------------------------------------
X.de EF \" end figure
X.sp .5v
X.B2
X.CE
X.ce
X\\fBFigure \\n+(FN \\(em \\*(FN\\fR
X.sp
X.fi
X.ad
X.KE
X..
X.\" --------------------------------------------------------
X.de LB \" little and bold
X.ft B
X.if !"\\$1"" \&\s-1\\$1\s+1 \\$2 \\$3 \\$4 \\$5 \\$6
X.ft R
X..
X.\" End macro definitions
X.\" --------------------------------------------------------
X.TL
X\s+2The Answer to All Man's Problems\s-2
X.AU
X\s+2\fITom Christiansen\fP\s-2
X.AI
X\s-1CONVEX\s+1 Computer Corporation
XPOB 833851
X3000 Waterview Parkway
XRichardson, TX 75083-3851
X.sp
X\fI{uunet,uiucdcs,sun}!convex!tchrist
Xtchrist at convex.com\fP
X.AB no
X.ps -1
XThe \s-1UNIX\s0 on-line manual system was designed many years ago to suit
Xthe needs of systems at the time, but
Xdespite the growth in complexity of typical
Xsystems and the need for more sophisticated software,
Xfew modifications have been
Xmade to it since then.
XThis paper
Xpresents the results of a complete rewrite of the man system. The
Xthree principal goals were to effect substantial gains in
Xfunctionality, extensibility, and speed. The secondary goal was to
Xrewrite a basic \s-1UNIX\s0 utility in the perl programming language to
Xobserve how perl affected development time, execution time, and design
Xdecisions.
X.PP
X.ps -1
XExtensions to the original man system include storing the whatis
Xdatabase in \s-1DBM\s0 format for quicker access, intelligent handling of
Xentries with multiple names (via \fB.so\fP inclusion, links, or the \s-1NAME\s0
Xsection), embedded tbl and eqn directives, multiple man trees,
Xextensible section naming possibilities,
Xuser-definable section and sub-section search ordering,
Xan indexing mechanism
Xfor long man pages,
Xtypesetting of man pages,
Xtext-previewer support for bit mapped displays,
Xautomatic validity checks on the \s-1SEE\s0 \s-1ALSO\s0 sections,
Xsupport for compressed man pages to conserve disk usage,
Xper-tree man macro definitions,
Xand support for man pages for multiple
Xarchitectures or software versions from the same host.
X.ps +1
X.AE
X.NH
XIntroduction
X.PP
XThe \s-1UNIX\s0 on-line manual system was
Xdesigned many years ago to suit the needs of the systems
Xat the time. Since then,
Xdespite
Xthe growth in complexity of
Xtypical systems and the need for more sophisticated software
Xto support them,
Xfew modifications of major significance
Xhave been
Xmade to the program.
XThis paper describes problems inherent
Xin earlier versions of the \fIman\fP program, proposes solutions
Xto these problems, and outlines one implementation of these solutions.
X.NH
XThe Problem
X.NH 2
XThe Monolithic Approach
X.PP
XOne of the most serious problems with the \fIman\fP program up to
Xand including the \s-1BSD\s04.2 release was that
Xall man pages on the entire system were expected to reside
Xunder a common directory,
X\fI/usr/man\fR.
XThere was no
Xnotion of separate sets of man pages installed on
Xthe same machine in different subdirectories.
XAt large installations,
Xsituations commonly arise in which this
Xfunctionality is desirable.
XA site may wish to keep vendor-supplied man pages
Xseparate from man pages that were developed locally
Xor acquired from some third party.
XAn individual or group may wish to maintain their own set
Xof man pages.
XMultiple versions of the same software package
Xmight be simultaneously installed on the same machine.
XA heterogeneous environment may want to be able to view man pages for
Xall available architectures from any machine.
XGiven the requirement that all man pages live in the
Xsame directory, these scenarios are difficult to impossible to
Xsupport.
X.PP
XThe \fIman\fP program distributed in the \s-1BSD\s04.3 release
Xincluded the concept of a \s-1MANPATH\s0,
Xa colon-delimited
Xlist of complete man trees taken either from the user's
Xenvironment or supplied on the command line.
XWhile this was a vast improvement over the previous monolithic approach,
Xseveral significant problems remained.
XFor one thing, the program still had to use
Xthe
X.M access 2
Xsystem call on all possible paths to find out
Xwhere the man page for a particular topic
Xexisted.
XWhen the user has a \s-1MANPATH\s0 containing multiple
Xcomponents, the time needed for the \fIman\fP program to locate
Xa man page is often noticeable, particularly when the target
Xman page does not exist.
X.NH 2
XHard-coded Section Names
X.PP
XAnother problem with the \fIman\fP program unresolved by
Xthe \s-1BSD\s04.3 release
Xwas that all possible sections in which a man page could
Xreside were hard-coded
Xinto the program. This means that while a
X.B manp
More information about the Alt.sources
mailing list