The Answer to All Man's Problems (part 2 of 6)
Tom Christiansen
tchrist at convex.COM
Tue Jan 8 09:17:51 AEST 1991
X
X.\" .ne 3
Xman old makewhatis # show me the makewhatis man page from mano
Xman new csh # show me the csh man page from mann
X
X.\" .ne 3
Xman sun csh # show me the csh man page for suns
X (assumes $MANALT/sun contains sun man pages)
X
X.\" .ne 6
Xman -i uucp # get list of sections in uucp man page
Xman -ai tty # give list of sections on all tty pages
Xman adb/bugs # check for BUGS section of adb man page
Xman man/exam # start at this example section
Xman ksh/ # select from section menu for ksh man page
Xman sun cron/files # go to the FILES section of the sun cron man page
X
X.\" .ne 4
Xman -f rcs # what is rcs?
Xwhatis rcs # same as previous
Xwhatis vax rcs # same as previous, but only vax man pages
X
X.\" .ne 4
Xman -k rcs # what knows about rcs?
Xapropos rcs # same as previous
Xapropos sun rcs # same as previous, but only sun man pages
X
X.\" .ne 3
Xman -S231 wait # override system section ordering
Xman -S3f:3s:3:2:1 system # subsection ordering
X
X.\" .ne 2
Xman -M\ \ ~/man hack # use ~/man as only man tree
X
X.\" .ne 4
Xman -t 4 tty # troff tty(4) man page
Xman -at tty # troff all tty pages
Xman -Tpnitroff perl # preview perl man page
Xman -lTpnitroff ../foo.1 # preview local file as man page
X
X.\" .ne 3
Xman -l file.x # run man on local file
Xman -tl file.x # print local file as man would
Xman -il file.x # get section index on local page
X.fi
X.ft R
X.\" .ne 5
X.SH ENVIRONMENT
X.I Man
Xexplicitly checks for the following environment variables; if they are
Xpresent, they
Xwill override its internal defaults:
X.IP \fBMANPATH\fP 15
XThe colon-separated list of man trees for locating man pages. This
Xmay itself be overridden by the command line flags
X.B \-M
Xor by
Xspecifying an alternate hardware type.
X.IP \fBMANSECT\fP 15
XThe default ordering for section and subsection sorting. It need only
Xbe separated by colons if multi-character sections such as
X.B man1m
Xexist
Xor if subsection ordering is desired, such as to place subsection
X.B 3f
Xin front of section
X.B 3 .
X.IP \fBMANALT\fP 15
XThe directory to check for alternate sets of man trees. This is useful
Xfor storing the man pages for several different machine architectures or
Xversions of the operating system. See the
X.B Search Strategy
Xsection
Xfor details.
X.IP \fBPAGER\fP 15
XThe user's preferred viewer of paged output. Note that often the pager
Xitself will consult the environment; for example,
X.I more
Xlooks for a
X.SB MORE
Xvariable
Xand
X.I less
Xlooks for a
X.SB LESS
Xvariable
Xin the environment.
X.IP \fBTROFF\fP 15
XThe preferred typesetter program. It should recognize
X.I troff
Xinput and switches.
XThis may be overridden using the
X.B \-T
Xcommand line flag.
X.SH FILES
X.nf
X.ta \w'/usr/lib/perl/getopts.pl 'u
X\fI/usr/man\fR default man tree
X\fI/usr/man/man*/*.*\fR unformatted (nroff source) man pages
X\fI/usr/man/cat*/*.*\fR formatted man pages
X\fI/usr/man/idx*/*.*\fR indices for section headers
X\fI/usr/man/whatis\fR default whatis database, text version
X\fI/usr/man/whatis.dir\fR \fIdbm\fP index file for default \fIwhatis\fP database
X\fI/usr/man/whatis.pag\fR \fIdbm\fP data file for default \fIwhatis\fP database
X\fI/usr/lib/perl/getopts.pl\fR required \fIperl\fR library file
X\fI/usr/lib/perl/stat.pl\fR required \fIperl\fR library file
X.fi
X.SH "SEE ALSO"
X.M egrep 1 ,
X.M perl 1 ,
X.M more 1 ,
X.M eqn 1 ,
X.M tbl 1 ,
X.M nroff 1 ,
X.M troff 1L ,
X.M compress 1L ,
X.M dbm 3X ,
X.M man 7 ,
X.M catman 8 ,
X.M makewhatis 8
X.SH NOTES
XThis version of
X.I man
Xis written entirely in the
X.M perl 1
Xprogramming language
Xand thus requires that
X.I perl
Xbe properly installed on your system to run.
XBecause
X.I man
Xis distributed in a script, it can be easily
Xreconfigured by the system managers to suit their site's particular style.
XThis is good, as some of the default settings are somewhat
Xidiosyncratic to the set-up at the \s-1CONVEX\s0 home office.
X.sp
X.in +5n
X\fBBe sure to save a copy of the
Xoriginal \fIman\fP
Xprogram before any modification.\fR
X.in -5n
X.ft R
X.sp
X.ne 4
XThings that can be configured include:
X.in +5n
X.IP \(bu 5
Xthe default
X.SB PAGER
Xand its flags (alternate flags can be provided for
X.I less\c
X)
X.IP \(bu 5
Xsystem defaults for
X.SB MANPATH ,
X.SB MANSECT ,
X.SB MANALT ,
Xand
X.SB TROFF .
X.IP \(bu 5
Xpaths for
X\fItroff\fP,
X\fInroff\fP,
X\fItbl\fP,
X\fIeqn\fP,
X\fIneqn\fP,
X\fIul\fP,
X\fIcol\fP,
X\fIegrep\fP, and
X\fIcompress\fP
X.IP \(bu 5
Xwhether you have compressed man pages and how they are stored
X.IP \(bu 5
Xwhich section aliases you want (as in
X.B public
Xbeing recognized
Xas section \fBp\fP)
X.IP \(bu 5
Xwhether to recognize man pages whose
X.SB NAME
Xsections don't mention their
Xown names
X.in -5n
X.PP
XTo save disk space at the expense of execution time, a site may
Xwish to run
X.M compress 1L
Xon the manual entries where available. The
X.I man
Xprogram
Xunderstands how to read compressed man
Xpages, and knows to create a compressed cat page if the source
Xman page was compressed to start with.
X.PP
XWhen running on slow \s-1CPU\s0s, the start-up time for parsing the
Xscript may be annoying. These sites can skip this parsing phase
Xat each invocation of
X.M man 1
Xby using \fIperl\fP's
X.B \-u
Xflag to dump a binary image of the interpreter.
X.SH DIAGNOSTICS
XSeveral self-explanatory diagnostics are possible, such as
X.TY "No manual entry for xyzzy" ,
Xbut the following warnings may not be intuitive:
X.sp
X.TY "But what do you want from section %s?"
X.in +5n
XA section was specified but no topic.
X.in -5n
X.sp
X.TY "No dbm file for %s: %m"
X.in +5n
X.br
XThis means that the named man tree does not have an
Xaccessible
X.I dbm
Xversion
Xof its
X.I whatis
Xdatabase and that
X.M makewhatis 8
Xshould be run on it. This only shows up when
X.B \-d
Xoption is used. \fB%m\fP is the appropriate
X.M perror 3
Xmessage.
X.in -5n
X.sp
X.TY "%s has disappeared -- rerun makewhatis"
X.in +5n
X.br
XA man page has been removed since
X.I makewhatis
Xwas last run.
XNote that new man pages being added will NOT be detected.
X.in -5n
X.sp
X.TY "nroff of %s failed"
X.br
X.in +5n
XFor some reason
X.I nroff
Xdid not exit correctly. The disk may
Xbe mounted read-only, it might be full, or
X.I nroff
Xmay
Xnot be installed on your system. Contact your system manager.
X.in -5n
X.sp
X.TY "%s was length 0; disk full?"
X.br
X.in +5n
XA cat page was empty.
XThe
X.I man
Xprogram
Xunlinks the useless cat page,
Xissues this warning, and exits non-zero. Rerun the command and
Xif the problem persists, contact your system manager.
X.in -5n
X.sp
X.TY "/tmp not writable"
X.br
X.in +5n
XThe
X.I /tmp
Xand
X.I /usr/man/cat*
Xdirectories are not writable by you. Contact your system manager.
X.in -5n
X.sp
X.TY "No whatis databases found, please run makewhatis"
X.br
X.in +5n
XThe
X.I man
Xprogram was unable to find a
X.I whatis
Xdatabase for use with
X.I apropos
Xor
X.I man -k
Xin any of the directories listed in the
X.BR MANPATH .
XHave your system manager run
X.I makewhatis
Xon the system manual page directories, and run
X.I makewhatis
Xon any personal manual page directories.
X.in -5n
X.sp
X.TY "bad eval: %s"
X.br
X.TY "can't eval %s: %s"
X.br
X.in +5n
XThese are internal errors that should never occur. Contact
Xyour system manager, who should submit a problem report.
X.in -5n
X.SH RESTRICTIONS
XOnce a
X.M dbm 3X
X.I whatis
Xdatabase has been created for a particular man root,
Xnew man pages will not be found unless the
X.B \-h
Xflag is
Xused or until
X.I makewhatis
Xis rerun.
X.PP
XIf your
X.SB PAGER
Xis
X.M more 1 ,
Xbold text shows up in the normal font;
Xhowever,
X.M less 1
Xdoes display bold text in your terminal's bold font.
X.SH BUGS
XThe manual is supposed to be reproducible either on the phototypesetter
Xor on an \s-1ASCII\s0 terminal.
XHowever, on a terminal, some information is necessarily lost.
X.PP
XThe
X.B \-t
Xflag for
X.I man
Xonly works if the host system supports
X.IR troff .
X.PP
XNot all systems have
X.I compress
Xinstalled on them.
X.SH AUTHOR
XTom Christiansen
X.I <tchrist at convex.com>\c
X.SH COPYRIGHT
XCopyright 1990
X\s-1CONVEX\s0 Computer Corporation.
XYou are free to use, modify, and redistribute these scripts
Xas you wish for non-commercial purposes provided that this
Xnotice remains intact.
SHAR_EOF
if test 20992 -ne "`wc -c < 'man.1'`"
then
echo shar: "error transmitting 'man.1'" '(should have been 20992 characters)'
fi
chmod 644 'man.1'
fi
echo shar: "extracting 'catman'" '(4457 characters)'
if test -f 'catman'
then
echo shar: "will not over-write existing file 'catman'"
else
sed 's/^ X//' << \SHAR_EOF > 'catman'
X#!/usr/bin/perl
X#
X# perl rewrite of catman
X# author: tom christiansen <tchrist at convex.com>
X#
X# Copyright 1990 Convex Computer Corporation.
X# All rights reserved.
X
X$| = 1;
X
X$TBL = "tbl -D";
X$EQN = "eqn";
X$MAKEWHATIS = "/usr/lib/makewhatis";
X$COMPRESS = "compress";
X$NROFF = "nroff";
X$COL = "col";
X$CAT = "cat";
X$ZCAT = "zcat";
X
X# Command to format man pages to be viewed on a tty or printed on a line printer
X$CATSET = "$NROFF -h -man -";
X$CATSET .= " | $COL" if $COL;
X
Xumask 022;
X
Xdo 'getopts.pl' || die("can't do getopts.pl", $@?$@:$!, "\n");
Xdo 'stat.pl' || die("can't do stat.pl ", $@?$@:$!, "\n");
Xdo 'ctime.pl' || die("can't do ctime.pl ", $@?$@:$!, "\n");
X
X
X# -Z flag is planning for the future
Xunless (&Getopts('dpnwZP:M:') && $ARGV <= 1) {
X die "usage: $0 [-pnwZ] [-M manpath] [sections]\n";
X}
X
X$debug = $opt_d;
X$makewhatis = !$opt_n;
X$catman = !$opt_w;
X$fakeout = $opt_p;
X$compress = $opt_Z;
X
X($sections = shift) &&
X (@sections = split($sections =~ /:/ ? ':' : '', $sections));
X
X($manpath = $opt_P) ||
X ($manpath = $opt_M) ||
X ($manpath = "/usr/man");
X
Xpath: foreach $path (split(/:/,$manpath)) {
X unless (chdir $path) {
X warn "can't chdir to $path: $!";
X $status = 1;
X next path;
X }
X &run ("$MAKEWHATIS $path") if $makewhatis;
X next unless $catman;
X print "chdir $path\n" if $debug;
X
Xmandir: foreach $mandir (<man*>) {
X next if $sections && !grep($mandir =~ /man$_/, @sections);
X print "considering $mandir\n" if $debug;
X $found++;
X ($catdir = $mandir) =~ s/man/cat/;
X $catdir = "$path/$catdir";
X next unless -w $catdir;
X opendir(mandir,$mandir);
X
Xmanpage: foreach $manpage ( readdir(mandir) ) {
X local(@st_man, @st_cat);
X next manpage if $manpage =~ /^\.{1,2}/;
X
X if ($manpage !~ /\S\.\S/) {
X print "skipping non man file: $manpage\n" if $debug;
X next manpage;
X }
X
X next manpage if $manpage =~ /\.(old|bak|out)$/i;
X next manpage if $manpage =~ /~$/;
X
X $zpage = $zdir || $manpage =~ /\.Z$/;
X
X $manpage = "$path/$mandir/$manpage";
X
X ($catpage = $manpage)
X =~ s,^(.*)/man([^\.]*)(\.Z)?/([^/]*)$,$1/cat$2$3/$4,;
X
X @st_man = &Stat($manpage);
X @st_cat = &Stat($catpage);
X
X if ($st_cat[$ST_MTIME] < $st_man[$ST_MTIME]) {
X $command = (($manpage =~ m:\.Z:) ? $ZCAT : $CAT)
X . " < $manpage | $CATSET";
X
X $command = &insert_filters($command, $manpage);
X $command =~ s,-man,$path/tmac.an, if -e "$path/tmac.an";
X
X $command .= "| $COMPRESS " if $catpage =~ /\.Z/;
X
X $command .= "> $catpage";
X
X &reformat($command);
X }
X }
X }
X}
X
Xsub insert_filters {
X local($filters,$eqn, $tbl, $_);
X local(*PAGE);
X local($command, $PAGE) = @_;
X
X
X $PAGE = "$ZCAT < $PAGE|" if $PAGE =~ /\.Z/;
X
X (open PAGE) || die ("can't open $page to check filters: $!\n");
X
X while (<PAGE>) {
X if (/^\.EQ/) {
X $_ = <PAGE>;
X $eqn = 1 unless /\.(if|nr)/; # has eqn output not input
X }
X if (/^\.TS/) {
X $_ = <PAGE>;
X $tbl = 1 unless /\.(if|nr)/; # has tbl output not input
X }
X last if $eqn && $tbl;
X }
X close PAGE;
X
X $eqn && $_[0] =~ s/(\S+roff)/$EQN | $1/;
X $tbl && $_[0] =~ s/(\S+roff)/$TBL | $1/;
X
X $_[0];
X}
X
X
Xsub run {
X local($command) = $_[0];
X
X $command =~ s/^\s*cat\s*<?\s*([^\s|]+)\s*\|\s*([^|]+)/$2 < $1/;
X $command =~ s/^([^|<]+)<([^Z|<]+)$/$1 $2/;
X print STDERR "$command\n" if $debug || $fakeout;
X if (!$fakeout && system $command) {
X $status = 1;
X printf STDERR "\"%s\" exited %d, sig %d\n", $command,
X ($? >> 8), ($? & 255) if $debug;
X }
X return ($? == 0);
X}
X
Xsub print {
X local($_) = @_;
X
X if (!$inbold) {
X print;
X } else {
X for (split(//)) {
X print /[!-~]/ ? $_."\b".$_ : $_;
X }
X }
X}
X
Xsub reformat {
X local($_) = @_;
X local($nroff, $col);
X local($inbold) = 0;
X
X s/^\s*cat\s*<?\s*([^\s|]+)\s*\|\s*([^|]+)/$2 < $1/;
X s/^([^|<]+)<([^Z|<]+)$/$1 $2/;
X ($nroff, $col) = m!(.*)\|\s*($COL.*)!;
X
X print "$nroff | (this proc) | $col\n" if $debug;
X
X open (NROFF, "$nroff |");
X open (COL, "| $col");
X
X select(COL);
X
X while (<NROFF>) {
X s/\033\+/\001/;
X s/\033\,/\002/;
X if ( /^([^\001]*)\002/ || /^([^\002]*)\001/ ) {
X &print($1);
X $inbold = !$inbold;
X $_ = $';
X redo;
X }
X &print($_);
X }
X
X close NROFF;
X if ($?) {
X warn "$program: \"$nroff\" failed!\n";
X $status++;
X }
X close COL;
X if ($?) {
X warn "$program: \"$col\" failed!\n";
X $status++;
X }
X select(STDOUT);
X}
SHAR_EOF
if test 4457 -ne "`wc -c < 'catman'`"
then
echo shar: "error transmitting 'catman'" '(should have been 4457 characters)'
fi
chmod 755 'catman'
fi
echo shar: "extracting 'WISHES'" '(538 characters)'
if test -f 'WISHES'
then
echo shar: "will not over-write existing file 'WISHES'"
else
sed 's/^ X//' << \SHAR_EOF > 'WISHES'
Xincremental makewhatis
Xnew man(5) page
Xnew catman(8) page
Xadd to makewhatis(8) section on whatis format?
Xcatman new switches
X z compress
X u uncompress
X i initialize -- create cat* and idx* directories
X r remove old cat pages first, warn of cat pages w/o man pages
X R remove recursivley old cat dirs first, then invoke -i
Xman - collapse case on lookups
Xcfman - option to use dbm files
Xman - use optimized perl wth eval trick for apropos unless GNU grep
Xman - option to ask which page out of many; i.e. -a + selection menu
SHAR_EOF
if test 538 -ne "`wc -c < 'WISHES'`"
then
echo shar: "error transmitting 'WISHES'" '(should have been 538 characters)'
fi
chmod 664 'WISHES'
fi
echo shar: "extracting 'BUGS'" '(268 characters)'
if test -f 'BUGS'
then
echo shar: "will not over-write existing file 'BUGS'"
else
sed 's/^ X//' << \SHAR_EOF > 'BUGS'
Xcatman needs to reference the database instead
Xof globbing to find manpage names to avoid duplicating
Xoutput from .so's.
X
Xcfman doesn't use the database, so its idea of what
Xman can find is wrong.
X
Xif man is invoked as whman, it doesn't get the right
Xoptions string.
SHAR_EOF
if test 268 -ne "`wc -c < 'BUGS'`"
then
echo shar: "error transmitting 'BUGS'" '(should have been 268 characters)'
fi
chmod 664 'BUGS'
fi
echo shar: "extracting 'README'" '(636 characters)'
if test -f 'README'
then
echo shar: "will not over-write existing file 'README'"
else
sed 's/^ X//' << \SHAR_EOF > 'README'
Xread the man pages first. then check out the configuration section
Xin man to make sure it's as you like it.
X
Xyou have to run makewhatis to build the database to make this work.
Xyou should actually remove your catpages and rerun catman,
Xwho will call /usr/lib/makewhatis, which it assumes to be mine.
Xthe catpages may be in a slightly different format than you are used to.
X
Xyou will need ndbm.
X
Xyou might want to create idx* directories for speed.
X
Xless makes a better pager than more.
X
Xyou can read the paper at your leisure. it's not essential.
X
Xcopying is ok, just don't remove my name or try to sell it.
Xread the man pages first.
SHAR_EOF
if test 636 -ne "`wc -c < 'README'`"
then
echo shar: "error transmitting 'README'" '(should have been 636 characters)'
fi
chmod 664 'README'
fi
echo shar: "extracting 'cfman'" '(10347 characters)'
if test -f 'cfman'
then
echo shar: "will not over-write existing file 'cfman'"
else
sed 's/^ X//' << \SHAR_EOF > 'cfman'
X#!/usr/bin/perl
X#
X# cfman v2.0: man page cross-referencer
X# author: Tom Christiansen <tchrist at convex.com>
X# date: 15 November 89
X#
X# usage: cfman [ -d debug-devel ] [ -s sub-sections ]
X# [ -p manpath ] [ -x xrefpath ]
X
X($iam = $0) =~ s%.*/%%;
X
X$] =~ /(\d+\.\d+).*\nPatch level: (\d+)/;
Xdie "$iam: requires at least perl version 3.0, patchlevel 1 to run correctly\n"
X if $1 < 3.0 || ($1 == 3.0 && $2 < 1);
X
X&Getopts('fd:s:p:P:x:') || &usage;
X
X$manpath = $opt_p if defined $opt_p;
X$manpath = $opt_P if defined $opt_P;
X$manpath = $ENV{'MANPATH'} unless $manpath;
X$manpath = "/usr/man" unless $manpath;
X at manpath = split(/:/,$manpath);
X
X$opt_x =~ /^:/ && ( $opt_x = $manpath . $opt_x );
X at xrefpath = $opt_x ? split(/:/,$opt_x) : @manpath;
X
X$debug = $opt_d;
X$use_DBM = $opt_f;
X
X at sections = $opt_s ? split(/ */,$opt_s) : 1..8;
X
Xif ($debug) {
X $" = ':';
X print "manpath is @manpath\n";
X print "xrefpath is @xrefpath\n";
X $" = ' ';
X}
X
Xfile: foreach $file ( $#ARGV >= $[ ? @ARGV : '*.*' ) {
X printf STDERR "considering %s\n", $file if $debug & 1;
X $bingo = 0;
Xtree: foreach $tree ( @manpath ) {
X print "ROOT is $tree\n" if $debug;
X if (!chdir $tree) {
X warn "cannot chdir to $tree: $!";
X next tree;
X }
X $rootdir = $tree;
X if ( $file =~ m#^/# ) {
X &read_manpages($file);
X next file;
X }
Xsection: foreach $section ( @sections ) {
X &scan_section($tree,$section,$file);
X }
X }
X print "no man pages matched \"$file\"\n" unless $bingo;
X }
X
X
Xexit 0;
X
X############################################################################
X#
X# scan_section()
X#
X# checks a given man tree (like /usr/local/man) in a
X# certain subsection (like '1'), checking for a certain
X# file, like 'tty' (which mean 'tty.*', 'system.3*', or '*.*'.
X#
X# will recurse on a subsection name contaning a shell meta-character
X#
X############################################################################
X
Xsub scan_section {
X local ( $manroot, $subsec, $files ) = @_;
X local ( $mandir );
X
X $mandir = "man" . $subsec;
X
X
X # subsec may have been ? or *; if so, recurse!
X if ( &has_meta($mandir) ) {
X for (<${mandir}>) {
X if (&has_meta($_)) {
X warn "bad glob of $mandir";
X last;
X }
X s/^man//;
X &scan_section($manroot,$_,$files);
X }
X return;
X }
X
X $files = "$files.*" unless $files =~ /\./;
X
X if (!chdir $mandir) {
X warn "couldn't chdir to $mandir: $!\n" if $debug;
X return;
X }
X
X printf STDERR "chdir to %s of %s\n", $mandir, $manroot if $debug & 1;
X
X &read_manpages ( &has_meta($files) ? &glob($files) : ($files));
X
X chdir('..');
X}
X
X############################################################################
X#
X# read_manpages()
X#
X# passed a list of filename, which are man pages. opens each one
X# verifying that the file really is in the place that the .TH line.
X# skips to SEE ALSO section and then verifies existence of each
X# referenced man page.
X############################################################################
X
X
Xsub read_manpages {
X local (@pages) = @_;
X
X local ($junk, $sopage, $basename, $line, $page, $pname, $pext, $gotTH);
X local(%seen);
X
X
Xpage:
X foreach $page ( @pages ) {
X next page if $page =~ /\.(BAK|OLD)$/i;
X
X if ($seen{$page}++) {
X print "already saw $page\n" if $debug & 1;
X next page;
X }
X
X if (!open page) {
X warn "couldn't open $page: $!\n";
X next page;
X }
X
X $bingo = 1; # global var
X
X print "checking $page\n" if $debug & 1;
X
X $gotTH = 0;
X $line = 0;
X $sopage = '';
X
Xline: while (<page>) {
X print if $debug & 16;
X next line if /^'''/ || /^\.\\"/;
X
X # deal with .so's on the first line.
X # /usr/ucb/man uses this instead of links.
X if (!($line++) && /^\.so\s+(.*)/) {
X $sopage = $1;
X print "$page -> $sopage\n" if $debug & 1;
X ($basename = $sopage) =~ s%.*/%%;
X if ($seen{$basename}++) {
X print "already saw $basename\n" if $debug & 1;
X next page;
X }
X if (!open(page,"../$sopage")) {
X print "$page: cannot open $sopage: $!\n";
X next page;
X }
X $page = $basename;
X next line;
X }
X
X # check for internally consistent .TH line
X if ( /^\.(TH|SC)/ ) { # SC is for mh
X $gotTH++;
X printf STDERR "TH checking %s", $_ if $debug & 4;
X do flush();
X s/"+//g;
X ($junk, $pname, $pext) = split;
X if (¯o($pname)) {
X printf STDERR "%s: can't resolve troff macro in .TH: %s\n",
X $page, $pname;
X next line;
X }
X $pext =~ y/A-Z/a-z/;
X $pname =~ s/\\-/-/g;
X $pname =~ y/A-Z/a-z/ if $pname =~ /^[\$0-9A-Z_\055]+$/;
X ($pexpr = $page) =~ s/([.+])/\\$1/g;
X $pexpr =~ s%.*/%%;
X if ( "$pname.$pext" !~ /^$pexpr$/i) {
X printf "%s: thinks it's in %s(%s)\n",
X $page, $pname, $pext;
X }
X next line;
X }
X
X next line unless /^\.S[Hh]\s+"*SEE ALSO"*/
X || /^\.S[Hh]\s+REFERENCES/ # damn posix
X || /^\.Sa\s*$/; # damn mh
X
X # finally found the cross-references
Xxref: while (<page>) {
X print if $debug & 16;
X last line if /^\.(S[Hh]|Co|Hi|Bu)/; # i really hate mh macros
X next xref unless /\(/;
X next xref if /^.PP/;
X chop;
X s/\\f[RIPB]//g;
X s/\\\|//g;
X s/\\-/-/g;
Xentry: foreach $entry ( split(/,/) ) {
X #print "got entry $entry\n";
X next entry unless $entry =~ /\(.*\)/;
X $pname = ''; $pext = '';
X $1 = ''; $2 = '';
X ($pname, $pext) =
X ($entry =~ /([A-Za-z0-9\$._\-]+)\s*\(([^)]+)\).*$/);
X if ($debug & 8) {
X printf STDERR "entry was %s, pname is %s, pext is %s\n",
X $entry, $pname, $pext;
X }
X if (¯o($pname)) {
X printf "%s: can't resolve troff macro in SEE ALSO: %s\n",
X $page, $pname;
X next entry;
X }
X next entry if !$pname || !$pext || $pext !~ /^\w+$/;
X $pext =~ y/A-Z/a-z/;
X $pname =~ y/A-Z/a-z/ if $pname =~ /^[A-Z_0-9\-]+$/;
X #($psect = $pext) =~ s/^(.).*/$1/;
X do check_xref($page,$pname,$pext);
X
X } # entry: foreach $entry ( split(/,/) )
X } # xref: while (<page>)
X } # line: while (<page>)
X printf "%s: missing .TH\n", $page if (!$gotTH);
X } # page: foreach $page ( @pages )
X} # sub read_manapages
X
X
X###########################################################################
X#
X# check_xref()
X#
X# given the name of the page we're looking for, check for a
X# cross reference of a given man page and its assumed subsection
X#
X###########################################################################
X
Xsub check_xref {
X local ($name, $target, $section) = @_;
X local ($basesec, $subsec, $newsec );
X
X printf STDERR " xref of %s(%s)\n", $target, $section if $debug & 2;
X
X return if &pathcheck($target,$section);
X
X
X # if we get this far, something's wrong, so begin notify
X printf "%s: %s(%s)", $name, $target, $section;
X
X ($basesec, $subsec) = ($section =~ /^(\d)(.*)$/);
X
X if ($name =~ /\.\d*([nlp])$/ && ($section == 1 || $section == 8)
X && ($newsec = &pathcheck($target,$1))) { # hack for manl idiocy
X &really($target,$newsec);
X return;
X }
X
X # first check if page.Xn is really in page.X
X if ( $subsec && ($newsec = &pathcheck($target,$basesec))) {
X &really($target,$newsec);
X return;
X }
X
X if ( $basesec == 1 && &pathcheck($target,8)) {
X &really($target,8);
X return;
X }
X
X if ( $basesec == 8 && &pathcheck($target,1)) {
X &really($target,1);
X return;
X }
X
X # maybe it thinks it's in 8 but got erroneously in 1
X if ( $basesec =~ /[18]/ && ($newsec = &pathcheck($target,'l'))) {
X &really($target,$newsec);
X return;
X }
X
X # maybe page.X is really in page.Xn; this is expensive
X if ( !$subsec && ($newsec = &pathcheck($target,$basesec.'*'))) {
X &really($target,$newsec);
X return;
X }
X
X printf " missing\n";
X do flush();
X}
X
X###########################################################################
X#
X# pathcheck()
X#
X# takes a name (like 'tty') and a section (like '1d')
X# and looks for 'tty.1d' first in the current root,
X# then in all other elements of @xrefpath. the section
X# may have a meta-character in it (like '8*').
X#
X# returns the subsection in which we found the page, or
X# null if we failed.
X#
X###########################################################################
X
Xsub pathcheck {
X local ( $name, $section ) = @_;
X local ( $basesec, $metasec, $fullpath, @expansion, $tree, %checked );
X local ( $return ) = 0;
X
X $metasec = &has_meta($section);
X
X ($basesec) = ($section =~ /^(.)/);
X
X foreach $tree ( $rootdir, @xrefpath ) {
X next if !$tree || $checked{$tree}++; # only check each tree once
X
X $fullpath = "$tree/man$basesec/$name.$section";
X
X print " testing $fullpath\n" if $debug & 8;
X
X if (!$metasec) {
X if (-e $fullpath) {
X $return = $section;
X }
X } else {
X if ($use_DBM && &dbmopen($tree)) {
X next;
X }
X open(SAVERR, '>&STDERR'); # csh globbing brain damage
X close STDERR;
X if ((@expansion = <${fullpath}>) && !&has_meta($expansion[0])) {
X # redundant meta check due to sh brain-damage
X #for (@expansion) { s/.*\.//; }
X #$section = join(' or ', at expansion);
X ($section) = ($expansion[0] =~ /([^.]+)$/);
X $return = $section;
X }
X open(STDERR, '>&SAVERR'); # csh globbing brain damage
X close SAVERR;
More information about the Alt.sources
mailing list