159191Skris: #!/usr/bin/perl-5.005
259191Skris    eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
359191Skris	if $running_under_some_shell;
459191Skris
559191Skris$DEF_PM_SECTION = '3pm' || '3';
659191Skris
759191Skris=head1 NAME
859191Skris
959191Skrispod2man - translate embedded Perl pod directives into man pages
1059191Skris
1159191Skris=head1 SYNOPSIS
1259191Skris
1359191SkrisB<pod2man>
1459191Skris[ B<--section=>I<manext> ]
1559191Skris[ B<--release=>I<relpatch> ]
1659191Skris[ B<--center=>I<string> ]
1759191Skris[ B<--date=>I<string> ]
1859191Skris[ B<--fixed=>I<font> ]
1959191Skris[ B<--official> ]
2059191Skris[ B<--lax> ]
2159191SkrisI<inputfile>
2259191Skris
2359191Skris=head1 DESCRIPTION
2459191Skris
2559191SkrisB<pod2man> converts its input file containing embedded pod directives (see
2659191SkrisL<perlpod>) into nroff source suitable for viewing with nroff(1) or
2759191Skristroff(1) using the man(7) macro set.
2859191Skris
2959191SkrisBesides the obvious pod conversions, B<pod2man> also takes care of
3059191Skrisfunc(), func(n), and simple variable references like $foo or @bar so
3159191Skrisyou don't have to use code escapes for them; complex expressions like
3259191SkrisC<$fred{'stuff'}> will still need to be escaped, though.  Other nagging
3359191Skrislittle roffish things that it catches include translating the minus in
3459191Skrissomething like foo-bar, making a long dash--like this--into a real em
3559191Skrisdash, fixing up "paired quotes", putting a little space after the
3659191Skrisparens in something like func(), making C++ and PI look right, making
3759191Skrisdouble underbars have a little tiny space between them, making ALLCAPS
3859191Skrisa teeny bit smaller in troff(1), and escaping backslashes so you don't
3959191Skrishave to.
4059191Skris
4159191Skris=head1 OPTIONS
4259191Skris
4359191Skris=over 8
4459191Skris
4559191Skris=item center
4659191Skris
4759191SkrisSet the centered header to a specific string.  The default is
4859191Skris"User Contributed Perl Documentation", unless the C<--official> flag is
4959191Skrisgiven, in which case the default is "Perl Programmers Reference Guide".
5059191Skris
5159191Skris=item date
5259191Skris
5359191SkrisSet the left-hand footer string to this value.  By default,
5459191Skristhe modification date of the input file will be used.
5559191Skris
5659191Skris=item fixed
5759191Skris
5859191SkrisThe fixed font to use for code refs.  Defaults to CW.
5959191Skris
6059191Skris=item official
6159191Skris
6259191SkrisSet the default header to indicate that this page is of
6359191Skristhe standard release in case C<--center> is not given.
6459191Skris
6559191Skris=item release
6659191Skris
6759191SkrisSet the centered footer.  By default, this is the current
6859191Skrisperl release.
6959191Skris
7059191Skris=item section
7159191Skris
7259191SkrisSet the section for the C<.TH> macro.  The standard conventions on
7359191Skrissections are to use 1 for user commands,  2 for system calls, 3 for
7459191Skrisfunctions, 4 for devices, 5 for file formats, 6 for games, 7 for
7559191Skrismiscellaneous information, and 8 for administrator commands.  This works
7659191Skrisbest if you put your Perl man pages in a separate tree, like
7759191SkrisF</usr/local/perl/man/>.  By default, section 1 will be used
7859191Skrisunless the file ends in F<.pm> in which case section 3 will be selected.
7959191Skris
8059191Skris=item lax
8159191Skris
8259191SkrisDon't complain when required sections aren't present.
8359191Skris
8459191Skris=back
8559191Skris
8659191Skris=head1 Anatomy of a Proper Man Page
8759191Skris
8859191SkrisFor those not sure of the proper layout of a man page, here's
8959191Skrisan example of the skeleton of a proper man page.  Head of the
9059191Skrismajor headers should be setout as a C<=head1> directive, and
9159191Skrisare historically written in the rather startling ALL UPPER CASE
9259191Skrisformat, although this is not mandatory.
9359191SkrisMinor headers may be included using C<=head2>, and are
9459191Skristypically in mixed case.
9559191Skris
9659191Skris=over 10
9759191Skris
9859191Skris=item NAME
9959191Skris
10059191SkrisMandatory section; should be a comma-separated list of programs or
10159191Skrisfunctions documented by this podpage, such as:
10259191Skris
10359191Skris    foo, bar - programs to do something
10459191Skris
10559191Skris=item SYNOPSIS
10659191Skris
10759191SkrisA short usage summary for programs and functions, which
10859191Skrismay someday be deemed mandatory.
10959191Skris
11059191Skris=item DESCRIPTION
11159191Skris
11259191SkrisLong drawn out discussion of the program.  It's a good idea to break this
11359191Skrisup into subsections using the C<=head2> directives, like
11459191Skris
11559191Skris    =head2 A Sample Subection
11659191Skris
11759191Skris    =head2 Yet Another Sample Subection
11859191Skris
11959191Skris=item OPTIONS
12059191Skris
12159191SkrisSome people make this separate from the description.
12259191Skris
12359191Skris=item RETURN VALUE
12459191Skris
12559191SkrisWhat the program or function returns if successful.
12659191Skris
12759191Skris=item ERRORS
12859191Skris
12959191SkrisExceptions, return codes, exit stati, and errno settings.
13059191Skris
13159191Skris=item EXAMPLES
13259191Skris
13359191SkrisGive some example uses of the program.
13459191Skris
13559191Skris=item ENVIRONMENT
13659191Skris
13759191SkrisEnvariables this program might care about.
13859191Skris
13959191Skris=item FILES
14059191Skris
14159191SkrisAll files used by the program.  You should probably use the FE<lt>E<gt>
14259191Skrisfor these.
14359191Skris
14459191Skris=item SEE ALSO
14559191Skris
14659191SkrisOther man pages to check out, like man(1), man(7), makewhatis(8), or catman(8).
14759191Skris
14859191Skris=item NOTES
14959191Skris
15059191SkrisMiscellaneous commentary.
15159191Skris
15259191Skris=item CAVEATS
15359191Skris
15459191SkrisThings to take special care with; sometimes called WARNINGS.
15559191Skris
15659191Skris=item DIAGNOSTICS
15759191Skris
15859191SkrisAll possible messages the program can print out--and
15959191Skriswhat they mean.
16059191Skris
16159191Skris=item BUGS
16259191Skris
16359191SkrisThings that are broken or just don't work quite right.
16459191Skris
16559191Skris=item RESTRICTIONS
16659191Skris
16759191SkrisBugs you don't plan to fix :-)
16859191Skris
16959191Skris=item AUTHOR
17059191Skris
17159191SkrisWho wrote it (or AUTHORS if multiple).
17259191Skris
17359191Skris=item HISTORY
17459191Skris
17559191SkrisPrograms derived from other sources sometimes have this, or
17659191Skrisyou might keep a modification log here.
17759191Skris
17859191Skris=back
17959191Skris
18059191Skris=head1 EXAMPLES
18159191Skris
18259191Skris    pod2man program > program.1
18359191Skris    pod2man some_module.pm > /usr/perl/man/man3/some_module.3
18459191Skris    pod2man --section=7 note.pod > note.7
18559191Skris
18659191Skris=head1 DIAGNOSTICS
18759191Skris
18859191SkrisThe following diagnostics are generated by B<pod2man>.  Items
18959191Skrismarked "(W)" are non-fatal, whereas the "(F)" errors will cause
19059191SkrisB<pod2man> to immediately exit with a non-zero status.
19159191Skris
19259191Skris=over 4
19359191Skris
19459191Skris=item bad option in paragraph %d of %s: ``%s'' should be [%s]<%s>
19559191Skris
19659191Skris(W) If you start include an option, you should set it off
19759191Skrisas bold, italic, or code.
19859191Skris
19959191Skris=item can't open %s: %s
20059191Skris
20159191Skris(F) The input file wasn't available for the given reason.
20259191Skris
20359191Skris=item Improper man page - no dash in NAME header in paragraph %d of %s
20459191Skris
20559191Skris(W) The NAME header did not have an isolated dash in it.  This is
20659191Skrisconsidered important.
20759191Skris
20859191Skris=item Invalid man page - no NAME line in %s
20959191Skris
21059191Skris(F) You did not include a NAME header, which is essential.
21159191Skris
21259191Skris=item roff font should be 1 or 2 chars, not `%s'  (F)
21359191Skris
21459191Skris(F) The font specified with the C<--fixed> option was not
21559191Skrisa one- or two-digit roff font.
21659191Skris
21759191Skris=item %s is missing required section: %s
21859191Skris
21959191Skris(W) Required sections include NAME, DESCRIPTION, and if you're
22059191Skrisusing a section starting with a 3, also a SYNOPSIS.  Actually,
22159191Skrisnot having a NAME is a fatal.
22259191Skris
22359191Skris=item Unknown escape: %s in %s
22459191Skris
22559191Skris(W) An unknown HTML entity (probably for an 8-bit character) was given via
22659191Skrisa C<EE<lt>E<gt>> directive.  Besides amp, lt, gt, and quot, recognized
22759191Skrisentities are Aacute, aacute, Acirc, acirc, AElig, aelig, Agrave, agrave,
22859191SkrisAring, aring, Atilde, atilde, Auml, auml, Ccedil, ccedil, Eacute, eacute,
22959191SkrisEcirc, ecirc, Egrave, egrave, ETH, eth, Euml, euml, Iacute, iacute, Icirc,
23059191Skrisicirc, Igrave, igrave, Iuml, iuml, Ntilde, ntilde, Oacute, oacute, Ocirc,
23159191Skrisocirc, Ograve, ograve, Oslash, oslash, Otilde, otilde, Ouml, ouml, szlig,
23259191SkrisTHORN, thorn, Uacute, uacute, Ucirc, ucirc, Ugrave, ugrave, Uuml, uuml,
23359191SkrisYacute, yacute, and yuml.
23459191Skris
23559191Skris=item Unmatched =back
23659191Skris
23759191Skris(W) You have a C<=back> without a corresponding C<=over>.
23859191Skris
23959191Skris=item Unrecognized pod directive: %s
24059191Skris
24159191Skris(W) You specified a pod directive that isn't in the known list of
24259191SkrisC<=head1>, C<=head2>, C<=item>, C<=over>, C<=back>, or C<=cut>.
24359191Skris
24459191Skris
24559191Skris=back
24659191Skris
24759191Skris=head1 NOTES
24859191Skris
24959191SkrisIf you would like to print out a lot of man page continuously, you
25059191Skrisprobably want to set the C and D registers to set contiguous page
25159191Skrisnumbering and even/odd paging, at least on some versions of man(7).
25259191SkrisSettting the F register will get you some additional experimental
25359191Skrisindexing:
25459191Skris
25559191Skris    troff -man -rC1 -rD1 -rF1 perl.1 perldata.1 perlsyn.1 ...
25659191Skris
25759191SkrisThe indexing merely outputs messages via C<.tm> for each
25859191Skrismajor page, section, subsection, item, and any C<XE<lt>E<gt>>
25959191Skrisdirectives.
26059191Skris
26159191Skris
26259191Skris=head1 RESTRICTIONS
26359191Skris
26459191SkrisNone at this time.
26559191Skris
26659191Skris=head1 BUGS
26759191Skris
26859191SkrisThe =over and =back directives don't really work right.  They
26959191Skristake absolute positions instead of offsets, don't nest well, and
27059191Skrismaking people count is suboptimal in any event.
27159191Skris
27259191Skris=head1 AUTHORS
27359191Skris
27459191SkrisOriginal prototype by Larry Wall, but so massively hacked over by
27559191SkrisTom Christiansen such that Larry probably doesn't recognize it anymore.
27659191Skris
27759191Skris=cut
27859191Skris
27959191Skris$/ = "";
28059191Skris$cutting = 1;
28159191Skris@Indices = ();
28259191Skris
28359191Skris# We try first to get the version number from a local binary, in case we're
28459191Skris# running an installed version of Perl to produce documentation from an
28559191Skris# uninstalled newer version's pod files.
28659191Skrisif ($^O ne 'plan9' and $^O ne 'dos' and $^O ne 'os2' and $^O ne 'MSWin32') {
28759191Skris  my $perl = (-x './perl' && -f './perl' ) ?
28859191Skris                 './perl' :
28959191Skris                 ((-x '../perl' && -f '../perl') ?
29059191Skris                      '../perl' :
29159191Skris                      '');
29259191Skris  ($version,$patch) = `$perl -e 'print $]'` =~ /^(\d\.\d{3})(\d{2})?/ if $perl;
29359191Skris}
29459191Skris# No luck; we'll just go with the running Perl's version
29559191Skris($version,$patch) = $] =~ /^(.{5})(\d{2})?/ unless $version;
29659191Skris$DEF_RELEASE  = "perl $version";
29759191Skris$DEF_RELEASE .= ", patch $patch" if $patch;
29859191Skris
29959191Skris
30059191Skrissub makedate {
30159191Skris    my $secs = shift;
30259191Skris    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($secs);
30359191Skris    my $mname = (qw{Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec})[$mon];
30459191Skris    $year += 1900;
30559191Skris    return "$mday/$mname/$year";
30659191Skris}
30759191Skris
30859191Skrisuse Getopt::Long;
30959191Skris
31059191Skris$DEF_SECTION = 1;
31159191Skris$DEF_CENTER = "User Contributed Perl Documentation";
31259191Skris$STD_CENTER = "Perl Programmers Reference Guide";
31359191Skris$DEF_FIXED = 'CW';
31459191Skris$DEF_LAX = 0;
31559191Skris
31659191Skrissub usage {
31759191Skris    warn "$0: @_\n" if @_;
31859191Skris    die <<EOF;
31959191Skrisusage: $0 [options] podpage
32059191SkrisOptions are:
32159191Skris	--section=manext      (default "$DEF_SECTION")
32259191Skris	--release=relpatch    (default "$DEF_RELEASE")
32359191Skris	--center=string       (default "$DEF_CENTER")
32459191Skris	--date=string         (default "$DEF_DATE")
32559191Skris	--fixed=font	      (default "$DEF_FIXED")
32659191Skris	--official	      (default NOT)
32759191Skris	--lax                 (default NOT)
32859191SkrisEOF
32959191Skris}
33059191Skris
33159191Skris$uok = GetOptions( qw(
33259191Skris	section=s
33359191Skris	release=s
33459191Skris	center=s
33559191Skris	date=s
33659191Skris	fixed=s
33759191Skris	official
33859191Skris	lax
33959191Skris	help));
34059191Skris
34159191Skris$DEF_DATE = makedate((stat($ARGV[0]))[9] || time());
34259191Skris
34359191Skrisusage("Usage error!") unless $uok;
34459191Skrisusage() if $opt_help;
34559191Skrisusage("Need one and only one podpage argument") unless @ARGV == 1;
34659191Skris
34759191Skris$section = $opt_section || ($ARGV[0] =~ /\.pm$/
34859191Skris				? $DEF_PM_SECTION : $DEF_SECTION);
34959191Skris$RP = $opt_release || $DEF_RELEASE;
35059191Skris$center = $opt_center || ($opt_official ? $STD_CENTER : $DEF_CENTER);
35159191Skris$lax = $opt_lax || $DEF_LAX;
35259191Skris
35359191Skris$CFont = $opt_fixed || $DEF_FIXED;
35459191Skris
35559191Skrisif (length($CFont) == 2) {
35659191Skris    $CFont_embed = "\\f($CFont";
35759191Skris}
35859191Skriselsif (length($CFont) == 1) {
35959191Skris    $CFont_embed = "\\f$CFont";
36059191Skris}
36159191Skriselse {
36259191Skris    die "roff font should be 1 or 2 chars, not `$CFont_embed'";
36359191Skris}
36459191Skris
36559191Skris$date = $opt_date || $DEF_DATE;
36659191Skris
36759191Skrisfor (qw{NAME DESCRIPTION}) {
36859191Skris# for (qw{NAME DESCRIPTION AUTHOR}) {
36959191Skris    $wanna_see{$_}++;
37059191Skris}
37159191Skris$wanna_see{SYNOPSIS}++ if $section =~ /^3/;
37259191Skris
37359191Skris
37459191Skris$name = @ARGV ? $ARGV[0] : "<STDIN>";
37559191Skris$Filename = $name;
37659191Skrisif ($section =~ /^1/) {
37759191Skris    require File::Basename;
37859191Skris    $name = uc File::Basename::basename($name);
37959191Skris}
38059191Skris$name =~ s/\.(pod|p[lm])$//i;
38159191Skris
38259191Skris# Lose everything up to the first of
38359191Skris#     */lib/*perl*	standard or site_perl module
38459191Skris#     */*perl*/lib	from -D prefix=/opt/perl
38559191Skris#     */*perl*/		random module hierarchy
38659191Skris# which works.
38759191Skris$name =~ s-//+-/-g;
38859191Skrisif ($name =~ s-^.*?/lib/[^/]*perl[^/]*/--i
38959191Skris	or $name =~ s-^.*?/[^/]*perl[^/]*/lib/--i
39059191Skris	or $name =~ s-^.*?/[^/]*perl[^/]*/--i) {
39159191Skris    # Lose ^site(_perl)?/.
39259191Skris    $name =~ s-^site(_perl)?/--;
39359191Skris    # Lose ^arch/.	(XXX should we use Config? Just for archname?)
39459191Skris    $name =~ s~^(.*-$^O|$^O-.*)/~~o;
39559191Skris    # Lose ^version/.
39659191Skris    $name =~ s-^\d+\.\d+/--;
39759191Skris}
39859191Skris
39959191Skris# Translate Getopt/Long to Getopt::Long, etc.
40059191Skris$name =~ s(/)(::)g;
40159191Skris
40259191Skrisif ($name ne 'something') {
40359191Skris    FCHECK: {
40459191Skris	open(F, "< $ARGV[0]") || die "can't open $ARGV[0]: $!";
40559191Skris	while (<F>) {
40659191Skris	    next unless /^=\b/;
40759191Skris	    if (/^=head1\s+NAME\s*$/) {  # an /m would forgive mistakes
40859191Skris		$_ = <F>;
40959191Skris		unless (/\s*-+\s+/) {
41059191Skris		    $oops++;
41159191Skris		    warn "$0: Improper man page - no dash in NAME header in paragraph $. of $ARGV[0]\n"
41259191Skris                } else {
41359191Skris		    my @n = split /\s+-+\s+/;
41459191Skris		    if (@n != 2) {
41559191Skris			$oops++;
41659191Skris			warn "$0: Improper man page - malformed NAME header in paragraph $. of $ARGV[0]\n"
41759191Skris		    }
41859191Skris		    else {
419100936Snectar			$n[0] =~ s/\n/ /g;
420100936Snectar			$n[1] =~ s/\n/ /g;
42159191Skris			%namedesc = @n;
42259191Skris		    }
42359191Skris		}
42459191Skris		last FCHECK;
42559191Skris	    }
42659191Skris	    next if /^=cut\b/;	# DB_File and Net::Ping have =cut before NAME
42759191Skris	    next if /^=pod\b/;  # It is OK to have =pod before NAME
428205128Ssimon	    next if /^=(for|begin|end)\s+comment\b/;  # It is OK to have =for =begin or =end comment before NAME
42959191Skris	    die "$0: Invalid man page - 1st pod line is not NAME in $ARGV[0]\n" unless $lax;
43059191Skris	}
43159191Skris	die "$0: Invalid man page - no documentation in $ARGV[0]\n" unless $lax;
43259191Skris    }
43359191Skris    close F;
43459191Skris}
43559191Skris
43659191Skrisprint <<"END";
43759191Skris.rn '' }`
43859191Skris''' \$RCSfile\$\$Revision\$\$Date\$
43959191Skris'''
44059191Skris''' \$Log\$
44159191Skris'''
44259191Skris.de Sh
44359191Skris.br
44459191Skris.if t .Sp
44559191Skris.ne 5
44659191Skris.PP
44759191Skris\\fB\\\\\$1\\fR
44859191Skris.PP
44959191Skris..
45059191Skris.de Sp
45159191Skris.if t .sp .5v
45259191Skris.if n .sp
45359191Skris..
45459191Skris.de Ip
45559191Skris.br
45659191Skris.ie \\\\n(.\$>=3 .ne \\\\\$3
45759191Skris.el .ne 3
45859191Skris.IP "\\\\\$1" \\\\\$2
45959191Skris..
46059191Skris.de Vb
46159191Skris.ft $CFont
46259191Skris.nf
46359191Skris.ne \\\\\$1
46459191Skris..
46559191Skris.de Ve
46659191Skris.ft R
46759191Skris
46859191Skris.fi
46959191Skris..
47059191Skris'''
47159191Skris'''
47259191Skris'''     Set up \\*(-- to give an unbreakable dash;
47359191Skris'''     string Tr holds user defined translation string.
47459191Skris'''     Bell System Logo is used as a dummy character.
47559191Skris'''
47659191Skris.tr \\(*W-|\\(bv\\*(Tr
47759191Skris.ie n \\{\\
47859191Skris.ds -- \\(*W-
47959191Skris.ds PI pi
48059191Skris.if (\\n(.H=4u)&(1m=24u) .ds -- \\(*W\\h'-12u'\\(*W\\h'-12u'-\\" diablo 10 pitch
48159191Skris.if (\\n(.H=4u)&(1m=20u) .ds -- \\(*W\\h'-12u'\\(*W\\h'-8u'-\\" diablo 12 pitch
48259191Skris.ds L" ""
48359191Skris.ds R" ""
48459191Skris'''   \\*(M", \\*(S", \\*(N" and \\*(T" are the equivalent of
48559191Skris'''   \\*(L" and \\*(R", except that they are used on ".xx" lines,
48659191Skris'''   such as .IP and .SH, which do another additional levels of
48759191Skris'''   double-quote interpretation
48859191Skris.ds M" """
48959191Skris.ds S" """
49059191Skris.ds N" """""
49159191Skris.ds T" """""
49259191Skris.ds L' '
49359191Skris.ds R' '
49459191Skris.ds M' '
49559191Skris.ds S' '
49659191Skris.ds N' '
49759191Skris.ds T' '
49859191Skris'br\\}
49959191Skris.el\\{\\
50059191Skris.ds -- \\(em\\|
50159191Skris.tr \\*(Tr
50259191Skris.ds L" ``
50359191Skris.ds R" ''
50459191Skris.ds M" ``
50559191Skris.ds S" ''
50659191Skris.ds N" ``
50759191Skris.ds T" ''
50859191Skris.ds L' `
50959191Skris.ds R' '
51059191Skris.ds M' `
51159191Skris.ds S' '
51259191Skris.ds N' `
51359191Skris.ds T' '
51459191Skris.ds PI \\(*p
51559191Skris'br\\}
51659191SkrisEND
51759191Skris
51859191Skrisprint <<'END';
51959191Skris.\"	If the F register is turned on, we'll generate
52059191Skris.\"	index entries out stderr for the following things:
52159191Skris.\"		TH	Title
52259191Skris.\"		SH	Header
52359191Skris.\"		Sh	Subsection
52459191Skris.\"		Ip	Item
52559191Skris.\"		X<>	Xref  (embedded
52659191Skris.\"	Of course, you have to process the output yourself
52759191Skris.\"	in some meaninful fashion.
52859191Skris.if \nF \{
52959191Skris.de IX
53059191Skris.tm Index:\\$1\t\\n%\t"\\$2"
53159191Skris..
53259191Skris.nr % 0
53359191Skris.rr F
53459191Skris.\}
53559191SkrisEND
53659191Skris
53759191Skrisprint <<"END";
53859191Skris.TH $name $section "$RP" "$date" "$center"
53959191Skris.UC
54059191SkrisEND
54159191Skris
54259191Skrispush(@Indices, qq{.IX Title "$name $section"});
54359191Skris
54459191Skriswhile (($name, $desc) = each %namedesc) {
54559191Skris    for ($name, $desc) { s/^\s+//; s/\s+$//; }
54659191Skris    push(@Indices, qq(.IX Name "$name - $desc"\n));
54759191Skris}
54859191Skris
54959191Skrisprint <<'END';
55059191Skris.if n .hy 0
55159191Skris.if n .na
55259191Skris.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
55359191Skris.de CQ          \" put $1 in typewriter font
55459191SkrisEND
55559191Skrisprint ".ft $CFont\n";
55659191Skrisprint <<'END';
55759191Skris'if n "\c
55859191Skris'if t \\&\\$1\c
55959191Skris'if n \\&\\$1\c
56059191Skris'if n \&"
56159191Skris\\&\\$2 \\$3 \\$4 \\$5 \\$6 \\$7
56259191Skris'.ft R
56359191Skris..
56459191Skris.\" @(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2
56559191Skris.	\" AM - accent mark definitions
56659191Skris.bd B 3
56759191Skris.	\" fudge factors for nroff and troff
56859191Skris.if n \{\
56959191Skris.	ds #H 0
57059191Skris.	ds #V .8m
57159191Skris.	ds #F .3m
57259191Skris.	ds #[ \f1
57359191Skris.	ds #] \fP
57459191Skris.\}
57559191Skris.if t \{\
57659191Skris.	ds #H ((1u-(\\\\n(.fu%2u))*.13m)
57759191Skris.	ds #V .6m
57859191Skris.	ds #F 0
57959191Skris.	ds #[ \&
58059191Skris.	ds #] \&
58159191Skris.\}
58259191Skris.	\" simple accents for nroff and troff
58359191Skris.if n \{\
58459191Skris.	ds ' \&
58559191Skris.	ds ` \&
58659191Skris.	ds ^ \&
58759191Skris.	ds , \&
58859191Skris.	ds ~ ~
58959191Skris.	ds ? ?
59059191Skris.	ds ! !
59159191Skris.	ds /
59259191Skris.	ds q
59359191Skris.\}
59459191Skris.if t \{\
59559191Skris.	ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
59659191Skris.	ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
59759191Skris.	ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
59859191Skris.	ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
59959191Skris.	ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
60059191Skris.	ds ? \s-2c\h'-\w'c'u*7/10'\u\h'\*(#H'\zi\d\s+2\h'\w'c'u*8/10'
60159191Skris.	ds ! \s-2\(or\s+2\h'-\w'\(or'u'\v'-.8m'.\v'.8m'
60259191Skris.	ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
60359191Skris.	ds q o\h'-\w'o'u*8/10'\s-4\v'.4m'\z\(*i\v'-.4m'\s+4\h'\w'o'u*8/10'
60459191Skris.\}
60559191Skris.	\" troff and (daisy-wheel) nroff accents
60659191Skris.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
60759191Skris.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
60859191Skris.ds v \\k:\h'-(\\n(.wu*9/10-\*(#H)'\v'-\*(#V'\*(#[\s-4v\s0\v'\*(#V'\h'|\\n:u'\*(#]
60959191Skris.ds _ \\k:\h'-(\\n(.wu*9/10-\*(#H+(\*(#F*2/3))'\v'-.4m'\z\(hy\v'.4m'\h'|\\n:u'
61059191Skris.ds . \\k:\h'-(\\n(.wu*8/10)'\v'\*(#V*4/10'\z.\v'-\*(#V*4/10'\h'|\\n:u'
61159191Skris.ds 3 \*(#[\v'.2m'\s-2\&3\s0\v'-.2m'\*(#]
61259191Skris.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
61359191Skris.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
61459191Skris.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
61559191Skris.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
61659191Skris.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
61759191Skris.ds ae a\h'-(\w'a'u*4/10)'e
61859191Skris.ds Ae A\h'-(\w'A'u*4/10)'E
61959191Skris.ds oe o\h'-(\w'o'u*4/10)'e
62059191Skris.ds Oe O\h'-(\w'O'u*4/10)'E
62159191Skris.	\" corrections for vroff
62259191Skris.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
62359191Skris.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
62459191Skris.	\" for low resolution devices (crt and lpr)
62559191Skris.if \n(.H>23 .if \n(.V>19 \
62659191Skris\{\
62759191Skris.	ds : e
62859191Skris.	ds 8 ss
62959191Skris.	ds v \h'-1'\o'\(aa\(ga'
63059191Skris.	ds _ \h'-1'^
63159191Skris.	ds . \h'-1'.
63259191Skris.	ds 3 3
63359191Skris.	ds o a
63459191Skris.	ds d- d\h'-1'\(ga
63559191Skris.	ds D- D\h'-1'\(hy
63659191Skris.	ds th \o'bp'
63759191Skris.	ds Th \o'LP'
63859191Skris.	ds ae ae
63959191Skris.	ds Ae AE
64059191Skris.	ds oe oe
64159191Skris.	ds Oe OE
64259191Skris.\}
64359191Skris.rm #[ #] #H #V #F C
64459191SkrisEND
64559191Skris
64659191Skris$indent = 0;
64759191Skris
64859191Skris$begun = "";
64959191Skris
65059191Skris# Unrolling [^A-Z>]|[A-Z](?!<) gives:    // MRE pp 165.
65159191Skrismy $nonest = '(?:[^A-Z>]*(?:[A-Z](?!<)[^A-Z>]*)*)';
65259191Skris
65359191Skriswhile (<>) {
65459191Skris    if ($cutting) {
65559191Skris	next unless /^=/;
65659191Skris	$cutting = 0;
65759191Skris    }
65859191Skris    if ($begun) {
65959191Skris	if (/^=end\s+$begun/) {
66059191Skris            $begun = "";
66159191Skris	}
66259191Skris	elsif ($begun =~ /^(roff|man)$/) {
66359191Skris	    print STDOUT $_;
66459191Skris        }
66559191Skris	next;
66659191Skris    }
66759191Skris    chomp;
66859191Skris
66959191Skris    # Translate verbatim paragraph
67059191Skris
67159191Skris    if (/^\s/) {
67259191Skris	@lines = split(/\n/);
67359191Skris	for (@lines) {
67459191Skris	    1 while s
67559191Skris		{^( [^\t]* ) \t ( \t* ) }
67659191Skris		{ $1 . ' ' x (8 - (length($1)%8) + 8 * (length($2))) }ex;
67759191Skris	    s/\\/\\e/g;
67859191Skris	    s/\A/\\&/s;
67959191Skris	}
68059191Skris	$lines = @lines;
68159191Skris	makespace() unless $verbatim++;
68259191Skris	print ".Vb $lines\n";
68359191Skris	print join("\n", @lines), "\n";
68459191Skris	print ".Ve\n";
68559191Skris	$needspace = 0;
68659191Skris	next;
68759191Skris    }
68859191Skris
68959191Skris    $verbatim = 0;
69059191Skris
69159191Skris    if (/^=for\s+(\S+)\s*/s) {
69259191Skris	if ($1 eq "man" or $1 eq "roff") {
69359191Skris	    print STDOUT $',"\n\n";
69459191Skris	} else {
69559191Skris	    # ignore unknown for
69659191Skris	}
69759191Skris	next;
69859191Skris    }
69959191Skris    elsif (/^=begin\s+(\S+)\s*/s) {
70059191Skris	$begun = $1;
70159191Skris	if ($1 eq "man" or $1 eq "roff") {
70259191Skris	    print STDOUT $'."\n\n";
70359191Skris	}
70459191Skris	next;
70559191Skris    }
70659191Skris
70759191Skris    # check for things that'll hosed our noremap scheme; affects $_
70859191Skris    init_noremap();
70959191Skris
71059191Skris    if (!/^=item/) {
71159191Skris
71259191Skris	# trofficate backslashes; must do it before what happens below
71359191Skris	s/\\/noremap('\\e')/ge;
71459191Skris
71559191Skris	# protect leading periods and quotes against *roff
71659191Skris	# mistaking them for directives
71759191Skris	s/^(?:[A-Z]<)?[.']/\\&$&/gm;
71859191Skris
71959191Skris	# first hide the escapes in case we need to
72059191Skris	# intuit something and get it wrong due to fmting
72159191Skris
72259191Skris	1 while s/([A-Z]<$nonest>)/noremap($1)/ge;
72359191Skris
72459191Skris	# func() is a reference to a perl function
72559191Skris	s{
72659191Skris	    \b
72759191Skris	    (
72859191Skris		[:\w]+ \(\)
72959191Skris	    )
73059191Skris	} {I<$1>}gx;
73159191Skris
73259191Skris	# func(n) is a reference to a perl function or a man page
73359191Skris	s{
73459191Skris	    ([:\w]+)
73559191Skris	    (
73659191Skris		\( [^\051]+ \)
73759191Skris	    )
73859191Skris	} {I<$1>\\|$2}gx;
73959191Skris
74059191Skris	# convert simple variable references
74159191Skris	s/(\s+)([\$\@%][\w:]+)(?!\()/${1}C<$2>/g;
74259191Skris
74359191Skris	if (m{ (
74459191Skris		    [\-\w]+
74559191Skris		    \(
74659191Skris			[^\051]*?
74759191Skris			[\@\$,]
74859191Skris			[^\051]*?
74959191Skris		    \)
75059191Skris		)
75159191Skris	    }x && $` !~ /([LCI]<[^<>]*|-)$/ && !/^=\w/)
75259191Skris	{
75359191Skris	    warn "$0: bad option in paragraph $. of $ARGV: ``$1'' should be [LCI]<$1>\n";
75459191Skris	    $oops++;
75559191Skris	}
75659191Skris
75759191Skris	while (/(-[a-zA-Z])\b/g && $` !~ /[\w\-]$/) {
75859191Skris	    warn "$0: bad option in paragraph $. of $ARGV: ``$1'' should be [CB]<$1>\n";
75959191Skris	    $oops++;
76059191Skris	}
76159191Skris
76259191Skris	# put it back so we get the <> processed again;
76359191Skris	clear_noremap(0); # 0 means leave the E's
76459191Skris
76559191Skris    } else {
76659191Skris	# trofficate backslashes
76759191Skris	s/\\/noremap('\\e')/ge;
76859191Skris
76959191Skris    }
77059191Skris
77159191Skris    # need to hide E<> first; they're processed in clear_noremap
77259191Skris    s/(E<[^<>]+>)/noremap($1)/ge;
77359191Skris
77459191Skris
77559191Skris    $maxnest = 10;
77659191Skris    while ($maxnest-- && /[A-Z]</) {
77759191Skris
77859191Skris	# can't do C font here
77959191Skris	s/([BI])<($nonest)>/font($1) . $2 . font('R')/eg;
78059191Skris
78159191Skris	# files and filelike refs in italics
78259191Skris	s/F<($nonest)>/I<$1>/g;
78359191Skris
78459191Skris	# no break -- usually we want C<> for this
78559191Skris	s/S<($nonest)>/nobreak($1)/eg;
78659191Skris
78759191Skris	# LREF: a la HREF L<show this text|man/section>
78859191Skris	s:L<([^|>]+)\|[^>]+>:$1:g;
78959191Skris
79059191Skris	# LREF: a manpage(3f)
79159191Skris	s:L<([a-zA-Z][^\s\/]+)(\([^\)]+\))?>:the I<$1>$2 manpage:g;
79259191Skris
79359191Skris	# LREF: an =item on another manpage
79459191Skris	s{
79559191Skris	    L<
79659191Skris		([^/]+)
79759191Skris		/
79859191Skris		(
79959191Skris		    [:\w]+
80059191Skris		    (\(\))?
80159191Skris		)
80259191Skris	    >
80359191Skris	} {the C<$2> entry in the I<$1> manpage}gx;
80459191Skris
80559191Skris	# LREF: an =item on this manpage
80659191Skris	s{
80759191Skris	   ((?:
80859191Skris	    L<
80959191Skris		/
81059191Skris		(
81159191Skris		    [:\w]+
81259191Skris		    (\(\))?
81359191Skris		)
81459191Skris	    >
81559191Skris	    (,?\s+(and\s+)?)?
81659191Skris	  )+)
81759191Skris	} { internal_lrefs($1) }gex;
81859191Skris
81959191Skris	# LREF: a =head2 (head1?), maybe on a manpage, maybe right here
82059191Skris	# the "func" can disambiguate
82159191Skris	s{
82259191Skris	    L<
82359191Skris		(?:
82459191Skris		    ([a-zA-Z]\S+?) /
82559191Skris		)?
82659191Skris		"?(.*?)"?
82759191Skris	    >
82859191Skris	}{
82959191Skris	    do {
83059191Skris		$1 	# if no $1, assume it means on this page.
83159191Skris		    ?  "the section on I<$2> in the I<$1> manpage"
83259191Skris		    :  "the section on I<$2>"
83359191Skris	    }
83459191Skris	}gesx; # s in case it goes over multiple lines, so . matches \n
83559191Skris
83659191Skris	s/Z<>/\\&/g;
83759191Skris
83859191Skris	# comes last because not subject to reprocessing
83959191Skris	s/C<($nonest)>/noremap("${CFont_embed}${1}\\fR")/eg;
84059191Skris    }
84159191Skris
84259191Skris    if (s/^=//) {
84359191Skris	$needspace = 0;		# Assume this.
84459191Skris
84559191Skris	s/\n/ /g;
84659191Skris
84759191Skris	($Cmd, $_) = split(' ', $_, 2);
84859191Skris
84959191Skris	$dotlevel = 1;
85059191Skris	if ($Cmd eq 'head1') {
85159191Skris	   $dotlevel = 1;
85259191Skris	}
85359191Skris	elsif ($Cmd eq 'head2') {
85459191Skris	   $dotlevel = 1;
85559191Skris	}
85659191Skris	elsif ($Cmd eq 'item') {
85759191Skris	   $dotlevel = 2;
85859191Skris	}
85959191Skris
86059191Skris	if (defined $_) {
86159191Skris	    &escapes($dotlevel);
86259191Skris	    s/"/""/g;
86359191Skris	}
86459191Skris
86559191Skris	clear_noremap(1);
86659191Skris
86759191Skris	if ($Cmd eq 'cut') {
86859191Skris	    $cutting = 1;
86959191Skris	}
87059191Skris	elsif ($Cmd eq 'head1') {
87159191Skris	    s/\s+$//;
87259191Skris	    delete $wanna_see{$_} if exists $wanna_see{$_};
87359191Skris	    print qq{.SH "$_"\n};
87459191Skris      push(@Indices, qq{.IX Header "$_"\n});
87559191Skris	}
87659191Skris	elsif ($Cmd eq 'head2') {
87759191Skris	    print qq{.Sh "$_"\n};
87859191Skris      push(@Indices, qq{.IX Subsection "$_"\n});
87959191Skris	}
88059191Skris	elsif ($Cmd eq 'over') {
88159191Skris	    push(@indent,$indent);
88259191Skris	    $indent += ($_ + 0) || 5;
88359191Skris	}
88459191Skris	elsif ($Cmd eq 'back') {
88559191Skris	    $indent = pop(@indent);
88659191Skris	    warn "$0: Unmatched =back in paragraph $. of $ARGV\n" unless defined $indent;
88759191Skris	    $needspace = 1;
88859191Skris	}
88959191Skris	elsif ($Cmd eq 'item') {
89059191Skris	    s/^\*( |$)/\\(bu$1/g;
89159191Skris	    # if you know how to get ":s please do
89259191Skris	    s/\\\*\(L"([^"]+?)\\\*\(R"/'$1'/g;
89359191Skris	    s/\\\*\(L"([^"]+?)""/'$1'/g;
89459191Skris	    s/[^"]""([^"]+?)""[^"]/'$1'/g;
89559191Skris	    # here do something about the $" in perlvar?
89659191Skris	    print STDOUT qq{.Ip "$_" $indent\n};
89759191Skris      push(@Indices, qq{.IX Item "$_"\n});
89859191Skris	}
89959191Skris	elsif ($Cmd eq 'pod') {
90059191Skris	    # this is just a comment
90159191Skris	}
90259191Skris	else {
90359191Skris	    warn "$0: Unrecognized pod directive in paragraph $. of $ARGV: $Cmd\n";
90459191Skris	}
90559191Skris    }
90659191Skris    else {
90759191Skris	if ($needspace) {
90859191Skris	    &makespace;
90959191Skris	}
91059191Skris	&escapes(0);
91159191Skris	clear_noremap(1);
91259191Skris	print $_, "\n";
91359191Skris	$needspace = 1;
91459191Skris    }
91559191Skris}
91659191Skris
91759191Skrisprint <<"END";
91859191Skris
91959191Skris.rn }` ''
92059191SkrisEND
92159191Skris
92259191Skrisif (%wanna_see && !$lax) {
92359191Skris    @missing = keys %wanna_see;
92459191Skris    warn "$0: $Filename is missing required section"
92559191Skris	.  (@missing > 1 && "s")
92659191Skris	.  ": @missing\n";
92759191Skris    $oops++;
92859191Skris}
92959191Skris
93059191Skrisforeach (@Indices) { print "$_\n"; }
93159191Skris
93259191Skrisexit;
93359191Skris#exit ($oops != 0);
93459191Skris
93559191Skris#########################################################################
93659191Skris
93759191Skrissub nobreak {
93859191Skris    my $string = shift;
93959191Skris    $string =~ s/ /\\ /g;
94059191Skris    $string;
94159191Skris}
94259191Skris
94359191Skrissub escapes {
94459191Skris    my $indot = shift;
94559191Skris
94659191Skris    s/X<(.*?)>/mkindex($1)/ge;
94759191Skris
94859191Skris    # translate the minus in foo-bar into foo\-bar for roff
94959191Skris    s/([^0-9a-z-])-([^-])/$1\\-$2/g;
95059191Skris
95159191Skris    # make -- into the string version \*(-- (defined above)
95259191Skris    s/\b--\b/\\*(--/g;
95359191Skris    s/"--([^"])/"\\*(--$1/g;  # should be a better way
95459191Skris    s/([^"])--"/$1\\*(--"/g;
95559191Skris
95659191Skris    # fix up quotes; this is somewhat tricky
95759191Skris    my $dotmacroL = 'L';
95859191Skris    my $dotmacroR = 'R';
95959191Skris    if ( $indot == 1 ) {
96059191Skris	$dotmacroL = 'M';
96159191Skris	$dotmacroR = 'S';
96259191Skris    }
96359191Skris    elsif ( $indot >= 2 ) {
96459191Skris	$dotmacroL = 'N';
96559191Skris	$dotmacroR = 'T';
96659191Skris    }
96759191Skris    if (!/""/) {
96859191Skris	s/(^|\s)(['"])/noremap("$1\\*($dotmacroL$2")/ge;
96959191Skris	s/(['"])($|[\-\s,;\\!?.])/noremap("\\*($dotmacroR$1$2")/ge;
97059191Skris    }
97159191Skris
97259191Skris    #s/(?!")(?:.)--(?!")(?:.)/\\*(--/g;
97359191Skris    #s/(?:(?!")(?:.)--(?:"))|(?:(?:")--(?!")(?:.))/\\*(--/g;
97459191Skris
97559191Skris
97659191Skris    # make sure that func() keeps a bit a space tween the parens
97759191Skris    ### s/\b\(\)/\\|()/g;
97859191Skris    ### s/\b\(\)/(\\|)/g;
97959191Skris
98059191Skris    # make C++ into \*C+, which is a squinched version (defined above)
98159191Skris    s/\bC\+\+/\\*(C+/g;
98259191Skris
98359191Skris    # make double underbars have a little tiny space between them
98459191Skris    s/__/_\\|_/g;
98559191Skris
98659191Skris    # PI goes to \*(PI (defined above)
98759191Skris    s/\bPI\b/noremap('\\*(PI')/ge;
98859191Skris
98959191Skris    # make all caps a teeny bit smaller, but don't muck with embedded code literals
99059191Skris    my $hidCFont = font('C');
99159191Skris    if ($Cmd !~ /^head1/) { # SH already makes smaller
99259191Skris	# /g isn't enough; 1 while or we'll be off
99359191Skris
99459191Skris#	1 while s{
99559191Skris#	    (?!$hidCFont)(..|^.|^)
99659191Skris#	    \b
99759191Skris#	    (
99859191Skris#		[A-Z][\/A-Z+:\-\d_$.]+
99959191Skris#	    )
100059191Skris#	    (s?)
100159191Skris#	    \b
100259191Skris#	} {$1\\s-1$2\\s0}gmox;
100359191Skris
100459191Skris	1 while s{
100559191Skris	    (?!$hidCFont)(..|^.|^)
100659191Skris	    (
100759191Skris		\b[A-Z]{2,}[\/A-Z+:\-\d_\$]*\b
100859191Skris	    )
100959191Skris	} {
101059191Skris	    $1 . noremap( '\\s-1' .  $2 . '\\s0' )
101159191Skris	}egmox;
101259191Skris
101359191Skris    }
101459191Skris}
101559191Skris
101659191Skris# make troff just be normal, but make small nroff get quoted
101759191Skris# decided to just put the quotes in the text; sigh;
101859191Skrissub ccvt {
101959191Skris    local($_,$prev) = @_;
102059191Skris    noremap(qq{.CQ "$_" \n\\&});
102159191Skris}
102259191Skris
102359191Skrissub makespace {
102459191Skris    if ($indent) {
102559191Skris	print ".Sp\n";
102659191Skris    }
102759191Skris    else {
102859191Skris	print ".PP\n";
102959191Skris    }
103059191Skris}
103159191Skris
103259191Skrissub mkindex {
103359191Skris    my ($entry) = @_;
103459191Skris    my @entries = split m:\s*/\s*:, $entry;
103559191Skris    push @Indices, ".IX Xref " . join ' ', map {qq("$_")} @entries;
103659191Skris    return '';
103759191Skris}
103859191Skris
103959191Skrissub font {
104059191Skris    local($font) = shift;
104159191Skris    return '\\f' . noremap($font);
104259191Skris}
104359191Skris
104459191Skrissub noremap {
104559191Skris    local($thing_to_hide) = shift;
104659191Skris    $thing_to_hide =~ tr/\000-\177/\200-\377/;
104759191Skris    return $thing_to_hide;
104859191Skris}
104959191Skris
105059191Skrissub init_noremap {
105159191Skris	# escape high bit characters in input stream
105259191Skris	s/([\200-\377])/"E<".ord($1).">"/ge;
105359191Skris}
105459191Skris
105559191Skrissub clear_noremap {
105659191Skris    my $ready_to_print = $_[0];
105759191Skris
105859191Skris    tr/\200-\377/\000-\177/;
105959191Skris
106059191Skris    # trofficate backslashes
106159191Skris    # s/(?!\\e)(?:..|^.|^)\\/\\e/g;
106259191Skris
106359191Skris    # now for the E<>s, which have been hidden until now
106459191Skris    # otherwise the interative \w<> processing would have
106559191Skris    # been hosed by the E<gt>
106659191Skris    s {
106759191Skris	    E<
106859191Skris	    (
106959191Skris	        ( \d + )
107059191Skris	        | ( [A-Za-z]+ )
107159191Skris	    )
107259191Skris	    >
107359191Skris    } {
107459191Skris	 do {
107559191Skris	     defined $2
107659191Skris		? chr($2)
107759191Skris		:
107859191Skris	     exists $HTML_Escapes{$3}
107959191Skris		? do { $HTML_Escapes{$3} }
108059191Skris		: do {
108159191Skris		    warn "$0: Unknown escape in paragraph $. of $ARGV: ``$&''\n";
108259191Skris		    "E<$1>";
108359191Skris		}
108459191Skris	 }
108559191Skris    }egx if $ready_to_print;
108659191Skris}
108759191Skris
108859191Skrissub internal_lrefs {
108959191Skris    local($_) = shift;
109059191Skris    local $trailing_and = s/and\s+$// ? "and " : "";
109159191Skris
109259191Skris    s{L</([^>]+)>}{$1}g;
109359191Skris    my(@items) = split( /(?:,?\s+(?:and\s+)?)/ );
109459191Skris    my $retstr = "the ";
109559191Skris    my $i;
109659191Skris    for ($i = 0; $i <= $#items; $i++) {
109759191Skris	$retstr .= "C<$items[$i]>";
109859191Skris	$retstr .= ", " if @items > 2 && $i != $#items;
109959191Skris	$retstr .= " and " if $i+2 == @items;
110059191Skris    }
110159191Skris
110259191Skris    $retstr .= " entr" . ( @items > 1  ? "ies" : "y" )
110359191Skris	    .  " elsewhere in this document";
110459191Skris    # terminal space to avoid words running together (pattern used
110559191Skris    # strips terminal spaces)
110659191Skris    $retstr .= " " if length $trailing_and;
110759191Skris    $retstr .=  $trailing_and;
110859191Skris
110959191Skris    return $retstr;
111059191Skris
111159191Skris}
111259191Skris
111359191SkrisBEGIN {
111459191Skris%HTML_Escapes = (
111559191Skris    'amp'	=>	'&',	#   ampersand
111659191Skris    'lt'	=>	'<',	#   left chevron, less-than
111759191Skris    'gt'	=>	'>',	#   right chevron, greater-than
111859191Skris    'quot'	=>	'"',	#   double quote
111959191Skris
112059191Skris    "Aacute"	=>	"A\\*'",	#   capital A, acute accent
112159191Skris    "aacute"	=>	"a\\*'",	#   small a, acute accent
112259191Skris    "Acirc"	=>	"A\\*^",	#   capital A, circumflex accent
112359191Skris    "acirc"	=>	"a\\*^",	#   small a, circumflex accent
112459191Skris    "AElig"	=>	'\*(AE',	#   capital AE diphthong (ligature)
112559191Skris    "aelig"	=>	'\*(ae',	#   small ae diphthong (ligature)
112659191Skris    "Agrave"	=>	"A\\*`",	#   capital A, grave accent
112759191Skris    "agrave"	=>	"A\\*`",	#   small a, grave accent
112859191Skris    "Aring"	=>	'A\\*o',	#   capital A, ring
112959191Skris    "aring"	=>	'a\\*o',	#   small a, ring
113059191Skris    "Atilde"	=>	'A\\*~',	#   capital A, tilde
113159191Skris    "atilde"	=>	'a\\*~',	#   small a, tilde
113259191Skris    "Auml"	=>	'A\\*:',	#   capital A, dieresis or umlaut mark
113359191Skris    "auml"	=>	'a\\*:',	#   small a, dieresis or umlaut mark
113459191Skris    "Ccedil"	=>	'C\\*,',	#   capital C, cedilla
113559191Skris    "ccedil"	=>	'c\\*,',	#   small c, cedilla
113659191Skris    "Eacute"	=>	"E\\*'",	#   capital E, acute accent
113759191Skris    "eacute"	=>	"e\\*'",	#   small e, acute accent
113859191Skris    "Ecirc"	=>	"E\\*^",	#   capital E, circumflex accent
113959191Skris    "ecirc"	=>	"e\\*^",	#   small e, circumflex accent
114059191Skris    "Egrave"	=>	"E\\*`",	#   capital E, grave accent
114159191Skris    "egrave"	=>	"e\\*`",	#   small e, grave accent
114259191Skris    "ETH"	=>	'\\*(D-',	#   capital Eth, Icelandic
114359191Skris    "eth"	=>	'\\*(d-',	#   small eth, Icelandic
114459191Skris    "Euml"	=>	"E\\*:",	#   capital E, dieresis or umlaut mark
114559191Skris    "euml"	=>	"e\\*:",	#   small e, dieresis or umlaut mark
114659191Skris    "Iacute"	=>	"I\\*'",	#   capital I, acute accent
114759191Skris    "iacute"	=>	"i\\*'",	#   small i, acute accent
114859191Skris    "Icirc"	=>	"I\\*^",	#   capital I, circumflex accent
114959191Skris    "icirc"	=>	"i\\*^",	#   small i, circumflex accent
115059191Skris    "Igrave"	=>	"I\\*`",	#   capital I, grave accent
115159191Skris    "igrave"	=>	"i\\*`",	#   small i, grave accent
115259191Skris    "Iuml"	=>	"I\\*:",	#   capital I, dieresis or umlaut mark
115359191Skris    "iuml"	=>	"i\\*:",	#   small i, dieresis or umlaut mark
115459191Skris    "Ntilde"	=>	'N\*~',		#   capital N, tilde
115559191Skris    "ntilde"	=>	'n\*~',		#   small n, tilde
115659191Skris    "Oacute"	=>	"O\\*'",	#   capital O, acute accent
115759191Skris    "oacute"	=>	"o\\*'",	#   small o, acute accent
115859191Skris    "Ocirc"	=>	"O\\*^",	#   capital O, circumflex accent
115959191Skris    "ocirc"	=>	"o\\*^",	#   small o, circumflex accent
116059191Skris    "Ograve"	=>	"O\\*`",	#   capital O, grave accent
116159191Skris    "ograve"	=>	"o\\*`",	#   small o, grave accent
116259191Skris    "Oslash"	=>	"O\\*/",	#   capital O, slash
116359191Skris    "oslash"	=>	"o\\*/",	#   small o, slash
116459191Skris    "Otilde"	=>	"O\\*~",	#   capital O, tilde
116559191Skris    "otilde"	=>	"o\\*~",	#   small o, tilde
116659191Skris    "Ouml"	=>	"O\\*:",	#   capital O, dieresis or umlaut mark
116759191Skris    "ouml"	=>	"o\\*:",	#   small o, dieresis or umlaut mark
116859191Skris    "szlig"	=>	'\*8',		#   small sharp s, German (sz ligature)
116959191Skris    "THORN"	=>	'\\*(Th',	#   capital THORN, Icelandic
117059191Skris    "thorn"	=>	'\\*(th',,	#   small thorn, Icelandic
117159191Skris    "Uacute"	=>	"U\\*'",	#   capital U, acute accent
117259191Skris    "uacute"	=>	"u\\*'",	#   small u, acute accent
117359191Skris    "Ucirc"	=>	"U\\*^",	#   capital U, circumflex accent
117459191Skris    "ucirc"	=>	"u\\*^",	#   small u, circumflex accent
117559191Skris    "Ugrave"	=>	"U\\*`",	#   capital U, grave accent
117659191Skris    "ugrave"	=>	"u\\*`",	#   small u, grave accent
117759191Skris    "Uuml"	=>	"U\\*:",	#   capital U, dieresis or umlaut mark
117859191Skris    "uuml"	=>	"u\\*:",	#   small u, dieresis or umlaut mark
117959191Skris    "Yacute"	=>	"Y\\*'",	#   capital Y, acute accent
118059191Skris    "yacute"	=>	"y\\*'",	#   small y, acute accent
118159191Skris    "yuml"	=>	"y\\*:",	#   small y, dieresis or umlaut mark
118259191Skris);
118359191Skris}
118459191Skris
1185