#!/usr/local/bin/perl -w
eval 'exec perl -S $0 ${1+"$@"}'
	if $running_under_some_shell;

=head1 NAME

pod2fm - convert pod format to FrameMaker documents and book file

=head1 SYNOPSIS

Under UNIX system (where fmbatch can be run):

    pod2fm [-mmlonly |
	    -nodoc [-lock]
	    [-book [I<book_name>] [-noopen]
		[-template I<document> [-format I<types>]... [-toc] [-index]
	    ]
	]
	[ -dir I<location> | I<pod>...]

Under Win32 and Macintosh:

    pod2fm [ -dir I<location> | I<pod>...]

=head1 DESCRIPTION

This program parses all files with .pod extension and creates FrameMaker
documents. You can control what is generated by arguments given on the
command line. On systems where B<fmbatch> is available (i.e.: UNIX systems)
I<Pod2fm> can:

=item * Generate Frame MML, MIF, and binary formats.

=item * Generate hypertext links to a group of documents.

=item * Create a Frame 'book' that includes all of the documents from a run.

=item * Create Table of Contents and Index documents.

=item * Create documents that can be used with FrameViewer for On-Line Docs.

=head1 OPTIONS

=over 12

=item B<-mmlonly>

=item B<-nommlonly>

This switch tells I<pod2fm> if it should stop execution after it has generated
the 'MML' version of the document. The document is written into a file with the
'.mml' extension.

If B<-mmlonly> is specified, it can be the only command line switch.

The default, under UNIX is 'B<-nommlonly>'. On Win32 and Macintosh, B<-mmlonly>
is always on.

=item B<-nodoc>

=item B<-doc>

Available only on UNIX systems.

The switch instructs I<pod2fm> to use the FrameMaker tool 'fmbatch' to convert
the '.doc' file, which is in MIF format, in to the binary FrameMaker format.

The default is B<-doc>.

=item B<-lock>

=item B<-nolock>

Available only on UNIX systems.

I<Pod2fm> generates Hypertext Marker that allow you to click on a marked word in
a document and Frame will take you to the spot in a document that the marker
is pointing too. To be able to use this feature, you need to save the
documents as 'locked' or 'read only'. The B<-lock> option will cause I<pod2fm>
to generate 'locked' versions of the documents.

The B<-lock> option only works if you are generating binary documents. (See
the B<-doc> option.)

The default is B<-nolock>.

=item B<-book> [I<book_name>]

Available only on UNIX systems.

This switch allows I<pod2fm> to create a FrameMaker book file that contains
all of the documents that are on the command line. A book is a way to
organize a group of related documents so they can operated on at the same
time.  A book file allow you to apply a common format to all the documents, and
print all of them at the same time.

I<book_name> is an optional argument to -book. It allows you to specify a name
for the book file. If I<book_name> is not specified, it defaults to 'perl'.
In any case, the file name extension is '.book'.

=item B<-noopen>

=item B<-open>

Available only on UNIX systems.

If this option is on the command line, I<pod2mf> will try to open the book it
created in FrameMaker. Because this options works on the book file, you must be
generating a book with the B<-book> option.

The default is B<-open>.

=item B<-template> I<document>

Available only on UNIX systems.

I<Pod2fm> generates a minimal format for the documents it produces. You can 
use the B<-template> option to specify a template document that I<pod2fm> can
copy the format from so that you can control the format. You can control which
format in the template document to use with the B<-format> option. The
I<document> name is required argument to B<-template>, and specifies path to
the document template.

=item B<-format> I<type>

Available only on UNIX systems.

The option B<-format> allows you to control which format to copy from the
template document specified with the B<-template> option. You can specify one
or more arguments to each B<-format> option by giving a comma separated list
of format types, like this:

    -format Page,Paragraph,Character

You can also have more than one B<-format> option on the command line.

The legal format I<type>s are:

    all		All type are specified (Default).
    Character	Character Formats.
    Paragraph	Paragraph Formats.
    Page	Master Page Layouts.
    Reference	Reference Page Layouts.
    Table	Table Formats.
    Variables	Variable Definitions.
    Math	Math Definitions.
    Cross	Cross-Reference Definitions.
    Color	Color Definitions.
    Conditional	Conditional Text Definitions.

There are two other I<type>s that can be included as an argument to control
how the other I<types> are used:

    Break	Preserve Page Breaks
    Other	Preserve Other Format Changes.

=item B<-toc>

=item B<-notoc>

=item B<-index>

=item B<-noindex>

Available only on UNIX systems.

When you are generating a book from a template with I<pod2fm>, you can generate
a Table of Contents and an Index by specifying the B<-toc> and the B<-index>
options. See the I<Table of Contents> and I<Index> sub-sections of the 
B<TEMPLATES> section of this man page, for more information.

The defaults are B<-notoc> and B<-noindex>.

=item B<-dir> I<location>

=item I<pod>...

By default, I<pod2fm> will look for pod files from the standard perl install
(the C<$installprivlib> from C<Config.pm>.) You can override this by using the
B<-dir> command line option. You can also specify the pods that you want on
the command line, but you can't mix the B<-dir> and pods in the same command.

=back

=head1 TEMPLATES

By using the B<-template> command line option, when you are generating a book
using the B<-book> option, you can override the default formats that I<pod2fm>
produces.

A template is a FrameMaker document, the binary form or MIF, that has formats
you want already applied to it. With this version of I<pod2fm>, you can
override the Master Page and Reference Page layouts, and Paragraph formats.
There are other formats that you can specify, like Character formats and Color
definitions, but this version of I<pod2fm> does not do anything with them.

=head2 Paragraph Formats

There are several Paragraph Formats that I<pod2fm> uses and there is a mapping
from the pod command to the paragraph format that is produced. The exception
to the mapping is the I<=over> and I<=back> commands: they modify the paragraph
format by shifting its left edge by .1" times the amount in the I<=over> command.
You need to take this into account when you are changing the paragraph format.
If you drop the size of the font in the format, you do not get a smaller amount
of shifting. An I<=over> 5 always give an indent of .5".

The paragraph formats that I<pod2fm> uses are:

=over 12

=item B<pod_TITLE>

Paragraphs marked with this format contain the name of the pod. The name is
automatically added to the start of each document, and this format is only
used here.

You can use the B<pod_TITLE> tag to generate a header or footer with the name of
the pod in it by changing the Master Page layout. If you are generating a book,
this format is exported so that you can create a Table of Contents by changing
the Reference Page.

=item B<pod_Body>

This format marks a standard paragraph. The left edge moves with
each I<=over> I<n> and I<=back>. The edge moves by I<n>*.1".

=item B<pod_head1>

This format is used for section headers. The command is used like:

    =head1 I<text>

where I<text> is printed in this format. The I<=over> or I<=back> command do not
change this format.

If you are generating a book, this format is exported so that you can create a
Table of Contents by changing the Reference Page. Also, a Marker is placed on
the I<text> so that it can be placed in an Index.

=item B<pod_head2>

This format is used for sub-section headers. The command is used like:

    =head2 I<text>

where I<text> is printed in this format. The I<=over> or I<=back> command do not
change this format.

If you are generating a book, this format is exported so that you can create a
Table of Contents by changing the Reference Page. Also, a Marker is placed on
the I<text> so that it can be placed in an Index.

=item B<pod_ol>

This format is used on ordered (numbered) lists. If the indent command is in
this form:

    =item I<n>[I<.>]

where I<n> is any number followed by an optional period. The next paragraph 
will be marked with this format and will print as a hanging indent that starts
with an automatically generated number and a period. The start of the 
paragraph is shifted by the amount in the I<=over> command. Any paragraphs that
come after the first are marked with B<pod_Body> and the left edge is shifted
by the amount from the I<=over> command.

=item B<pod_ul>

This format is used on unordered lists. If the indent command is in this form:

    =item *

the next paragraph will be marked with this format and will print as a
hanging indent that starts bullet. The start of the paragraph is shifted by
the amount in the I<=over> command. Any paragraphs that come after the first
are marked with B<pod_Body> and the left edge is shifted by the amount from
the I<=over> command.

=item B<pod_dl>

This format is used on description lists. If the indent command is in this form:

    =item * I<text>

the I<text> will be printed after a bullet, on a line by itself.  Any
paragraphs that come after the first are marked with B<pod_Body> and the left
edge is shifted by the amount from the I<=over> command.

=item B<pod_hi>

This format is used on hanging indent lists. If the indent command is in
this form:

    =item I<text>

the I<text> will be printed as a hanging indent. The next paragraph will be
marked with this format and will print with the start of the paragraph shifted
by the amount in the I<=over> command.  Any paragraphs that come after the first
are marked with B<pod_Body> and the left edge is shifted by the amount from
the I<=over> command.

=item B<pod_il>

This format is used on implied lists. If the first line of a paragraph is
in this form:

    ____I<hang>_______I<text>
     |          |
     +- spaces  +- tabs
	  or
	 tabs

the I<hang> will be printed as a hanging indent and the I<text> will be printed
with the left edge shifted to 2.5" from the current B<pod_Body> left edge.  The
rest of the lines in the paragraph are treated the same, i.e.: each line in the
pod's paragraph is converted to a FrameMaker paragraph that is marked with
B<pod_il>. Any paragraphs that come after the first are marked with
B<pod_Body> and the left edge is shifted by the amount from the I<=over>
command.

=item B<pod_pre>

This format is used on verbatim paragraphs. If the first line of a
paragraph is in this form:

    ____I<text>
     |
     +- spaces
	  or
	 tabs

the I<text>, including the leading white space,  will be printed with the
left edge shifted to the current B<pod_Body> left edge.  The rest of the lines
in the paragraph are treated the same, i.e.: each line in the pod's paragraph is
converted to a FrameMaker paragraph that is marked with B<pod_pre>. Any
paragraphs that come after the first are marked with B<pod_Body> and the left
edge is shifted by the amount from the I<=over> command.

=back

=head2 Table of Contents

If you are producing a book, and you have a B<-template> command line option
and you are importing the Master Page Layout (B<-format Page> or the default),
you can produce a Table of Contents by adding the B<-toc> option. I<Pod2fm>
will automatically add a generated document called I<book_name>TOC.doc to
the book file, where I<book_name> is the optional argument to the B<-book>
command line option. If no argument is give on the B<-book>, you will get a
document called perlTOC.doc.

To specify the format of the Table of Contents, you need to go to the reference
pages of the template document and create a flow called 'TOC'. Within the flow,
you need to create a picture of what the Table of Contents will look like.
You can add I<Building block> to the picture that allows you to control what
is printed, things like the page number and text for the TOC entry. See the
FrameMaker On-Line Help or I<Using FrameMaker> printed manual for a complete
description of how to set up a TOC Reference page.

The TOC entry is derived from paragraphs in the documents in the book that are
marked with specific paragraph formats. I<Pod2fm> uses the paragraph formats
B<pod_TITLE>, B<pod_head1>, and B<pod_head2> to mark the TOC entries.

To make a TOC entry show, you need to create a new paragraph format that tracks
the format used in the documents. The new paragraph have the form:

    I<format_name>TOC

where I<format_name> is the format name used in the document. Here is an
example of TOC specification:

    Paragraph tagged	Specifies
    ----------------	---------
    pod_TITLE		<$paratext><$nopage>
    pod_head1		    <$paratext>\t<$pagenum>
    pod_head2			<$paratext>\t<$pagenum>

would print something like this:

    POD2FM
	NAME					1
	SYNOPSIS				1
	DESCRIPTION				1
	OPTIONS					1
	TEMPLATES				3
	    Paragraph Formats			3
	    Table of Contents			5
	    Index				6
	BUGS					6
	AUTHORS					7

=head2 Index

An Index document is much the same as a Table of Contents document: you must
be generating a book and importing Reference Page Layouts from a template,
and have a B<-index> command line option.

The format for the Index is also specified on a Reference Page in a flow called
B<IX>, and it has it's own set of I<Building Blocks>. Please see the FrameMaker
documentation for more details on how to create the Index Reference Page.

I<Pod2fm> generates the index from any I<Index> markers that have been place
in the documents. The markers are generated on any I<=head> or I<=item> command,
and any interior sequences (like I\<\>, B\<\>, and L\<\>) that refers to
and I<=head> or I<=item>.

=head1 CHANGES

=head2 Changes in 1.9

=over 4

=item *

Added checks for Win32 and Macintosh versions of Perl.

=back

=head2 Changes in 1.8 from 0.10

=over 4

=item *

Cleaned up for newer versions of Perl (5.003 and up)

=item *

Added the B<-dir> option to use all of the pod found in a directory as input.
Fixed bug in the processing of TOC and Index.

=back

=head1 BUGS

You can't change the amount of indent using a template file (yet...).

=head1 AUTHORS

Based on pod2html.

Extended for MML by S<Mark Pease ><Mark_Pease-RXYE0@email.mot.com>.

fmbatch and book support added by S<Tim Bunce ><Tim.Bunce@ig.co.uk>.

Please send bug reports to S<Mark Pease ><Mark_Pease-RXYE0@email.mot.com>.

=cut

use strict;
use Getopt::Long;
use File::Find;
use File::Basename;
use Config;
use vars qw(
    $gt
    $lt
    %HTML_Escapes
    $VERSION
    $running_under_some_shell
    $OUTPUT_AUTOFULSH
    @opt_debug
    $opt_mmlonly
    $opt_doc
    $opt_book
    $opt_lock
    $opt_template
    @opt_format
    $opt_toc
    $opt_index
    $opt_open
    $opt_dir
    );

$VERSION = do { my @r=(q$Revision: 1.9 $=~/\d+/g); sprintf "%d."."%02d"x$#r,@r};

$OUTPUT_AUTOFULSH = 1;

################################################################################
# CONFIGURE
#
#
################################################################################

my $book_ext = 'book';
my $doc_ext = 'doc';
my $fmbatch = 'fmbatch';
$fmbatch = 'fmbatch -i' if $ENV{FM_PROGNAME} && $ENV{FM_PROGNAME} =~ m/^i/;

#
# Page formats
#
my $TopMargin = .75;
my $BottomMargin = .75;
my $LeftMargin = .75;
my $RightMargin = .75;

#
# Paragraph indents and tab stop locations in inches.
#
my $IndentAmount = 0.1;

my $BodyLeft = 0.3;
my $BodyIndent = 0.3;

my @ListTab = ($BodyLeft, $BodyLeft + 1, $BodyLeft + 2);

my $ilLeft = $BodyLeft + 2.0;
my $ilIndent = $BodyLeft + 0.5;
my @ilTab = ($ilLeft, $ilLeft + 1, $ilLeft + 2);

my $dlLeft = $BodyLeft;
my $dlIndent = $BodyLeft;

# look in these pods for things not found within the current pod
# be careful tho, namespace collisions cause stupid links

my @inclusions = qw[
     perlfunc perlvar perlrun perlop 
];

################################################################################
# END CONFIGURE
################################################################################

################################################################################
# GENERAL GLOGAL VALUES
################################################################################

my %index = ();
my @Pods = ();
my %Podnames = ();
my $A = {};	# The beginning of all things

################################################################################
# COMMAND LINE ACTIONS
#
#   Set up defaults for the command line, and process it.
################################################################################

my $do_mmlonly = 0;		# Produce MIF ".doc" files
my $do_doc = 1;			# Generate the binary ".doc" files
my $save_type = 'd';		# SaveAs type: "d" - normal format, "l" - locked
my $do_book = 0;		# Don't Generate a book
my $book_name = 'perl';		# The default name for a book.
my $import_formats = 'pflcvrtxkmBO';# Default formats to import from Template
my $do_toc = 0;			# Don't include a TOC
my $do_index = 0;			# Don't include a INDEX
my $open_frame = 1;		# Open maker on the book file once it is built
my $dir = $Config{installprivlib};	# Take the installed pods as default;

if ($Config{'osname'} eq 'MacOS' || $Config{'osname'} eq 'MSWin32'){
    # For system that don't have fmbatch.

    $do_mmlonly = 1;		# Produce MIF ".mml" files
    $do_doc = 0;		# Don't Generate the binary ".doc" files

    GetOptions(
	"dir=s"
    ) || die "$0: Unable to process command line.\n";
} else {
    GetOptions(
	"debug=s@",
	"mmlonly!",
	"doc!",
	"book:s",
	"lock!",
	"template=s",
	"format=s@",
	"toc!",
	"index!",
	"open!",
	"doc=s",
	"dir=s"
    ) || die "$0: Unable to process command line.\n";
}

# Fix up debug, if necessary.
my %opt_debug = ();
foreach my $tmp (@opt_debug) {
    $opt_debug{$tmp} = 1;
}

#
# Verify options
#

my $batch_name = '';

if (defined $opt_mmlonly and $opt_mmlonly) {
    #
    # Generate MML only.
    #
    $do_mmlonly = 1;
    $do_doc = 0;
    $do_book = 0;
    $do_toc = 0;
    $do_index = 0;
    $open_frame = 0;

    warn "$0: You can't produce .${doc_ext} files because you asked for MML only.
    Continuing, only producing .mml\n"
	if $opt_doc;

    warn "$0: You can't generate a book because you asked for MML only.
    Continuing, only producing .mml\n"
	if $opt_book or $opt_lock or $opt_toc or $opt_index;

    warn "$0: You can't import formats because you asked for MML only.
    Continuing, only producing .mml\n"
	if defined $opt_template or defined @opt_format;

} else {
    #
    # Generate MIF, and maybe other stuff.
    #
    $do_mmlonly = 0;

    #
    # Process Document Generation options.
    #
    $do_doc = $opt_doc if defined $opt_doc;

    #
    # Process book options.
    #
    if (defined $opt_book or $do_book) {
	#
	# Generate a MIF file for the book, with the default name of "perl".
	#
	$do_book = 1;
	$opt_book = $book_name unless $opt_book;
	$batch_name = $opt_book;

	#
	# Process lock options.
	#
	$save_type = (defined $opt_lock and $opt_lock) ? 'l' : 'd';

	#
	# Check for templates and formats.
	#
	die "$0: Template file $opt_template does not exist!\n"
	    if defined($opt_template) and !(-e $opt_template);

	die "$0: You must specify a template using -template <file>."
	    if defined(@opt_format) and !defined($opt_template);

	#
	# Process the format options.
	#
	if (defined(@opt_format)) {
	    my %type;

    FORMAT: foreach (@opt_format) {
		#
		# Each format argument could be a "," seperated list.
		#
		foreach (split /,/) {
		    {
			# Do it all
			/all/i	and do {$type{$_}='pflcvrtxkmBO',last FORMAT;};

			# Presere Page Breaks
			/^b/i	and do {$type{$_}='m',last;};

			# Character Formats
			/^ch/i	and do {$type{$_}='f',last;};

			# Color Definitions
			/^col/i	and do {$type{$_}='k',last;};

			# Conditional Text
			/^con/i	and do {$type{$_}='x',last;};

			# Cross-references
			/^cr/i	and do {$type{$_}='c',last;};

			# Math Definitions
			/^m/i	and do {$type{$_}='m',last;};

			# Presere Other Formats
			/^o/i	and do {$type{$_}='m',last;};

			# Master Page Layouts
			/^pag/i	and do {$type{$_}='l',last;};

			# Paragraph Formats
			/^par/i	and do {$type{$_}='p',last;};

			# References Pages
			/^r/i	and do {$type{$_}='r',last;};

			# Table Formats
			/^t/i	and do {$type{$_}='t',last;};

			# Varables
			/^v/i	and do {$type{$_}='v',last;};

			# Default
			die "$0: Unknow format type $_\n";
		    }
		}
	    }
	    $import_formats = '';	    # Start with nothing.
	    foreach (keys %type) {
		$import_formats .= $type{$_};
	    }
	}

	#
	# Make sure we can do TOC and INDEX's
	#
	if (defined $opt_toc and $opt_toc ) {
	    if (!$opt_template or !$import_formats =~ /r/) {
		warn "$0: You can't generate a Table of Contents unless you " .
		"specify a template and you ask for Page formats to be " .
		"imported.\n" .
		"Continuing with out generating a TOC.\n";
		$do_toc = 0;
	    } else {
		$do_toc = 1;
	    }
	}

	if (defined $opt_index and $opt_index) {
	    if (!$opt_template and !$import_formats =~ /r/) {
		warn "$0: You can't generate an Index unless you specify a " .
		"template and you ask for Page formats to be imported.\n" .
		"Continuing with out generating an INDEX.\n";
		$do_index = 0;
	    } else {
		$do_index = 1;
	    }
	}
    } else {
	#
	# We are not working with a book.
	#
	$batch_name = "batch";
	$do_book = 0;
	$do_toc = 0;
	$do_index = 0;
	$open_frame = 0;
    }
}

#
# Check to see if a directory is asked for
#
if ($opt_dir) {
    die "$0: You can't specify a dir if you also specify pod names\n"
	if scaler(@ARGV);
    $dir = $opt_dir;
} else {
    #
    # check for podnames on command line
    #
    while ($ARGV[0]) {
	push(@Pods,shift);
    }
}

unless(@Pods){
    find (
	sub {
	    if (-f $_) {
		push(@Pods, $File::Find::name)
		    if $File::Find::name =~ /\.(pm|pod)$/;
	    }
	},
	$dir
    );
}

@Pods or die "$0: No pod file found on command line or in $dir\n";

my @book;	# Build a FrameMaker book file for all the parts
my @fmbatch;	# Build an fmbatch script for mif-doc conversion

if ($do_book or $do_doc) {
    if ($do_book) {
	push @book, "<Book 3.00>";
	push @book, "<BWindowRect 5 26 301 870>";
	if ($do_toc) {
	    #
	    # Create a TOC document.
	    #
	    if(open(TOC, ">${opt_book}TOC.mml")) {
		push @fmbatch, "echo Building ${opt_book}TOC.${doc_ext}";
		push @fmbatch, "Open ${opt_book}TOC.${doc_ext}";
		push @fmbatch, "Validate ${opt_book}TOC.${doc_ext}";	# test
		push @fmbatch, "SaveAs $save_type  ${opt_book}TOC.${doc_ext} ${opt_book}TOC.${doc_ext}";
		push @fmbatch, "Quit ${opt_book}TOC.${doc_ext}";
		push @book, "<BookComponent";
		push @book, " <FileName `<c\\>${opt_book}TOC.${doc_ext}'>";
		push @book, " <PageNumPrefix `'>";
		push @book, " <PageNumSuffix `'>";
		push @book, " <FileNameSuffix `TOC'>";
		push @book, " <DeriveType TOC>";
		foreach(qw(pod_TITLE pod_head1 pod_head2)) {
		    push @book, " <DeriveTag `$_'>";
		}
		push @book, " <DefaultPrint Yes>";
		push @book, " <DefaultApply No>";
		push @book, " <DefaultDerive Yes>";
		push @book, " <DeriveLinks Yes>";
		push @book, ">";

		print TOC mml_header();
		close(TOC);
		unless ($do_mmlonly) {
		    system("mmltomif ${opt_book}TOC.mml ${opt_book}TOC.${doc_ext}");
		    warn "$0: Unable to run mmltomif on ${opt_book}TOC.mml\n"
			if $? >> 8;
		    unlink("${opt_book}TOC.mml") unless $opt_debug{'keep_mml'};
		}
	    } else {
		warn "$0: Unable to create a TOC! Continuing...\n";
		$do_toc = '';
	    }
	}
    }
}

# loop twice through the pods, first to learn the links, then to produce mml
for my $count (0,1){
    my $in_mml = '';
    (print "Scanning pods...\n") unless $count;
    foreach my $podfh ( @Pods ) {
	my $in_list = '';
	my $cmd = '';
	my $title = '';
	my $rest = '';
	my @depth = ();
	my $pod = basename($podfh, ".pm", ".pod");
	Debug("files", "opening 2 $podfh" );
	(print "Creating $pod.${doc_ext} from $podfh\n") if $count;
	$/ = "\n=";	    # grok pods by item (Nonstandard but effecient)
	open(PODFH,"<".$podfh)  || die "can't open $podfh: $!";
	my @all=<PODFH>;
	close(PODFH);
	$/ = "\n";
	$all[0] =~ s/^=// or shift(@all);
	for(my $i=0; $i <= $#all; $i++) {
	    splice(@all, $i+1, 1) unless ($all[$i] =~ s/=$//) &&
		((!defined $all[$i+1]) || ($all[$i+1] !~ /^cut/));
	}

	#
	# We don't need to continue if no pod information was found in the
	# file.
	#
	next unless scalar(@all);

	unless (grep(/head\d\s+NAME/, @all)) {
	    warn "$0: NAME header not found in $podfh, skipping\n";
	    next;
	}
	$Podnames{$pod} = 1;
	my $mml=$pod.".${doc_ext}";
	if($count){		# give us a mml and rcs header
	    open(MML, ">$pod.mml")
			|| die "$0: can't create $mml: $!";
	    print MML mml_header(), "<pod_TITLE>\n\U$pod\E";

	    if ($do_doc) {
		push @fmbatch, "echo Building $pod.${doc_ext}";
		push @fmbatch, "Open $pod.${doc_ext}";
		push @fmbatch, "Validate $pod.${doc_ext}";	# test
		push @fmbatch, "SaveAs $save_type  $pod.${doc_ext} $pod.${doc_ext}";
		push @fmbatch, "Quit $pod.${doc_ext}";
	    }
	    if ($do_book) {
		push @book, "<BookComponent";
		push @book, " <FileName `<c\\>$pod.${doc_ext}'>";
		push @book, " <PageNumPrefix `'>";
		push @book, " <PageNumSuffix `'>";
		push @book, " <DefaultPrint Yes>";
		push @book, " <DefaultApply Yes>";
		push @book, ">";
	    }
	}

	my $i;
	for($i=0;$i<=$#all;$i++){	# decide what to do with each chunk
	    ($cmd,$title,$rest) = ($all[$i] =~ /^(\w+)\s*(.*)\n?([^\0]*)$/o);
	    if ($cmd =~ /^item/o) {
		if($count ){	# producting mml
		    (scalar(@depth))
			or do_list("over","5",$all[$i],\$in_list,\@depth);
		    do_item($pod,$title,$rest,$in_list,@depth);
		}
		else{
		    # scan item
		    scan_thing("item",$title,$pod);
		}
	    }
	    elsif ($cmd =~ /^head([12])/o){
		my $num=$1;
		if($count){	# producting mml
		    do_hdr($pod,$num,$title,$rest,@depth);
		}
		else{
		    # header scan
		    scan_thing($cmd,$title,$pod); # skip head1
		}
	    }
	    elsif ($cmd =~ /^over/o) {
		$count and do_list("over",$title,$all[$i+1],\$in_list,\@depth);
	    }
	    elsif ($cmd =~ /^back/o) {
		if($count){	# producting mml
		    scalar(@depth) or next; # just skip it
		    do_list("back",$title,$all[$i+1],\$in_list,\@depth);
		    print_Body(@depth);
		    do_rest($pod,$title.$rest,$in_mml,@depth);
		}
	    }
	    elsif ($cmd =~ /^cut/o) {
		next;
	    }
	    elsif ($cmd =~ /^for/o){  # experimental pragma mml
		if($count){  # producing mml
		    if($title =~ s/^mml//){
			$in_mml =1;
			do_rest($pod,$title.$rest,$in_mml,@depth);
		    }
		}
	    }
	    elsif ($cmd =~ /^begin/o){  # experimental pragma mml
		if($count){  # producing mml
		    if($title =~ s/^mml//){
			print MML $title,"\n",$rest;
		    }
		    elsif($title =~ /^end/){
			next;
		    }
		}
	    }
	    else {
		Debug("misc", "unrecognized header: $cmd");
	    }
	}
        # close open lists without '=back' stmts
	if($count){ # producing html
	    while(scalar(@depth)){
		 do_list("back",$title,$all[$i+1],\$in_list,\@depth);
		print_Body(@depth);
	    }

	    close(MML);	# must close to flush pipes etc

	    #
	    # Start mif converter, if we can.
	    #
	    unless ($do_mmlonly) {
		system("mmltomif $pod.mml $mml");
		warn "$0: Unable to run mmltomif on $pod.mml\n" if $? >> 8;
		unlink("$pod.mml") unless $opt_debug{'keep_mml'};
	    }
	}
    }
}

if ($do_doc) {
    if ($do_book) {
	if ($do_index) {
	    if(open INDEX, ">${opt_book}IDX.mml") {
		push @fmbatch, "echo Building ${opt_book}IDX.${doc_ext}";
		push @fmbatch, "Open ${opt_book}IDX.${doc_ext}";
		push @fmbatch, "Validate ${opt_book}IDX.${doc_ext}";	# test
		push @fmbatch, "SaveAs $save_type ${opt_book}IDX.${doc_ext} ${opt_book}IDX.${doc_ext}";
		push @fmbatch, "Quit ${opt_book}IDX.${doc_ext}";
		push @book, "<BookComponent";
		push @book, " <FileName `<c\\>${opt_book}IDX.${doc_ext}'>";
		push @book, " <PageNumPrefix `'>";
		push @book, " <PageNumSuffix `'>";
		push @book, " <FileNameSuffix `doc'>";
		push @book, " <DeriveType IDX>";
		foreach(qw(Index)) {
		    push @book, " <DeriveTag `$_'>";
		}
		push @book, " <DefaultPrint Yes>";
		push @book, " <DefaultApply No>";
		push @book, " <DefaultDerive Yes>";
		push @book, " <DeriveLinks Yes>";
		push @book, ">";
		print INDEX mml_header();
		close(INDEX);
		unless ($do_mmlonly) {
		    system("mmltomif ${opt_book}IDX.mml ${opt_book}IDX.${doc_ext}");
		    warn "$0: Unable to run mmltomif on ${opt_book}IDX.mml\n"
			if $? >> 8;
		    unlink("${opt_book}IDX.mml") unless $opt_debug{'keep_mml'};
		}
	    } else {
		warn "$0: Unable to create an index file. Continuing...";
		$do_index = '';
	    }
	}
	open(BOOK,">${opt_book}.${book_ext}")
	    || die "$0: Unable to open the book file ${opt_book}.${book_ext}: $!\n";
	print BOOK join("\n", @book);
	close(BOOK);

	push @fmbatch,
	    "echo Components complete, updating ${opt_book}.${book_ext}...";
	push @fmbatch, "Open ${opt_book}.${book_ext}";
	#push @fmbatch, "Validate ${opt_book}.${book_ext}";	# test
	if ($opt_template) {
	    # hack to avoid locks :-)
	    # system("cp $opt_template x.${doc_ext}");
	    # $opt_template = 'x.${doc_ext}';
	    push @fmbatch,"Open $opt_template";
	    push @fmbatch,
		"ImportFormats $import_formats ${opt_book}.${book_ext} $opt_template";
	    push @fmbatch,"Quit $opt_template";
	}
	push @fmbatch, "Update ${opt_book}.${book_ext}";	# Now Update
	push @fmbatch, "SaveAs d ${opt_book}.${book_ext} ${opt_book}.${book_ext}";
	push @fmbatch, "Quit ${opt_book}.${book_ext}";
    }

    open(BATCH, ">${batch_name}.fmbatch")
	|| die "$0: Unable to create ${opt_book}.fmbatch\n";
    print BATCH join("\n", @fmbatch);
    close(BATCH);

    system("$fmbatch ${batch_name}.fmbatch");
    die "$0: Unable to run $fmbatch on ${opt_book}.fmbatch\n" if $? >> 8;
}

system("fmclient -f ${opt_book}.${book_ext}") if $open_frame;

exit 0;

################################################################################
#
# Subroutine: print_Body
#
# Description:
#   This routine handles the formating of Body paragraphs.
#
################################################################################

sub print_Body {
    my(@depth) = @_;
    my $temp;

    my ($over) = get_shift(@depth);

    print MML "<pod_Body>\n";
    $temp = $BodyLeft + $over;
    print MML "<LeftIndent $temp\">\n";
    $temp = $BodyIndent + $over;
    print MML "<FirstIndent $temp\">\n";
}

################################################################################
#
# Subroutine: print_pre
#
# Description:
#   This routine handles the formating of pre (preformated) paragraphs.
#
################################################################################

sub print_pre {
    my(@depth) = @_;
    my $temp;

    my ($over) = get_shift(@depth);

    print MML "<pod_pre>\n";
    $temp = $BodyLeft + $over;
    print MML "<LeftIndent $temp\">\n";
    $temp = $BodyLeft + $over;
    print MML "<FirstIndent $temp\">\n";
}

################################################################################
#
# Subroutine: print_il
#
# Description:
#   This routine handles the formating of il (indented) lists. This is an
#   implied format.
#
################################################################################

sub print_il {
    my(@depth) = @_;
    my $temp;

    my ($over, $list) = get_shift(@depth);

    print MML	"<pod_il>\n";
    $temp = $ilLeft + $over;
    print MML "<LeftIndent $temp\">\n";
    $temp = $ilIndent + $over;
    print MML "<FirstIndent $temp\">\n";
    print MML	"<TabStops \n";
    foreach my $tab (@ilTab) {
	$temp = $tab +$over;
	print MML "    <TabStop $temp\">\n";
    }
    print MML ">\n";
}

################################################################################
#
# Subroutine: print_ol
#
# Description:
#   This routine handles the formating of ol (ordered or numbered) lists.
#
################################################################################

sub print_ol {
    my(@depth) = @_;
    my $temp;

    my ($over, $list) = get_shift(@depth);

    print MML	"<pod_ol>\n";
    $temp = $BodyLeft + $over;
    print MML "<LeftIndent $temp\">\n";
    $temp = $BodyLeft + $list;
    print MML "<FirstIndent $temp\">\n";
    print MML	"<TabStops \n";
    foreach my $tab (@ListTab) {
	$temp = $tab + $over;
	print MML "    <TabStop $temp\">\n";
    }
    print MML ">\n";
}

################################################################################
#
# Subroutine: print_ul
#
# Description:
#   This routine handles the formating of ul (unordered/unnumbered) lists.
#
################################################################################

sub print_ul {
    my(@depth) = @_;
    my $temp;

    my ($over, $list) = get_shift(@depth);

    print MML	"<pod_ul>\n";
    $temp = $BodyLeft + $over;
    print MML "<LeftIndent $temp\">\n";
    $temp = $BodyLeft + $list;
    print MML "<FirstIndent $temp\">\n";
    print MML	"<TabStops \n";
    foreach my $tab (@ListTab) {
	$temp = $tab + $over;
	print MML "    <TabStop $temp\">\n";
    }
    print MML ">\n";
}

################################################################################
#
# Subroutine: print_dl
#
# Description:
#   This routine handles the formating of dl (description) lists.
#
################################################################################

sub print_dl {
    my(@depth) = @_;
    my $temp;

    my ($over, $list) = get_shift(@depth);

    print MML	"<pod_dl>\n";
    $temp = $dlLeft + $list;
    print MML "<LeftIndent $temp\">\n";
    $temp = $dlIndent + $list;
    print MML "<FirstIndent $temp\">\n";
}

################################################################################
#
# Subroutine: print_hi
#
# Description:
#   This routine handles the formating of hi (hanging indent) paragraphs.
#
################################################################################

sub print_hi {
    my(@depth) = @_;
    my $temp;

    my ($over, $list) = get_shift(@depth);

    print MML	"<pod_hi>\n";
    $temp = $BodyLeft + $over;
    print MML "<LeftIndent $temp\">\n";
    $temp = $BodyLeft + $list;
    print MML "<FirstIndent $temp\">\n";
    $temp = $BodyLeft + $over;
    print MML	"<TabStops \n" .
		"    <TabStop $temp\">\n".
		">\n";
}

################################################################################
#
# Subroutine: get_shift
#
# Description:
#   This routine finds the amount of shift that needs to happen because of an
#   "over" or a "item".
#
################################################################################

sub get_shift {
    my @depth = @_;
    my $over = 0;
    my $list = 0;
    my $shift = 0;

    foreach $shift (@depth) {
	$list = $over;
	$over += $shift;
    }

    return ($over*$IndentAmount, $list*$IndentAmount);
}

################################################################################
#
# Subroutine: print_marker
#
# Description:
#   This routine outputs a hypertext marker, and, if an index is going to be
#   generated, an index marker.
#
################################################################################

sub print_marker {
    my ($type, $value, $file) = @_;
    my $marker;

    if ($type eq "NAME") {
	$marker =
	"${lt}Marker ${lt}MType 8${gt} ${lt}MText `newlink ${value}'${gt}${gt}";
	if ($do_index) {
	    $value = pre_escapes($index{$value});
	    $marker .=
	    "${lt}Marker ${lt}MType 2${gt} ${lt}MText `${value}'${gt}${gt}";
	}
    } else {
	$marker =
	"${lt}Marker ${lt}MType 8${gt} ${lt}MText `gotolink ${file}:${value}'${gt}${gt}";
    }
    return $marker;
}

sub do_list{
    my($which,$amount,$next_one,$list_type,$depth)=@_;
    my $key = '';
    if($which eq "over"){
	($key) = ($next_one =~ /^item\s+(.*)/);
	$key or Debug("misc", "Bad list, ($1) found in $next_one\n");
	if($key =~ /^\d\.?/){
	    $$list_type = "OL";
	} elsif($key =~ /^\*\s*$/){
	    $$list_type="UL";
	} elsif($key =~ /^\*\s*\w/){
	    $$list_type="DL";
	} elsif($key =~ /^\w+/){
	    $$list_type="HI";
	} else{
	    Debug("misc", "unknown list type for item $key");
	}
	push(@$depth, $amount);
    }
    elsif($which eq "back"){
	$$list_type="";
	$amount = pop(@$depth);
    }
}

sub do_hdr{
    my($pod,$num,$title,$rest,@depth)=@_;
    ($num == 1) and print MML "\n";
    process_thing($pod,\$title,"NAME");
    print MML qq{\n<pod_head$num>\n};
    print MML "$title\n"; 
    print_Body(@depth);
    do_rest($pod,$rest, '',@depth);
}

sub do_item{
    my($pod,$title,$rest,$list_type,@depth)=@_;
    process_thing($pod,\$title,"NAME");
    if($list_type eq "DL") {
	print_dl(@depth);
	$title =~ s/\*\s*//;
	print MML "<bold>$title<nobold>\n";
	print_Body(@depth);
    } elsif ($list_type eq "OL") {
	print_ol(@depth);
    } elsif ($list_type eq "UL") {
	print_ul(@depth);
    } else {
	print_hi(@depth);
	my $over = (get_shift(@depth))[0];
	my $raw_title = $title;
	$raw_title =~ s/<[^>]+?>//g;
	if ($over >= length($raw_title) * $IndentAmount) {
	    print MML "$title\t";
	} else {
	    print MML "$title\n";
	    print_Body(@depth);
	}
    }
    do_rest($pod,$rest, '',@depth);
    print_Body(@depth);
}

sub do_rest{	# the rest of the chunk handled here
    my($pod,$rest,$in_mml,@depth)=@_;
    my(@lines, $p, $q, $line, @paras, $inpre);
    @lines = ();
    @paras=split(/\n\n\n*/,$rest);
    for($p=0;$p<=$#paras;$p++){
	$paras[$p] =~ s/^\n//mg;	# Zap any extra empty lines.
	@lines=split(/\n/,$paras[$p]);
	if (!defined $lines[0]) {
	    # There must be only one line in the paragraph
	    $lines[0] = $paras[$p];
	}
	if($in_mml){	# handle =for mml paragraphs
	    print MML $paras[0];
	    $in_mml=0;
	    next;
	}
	elsif($lines[0] =~ /^\s+\w*\t+.*/){  # listing or unordered list
	    print_il(@depth);
	    foreach $line (@lines){ 
		my $key;
		my $rem;
		($line =~ /^\s+(\w*)\t+(.*)/) && (($key,$rem) = ($1,$2));
		process_thing($pod,\$rem, "MML");
		print MML defined($Podnames{$key}) ?
		    "<Marker <MType 8> <MText `gotolink $key.${doc_ext}:firstpage'>>$key\t$rem\n<par>\n" : 
			"$key\t$rem\n<par>\n";
	    }
	    print_Body(@depth);
	}
	elsif($lines[0] =~ /^\s/){       # preformatted code
	    print_pre(@depth);
	    while(defined($paras[$p])){
	        @lines=split(/\n/,$paras[$p]);
		foreach $q (@lines){	# mind your p's and q's here :-)
		    $q =~ s/ /\177/g;	# hide the spaces

		    # Convert tab's to hidden spaces
		    while($q =~  s/\t+/"\177" x (length($&) * 8 - length($`) % 8)/e){
			1;
		    }
		    process_thing($pod,\$q,"MML");
		    $q =~ s/\177/<hardspace>/g;	# make all spaces hard.
		    print MML  $q,"\n\n";	# put in extra \n to make a para
		}
		last if defined $paras[$p+1] and $paras[$p+1] !~ /^\s/;
		$p++;
	    }
	    print_Body(@depth);
	}
	else{                             # other text
	    process_thing($pod,\$paras[$p],"MML");
	    @lines=split(/\n/,$paras[$p]);
	    foreach $line (@lines){
		print MML qq{$line\n};
	    }
	}
	print_Body(@depth);
    }
}

sub process_thing{	# process a chunk, order important
    my($pod,$thing,$htype)=@_;
    pre_escapes($thing);
    find_refs($pod,$thing,$htype);
    post_escapes($thing);
}

sub scan_thing{		# scan a chunk for later references
    my($cmd,$title,$pod)=@_;
    $_=$title;
    s/\n$//;
    s/E<(.*?)>/&$1;/g;
    # remove any formatting information for the headers
    s/[SFCBI]<(.*?)>/$1/g;         
    # the "don't format me" thing
    s/Z<>//g;
    if ($cmd eq "item") {
        /^\*/ and  return;	# skip bullets
        /^\d+\.?/ and return; 	# skip numbers
        s/(-[a-z]).*/$1/i;
	trim($_);
        return if defined $A->{$pod}->{"Items"}->{$_};
        $A->{$pod}->{"Items"}->{$_} = gensym($pod, $_);
	$index{$A->{$pod}->{"Items"}->{$_}} = $title;
        $A->{$pod}->{"Items"}->{(split(' ',$_))[0]}=$A->{$pod}->{"Items"}->{$_};
        Debug("items", "item $_");
        if (!/^-\w$/ && /([%\$\@\w]+)/ && $1 ne $_ 
    	    && !defined($A->{$pod}->{"Items"}->{$_}) && ($_ ne $1)) 
        {
    	    $A->{$pod}->{"Items"}->{$1} = $A->{$pod}->{"Items"}->{$_};
    	    Debug("items", "item $1 REF TO $_");
        } 
        if ( m{^(tr|y|s|m|q[qwx])/.*[^/]} ) {
    	    my $pf = $1 . '//';
    	    $pf .= "/" if $1 eq "tr" || $1 eq "y" || $1 eq "s";
    	    if ($pf ne $_) {
    	        $A->{$pod}->{"Items"}->{$pf} = $A->{$pod}->{"Items"}->{$_};
    	        Debug("items", "item $pf REF TO $_");
    	    }
	}
    }
    elsif ($cmd =~ /^head[12]/){                
        return if defined($A->{$pod}->{"Headers"}->{$_});
        $A->{$pod}->{"Headers"}->{$_} = gensym($pod, $_);
	$index{$A->{$pod}->{"Headers"}->{$_}} = $title;
        Debug("headers", "header $_");
    } 
    else {
        Debug('misc', "unrecognized header: $cmd");
    } 
}


sub picrefs { 
    my($pod, $char, $bigkey, $lilkey, $htype) = @_;
    my($ref, $podname);
    my $key = '';
    my $marker = '';
    for $podname ($pod,@inclusions){
	my $value = '';
	for $ref ( "Items", "Headers" ) {
	    if (defined($A->{$podname}->{$ref}->{$bigkey})) {
		$key = $bigkey;
		$value = $A->{$podname}->{$ref}->{$key};
		Debug("subs", "bigkey is $bigkey, value is $value\n");
	    } 
	    elsif (defined($A->{$podname}->{$ref}->{$lilkey})) {
		$key = $lilkey;
		$value = $A->{$podname}->{$ref}->{$key};
		return "" if $lilkey eq '';
		Debug("subs", "lilkey is $lilkey, value is $value\n");
	    } 
	} 
	if (length($key)) {
            my ($pod2,$num) = split(/_/,$value,2);
	    $marker = print_marker($htype, $value, "$pod2.$doc_ext");
	    last;
	} 
    }
    if ($char =~ /[IF]/) {
	return "${marker}${lt}italic${gt}$bigkey${lt}noitalic${gt}";
    } elsif($char =~ /C/) {
	return "${marker}${lt}family Courier${gt}$bigkey${lt}family Times${gt}";
    } elsif($char =~ /S/) {
	$bigkey =~ s/ /\177/g;	# hide the spaces

	# Convert tab's to hidden spaces
	while($bigkey =~  s/\t+/"\177" x (length($&) * 8 - length($`) % 8)/e){
	    1;
	}
	$bigkey =~ s/\177/${lt}hardspace${gt}/g;	# make all spaces hard.
	return "${marker}$bigkey";
    } else {
	return "${marker}${lt}bold${gt}$bigkey${lt}nobold${gt}";
    }
} 

sub find_refs { 
    my($pod,$thing,$htype)=@_;
    my($orig) = $$thing;
    # LREF: a manpage(3f) we don't know about
    $$thing=~s/([\$\@%](?!&[gl]t)([\w:]+|\W\b))/varrefs($pod,$1,$htype)/gems;
    $$thing=~s:L<([a-zA-Z][^\s\/]+)(\([^\)]+\))>:the I<$1>$2 manpage:gms;
    $$thing=~s/L<([^>]*)>/lrefs($pod,$1,$htype)/gems;
    $$thing=~s/([CIBF])<(\W*?(-?\w*).*?)>/picrefs($pod, $1, $2, $3, $htype)/gems;
    $$thing=~s/(S)<([^\/]\W*?(-?\w*).*?)>/picrefs($pod, $1, $2, $3, $htype)/gems;
    $$thing=~s/((\w+)\(\))/picrefs($pod, "I", $1, $2,$htype)/gems;
    (($$thing eq $orig) && ($htype eq "NAME")) && 
	($$thing=picrefs($pod, "I", $$thing, "", $htype));
}

sub lrefs {
    my($pod, $page, $item) = split(m#/#, $_[0], 2);
    my($htype)=$_[1];
    my($podname);
    my($section) = $page =~ /\((.*)\)/;
    my $selfref;
    my $text = '';
    my $ref = '';
    if ($page =~ /^[A-Z]/ && $item) {
	$selfref++;
	$item = "$page/$item";
	$page = $pod;
    }  elsif (!$item && $page =~ /[^a-z\-]/ && $page !~ /^\$.$/) {
	$selfref++;
	$item = $page;
	$page = $pod;
    } 
    $item =~ s/\(\)$//;
    if (!$item) {
    	if (!defined $section && defined $Podnames{$page}) {
	    return print_marker("MML", "firstpage", "$page.${doc_ext}")
		. "\nthe ${lt}italic${gt}$page${lt}noitalic${gt} manpage";
	} else {
	    Debug('misc', "Bizarre entry $page/$item");
	    return "the ${lt}italic${gt}$_[0]${lt}noitalic${gt}  manpage\n";
	} 
    } 

    if ($item =~ s/"(.*)"/$1/ || ($item =~ /[^\w\/\-]/ && $item !~ /^\$.$/)) {
	$text = "${lt}italic${gt}$item${lt}noitalic${gt}";
	$ref = "Headers";
    } else {
	$text = "${lt}italic${gt}$item${lt}noitalic${gt}";
	$ref = "Items";
    } 
    for $podname ($pod, @inclusions){
	my $value = undef;
	my $pod2 = '';
	my $num = 0;
	if ($ref eq "Items") {
	    if (defined($value = $A->{$podname}->{$ref}->{$item})) {
		($pod2,$num) = split(/_/,$value,2);
		return print_marker(
		    ($pod eq $pod2) ?
			$htype :
			"MML",
			    $value, "$pod2.$doc_ext"). $text;
            }
        } 
	elsif($ref eq "Headers") {
	    if (defined($value = $A->{$podname}->{$ref}->{$item})) {
		($pod2,$num) = split(/_/,$value,2);
		return print_marker(
		    ($pod eq $pod2) ?
			$htype :
			"MML",
			    $value, "$pod2.$doc_ext"). $text;
            }
	}
    }
    Debug('misc', "No $ref reference for $item (@_)");
    return $text;
} 

sub varrefs {
    my ($pod,$var,$htype) = @_;
    my $value = '';
    for my $podname ($pod,@inclusions){
	if ($value = $A->{$podname}->{"Items"}->{$var}) {
	    my ($pod2,$num) = split(/_/,$value,2);
	    Debug("vars", "way cool -- var ref on $var");
		return print_marker(
		    ($pod eq $pod2) ?
			$htype :
			"MML",
			    $value, "$pod2.$doc_ext"). $var;
	}
    }
    Debug( "vars", "bummer, $var not a var");
    return $var;
} 

my %sawsym = ();
sub gensym {
    my ($podname, $key) = @_;
    $key =~ s/\s.*//;
    ($key = lc($key)) =~ tr/a-z/_/cs;
    my $name = "${podname}_${key}_0";
    $name =~ s/__/_/g;
    while ($sawsym{$name}++) {
        $name =~ s/_?(\d+)$/'_' . ($1 + 1)/e;
    }
    return $name;
} 

sub pre_escapes {   # twiddle these, and stay up late  :-)
    my($thing)=@_;
    $$thing =~ s {
	E<
	( [A-Za-z]+ )
	>
    } {
	do {
	    exists $HTML_Escapes{$1}
		? do { $HTML_Escapes{$1} }
		: do {
		    warn "Unknown escape: $& in $_";
		    "E<$1>";
		}
	}
    }egx;
    $$thing=~s/\\/noremap("\\\\")/eg;
    $$thing=~s/<</noremap("\\<\\<")/eg;
    $$thing=~s/^<|([^ESIBLCF])</$1 . noremap("\\<")/eg;
}
sub noremap {	# adding translator for hibit chars soon
    my $hide = $_[0];
    $hide =~ tr/\000-\177/\200-\377/;
    $hide;
} 

sub post_escapes {
    my($thing)=@_;
    $$thing=~s/^>>|(?=[^GM])>>/\\>\\>/g;
    $$thing=~s/^>|([^D]?[^\\MGA])>/$1\\>/g;
    $$thing=~tr/\200-\377/\000-\177/;	# undo the noremap characters.
}

sub Debug {
    my $level = shift;
    warn @_ if defined $opt_debug{$level};
} 

sub dumptable  {
    my $t = shift;
    print STDERR "TABLE DUMP $t\n";
    foreach my $k (sort keys %$t) {
	printf STDERR "%-20s <%s>\n", $t->{$k}, $k;
    } 
} 
sub trim {
    for (@_) {
        s/^\s+//;
        s/\s\n?$//;
    }
}

BEGIN {

# Create "Safe" '<' and '>' for use in hypertext markers.

$gt = noremap(">");
$lt = noremap("<");

%HTML_Escapes = (
    amp		=> '&',	#   ampersand
    'lt'	=> '<',	#   left chevron, less-than
    'gt'	=> '>',	#   right chevron, greater-than
    quot	=> '"',	#   double quote

    Aacut	=> "${lt}Character \\xe7${gt}",	#   capital A, acute accent
    aacute	=> "${lt}Character \\x87${gt}",	#   small a, acute accent
    Acirc	=> "${lt}Character \\xe5${gt}",	#   capital A, circumflex accent
    acirc	=> "${lt}Character \\x89${gt}",	#   small a, circumflex accent
    AElig	=> "${lt}Character \\xae${gt}",	#   capital AE diphthong (ligature)
    aelig	=> "${lt}Character \\xbe${gt}",	#   small ae diphthong (ligature)
    Agrave	=> "${lt}Character \\xcb${gt}",	#   capital A, grave accent
    agrave	=> "${lt}Character \\x88${gt}",	#   small a, grave accent
    Aring	=> "${lt}Character \\x81${gt}",	#   capital A, ring
    aring	=> "${lt}Character \\x8c${gt}",	#   small a, ring
    Atilde	=> "${lt}Character \\xcc${gt}",	#   capital A, tilde
    atilde	=> "${lt}Character \\x8b${gt}",	#   small a, tilde
    Auml	=> "${lt}Character \\x80${gt}",	#   capital A, dieresis or umlaut mark
    auml	=> "${lt}Character \\x8a${gt}",	#   small a, dieresis or umlaut mark
    Ccedil	=> "${lt}Character \\x82${gt}",	#   capital C, cedilla
    ccedil	=> "${lt}Character \\x8d${gt}",	#   small c, cedilla
    Eacute	=> "${lt}Character \\x83${gt}",	#   capital E, acute accent
    eacute	=> "${lt}Character \\x8e${gt}",	#   small e, acute accent
    Ecirc	=> "${lt}Character \\xe6${gt}",	#   capital E, circumflex accent
    ecirc	=> "${lt}Character \\x90${gt}",	#   small e, circumflex accent
    Egrave	=> "${lt}Character \\xe9${gt}",	#   capital E, grave accent
    egrave	=> "${lt}Character \\x8f${gt}",	#   small e, grave accent
    Euml	=> "${lt}Character \\xe8${gt}",	#   capital E, dieresis or umlaut mark
    euml	=> "${lt}Character \\x91${gt}",	#   small e, dieresis or umlaut mark
    Iacute	=> "${lt}Character \\xea${gt}",	#   capital I, acute accent
    iacute	=> "${lt}Character \\x92${gt}",	#   small i, acute accent
    Icirc	=> "${lt}Character \\xeb${gt}",	#   capital I, circumflex accent
    icirc	=> "${lt}Character \\x90${gt}",	#   small i, circumflex accent
    Igrave	=> "${lt}Character \\xe9${gt}",	#   capital I, grave accent
    igrave	=> "${lt}Character \\x93${gt}",	#   small i, grave accent
    Iuml	=> "${lt}Character \\xec${gt}",	#   capital I, dieresis or umlaut mark
    iuml	=> "${lt}Character \\x95${gt}",	#   small i, dieresis or umlaut mark
    Ntilde	=> "${lt}Character \\x84${gt}",	#   capital N, tilde
    ntilde	=> "${lt}Character \\x96${gt}",	#   small n, tilde
    Oacute	=> "${lt}Character \\xee${gt}",	#   capital O, acute accent
    oacute	=> "${lt}Character \\x97${gt}",	#   small o, acute accent
    Ocirc	=> "${lt}Character \\xef${gt}",	#   capital O, circumflex accent
    ocirc	=> "${lt}Character \\x99${gt}",	#   small o, circumflex accent
    Ograve	=> "${lt}Character \\xf1${gt}",	#   capital O, grave accent
    ograve	=> "${lt}Character \\x98${gt}",	#   small o, grave accent
    Oslash	=> "${lt}Character \\xaf${gt}",	#   capital O, slash
    oslash	=> "${lt}Character \\xbf${gt}",	#   small o, slash
    Otilde	=> "${lt}Character \\xcd${gt}",	#   capital O, tilde
    otilde	=> "${lt}Character \\x9b${gt}",	#   small o, tilde
    Ouml	=> "${lt}Character \\x85${gt}",	#   capital O, dieresis or umlaut mark
    ouml	=> "${lt}Character \\x9a${gt}",	#   small o, dieresis or umlaut mark
    Uacute	=> "${lt}Character \\xf2${gt}",	#   capital U, acute accent
    uacute	=> "${lt}Character \\x9c${gt}",	#   small u, acute accent
    Ucirc	=> "${lt}Character \\xf3${gt}",	#   capital U, circumflex accent
    ucirc	=> "${lt}Character \\x9e${gt}",	#   small u, circumflex accent
    Ugrave	=> "${lt}Character \\xf4${gt}",	#   capital U, grave accent
    ugrave	=> "${lt}Character \\x9d${gt}",	#   small u, grave accent
    Uuml	=> "${lt}Character \\x86${gt}",	#   capital U, dieresis or umlaut mark
    uuml	=> "${lt}Character \\x9f${gt}",	#   small u, dieresis or umlaut mark
    yuml	=> "${lt}Character \\xd8${gt}",	#   small y, dieresis or umlaut mark
);
}

sub mml_header { qq(
<MML>
<Comment \$Id\$ >
<Comment \$Log\$ >
<Comment "Paragraph Format Definition Section">
<!DefinePar pod_Body
    <LeftIndent $BodyLeft">
    <FirstIndent $BodyIndent">
    <WithNext No>
    <SpaceBefore 6pt>
    <SpaceAfter 6pt>
    <BlockSize 2>
    <pts 12>
>
<!DefinePar pod_TITLE
    <LeftIndent 0">
    <FirstIndent 0">
    <WithNext Yes>
    <SpaceBefore 12pt>
    <SpaceAfter 8pt>
    <pts 14>
    <bold>
>
<!DefinePar pod_head1
    <pts 14>
    <WithNext Yes>
    <SpaceBefore 12pt>
    <SpaceAfter 8pt>
    <bold>
>
<!DefinePar pod_head2
    <pts 14>
    <WithNext Yes>
    <SpaceBefore 12pt>
    <SpaceAfter 8pt>
    <bold>
>
<!DefinePar pod_ol
    <pts 12>
    <WithNext No>
    <SpaceBefore 6pt>
    <SpaceAfter 6pt>
    <nobold>
    <LeftIndent $BodyLeft">
    <FirstIndent $BodyLeft">
    <AutoNumber Yes>
    <NumberFormat "+.\\t">
    <TabStops
	<TabStop $ListTab[0]">
	<TabStop $ListTab[1]">
	<TabStop $ListTab[2]">
    >
>
<!DefinePar pod_ul
    <pts 12>
    <WithNext No>
    <SpaceBefore 6pt>
    <SpaceAfter 6pt>
    <nobold>
    <LeftIndent $BodyLeft">
    <FirstIndent $BodyLeft">
    <AutoNumber Yes>
    <NumberFormat "    \\xa5 \\t">
    <TabStops
	<TabStop $ListTab[0]">
	<TabStop $ListTab[1]">
	<TabStop $ListTab[2]">
    >
>
<!DefinePar pod_il
    <pts 12>
    <WithNext No>
    <SpaceBefore 3pt>
    <SpaceAfter 3pt>
    <nobold>
    <LeftIndent $ilLeft">
    <FirstIndent $ilIndent">
    <AutoNumber No>
    <TabStops
	<TabStop $ilTab[0]">
	<TabStop $ilTab[1]">
	<TabStop $ilTab[2]">
    >
>
<!DefinePar pod_dl
    <family Times>
    <pts 12>
    <WithNext No>
    <SpaceBefore 6pt>
    <SpaceAfter 6pt>
    <LeftIndent $dlLeft">
    <FirstIndent $dlIndent">
    <AutoNumber Yes>
    <NumberFormat "\\xa5  ">
>
<!DefinePar pod_hi
    <family Times>
    <pts 12>
    <WithNext No>
    <SpaceBefore 6pt>
    <SpaceAfter 6pt>
    <LeftIndent $BodyLeft">
    <FirstIndent $BodyLeft">
    <AutoNumber No>
    <TabStops
	<TabStop $BodyLeft">
    >
>
<!DefinePar pod_pre
    <family Courier>
    <pts 10>
    <AutoNumber No>
    <LeftIndent $BodyLeft">
    <FirstIndent $BodyLeft">
    <WithNext No>
    <SpaceBefore 0pt>
    <SpaceAfter 0pt>
>

<Comment "Document Layout Section">
<TopMargin $TopMargin>
<BottomMargin $BottomMargin>
<LeftMargin $LeftMargin>
<RightMargin $RightMargin>
<RightFooter "Page #">

<Comment "Document Text Section">
);}
