#!/usr/bin/perl
    eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
	if $running_under_some_shell;
#
# pod2texinfo, version 1.0
$VERSION='1.0';
# based on pod2latex version 1.1
# by Taro Kawagish (kawagish@imslab.co.jp),  Jan 11, 1995.

=head1 NAME

C<pod2texinfo>  -- Perl Online Documentation to TeXinfo

=head1 SYNOPSIS

C<pod2texinfo> filters Perl pod documents to TeXinfo documents.

=head1 Usage

C<pod2texinfo perl_doc_entry.pod>

this will write to a file F<perl_doc_entry.tex>.

=head1 DESCRIPTION

What C<pod2texinfo> does:

=over 1

=item * Pod file F<perl_doc_entry.pod>

is filtered to F<perl_doc_entry.tex>.

=item * Indented paragraphs

are translated into C<@example ... @end example>.

=item * other paragraphs are translated into strings with TeX special characters
escaped.

=back

=head2 How headings are handled

The headings are converted from their POD form into a TeXInfo equivalent, and
the uncommon ones are indexed:

=over 1

=item C<=head1 heading> command

is translated into

	@subheading heading
	@cindex heading

=item C<=head2 heading> command

is translated into

	@subsubheading heading
	@cindex heading

only when heading does not match frequent patterns such as
DESCRIPTION, DIAGNOSTICS,... otherwise it is translated into:

	@subsubheading heading

=back

=head2 How lists are handled

=over 1

=item C<=over N> command

is translated into

	@itemize

if following C<=item> starts with *,

	@enumerate

if following C<=item> starts with 1.,

	@table

if else.

Indentation level N is ignored.

=item C<=back> command

is translated, as appropriate, into

	@end itemize

if started with C<@itemize>,

	@end enumerate

if started with C<@enumerate>,

	@end table

if started with C<@table>.

=item C<=item * heading> command

is translated into

	@item
	heading

=item C<=item 1. heading> command

is translated into

	@item
	heading

=item C<=item heading> command(other)

is translated into

	@item
	heading
	@cindex heading

=back

=head2 How POD quotes are translated

In heading text, and other paragraphs, the following translation of pod
quotes are done, and then TeX special characters are escaped after that.

=over 1

=item C<I><text>

@emph{text}

=item C<B><text>

@strong{text},

=item C<S><text>

text1,
where text1 is a string with blank characters replaced with ~,

=item C<C><text>

@code{text2},
where text2 is a string with TeX special characters escaped to
obtain a literal printout,

=item C<E><text> (HTML escape)

TeXInfo escaped string,

=item C<L><text>

This may include a URL or a referencing string as is done by pod2man,

=item C<F><file>

@file{file},

=item C<Z><>

a null string,

=back

=head1 Installation

The package can be acquired from CPAN (L<http://www.cpan.org/>) or from
L<http://www.geocities.com/CapeCanaveral/Lab/1862/script/pod2texinfo-10.tgz>

This installation is the same as any other Perl 5 module:

=over 1

=item un-tar the tarball

=item C<perl Makefile.PL>

=item C<make>

=item C<make install>

=back

The documentation is contained in the F<pod2texinfo> file, in POD format.  The
man pages will install automatically, or may be extracted manually by:

C<pod2man pod2texinfo > pod2texinfo.man>

=head1 SEE ALSO

A version of this documentation can be found at
L<http://www.geocities.com/CapeCanaveral/Lab/1862/script/pod2texinfo.html>


=head1 Notes

=head2 Bugs

If HTML escapes C<E><text> other than C<E><amp>,C<E><lt>,C<E><gt>,C<E><quot> are
used in C<C><>, translation will produce wrong character strings.
Translation of HTML escapes of various European accents might be wrong.

=head2 Version

Version 1.0.  November 25, 1998.

=head2 Author

This script is a modified version of C<pod2latex>, which itself is a
modified version of C<pod2man>.

Randall Maas L<mailto:randym@acm.org> change LaTeX to TeXInfo and made a few
appropriate changes

=cut

$/ = "";			# record separator is blank lines
# TeX special characters.
##$tt_ables = "!@*()-=+|;:'\"`,./?<>";
$backslash_escapables = "#{}@";#\$%&
##$nonverbables = "^\\~";
##$bracketesc = "[]";
##@tex_verb_fences = unpack("aaaaaaaaa","|#@!*+?:;");

@head1_freq_patterns		# =head1 patterns which need not be index'ed
    = ("AUTHOR","BUGS","DATE","DESCRIPTION","DIAGNOSTICS","VERSION",
       "ENVIRONMENT","EXAMPLES","FILES","INTRODUCTION","NAME","NOTE","NOTES",
       "SEE ALSO","SYNOPSIS","WARNING","USAGE");

$indent = 0;

# parse the pods, produce TeXInfo.

die "usage: pod2texinfo PERLFILE[.pod]\n" if !defined $ARGV[0];
open(POD,"<$ARGV[0]") || die "cant open $ARGV[0]";
($pod=$ARGV[0]) =~ s/\.(pod|pl|cgi|p|pm)$//;
open(TEXI,">$pod.tex");
&do_hdr();

$cutting = 1;
$begun = "";
$line = 0;
while (<POD>) {
    $line++;
    if ($cutting) {
	next unless /^=/;
	$cutting = 0;
    }
    if ($begun) {
       if (/^=end\s+$begun/) {
           $begun = "";
       }
       elsif ($begun =~ /^(tex|latex|texinfo)$/) {
           print TEXI $_;
       }
       next;
    }
    chop;
    length || (print TEXI  "\n") && next;

    # translate indented lines as a verabatim paragraph
    if (/^\s/) {
	@lines = split(/\n/);
	print TEXI  "\@example\n";
	for (@lines) {
	    1 while s
		{^( [^\t]* ) \t ( \t* ) }
		{ $1 . ' ' x (8 - (length($1)%8) + 8*(length($2))) }ex;
	    print TEXI  $_,"\n";
	}
	print TEXI  "\@end example\n";
	next;
    }

    if (/^=for\s+(\S+)\s*/s) {
	if ($1 eq "tex" or $1 eq "latex" or $1 eq 'texinfo') {
	    print TEXI $',"\n";
	} else {
	    # ignore unknown for
	}
	next;
    }
    elsif (/^=begin\s+(\S+)\s*/s) {
	$begun = $1;
	if ($1 eq "tex" or $1 eq "latex" or $1 eq 'texinfo') {
	    print TEXI $'."\n";
	}
	next;
    }

    # preserve '=item' line with pod quotes as they are.
    if (/^=item/) {
	($bareitem = $_) =~ s/^=item\s*//;
    }

    # check for things that'll hosed our noremap scheme; affects $_
    &init_noremap();

    # expand strings "func()" as pod quotes.
    if (!/^=item/) {
	# first hide pod escapes.
	# escaped strings are mapped into the ones with the MSB's on.
	s/([A-Z]<[^<>]*>)/noremap($1)/ge;

	# func() is a reference to a perl function
	s{\b([:\w]+\(\))}{I<$1>}g;
	# func(n) is a reference to a man page
	s{(\w+)(\([^\s,\051]+\))}{I<$1>$2}g;
	# convert simple variable references
#	s/([\$\@%][\w:]+)/C<$1>/g;
#	s/\$[\w:]+\[[0-9]+\]/C<$&>/g;

	if (m{ ([\-\w]+\([^\051]*?[\@\$,][^\051]*?\))
	       }x && $` !~ /([LCI]<[^<>]*|-)$/ && !/^=\w/)
	{
	    warn "$line: ``$1'' should be a [LCI]<$1> ref";
	}
	while (/(-[a-zA-Z])\b/g && $` !~ /[\w\-]$/) {
	    warn "$line: ``$1'' should be [CB]<$1> ref";
	}

	# put back pod quotes so we get the inside of <> processed;
	$_ = &clear_noremap($_);
    }


    # process TeX special characters

    # First hide HTML quotes E<> since they can be included in C<>.
    s/(E<[^<>]+>)/noremap($1)/ge;

    # Then hide C<> type literal quotes.
    # String inside of C<> will later be expanded into @code{..} strings
    # with TeX special characters escaped as needed.
    s/(C<[^<>]*>)/&noremap($1)/ge;

    # Next escape TeX special characters including other pod quotes B< >,...
    #
    # NOTE: s/re/&func($str)/e evaluates $str just once in perl5.
    # (in perl4 evaluation takes place twice before getting passed to func().)

    # - hyphen => ---
    s/(\S+)(\s+)-+(\s+)(\S+)/"$1".&noremap(" --- ")."$4"/ge;
    # '-', '--', "-"  =>  '@code{-}', '@code{--}', "@code{-}"
##    s/("|')(\s*)(-+)(\s*)\1/&noremap("$1$2\@code\{$3\}$4$1")/ge;
## changed Wed Jan 25 15:26:39 JST 1995
    # '-', '--', "-"  =>  '$-$', '$--$', "$-$"
#    s/(\s+)(['"])(-+)([^'"\-]*)\2(\s+|[,.])/"$1$2".&noremap("\$$3\$")."$4$2$5"/ge;
#    s/(\s+)(['"])([^'"\-]*)(-+)(\s*)\2(\s+|[,.])/"$1$2$3".&noremap("\$$4\$")."$5$2$6"/ge;
    # (--|-)  =>  ($--$|$-$)
    s/(\s+)\((-+)([=@%\$\+\\\|\w]*)(-*)([=@%\$\+\\\|\w]*)\)(\s+|[,.])/"$1\(".&noremap("\$$2\$")."$3".&noremap("\$$4\$")."$5\)$6"/ge;
    # numeral -  =>  $-$
#    s/(\(|[0-9]+|\s+)-(\s*\(?\s*[0-9]+)/&noremap("$1\$-\$$2")/ge;
    # -- in quotes  =>  two separate -
    s/B<([^<>]*)--([^<>]*)>/&noremap("B<$1\@code\{--\}$2>")/ge;

    # backslash escapable characters.
    s/([$backslash_escapables])/&noremap("\@$1")/ge;
    # quote TeX special characters |, ^, ~, \.
    s/\|/&noremap("\$|\$")/ge;
#    s/\^/&noremap("\$\@hat{}\$")/ge;
#    s/\~/&noremap("\$\@tilde{\@hspace{0.4em}}\$")/ge;
    # quote [ and ] to be used in \item[]
    s/([\[\]])/&noremap("\@code{$1}")/ge;
    # characters need to be treated differently in TeX
    # keep * if an item heading
    s/^(=item[ \t]+)[*]((.|\n)*)/"$1" . &noremap("*") . "$2"/ge;
#    s/[*]/&noremap("\$\@ast\$")/ge;	# other *

    # hide other pod quotes.
    s/([ABD-Z]<[^<>]*>)/&noremap($1)/ge;

    # put it back so we get the <> processed again;
    $_ = &clear_noremap($_);


    # Expand pod quotes recursively:
    # (1) type face directives [BIFS]<[^<>]*> to appropriate TeX commands,
    # (2) L<[^<>]*> to reference strings,
    # (3) C<[^<>]*> to TeX literal quotes,
    # (4) HTML quotes E<> inside of C<> quotes.

    # Hide E<> again since they can be included in C<>.
    s/(E<[^<>]+>)/noremap($1)/ge;

    $maxnest = 10;
    while ($maxnest-- && /[A-Z]</) {

	# bold and italic quotes
	s/B<([^<>]*)>/"\@strong{$1}"/eg;
	s#I<([^<>]*)>#"\@emph{$1}"#eg;

	# files and filelike refs in italics
	s#F<([^<>]*)>#"\@file{$1}"#eg;

	# no break quote -- usually we want C<> for this
	s/S<([^<>]*)>/&nobreak($1)/eg;

	# LREF: a URL reference --> url or email?
	s/L<(http|ftp):([^>]*)>/\@url{$1:$2}/gx;
	s/L<(mailto):([^>]*)>/\@email{$2}/gx;
	s/L<([\w\.\-]+)\@([^>]+)>/\@email{$1\@$2}/gx;
	
	# LREF: an =item on this manpage
	s{
	   ((?:L</([:\w]+(\(\))?)>
	    (,?\s+(and\s+)?)?)+)
	} { &internal_lrefs($1) }gex;

	# LREF: a manpage(3f)
#	s:L<([a-zA-Z][^\s\/]+)(\([^\)]+\))?>:the \@emph{$1}$2 manpage:g;
	s:L<([a-zA-Z][^\s\/]+)(\([^\)]+\))>:the \@emph{$1}$2 manpage:g;

	# LREF: a =head2 (head1?), maybe on a manpage, maybe right here
	# the "func" can disambiguate
	s{
	    L<(?:([a-zA-Z]\S+?) /)?"?(.*?)"?>
	}{
	    do {
		$1 	# if no $1, assume it means on this page.
		    ?  "the section on I<$2> in the I<$1> manpage"
		    :  "\@ref{$2}\n"; ##the section on I<$2>"
	    } 
	}gex;

	# LREF: an =item on another manpage
	s{
	    L<([^/]+)/([:\w]+(\(\))?)>
	} {the C<$2> entry in the I<$1> manpage}gx;


	s/Z<>/\\&/g;		# the "don't format me" thing

	# comes last because not subject to reprocessing
	s{
	    C<([^<>]*)>
	}{
	    do {
		($str = $1) =~ tr/\200-\377/\000-\177/; #normalize hidden stuff
		# expand HTML escapes if any;
		# WARNING: if HTML escapes other than E<amp>,E<lt>,E<gt>,
		# E<quot> are in C<>, they will not be printed correctly.
		$str = &expand_HTML_escapes($str);
		$strverb = &alltt($str);    # Tex verbatim escape of a string.
		&noremap($strverb);
	    }
	}gex;

#	if ( /C<([^<>]*)/ ) {
#	    $str = $1;
#	    if ($str !~ /\|/) {		# if includes |
#		s/C<([^<>]*)>/&noremap("\\verb|$str|")/eg;
#	    } else {
#		print STDERR "found \| in C<.*> at paragraph $.\n";
#		# find a character not contained in $str to use it as a
#		# separator of the \verb
#		($chars = $str) =~ s/(\W)/\\$1/g;
#		## ($chars = $str) =~ s/([\$<>,\|"'\-^{}()*+?\\])/\\$1/g;
#		@fence = grep(!/[ $chars]/,@tex_verb_fences);
#		s/C<([^<>]*)>/&noremap("\\verb$fence[0]$str$fence[0]")/eg;
#	    }
#	}
    }


    # process each pod command
    if (s/^=//) {				# if a command
	s/\n/ /g;
	($cmd, $rest) = split(/[\s\n\r]+/, $_, 2);
	$rest =~ s/^\s*//;
	$rest =~ s/\s*$//;

	if (defined $rest) {
	    &escapes;
	}

	$rest = &clear_noremap($rest);
	$rest = &expand_HTML_escapes($rest);

	if ($cmd eq 'cut') {
	    $cutting = 1;
	    $lastcmd = 'cut';
	}
	elsif ($cmd eq 'head1') {	# heading type 1
	    $rest =~ s/^\s*//; $rest =~ s/\s*$//;
	    print TEXI  "\n\@subheading $rest\n";
	    # put index entry
	    ($index = $rest) =~ s/^(An?\s+|The\s+)//i;	# remove 'A' and 'The'
	    # index only those heads not matching the frequent patterns.
	    foreach $pat (@head1_freq_patterns) {
		if ($index =~ /^$pat/i) {
		    goto freqpatt;
		}
	    }
	    print TEXI  "\n\@cindex $index\n" if ($index);
	  freqpatt:
	    $lastcmd = 'head1';
	}
	elsif ($cmd eq 'head2') {	# heading type 2
	    $rest =~ s/^\s*//; $rest =~ s/\s*$//;
	    print TEXI  "\n\@subsubheading $rest\n";
	    # put index entry
	    ($index = $rest) =~ s/^(An?\s+|The\s+)//i;	# remove 'A' and 'The'
	    $index =~ s/^Example\s*[1-9][0-9]*\s*:\s*//; # remove 'Example :'
	    print TEXI  "\n\@cindex $index\n"  if ($index);
	    $lastcmd = 'head2';
	}
	elsif ($cmd eq 'over') {	# 1 level within a listing environment
	    push(@indent,$indent);
	    $indent = $rest + 0;
	    $lastcmd = 'over';
	}
	elsif ($cmd eq 'back') {	# 1 level out of a listing environment
	    $indent = pop(@indent);
	    warn "$line: Unmatched =back\n" unless defined $indent;
	    $listingcmd = pop(@listingcmd);
	    print TEXI  "\n\@end $listingcmd\n"  if ($listingcmd);
	    $lastcmd = 'back';
	}
	elsif ($cmd eq 'item') {	# an item paragraph starts
	    if ($lastcmd eq 'over') {	# if we have just entered listing env
		# see what type of list environment we are in.
		if ($rest =~ /^[0-9]\.?/) {	# if numeral heading
		    $listingcmd = 'enumerate';
		} elsif ($rest =~ /^\*\s*/) {	# if * heading
		    $listingcmd = 'itemize';
		} elsif ($rest =~ /^[^*]/) {	# if other headings
		    $listingcmd = 'table';
		} else {
		    warn "$line: unknown list type for item $rest";
		}
		print TEXI  "\n\@$listingcmd ";
		print TEXI "\@asis\n" if $listingcmd eq 'table';
		print TEXI "\@bullet\n" if $listingcmd eq 'itemize';
		push(@listingcmd,$listingcmd);
	    } elsif ($lastcmd ne 'item') {
		warn "$line: Illegal '=item' command without preceding 'over':";
		warn "=item $bareitem";
	    }

	    if ($listingcmd eq 'enumerate') {
		$rest =~ s/^[0-9]+\.?\s*//;	# remove numeral heading
		print TEXI  "\n\@item\n";
		print TEXI  "$rest\n" if $rest;
	    } elsif ($listingcmd eq 'itemize') {
		$rest =~ s/^\*\s*//;		# remove * heading
		print TEXI  "\n\@item\n";
		print TEXI  "$rest\n" if $rest;
	    } else {				# description item
		print TEXI  "\n\@item $rest";
	    }
	    $lastcmd = 'item';
	    $rightafter_item = 'yes';

	    # check if the item heading is short or long.
	    ($itemhead = $rest) =~ s/\@strong{(\S*)}/$1/g;
	    if (length($itemhead) < 4) {
		$itemshort = "yes";
	    } else {
		$itemshort = "no";
	    }
	    # write index entry
	    if ($pod =~ "perldiag") {			# skip 'perldiag.pod'
		goto noindex;
	    }
	    # strip out the item of pod quotes and get a plain text entry
	    $bareitem =~ s/\n/ /g;			# remove newlines
	    $bareitem =~ s/\s*$//;			# remove trailing space
        
	    #Attempt to determine which index it belongs in (default is the
	    #concept index)
            my $idx='c';
            $_=$bareitem;
	    if (/([A-Z])<([^<>\(\)]*)(\([^\)]*\))?>/)
	      {
		#Remove <> quotes from bareitem
		$bareitem=$2;
		   if ($1 eq 'C' && ($3||$bareitem[0] eq '=')) {$idx='f';}
		elsif ($1 eq 'C')	{$idx='v';}
	      }
     
#	    $bareitem =~ s/[A-Z]<([^<>]*)>/$1/g;	# remove <> quotes
	    ($index = $bareitem) =~ s/^[\*\\&]\s+//;	# remove leading '*' &\\
	    $index =~ s/^(An?\s+|The\s+)//i;		# remove 'A' and 'The'
	    $index =~ s/^\s*[1-9][0-9]*\s*[.]\s*$//; # remove numeral only
	    $index =~ s/^\s*\w\s*$//;			# remove 1 char only's
		# quote ", @ and ! with " to be used in makeindex.
#	    $index =~ s/"/""/g;				# quote "
#	    $index =~ s/@/"@/g;				# quote @
#	    $index =~ s/!/"!/g;				# quote !
	    ($rest2=$rest) =~ s/^\*\s+//;	# remove *
#	    $rest2 =~ s/"/""/g;				# quote "
#	    $rest2 =~ s/@/"@/g;				# quote @
#	    $rest2 =~ s/!/"!/g;				# quote !
	    if ($pod =~ "(perlfunc|perlvar)") {	# when doc is perlfunc,perlvar
		# take only the 1st word of item heading
		$index =~ s/^([^{}\s]*)({.*})?([^{}\s]*)\s+.*/$1$2$3/;
		$rest2 =~ s/^([^{}\s]*)({.*})?([^{}\s]*)\s+.*/$1$2$3/;
	    }
	    if ($index =~ /[A-Za-z\$@%]/) {
		    #  write  \index{plain_text_entry@@TeX_string_entry}
		print TEXI  "\n\@".$idx."index $rest2\n"; #$index\@\@$rest2\n";
	    }
	  noindex:
	    ;
	}
	else {
	    warn "$line: Unrecognized directive: $cmd\n";
	}
    }
    else {					# if not command
	&escapes;
	$_ = &clear_noremap($_);
	$_ = &expand_HTML_escapes($_);

	# if the present paragraphs follows an =item declaration,
	# put a line break.
	if ($lastcmd eq 'item' &&
	    $rightafter_item eq 'yes' && $itemshort eq "no") {
	    $rightafter_item = 'no';
	}
	print TEXI  "\n",$_;
    }
}

print TEXI  "\n";
close(POD);
close(TEXI);


#########################################################################

sub do_hdr {
    print TEXI "\@c TeXInfo document produced by pod2texinfo from \"$pod.pod\".\n";
    print TEXI "\@c The followings need be defined in the preamble of this document:\n";
    print TEXI "\@c\\def\\C++{{\\rm C\\kern-.05em\\raise.3ex\\hbox{\\footnotesize ++}}}\n";
#    print TEXI "\@c\\def\\underscore{\\leavevmode\\kern.04em\\vbox{\\hrule width 0.4em height 0.3pt}}\n";
    print TEXI "\@c\\setlength{\\parindent}{0pt}\n";
    print TEXI "\n";
    $podq = &escape_tex_specials("\U$pod\E");
    print TEXI "\@section $podq\n\@cindex $podq\n";
}

sub nobreak {
    my $string = shift;
    $string =~ s/ +/~/g;		# TeX no line break
    $string;
}

sub noremap {
    local($thing_to_hide) = shift;
    $thing_to_hide =~ tr/\000-\177/\200-\377/;
    return $thing_to_hide;
}

sub init_noremap {
	# escape high bit characters in input stream
	s/([\200-\377])/"E<".ord($1).">"/ge;
}

sub clear_noremap {
    local($tmp) = shift;
    $tmp =~ tr/\200-\377/\000-\177/;
    return $tmp;
}

sub expand_HTML_escapes {
    local($s) = $_[0];
    $s =~ s { E<((\d+)|([A-Za-z]+))> }
    {
	do {
		defined($2) 
		? do { chr($2) }
		: 
	    exists $HTML_Escapes{$3} && defined $HTML_Escapes{$3}
	    ? do { $HTML_Escapes{$3} }
	    : do {
		warn "$line: Unknown escape: $& in $_";
		"E<$1>";
	    }
	}
    }egx;
    return $s;
}

sub escapes {
    # make C++ into \C++, which is to be defined as
    # \def\C++{{\rm C\kern-.05em\raise.3ex\hbox{\footnotesize ++}}}
    s/\bC\+\+/\@C++{}/g;
}

# Translate a string into a TeXInfo @code string to obtain a verbatim print out.
# TeX special characters are escaped by @.
# This can be used inside of TeXInfo command arguments.
sub alltt {
    local($str) = shift;
	# other chars than #,\,$,%,&,{,},\,^,~ ([ and ] included).
   $str =~ s/([^${backslash_escapables}\@\^\~]+)/&noremap("$&")/eg;
	# chars #,\,$,%,&,{,}  =>  \# , ...
    $str =~ s/([$backslash_escapables])/&noremap("\@$&")/eg;
	# chars _,\,^,~  =>  \char`\_ , ...
    $str =~ s/_/&noremap("\@char`\@_")/eg;
    $str =~ s/\\/&noremap("\@char`\\")/ge;
    $str =~ s/\^/\@char`\@^/g;
    $str =~ s/\~/\@char`\@~/g;

    $str =~ tr/\200-\377/\000-\177/;		# put back
    return '@code{'.$str.'}';			# make it a @code string
}

sub escape_tex_specials {
    local($str) = shift;
	# other chars than #,\,$,%,&,{,},  _,\,^,~ ([ and ] included).
    # backslash escapable characters #,\,$,%,&,{,}.
    $str =~ s/([$backslash_escapables])/&noremap("\@$1")/ge;
    # quote TeX special characters |, ^, ~, \.
    $str =~ s/\|/&noremap("\$|\$")/ge;
#    $str =~ s/\^/&noremap("\$\@hat{\@hspace{0.4em}}\$")/ge;
#    $str =~ s/\~/&noremap("\$\@tilde{\@hspace{0.4em}}\$")/ge;
    # characters need to be treated differently in TeX
#    # *
#    $str =~ s/[*]/&noremap("\$\@ast\$")/ge;
    $str =~ tr/\200-\377/\000-\177/;		# put back
    return $str;
}

sub internal_lrefs {
    local($_) = shift;

    s{L</([^>]+)>}{$1}g;
    my(@items) = split( /(?:,?\s+(?:and\s+)?)/ );
    my $retstr = "the ";
    my $i;
    for ($i = 0; $i <= $#items; $i++) {
	$retstr .= "C<$items[$i]>";
	$retstr .= ", " if @items > 2 && $i != $#items;
	$retstr .= " and " if $i+2 == @items;
    }
    $retstr .= " entr" . ( @items > 1  ? "ies" : "y" )
	    .  " elsewhere in this document";

    return $retstr;
}

# map of HTML escapes to TeX escapes.
BEGIN {
%HTML_Escapes = (
    'amp'	=>	'&',	#   ampersand
    'lt'	=>	'<',	#   left chevron, less-than
    'gt'	=>	'>',	#   right chevron, greater-than
    'quot'	=>	'"',	#   double quote

    "Aacute"	=>	"\@'{A}",	#   capital A, acute accent
    "aacute"	=>	"\@'{a}",	#   small a, acute accent
    "Acirc"	=>	"\@^{A}",	#   capital A, circumflex accent
    "acirc"	=>	"\@^{a}",	#   small a, circumflex accent
    "AElig"	=>	'@AE',		#   capital AE diphthong (ligature)
    "aelig"	=>	'@ae',		#   small ae diphthong (ligature)
    "Agrave"	=>	"\@`{A}",	#   capital A, grave accent
    "agrave"	=>	"\@`{a}",	#   small a, grave accent
    "Aring"	=>	'@u{A}',	#   capital A, ring
    "aring"	=>	'@u{a}',	#   small a, ring
    "Atilde"	=>	'@~{A}',	#   capital A, tilde
    "atilde"	=>	'@~{a}',	#   small a, tilde
    "Auml"	=>	'@"{A}',	#   capital A, dieresis or umlaut mark
    "auml"	=>	'@"{a}',	#   small a, dieresis or umlaut mark
    "Ccedil"	=>	'@c{C}',	#   capital C, cedilla
    "ccedil"	=>	'@c{c}',	#   small c, cedilla
    "Eacute"	=>	"\@'{E}",	#   capital E, acute accent
    "eacute"	=>	"\@'{e}",	#   small e, acute accent
    "Ecirc"	=>	"\@^{E}",	#   capital E, circumflex accent
    "ecirc"	=>	"\@^{e}",	#   small e, circumflex accent
    "Egrave"	=>	"\@`{E}",	#   capital E, grave accent
    "egrave"	=>	"\@`{e}",	#   small e, grave accent
    "ETH"	=>	'@OE',		#   capital Eth, Icelandic
    "eth"	=>	'@oe',		#   small eth, Icelandic
    "Euml"	=>	'@"{E}',	#   capital E, dieresis or umlaut mark
    "euml"	=>	'@"{e}',	#   small e, dieresis or umlaut mark
    "Iacute"	=>	"\@'{I}",	#   capital I, acute accent
    "iacute"	=>	"\@'{i}",	#   small i, acute accent
    "Icirc"	=>	"\@^{I}",	#   capital I, circumflex accent
    "icirc"	=>	"\@^{i}",	#   small i, circumflex accent
    "Igrave"	=>	"\@`{I}",	#   capital I, grave accent
    "igrave"	=>	"\@`{i}",	#   small i, grave accent
    "Iuml"	=>	'@"{I}',	#   capital I, dieresis or umlaut mark
    "iuml"	=>	'@"{i}',	#   small i, dieresis or umlaut mark
    "Ntilde"	=>	'@~{N}',	#   capital N, tilde
    "ntilde"	=>	'@~{n}',	#   small n, tilde
    "Oacute"	=>	"\@'{O}",	#   capital O, acute accent
    "oacute"	=>	"\@'{o}",	#   small o, acute accent
    "Ocirc"	=>	"\@^{O}",	#   capital O, circumflex accent
    "ocirc"	=>	"\@^{o}",	#   small o, circumflex accent
    "Ograve"	=>	"\@`{O}",	#   capital O, grave accent
    "ograve"	=>	"\@`{o}",	#   small o, grave accent
    "Oslash"	=>	"\@O",		#   capital O, slash
    "oslash"	=>	"\@o",		#   small o, slash
    "Otilde"	=>	"\@~{O}",	#   capital O, tilde
    "otilde"	=>	"\@~{o}",	#   small o, tilde
    "Ouml"	=>	'@"{O}',	#   capital O, dieresis or umlaut mark
    "ouml"	=>	'@"{o}',	#   small o, dieresis or umlaut mark
    "szlig"	=>	'@ss',		#   small sharp s, German (sz ligature)
    "THORN"	=>	'@L',		#   capital THORN, Icelandic
    "thorn"	=>	'@l',,		#   small thorn, Icelandic
    "Uacute"	=>	"\@'{U}",	#   capital U, acute accent
    "uacute"	=>	"\@'{u}",	#   small u, acute accent
    "Ucirc"	=>	"\@^{U}",	#   capital U, circumflex accent
    "ucirc"	=>	"\@^{u}",	#   small u, circumflex accent
    "Ugrave"	=>	"\@`{U}",	#   capital U, grave accent
    "ugrave"	=>	"\@`{u}",	#   small u, grave accent
    "Uuml"	=>	'@"{U}',	#   capital U, dieresis or umlaut mark
    "uuml"	=>	'@"{u}',	#   small u, dieresis or umlaut mark
    "Yacute"	=>	"\@'{Y}",	#   capital Y, acute accent
    "yacute"	=>	"\@'{y}",	#   small y, acute accent
    "yuml"	=>	'@"{y}',	#   small y, dieresis or umlaut mark
);
}
