Subject: bin/3627: Invalid crossreferences in bin/ manpages (perl script included)
To: None <gnats-bugs@gnats.netbsd.org>
From: None <abs@mono.org>
List: netbsd-bugs
Date: 05/14/1997 23:29:08
>Number:         3627
>Category:       bin
>Synopsis:       Invalid crossreferences in bin/ manpages (perl script included)
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          doc-bug
>Submitter-Id:   net
>Arrival-Date:   Wed May 14 23:35:00 1997
>Last-Modified:
>Originator:     David Brownlee
>Organization:
<a href="http://www.mono.org/">Monochrome</a>
>Release:        1.2
>Environment:
	
System: NetBSD lapton.mono.org 1.2D NetBSD 1.2D (_LAPTON_) #3: Sun Apr 27 22:24:02 BST 1997 root@lapton.mono.org:/usr/src/sys/arch/i386/compile/_LAPTON_ i386


>Description:
	There are many man pages with invalid on inaccurate crossreferences,
	eg: '.Xr ldconfig 1' instead of '.Xr ldconfig 8', or
	'gzip(1)' instead of '.Xr gzip 1'.

>How-To-Repeat:
	Read the man pages, or write a script to check for problems.

>Fix:
	The following patch contains fixes for:
	    src/bin/chmod/chmod.1
	    src/bin/csh/USD.doc/csh.2
	    src/bin/csh/USD.doc/csh.4
	    src/bin/csh/csh.1
	    src/bin/domainname/domainname.1
	    src/bin/ed/ed.1
	    src/bin/hostname/hostname.1
	    src/bin/ksh/ksh.1
	    src/bin/ps/ps.1
	    src/bin/sh/sh.1
	    src/bin/sync/sync.8

	After the patch is a copy of 'manxref' - a perl script to check a
	source tree for man page crossreferences. (Search for 'TODO')
	(When I say 'a source tree' I probably mean 'a NetBSD or very similar
	source tree' - it was written specifically to check the NetBSD tree :)

	It found nearly 500 inconsistencies in -current, I'm afraid I've wimped
	out and only provided patches for the worst ones in bin - if anyone
	is interested is patches for more - just let me know :)

	PS: Comments/thoughts on the script also appreciated!

--- /src/sup/old/src/bin/chmod/chmod.1	Fri Oct 13 23:39:32 1995
+++ src/bin/chmod/chmod.1	Sun May 11 23:12:32 1997
@@ -114,7 +114,8 @@
 .It Li 2000
 set-group-ID-on-execution
 .It Li 1000
-sticky bit, see chmod(2)
+sticky bit, see
+.Xr chmod 2
 .It Li 0400
 read by owner
 .It Li 0200
--- /src/sup/old/src/bin/csh/USD.doc/csh.2	Fri Oct 13 23:40:12 1995
+++ src/bin/csh/USD.doc/csh.2	Sun May 11 23:13:17 1997
@@ -112,7 +112,8 @@
 I create an
 .I alias
 ``ts'' which executes a
-\fItset\fR\|(1) command setting up the modes of the terminal.
+.Xr tset 1
+command setting up the modes of the terminal.
 The parameters to
 .I tset
 indicate the kinds of terminal which I usually use when not on a hardwired
--- /src/sup/old/src/bin/csh/USD.doc/csh.4	Fri Oct 13 23:40:13 1995
+++ src/bin/csh/USD.doc/csh.4	Sun May 11 23:14:13 1997
@@ -176,5 +176,7 @@
 The shell has a number of command line option flags mostly of use
 in writing \s-2UNIX\s0 programs,
 and debugging shell scripts.
-See the csh(1) manual section for a list of these options.
+See the
+.Xr csh 1
+manual section for a list of these options.
 .bp
--- /src/sup/old/src/bin/csh/csh.1	Mon May 12 12:18:29 1997
+++ src/bin/csh/csh.1	Wed May 14 23:16:41 1997
@@ -315,8 +315,9 @@
 implementation
 of the
 tty driver that allows generation of interrupt characters from
-the keyboard to tell jobs to stop.  See stty(1) for details
-on setting options in the new tty driver.
+the keyboard to tell jobs to stop.  See
+.Xr stty 1
+for details on setting options in the new tty driver.
 .Ss Status reporting
 This shell learns immediately whenever a process changes state.
 It normally informs you whenever a job becomes blocked so that
--- /src/sup/old/src/bin/domainname/domainname.1	Fri Oct 13 23:40:37 1995
+++ src/bin/domainname/domainname.1	Wed May 14 23:17:15 1997
@@ -52,8 +52,8 @@
 time.
 .Sh SEE ALSO
 .Xr hostname 1 ,
-.Xr getdomainname 2 ,
-.Xr setdomainname 2
+.Xr getdomainname 3 ,
+.Xr setdomainname 3 .
 .Sh HISTORY
 The
 .Nm domainname
--- /src/sup/old/src/bin/ed/ed.1	Mon Nov 11 12:06:09 1996
+++ src/bin/ed/ed.1	Sun May 11 23:16:08 1997
@@ -882,7 +882,9 @@
 Prompts for an encryption key which is used in subsequent reads and
 writes.  If a newline alone is entered as the key, then encryption is
 turned off.  Otherwise, echoing is disabled while a key is read.
-Encryption/decryption is done using the bdes(1) algorithm.
+Encryption/decryption is done using the
+.Xr bdes 1
+algorithm.
 
 .TP 8
 .RI (.+1)z n
--- /src/sup/old/src/bin/hostname/hostname.1	Fri Oct 13 23:42:31 1995
+++ src/bin/hostname/hostname.1	Sun May 11 23:16:24 1997
@@ -60,8 +60,8 @@
 .El
 .Sh SEE ALSO
 .Xr domainname 1 ,
-.Xr gethostname 2 ,
-.Xr sethostname 2
+.Xr gethostname 3 ,
+.Xr sethostname 3 .
 .Sh HISTORY
 The
 .Nm hostname
--- /src/sup/old/src/bin/ksh/ksh.1	Mon Jan 13 12:06:21 1997
+++ src/bin/ksh/ksh.1	Sun May 11 23:42:31 1997
@@ -36,7 +36,9 @@
 .SH DESCRIPTION
 \fBksh\fP is a command interpreter that is intended for both 
 interactive and shell script use.  Its command language is a superset
-of the \fIsh\fP(1) shell language.
+of the
+.Xr sh 1
+shell language.
 .\"{{{  Shell Startup
 .SS "Shell Startup"
 The following options can be specified only on the command line:
@@ -96,7 +98,9 @@
 .PP
 A shell is \fBprivileged\fP if the \fB\-p\fP option is used or if
 the real user-id or group-id does not match the effective user-id
-or group-id (see \fIgetuid\fP(2), \fIgetgid\fP(2)).
+or group-id (see
+.Xr getuid 2 ,
+.Xr getgid 2 ).
 A privileged shell does not process $HOME/.profile nor the \fBENV\fP
 parameter (see below), instead the file /etc/suid_profile is processed.
 Clearing the privileged option causes the shell to set its effective
@@ -159,8 +163,9 @@
 \fB`\fP introduces an old-style command substitution
 (see Substitution below);
 \fB~\fP begins a directory expansion (see Tilde Expansion below);
-\fB{\fP and \fB}\fP delimit \fIcsh\fP(1) style alternations
-(see Brace Expansion below);
+\fB{\fP and \fB}\fP delimit
+.Xr csh 1
+style alternations (see Brace Expansion below);
 and, finally, \fB*\fP, \fB?\fP and \fB[\fP are used in file name generation
 (see File Name Patterns below).
 .\"}}}
@@ -181,9 +186,10 @@
 command\fP, \fIi.e.\fP, a separate executable file that is located using the
 \fBPATH\fP parameter (see Command Execution below).
 Note that all command constructs have an \fIexit status\fP: for external
-commands, this is related to the status returned by \fIwait\fP(2) (if the
-command could not be found, the exit status is 127, if it could not be
-executed, the exit status is 126);
+commands, this is related to the status returned by
+.Xr wait 2
+(if the command could not be found, the exit status is 127, if it could
+not be executed, the exit status is 126);
 the exit status of other command constructs (built-in commands, functions,
 compound-commands, pipelines, lists, \fIetc.\fP) are all well defined and are
 described where the construct is described.
@@ -195,8 +201,9 @@
 .PP
 Commands can be chained together using the \fB|\fP token to
 form \fIpipelines\fP, in which the standard output of each command but
-the last is piped (see \fIpipe\fP(2)) to the standard input of the following
-command.
+the last is piped (see
+.Xr pipe 2 )
+to the standard input of the following command.
 The exit status of a pipeline is that of its last command.
 A pipeline may be prefixed by the \fB!\fP reserved word which
 causes the exit status of the pipeline to be logically
@@ -593,8 +600,9 @@
 .\"{{{  environment
 Parameters with the export attribute (set using the \fBexport\fP or
 \fBtypeset \-x\fP commands, or by parameter assignments followed by simple
-commands) are put in the environment (see \fIenviron\fP(5)) of commands
-run by the shell as \fIname\fP\fB=\fP\fIvalue\fP pairs.
+commands) are put in the environment (see
+.Xr environ 5 )
+of commands run by the shell as \fIname\fP\fB=\fP\fIvalue\fP pairs.
 The order in which parameters appear in the environment of a command
 is unspecified.
 When the shell starts up, it extracts parameters and their values from its
@@ -1425,7 +1433,9 @@
 any command substitutions performed in generating the set command.
 For example, `\fBset \-\- `false`; echo $?\fP' prints 0 in posix mode,
 1 in non-posix mode.  This construct is used in most shell scripts that
-use the old \fIgetopt\fP(1) command.
+use the old
+.Xr getopt 1
+command.
 .IP \ \ \(bu
 argument expansion of \fBalias\fP, \fBexport\fP, \fBreadonly\fP, and
 \fBtypeset\fP commands: in posix mode, normal argument expansion done;
@@ -1643,7 +1653,8 @@
 .sp
 If no arguments are given, any IO redirection is permanent and the shell
 is not replaced.
-Any file descriptors greater than 2 which are opened or \fIdup\fP(2)-ed
+Any file descriptors greater than 2 which are opened or
+.Xr dup 2 -ed
 in this way are not made available to other executed commands (\fIi.e.\fP,
 commands that are not built-in to the shell).
 .\"}}}
@@ -2397,11 +2408,13 @@
 .\"{{{  umask [-S] [mask]
 .IP "\fBumask\fP [\fB\-S\fP] [\fImask\fP]"
 .RS
-Display or set the file permission creation mask, or umask (see \fIumask\fP(2)).
+Display or set the file permission creation mask, or umask (see
+.Xr umask 2 ).
 If the \fB\-S\fP option is used, the mask displayed or set is symbolic,
 otherwise it is an octal number.
 .sp
-Symbolic masks are like those used by \fIchmod\fP(1):
+Symbolic masks are like those used by
+.Xr chmod 1 :
 .RS
 [\fBugoa\fP]{{\fB=+-\fP}{\fBrwx\fP}*}+[\fB,\fP...]
 .RE
@@ -2932,7 +2945,9 @@
 .\"{{{  introduction
 .SS "Vi Interactive Input Line Editing"
 The vi command line editor in ksh has basically the same commands as the
-vi editor (see \fIvi\fP(1)), with the following exceptions:
+vi editor (see
+.Xr vi 1 ),
+with the following exceptions:
 .nr P2 \n(PD
 .IP \ \ \(bu
 you start out in insert mode,
@@ -2961,7 +2976,9 @@
 current cursor position as they are typed, however, some characters
 are treated specially.
 In particular, the following characters are taken from current tty settings
-(see \fIstty\fP(1)) and have their usual meaning (normal values are in
+(see
+.Xr stty 1 )
+and have their usual meaning (normal values are in
 parentheses):
 kill (\fB^U\fP), erase (\fB^?\fP), werase (\fB^W\fP), eof (\fB^D\fP),
 intr (\fB^C\fP) and quit (\fB^\e\fP).
@@ -3280,12 +3297,27 @@
 .\"}}}
 .\"{{{  See also
 .SH "SEE ALSO"
-awk(1), 
-sh(1),
-csh(1), ed(1), getconf(1), getopt(1), sed(1), stty(1), vi(1),
-dup(2), execve(2), getgid(2), getuid(2), open(2), pipe(2), wait(2),
-getopt(3), rand(3), signal(3), system(3),
-environ(5)
+.Xr awk 1 ,
+.Xr sh 1 ,
+.Xr csh 1 ,
+.Xr ed 1 ,
+.Xr getconf 1 ,
+.Xr getopt 1 ,
+.Xr sed 1 ,
+.Xr stty 1 ,
+.Xr vi 1 ,
+.Xr dup 2 ,
+.Xr execve 2 ,
+.Xr getgid 2 ,
+.Xr getuid 2 ,
+.Xr open 2 ,
+.Xr pipe 2 ,
+.Xr wait 2 ,
+.Xr getopt 3 ,
+.Xr rand 3 ,
+.Xr signal 3 ,
+.Xr system 3 ,
+.Xr environ 7 .
 .PP
 .IR "The KornShell Command and Programming Language" ,
 Morris Bolsky and David Korn, 1989, ISBN 0-13-516972-0.
--- /src/sup/old/src/bin/ps/ps.1	Thu Mar 21 12:07:48 1996
+++ src/bin/ps/ps.1	Sun May 11 23:20:57 1997
@@ -205,7 +205,7 @@
 .It Dv "P_WAITED" Ta No "0x0001000	debugging process has waited for child"
 .It Dv "P_WEXIT" Ta No "0x0002000	working on exiting"
 .It Dv "P_EXEC" Ta No "0x0004000	process called"
-.Xr exec 2
+.Xr exec 3
 .It Dv "P_OWEUPC" Ta No "0x0008000	owe process an addupc() call at next ast"
 .\" the routine addupc is not documented in the man pages
 .It Dv "P_FSTRACE" Ta No "0x0010000	tracing via file system"
@@ -295,7 +295,7 @@
 The process is a session leader.
 .It V
 The process is suspended during a
-.Xr vfork .
+.Xr vfork 2 .
 .It W
 The process is swapped out.
 .It X
--- /src/sup/old/src/bin/sh/sh.1	Sun Mar  9 12:06:30 1997
+++ src/bin/sh/sh.1	Sun May 11 23:23:29 1997
@@ -62,8 +62,9 @@
 either a file or the terminal, interprets them, and
 generally executes other commands. It is the program that is running
 when a user logs into the system (although a user can select
-a different shell with the chsh(1) command).
-The shell
+a different shell with the
+.Xr chsh 1
+command). The shell
 implements a language that has flow control constructs,
 a macro facility that provides a variety of features in
 addition to data storage, along with built in history and line
@@ -132,7 +133,9 @@
 Specifying a dash ``-'' turns the option on, while using a plus ``+''
 disables the option.
 The following options can be set from the command line or
-with the set(1) builtin (described later).
+with the
+.Xr set 1
+builtin (described later).
 .TP
 -a    allexport
 Export all variables assigned to.
@@ -188,14 +191,19 @@
 Read commands from standard input (set automatically
 if no file arguments are present).  This option has
 no effect when set after the shell has already started
-running (i.e. with set(1)).
+running (i.e. with
+.Xr set 1 ).
 .TP
 -V    vi
-Enable the built-in vi(1) command line editor (disables
+Enable the built-in
+.Xr vi 1
+command line editor (disables
 -E if it has been set).
 .TP
 -E    emacs
-Enable the built-in emacs(1) command line editor (disables
+Enable the built-in
+.Xr emacs 1
+command line editor (disables
 -V if it has been set).
 .TP
 -b    notify
@@ -272,7 +280,8 @@
 .B Aliases
 .sp
 .LP
-An alias is a name and corresponding value set using the alias(1)
+An alias is a name and corresponding value set using the
+.Xr alias 1
 builtin command.  Whenever a reserved word may occur (see above),
 and after checking for reserved words, the shell
 checks the word to see if it matches an alias. If it does,
@@ -424,8 +433,9 @@
 passing the arguments and the environment to the
 program. If the program is not a normal executable file
 (i.e., if it does not begin with the "magic number"
-whose ASCII representation is "#!", so execve(2) returns
-ENOEXEC then) the shell
+whose ASCII representation is "#!", so
+.Xr execve 2
+returns ENOEXEC then) the shell
 will interpret the program in a subshell.  The child shell will
 reinitialize itself in this case, so that the effect will
 be as if a new shell had been invoked to handle the ad-hoc shell
@@ -749,7 +759,9 @@
 A positional parameter is a parameter denoted by a number (n > 0).
 The shell sets these initially to the values of its command
 line arguments that follow the name of the shell script.
-The set(1) builtin can also be used to set or reset them.
+The
+.Xr set 1
+builtin can also be used to set or reset them.
 .sp 2
 .B Special Parameters
 .sp
@@ -1036,7 +1048,9 @@
 a pattern cannot match a string starting with a period
 unless the first character of the pattern is a period.
 The next section describes the patterns used for both
-Pathname Expansion and the case(1) command.
+Pathname Expansion and the
+.Xr case 1
+command.
 
 .sp 2
 .B Shell Patterns
@@ -1075,7 +1089,10 @@
 are builtin because they need to perform some  operation
 that can't be performed by a separate process. In addition to
 these, there are several other commands that may
-be builtin for efficiency (e.g. printf(1), echo(1), test(1),
+be builtin for efficiency (e.g.
+.Xr printf 1 ,
+.Xr echo 1 ,
+.Xr test 1 ,
 etc).
 .TP
 :
@@ -1160,7 +1177,8 @@
 is used as a default when -e is not specified.  If
 FCEDIT is null or unset, the value of the EDITOR
 variable is used.  If EDITOR is null or unset,
-ed(1) is used as the editor.
+.Xr ed 1
+is used as the editor.
 .TP 2
 -l (ell)
 List the commands rather than invoking
@@ -1346,7 +1364,9 @@
 the command is printed.
 .TP
 umask [ mask ]
-Set the value of umask (see umask(2)) to the specified
+Set the value of umask (see
+.Xr umask 2 )
+to the specified
 octal value. If the argument is omitted, the
 umask value is printed.
 .TP
--- /src/sup/old/src/bin/sync/sync.8	Fri Oct 13 23:44:52 1995
+++ src/bin/sync/sync.8	Sun May 11 23:24:42 1997
@@ -49,9 +49,9 @@
 or
 .Xr halt 8 .
 Generally, it is preferable to use
-.Xr reboot
+reboot 
 or
-.Xr halt
+halt
 to shut down the system,
 as they may perform additional actions
 such as resynchronizing the hardware clock
	

-------------------------------------------------------------------------------
>Audit-Trail:
>Unformatted:
>>>>>>> - copy of manxref script

#!/usr/local/bin/perl

# Copyright (c) 1997 David Brownlee (abs@mono.org). Licence at end of file.
# Check for invalid crossreferences in (NetBSD) source tree.   Version 1.3
#
# TODO: Suggest reverse references.
# TODO: Include MLINKS when checking for duplicates.
# TODO: Suggest correct sections for manpages specified as xxxx(n)
# TODO: Report references to obsolete manpages (ie sigpause)
# Two passes as trying to do it all in one pass can derange &find()... joy.

require 'getopts.pl';
require 'find.pl';

&Getopts('adqx') || &usage;
defined($opt_a) && ($opt_d=$opt_x=1);

$^W=1;
@srcdirs=('/usr/src');
$arch_match='(alpha|amiga|arm32|atari|hp300|i386|m68k|mac68k|mips|mvme68k|'.
	   'pc532|pica|pmax|powerpc|sparc|sun3|sun3x|vax|x68k)($|/)';

if( @ARGV )
    { @srcdirs=@ARGV; }

$|=1;
$pagecount=0;

&show_progress(  "       manpages  makefiles\n");
&show_progress(  "Scanning:".(' 'x12));
&find(@srcdirs);

&show_progress("\n Parsing:".(' 'x6));
$count=0;
foreach( @filelist )
    {
    &show_progress("\b\b\b\b\b%5d",++$count);
    &read_manpage($_);
    }

&show_progress('+'.(' 'x5));
$count=0;
foreach( @makefilelist )
    {
    &show_progress("\b\b\b\b\b%5d",++$count);
    &read_manlinks($_);
    }
&show_progress("\nChecking:  ");
&check_xrefs;
&prune_duplicates;
&show_progress("Done\n");

if( @errors )
    {
    &title('Errors found while parsing');
    print join("\n",@errors),"\n\n\n";
    }

if( %invalid_xref )
    {
    &title('Invalid crossreferences');
    foreach( sort keys %invalid_xref )
	{
	print "$_\n";
	if( $invalid_xref{$_} ne '' )
	    { print "    Invalid: $invalid_xref{$_}\n"; }
	if( defined($non_Xr_xref{$_}) )
	    { print "    Non_.Xr: $non_Xr_xref{$_}\n"; }
	print "\n";
	}
    print "\n\n";
    }

if( %duplicates )
    {
    &title('Duplicated pages');
    foreach( sort keys %duplicates )
	{ print "$_:\n\t$duplicates{$_}\n\n"; }
    print "\n\n";
    }
exit;

sub check_xrefs
    {
    local($page,$count,$check,$pagelist,@list);

    foreach $page ( sort keys %xref )
	{
	if( ++$count%32==0 )
	    { &show_progress(('|','/','-','\\')[($count/32)%4]."\b"); }
	@list=split(' ',$xref{$page});
	$pagelist='';
	foreach $check ( @list )
	    {
	    if( ($check eq $page) || !defined($xref_check{$check}) )
		{ $pagelist.=$check.&sections($check).' '; }
	    }
	if( $pagelist ne '' )
	    {
	    chop $pagelist;
	    $invalid_xref{$page}=$pagelist;
	    }
	}
    }


sub prune_duplicates
    {
    foreach( sort keys %duplicates )
	{
	if( ! scalar(grep(!/$arch_match/,split(' ',$duplicates{$_}))) )
	    { delete $duplicates{$_}; }
	}
    }
 

sub read_manlinks
    {
    local($file)=@_;
    local($to,$from);

    open(FILE,$file) || die("Unable to open Makefile '$file': $!");
    while( <FILE> )
	{
	while( /\\$/ )
	    {
	    chop;
	    chop;
	    $_.=<FILE>;
	    }
	if( /^[^#]*MLINKS\s*\+?=\s*(.*)/ )
	    {
	    $_=$1;
	    while( $_ )
		{
		($from,$to,$_)=split(/\s+/,$_,3);
		if( !defined($to) )
		    { push(@errors,"Invalid MLINKS line in $file."); }
		else
		    { $xref_check{$to}=1; }
		}
	    }
	}
    close(FILE);
    }

sub read_manpage
    {
    local($path)=@_;
    local(%pagelist,$pagelist,$file,$dir);

    $path =~ s#^\./##;
    ($dir,$file) = ($path =~ m#(.*/|)([^/]+$)#);
    $dir =~ s#/$##;

    open(FILE,$path) || die("Unable to open file '$path': $!");
    while ( <FILE> )
	{
	if( defined($opt_x) && substr($_,0,3) ne '.\\"' )
	    {
	    while( s/(\S+\(\d+\))// )
		{
		if( !defined($non_Xr_xref{$path}) )
		    {
		    $invalid_xref{$path}='';
		    $non_Xr_xref{$path}='';
		    }
		$non_Xr_xref{$path}.="$1 ";
		}
	    }
	if( /^.Xr/ )
	    {
	    if( /^.Xr\s+(\S+)(\s+(\S+)|)/ )
		{
		$_=( $3 eq '' )?$1:"$1.$3";	# Grr.. missing section number
		s/(.)/\l$1/;			# Remove initial caps if there
		$pagelist{$_}=1;
		}
	    else
		{
		chop;
		push(@errors,"Invalid .Xr line in $path ($_)");
		}
	    }
	}
    close(FILE);
    if( defined($opt_d) && defined($dupcheck{$file}) )
	{
	if( !defined($duplicates{$file}) )
	    { $duplicates{$file}=$dupcheck{$file}; }
	$duplicates{$file}.=" $dir";
	}
    else
	{ $dupcheck{$file}=$dir; }

    $xref{$path}='';
    foreach( sort keys %pagelist )
	{ $xref{$path}.=$_.' '; }
    chop $xref{$path};
    $xref_check{$file}=1;
    }

sub sections
    {
    local($page)=@_;
    local($list,$sec);

    $sec=0;	# Current section number is not an option...
    if( $page =~ s/\.([^.]+)$// ) # In case we get something.12 ... or worse
	{ $sec=$1; }
    $page.='.';

    $list='';
    for( $_=1 ; $_<10 ; ++$_ )
	{
	( $_ eq $sec ) && next;
	if( defined($xref_check{$page.$_}) )
	    { $list.=$_.','; }
	}
    chop $list;
    ($list eq '')?'':'('.$list.'?)';
    }

sub show_progress
    {
    defined($opt_q) || printf(STDERR @_);
    }

sub title
    {
    print $_[0],"\n",'^' x length($_[0]),"\n\n";
    }

sub usage
    {
    print "Usage: manxref [opts] [directories]

[opts]	-a : All checks (currently synonymous for '-d -x').
	-d : Report duplicate man pages.
	-q : Suppress progress reports.
	-x : Report cross references specfied as 'xxxx(n)' (Should be .Xr).

    Manxref checks for conflicting or inaccurate crossreferences,
    crossreferences to the same page, and duplicate manpages.
    By default it will check all manpages in '/usr/src'.

    It will (simply) parse any Makefile or Makefile.inc in the same
    directory as a manpage to determine if MLINKS are being used.

    If a reference to a manpage in the wrong section is made, valid
    sections will be listed in parenthesis.

    It will not pick up 'duplicated' MD manpages, but will report 
    when a MI and MD manpage of the same name is detected.

	(c) 1997 abs\@mono.org. 'Berkeley' style licence.
";
    exit(3);
    }

sub wanted
    {
    if( $_ =~ /\.[1-9]$/ && -f $_ )
	{
	push(@filelist,$name);
	&show_progress("%s%5d+%5d",("\b"x11),scalar(@filelist),
							scalar(@makefilelist));
	}
    elsif( $_ eq 'Makefile' || $_ eq 'Makefile.inc' )
	{
	push(@makefilelist,$name);
	&show_progress("%s%5d+%5d",("\b"x11),scalar(@filelist),
							scalar(@makefilelist));
	}
    }

# Copyright (c) 1997 David Brownlee (abs@mono.org).  All rights reserved.
#
# This program is free software.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.