#! /usr/bin/perl -w
#
# Create an FAQ from a single source file.  Handles both LaTeX and HTML output
# The file uses structured comments to provide information needed to create 
# the HTML, LaTeX, and Text forms of the FAQ, and do divide the faq into
# individual files suitable for use in the req bug-report system
#
# Set Defaults
$is_html           = 1;
$is_complete_html  = 1; 
$is_latex          = 1;
$is_complete_latex = 1;
$is_text           = 1;
$is_dos            = 0;
$use_contracted    = 1;
$faqfilename       = "faq.txt";
$htmlfilename      = "faq.htm";
$latexfilename     = "faq.tex";
$outfilename       = "";
$AddLaTeXMenu      = 0;
@LaTeXSections = ( "section", "subsection" );


# HTML options
$special_entity = 0;

$gDebug = 0;

#
# Read the args
foreach $_ (@ARGV) {
    if (/-elatex=(.*)/) {
	my $topsection = $1;
	$is_latex = 1;
	$is_complete_latex = 0;
	if ($topsection =~ /section/) {
	    @LaTeXSections = ( $topsection, "sub" . $topsection );
	}
	$is_html = 0;
	$is_text = 0;
    }
    elsif (/-latex/) { $is_latex = 1; }
    elsif (/-dosnl/) { $is_dos = 1; }
    elsif (/-outfile=(.*)/) {
	$outfilename = $1;
	if ($is_latex)   { $latexfilename = $outfilename; }
	elsif ($is_html) { $htmlfilename  = $outfilename; }
	elsif ($is_text) { $faqfilename   = $outfilename; }
    }
    else {
	print STDERR "Unrecognized arg $_\n";
    }
}

# Set values that may depend on command line options
if ($is_dos) {
    $nl = "\r\n";
}
else {
    $nl = "\n";
}

# Translations from the LaTeX allowed in faq.txt to HTML
%latexCmdToHtml = ( 'file' => '1:<tt>\1</tt>',
		    'textem' => '1:<em>\1</em>',
		    'textbf' => '1:<b>\1</b>',
		    'textrm' => '1:\1',
		    'emph'   => '1:<em>\1</em>',
		    'texttt' => '1:<tt>\1</tt>',
		    'url' => '1:<a href="\1">\1</a>',
		    'href' => '2:<a href="\1">\2</a>',
		    'item'   => '0:<li>',
		    'par'    => '0:<p>',
		    'begin'  => '1:',
		    'end'    => '1:',
		    'begin-verbatim' => '0:<pre>',
		    'end-verbatim' => '0:</pre>',
		    'begin-itemize' => '0:<menu>',
		    'end-itemize' => '0:</menu>',
		    'begin-enumerate' => '0:<ol>',
		    'end-enumerate' => '0:</ol>',
		    'begin-small' => '0:<font size=-1>',
		    'end-small'   => '0:</font>',
		    'paragraph'   => '1:<h3>\1</h3>',
		    'noindent'    => '0:',
		    '#'           => '0:#',
		    '_'           => '0:_',
		    '{'           => '0:{',
		    '}'           => '0:}',
		    );

# Translations from the LaTeX allowed in faq.txt to ASCII text
%latexCmdToText = ( 'file' => '1:\'\1\'',
		    'textem' => '1:\1',
		    'textbf' => '1:\1',
		    'textrm' => '1:\1',
		    'emph'   => '1:\1',
		    'texttt' => '1:\1',
		    'url' => '1:\1',
		    'href' => '2:\2(\1)',
		    'item'   => '0:* ',
		    'par'    => '0:',
		    'begin'  => '1:',
		    'end'    => '1:',
		    'begin-verbatim' => '0:',
		    'end-verbatim' => '0:',
		    'begin-itemize' => '0:',
		    'end-itemize' => '0:',
		    'begin-enumerate' => '0:',
		    'end-enumerate' => '0:',
		    'begin-small' => '0:',
		    'end-small'   => '0:',
		    'paragraph'   => '1:\1',
		    'noindent'    => '0:',
		    '#'           => '0:#',
		    '_'           => '0:_',
		    '{'           => '0:{',
		    '}'           => '0:}',
		    );
#
# Process the file
$FD = FD;
open $FD, "<$faqfilename" || die "Could not open $faqfilename";

@filelist      = ();      # List of files
%fileToHeading = ();      # indexed by filename, the heading
%fileToText    = ();      # indexed by filename, the text
%IndexToSectionHead = (); # maps an index into @filelist into a heading
                          # (defined by %% Section:) used to group items

$inItem = 0;
$itemText = "";
$heading = "";
$shortfile = "";
while (<$FD>) {
    # Get the next heading
    print "Read $_" if $gDebug;
    if (/^%%/) {
	if ($inItem) {
	    # Finish off this item
	    &processItem( $heading, $shortfile, $itemText );
	    $fileToText{$shortfile} = $itemText;
	    $inItem = 0;
	    $itemText = "";
	}
	($heading,$shortfile)      = &ReadHeading( $_, $FD );
	$filelist[$#filelist+1]    = $shortfile;
	$fileToHeading{$shortfile} = $heading;
	$inItem = 1;
    }
    elsif (/^\s*%/) {
	# Skip a comment line
	next;
    }
    else {
	$itemText .= $_;
    }
}
close $FD;

if ($inItem) {
    # Finish off this item (only does something for now when generating
    # text)
    &processItem( $heading, $shortfile, $itemText );
    $fileToText{$shortfile} = $itemText;
}

if ($is_html) {
    open HTMLFD, ">$htmlfilename" || die "Could not open $htmlfilename";
    &CreateHTMLHeader();
    &CreateHTMLMenu();
    &CreateHTMLBody();
    &CreateHTMLTail();
    close HTMLFD;
}
if ($is_latex) {
    open LATEXFD, ">$latexfilename" || die "Could not open $latexfilename";
    &CreateLatexHeader();
    if ($AddLaTeXMenu) {
	# Only add the menu if requested (it isn't as useful for 
	# LaTeX versions of the FAQ)
	&CreateLatexMenu();
    }
    &CreateLatexBody();
    &CreateLatexTail();
    close LATEXFD;
}

exit(0);

# -------------------------------------------------------------------------
# Support routines 
# -------------------------------------------------------------------------
sub ReadHeading {
    my ($line,$FD) = @_;
    my $heading = "";
    my $shortfile = "";
    my $foundEnd = 0;
    while ($line =~ /^%%/) {
	if ($line =~ /%%\s*[Hh][Ee][Aa][Dd][Ii][Nn][Gg]:\s*(\S.*\S)\s*/) {
	    $heading = $1;
	    while ($heading =~ /\\$/) {
		$heading =~ s/\\$//;
		$line = <$FD>;
		$line =~ s/\r?\n//;
		if ($line =~ /^\s*%/) {
		    $line =~ s/^\s*%*//;
		    print STDERR "Heading continuation lines do not need to start with %%\n";
		}
		$heading .= $line;
	    }
	}
	elsif ($line =~ /%%\s*[Ff][Ii][Ll][Ee]\s*[Nn][Aa][Mm][Ee]:\s*(\S.*\S)\s*/) {
	    $shortfile = $1;
	}
	elsif ($line =~ /%%\s*[Ee][Nn][Dd]/) {
	    $foundEnd = 1;
	    last;
	}
	elsif ($line =~ /%%\s*[Ss][Ee][Cc][Tt][Ii][Oo][Nn]:\s*(\S.*\S)\s*/) {
	    my $nextItem = $#filelist+1;
	    $IndexToSectionHead{$nextItem} = $1;
	}
	elsif ($line =~ /%%\s*(\S.*)/) {
	    print STDERR "Unrecognized heading $1\n";
	}
	$line = <$FD>;
	print "(ReadHeading) Read $line" if $gDebug;
    }
    if (! $foundEnd) {
	print STDERR "Malformed heading entry; no %% End found\n";
	if ($heading ne "") {
	    print STDERR "Heading was $heading\n";
	}
    }
    if ($shortfile eq "") {
	print STDERR "Malformed heading entry; no %% Filename: found\n";
	if ($heading ne "") {
	    print STDERR "Heading was $heading\n";
	}
    }
    return ($heading,$shortfile);
}

sub processItem {
    my ($heading, $shortfile, $itemText ) = @_;

    if ($is_text) {
	# Create the text file version
	if ("$shortfile.txt" eq "$faqfilename") {
	    print STDERR "Warning! Short name $shortfile.txt conflicts with FAQ source file name\n";
	    return;
	}
	open TFD, ">$shortfile.txt" || die "Cannot open $shortfile.txt"; 
	my $textheading = &textify( $heading );
	# Add a : to the end of the heading if there is no punctuation
	# there already
	if (! ($textheading =~ /[:\?\!\;\.]$/) ) {
	    $textheading .= ":";
	}
	print TFD "$textheading\n";
	foreach $line (split(/\n/,$itemText)) {
	    print TFD &textify( $line ). "\n";
	}
	close TFD;
    }
}

# Take the input and make it value HTML (handle simple LaTeX)
sub htmlify {
    $line = $_[0];

    # Fix HTML reserved characters
    $line =~ s%[\\]+&%&amp;%g;
    $line =~ s%[\\]+<%&lt;%g;
    $line =~ s%[\\]+>%&gt;%g;

    # These may occur within a verbatim environment
    # (We hope not to see a raw &, since we'd also need to 
    # watch for &amp;.
    #$line =~ s%&%&amp;%g;
    $line =~ s%<%&lt;%g;
    $line =~ s%>%&gt;%g;

    # Convert various TeX commands
    # $...$
    $line =~ s%\$([^\$]*)\$%<EM>$1</EM>%g;
    # \\file (so that ~ in file is handled as literal
    $line =~ s%\\file{~([^\}]*)}%<TT>--TILDE--$1</TT>%;
    $line =~ s%\\file{([^\}]*)}%<TT>$1</TT>%;
    # ~
    $line =~ s%([^\\]{1})~%$1&nbsp;%g;
    # Undo the --TILDE--
    $line =~ s%--TILDE--%~%;
    # \textrm{} (currently only strips out the command)
    $line =~ s%\\textrm{([^}]*)}%$1%g;
    # \textem{} (set to em, won't work if nested)
    $line =~ s%\\textem{([^}]*)}%<EM>$1</EM>%g;
    # \emph{} (set to em, won't work if nested)
    $line =~ s%\\emph{([^}]*)}%<EM>$1</EM>%g;
    # \texttt{} (set to tt, won't work if nested)
    $line =~ s%\\texttt{([^}]*)}%<TT>$1</TT>%g;
    # \url{} 
    $line =~ s%\\url{([^}]*)}%<A HREF=\"$1\">$1</A>%g;
    # {\tt ... }
    if ($announce_oldstyle && /\\tt /) {
        print STDERR "line $line_count: \\tt in $original_line";
    }
    $line =~ s%{\\tt([^}]*)}%<TT>$1</TT>%g;
    # {\it ... }
    if ($announce_oldstyle && /\\it /) {
        print STDERR "line $line_count: \\it in $original_line";
    }
    $line =~ s%{\\it([^}]*)}%<EM>$1</EM>%g;
    # \~{ }
    $line =~ s%\\~\{\s*\}%~%g;
    # verbatim
    $line =~ s%\\begin\{verbatim\}%<PRE>%;
    $line =~ s%\\end\{verbatim\}%</PRE>%;
    # itemize
    $line =~ s%\\begin\{itemize\}%<MENU>%;
    $line =~ s%\\end\{itemize\}%</MENU>%;
    $line =~ s%\\item%<LI>%;
    # enumerate
    $line =~ s%\\begin\{enumerate\}%<OL>%;
    $line =~ s%\\end\{enumerate\}%</OL>%;
    # small
    $line =~ s%\\begin\{small\}%<FONT SIZE=-1>%;
    $line =~ s%\\end\{small\}%</FONT>%;
    # urlname
    $line =~ s%\\urlname{([^\}]*)}{([^\}]*)}%<A HREF=\"$1\">$2</A>%;
    # \\paragraph
    $line =~ s%\\paragraph{([^\}]*)}%<H3>$1</H3>%;
    # \\code.  May contain <> &, (without \), so fix those up.
    while ($line =~ /\\code{([^\}]*)}/) {
	$codearg = $1;
	$codearg =~ s%\&%&amp;%g;
        $codearg =~ s%<%&lt;%g;
        $codearg =~ s%>%&gt;%g;
	$line =~ s%\\code{[^\}]*}%<TT>$codearg</TT>%;
    }
#    $line =~ s%\\code{([^\}]*)}%<TT>\1</TT>%g;
    # \\ (linebreak)
    $line =~ s%\\\\%<BR>%;
    # \noindent
    $line =~ s%\\noindent%%;
    # \par
    $line =~ s%\\par%<P>%;
    # \#
    $line =~ s%\\#%#%g;
    # \o
    $line =~ s%\\o([^A-Za-z]{1})%&oslash;$1%g;
    # \O
    $line =~ s%\\O([^A-Za-z]{1})%&Oslash;$1%g;
    # _{} -> <SUB>...</SUB>
    # ^{} -> <SUP>...</SUP>
    # \_ -> _
    $line =~ s%\\_%_%g;
    # \{ -> {
    # \} -> }
    # \(.*\) -> <EM>...</EM>
    # \'{letter} {} is optional
    $line =~ s%\\'\{([AEIOUYaeiouy]{1})\}%&$1acute;%;
    $line =~ s%\\'([AEIOUYaeiouy]{1})%&$1acute;%;
    # \~
    $line =~ s%\\~\{([ANOano]{1})\}%&$1tilde;%;
    $line =~ s%\\~([ANOano]{1})%&$1tilde;%;
    # \"
    $line =~ s%\\"\{([AEIOUaeiou]{1})\}%&$1uml;%;
    $line =~ s%\\"([AEIOUYaeiouy]{1})%&$1uml;%;
    # \`
    $line =~ s%\\`\{([AEIOUaeiou]{1})\}%&$1grave;%;
    $line =~ s%\\`([AEIOUaeiou]{1})%&$1grave;%;
    #
    # \.
    $line =~ s%\\`\{([AEIOUaeiou]{1})\}%&$1circ;%;
    $line =~ s%\\`([AEIOUaeiou]{1})%&$1circ;%;
    # --- -> &mdash;
    $line =~ s%---%&mdash;%g if $special_entity;
    # -- -> &ndash;
    $line =~ s%--%&ndash;%g if $special_entity;
    
    # Turn URLs into links in $_
    s%(http:[^ }"]*)%<A HREF="$1">$1</A>%g;
    s%(ftp:[^ }"]*)%<A HREF="$1">$1</A>%g;

    # Process \mpich and \ 
    $line =~ s%\\mpich%MPICH%g;
    $line =~ s%\\ % %g;

    return $line;
}

# -------------------------------------------------------------------------
# LaTeX special routines
sub CreateLatexHeader {
    if ($is_complete_latex) {
	print LATEXFD '\documentclass{article}
\usepackage[dvipdfm]{hyperref}
\begin{document}
\title{MPICH2 FAQ}
\maketitle
';
    }
}

#
# Create an itemized list of sections, with an enumerated list of topics
# within each section
sub CreateLatexMenu {
    # Create headings
    my $inEnumerate = 0;
    print LATEXFD "\\section{List of FAQ Items}\n";
    print LATEXFD "\\begin{itemize}\n";
    for (my $i=0; $i<=$#filelist; $i++) {
	if (defined($IndexToSectionHead{$i})) {
	    if ($inEnumerate) {
		print LATEXFD "\\end{enumerate}\n";
		$inEnumerate = 0;
	    }
	    print LATEXFD "\\item " . $IndexToSectionHead{$i} . "\n";
	}
	my $file = $filelist[$i];
	my $heading = $fileToHeading{$file};
	if (! $inEnumerate) {
	    print LATEXFD "\\begin{enumerate}\n";
	    $inEnumerate = 1;
	}
	print LATEXFD "\\item $heading\n";
    }
    if ($inEnumerate) {
	print LATEXFD "\\end{enumerate}\n";
    }
    print LATEXFD "\\end{itemize}\n";
}

sub CreateLatexBody {
    # Create items
    $topsection = $LaTeXSections[0];
    $subsection = $LaTeXSections[1];

    for (my $i=0; $i<=$#filelist; $i++) {
	my $file = $filelist[$i];
	my $heading = $fileToHeading{$file};
	if (defined($IndexToSectionHead{$i})) {
	    print LATEXFD "\\${topsection}{" . $IndexToSectionHead{$i} . "}\n";
	}
	print LATEXFD "\\${subsection}{$heading}\n";
	foreach $line (split(/\n/,$fileToText{$file})) {
	    print LATEXFD $line . "\n";
	}
    }
}

sub CreateLatexTail {
    if ($is_complete_latex) {
	print LATEXFD "\\end{document}\n";
    }
}

# -------------------------------------------------------------------------
# HTML Special Routines
sub CreateHTMLHeader {
    if ($is_complete_html) {
	print HTMLFD "<HTML>$nl<HEAD>$nl<TITLE>MPICH Frequently Asked Questions</TITLE>$nl";
	print HTMLFD "<!-- This FAQ automatically generated by faqbuild.  Do not edit -->$nl";
	print HTMLFD "</HEAD>$nl";
	print HTMLFD "<style type=\"text/css\">\
<!--\
dt { font-weight: bold; \
     margin-top: 2em;\
    }\
h2 { background:#DDDDFF; text-align:center }\
-->\
</style>$nl";

	if ($use_contracted) {
	    print HTMLFD "<style>$nl    .expanded { display:\"block\" }$nl";
	    print HTMLFD "    .contracted { display:\"none\" }$nl</style>$nl";
	    print HTMLFD "<body bgcolor=\"FFFFFF\" onload=\"$nl";
	    for (my $i=0; $i<=$#filelist; $i++) {
		print HTMLFD "    answer$i.className='contracted';$nl";
	    }
	    print HTMLFD "\">$nl";
	}
	else {
	    print HTMLFD "<body bgcolor=\"FFFFFF\">$nl";
	}
    }
    print HTMLFD "<h1>MPICH2 Frequently Asked Questions</h1>$nl";

}

sub CreateHTMLMenu {
    # Create the expand/contract all list 
    if ($use_contracted) {
	# style="background-color:#CCFFCC etc may be used within the <span>
	# element
	print HTMLFD "If you do not see the descriptions, click on the item to get$nl";
	print HTMLFD "a description of the topic.  Double-click to hide the description.$nl";
	print HTMLFD "These two items may be used$nl";
	print HTMLFD "to expand and collapse all entries:<br>$nl";
	print HTMLFD "<span onclick=\"$nl";
	for (my $i=0; $i<=$#filelist ; $i++) {
	    print HTMLFD "    answer$i.className='expanded';$nl";
	}
	print HTMLFD "\">Press to <b>Expand</b> all answers</span><br>$nl";
	print HTMLFD "<span onclick=\"";
	for (my $i=0; $i<=$#filelist ; $i++) {
	    print HTMLFD "    answer$i.className='contracted';$nl";
	}
	print HTMLFD "\">Press to <b>Collapse</b> all answers</span><br>$nl";
	print HTMLFD "<hr>$nl";
    }
    my $inMenu = 0;
    for (my $i=0; $i<=$#filelist; $i++) {
	my $file = $filelist[$i];
	if (defined($IndexToSectionHead{$i})) {
	    if ($inMenu) {
		print HTMLFD "</menu>$nl";
		$inMenu = 0;
	    }
	    print HTMLFD "<font size=+1>" . 
		&htmlify2($IndexToSectionHead{$i}) . "</font><br>$nl";
	}
	my $heading = &htmlify2( $fileToHeading{$file} );
	if (!$inMenu) {
	    print HTMLFD "<menu>$nl";
	    $inMenu = 1;
	}
	print HTMLFD "<li> <a href=\"\#$file\" onclick=\"answer$i.className='expanded'\">$heading</a>$nl";
    }
    if ($inMenu) {
	print HTMLFD "</menu>$nl";
    }
}

sub CreateHTMLBody {
    for (my $i=0; $i<=$#filelist; $i++) {
	my $file = $filelist[$i];
	my $heading = &htmlify2( $fileToHeading{$file} );
	if ($use_contracted) {
	    print HTMLFD "<h2 onclick=\"answer$i.className='expanded'\"$nl";
	    print HTMLFD "ondblclick=\"answer$i.className='contracted'\"><a name=\"$file\">$heading</a></h2>$nl";
	}
	else {
	    print HTMLFD "<h2><a name=\"$file\">$heading</a></h2>$nl";
	}
	print HTMLFD "<div id=\"answer$i\">$nl";
	foreach my $line (split(/\n/,$fileToText{$file})) {
	    if ($line =~ /</) { print "Saw less than: $line\n" ; }
	    $line = &tophtmlify2( $line );
	    print HTMLFD &htmlify2($line) . $nl;
	}
	print HTMLFD "</div>$nl";
    }
}
sub CreateHTMLTail {
    if ($is_complete_html) {
	print HTMLFD "</BODY>$nl</HTML>$nl";
    }
}

# Tophtmlify2 just handles the three special html characters (<,>,&)
# by making them look like \<, \>, and \&, which htmlify2 can handle.
# This is done to avoid processing HTML commands
sub tophtmlify2 {
    my $line = $_[0];

    my $before = "";
    my $after  = $line;
    while ($after =~ /([^<>&]*)([<>&])(.*)/) {
	$before .= $1;
	my $cmd = $2;
	$after  = $3;
	if (! ($before =~ /\\$/)) {
	    $before .= "\\";
	}
	$before .= $cmd;
    }
    $line = $before . $after;

    return $line;
}

sub htmlify2 {
    my $line = $_[0];

    $line =~ s%[\\]+&%&amp;%g;
    $line =~ s%[\\]+<%&lt;%g;
    $line =~ s%[\\]+>%&gt;%g;

    #$line =~ s%[\\]+&%&amp;%g;
    #$line =~ s%<%&lt;%g;
    #$line =~ s%>%&gt;%g;

    # --- -> &mdash;
    $line =~ s%---%&mdash;%g if $special_entity;
    # -- -> &ndash;
    $line =~ s%--%&ndash;%g if $special_entity;

    return &deLaTeX( $line, \%latexCmdToHtml );
}

sub textify {
    my $line = $_[0];
    return &deLaTeX( $line, \%latexCmdToText );
}

# Take the input and make it value HTML (handle simple LaTeX)
sub deLaTeX {
    my ($line, $cmdhash) = @_;

    if (!defined($line)) { return ""; }

    my $before = "";
    my $after  = "";

    while ($line =~ /([^\\]*)\\(\w+)(.*)/) {
	$before .= $1;
	my $cmd = $2;
	$after = $3;
	if ($cmd =~ /^([^A-Za-z])(.*)/) {
	    $cmd = $1;
	    $after = $2 . $after;
	}
	if (defined($$cmdhash{$cmd})) {
	    my $val = $$cmdhash{$cmd};
	    if ($val =~ /(\d+):(.*)/) {
		$argcount    = $1;
		$val         = $2;
	    }
	    else {
		print STDERR "Internal error in comamnd format for $cmd = $val\n";
		$before .= $cmd;
		$line   = $after;
		next;
	    }
	    # Get the arguments, if any.
	    my @args = ();
	    for (my $i=0; $i<$argcount; $i++) {
		if ($after =~ /^{([^{}]*)}(.*)/) {
		    $args[$i] = $1;
		    $after    = $2;
		}
		else {
		    print STDERR "Could not find expected argument $i for $cmd\n";
		    last;
		}
	    }
	    # Handle special options (e.g., \begin{name}
	    if ($cmd eq 'begin') {
		if ($argcount == 1) {
		    $argcount = 0;
		    my $name = $args[0];
		    $cmd = "begin-$name";
		    if (defined($$cmdhash{$cmd})) {
			$val = $$cmdhash{$cmd};
			$val =~ s/^\d+://;
		    }
		    else {
			print STDERR "Unrecognized Latex environment $args[0]\n";
		    }
		}
		else {
		    print STDERR "\\begin with no name\n";
		}
	    }
	    elsif ($cmd eq 'end') {
		if ($argcount == 1) {
		    $argcount = 0;
		    $cmd = "end-$args[0]";
		    if (defined($$cmdhash{$cmd})) {
			$val = $$cmdhash{$cmd};
			$val =~ s/^\d+://;
		    }
		    else {
			print STDERR "Unrecognized Latex environment $args[0]\n";
		    }
		}
		else {
		    print STDERR "\\end with no name\n";
		}
	    }

	    # Substitute the arguments
	    for (my $i=1; $i<=$argcount; $i++) {
		if (!defined($args[$i-1])) {
		    $args[$i-1] = "";
		}
		$val =~ s/\\$i/$args[$i-1]/g;
	    }
	    # Handle simple recursion (e.g., \_ within an argument)
	    $val = &htmlify2($val);
	    $before .= $val;
	}
	else {
	    print STDERR "Unrecognized command $cmd\n";
	}
	$line   = $after;
    }
    $line = $before . $line;

#     # Fix HTML reserved characters
#     $line =~ s%[\\]+&%&amp;%g;
#     $line =~ s%[\\]+<%&lt;%g;
#     $line =~ s%[\\]+>%&gt;%g;
#     # Convert various TeX commands
#     # $...$
#     $line =~ s%\$([^\$]*)\$%<EM>$1</EM>%g;
#     # \\file (so that ~ in file is handled as literal
#     $line =~ s%\\file{~([^\}]*)}%<TT>--TILDE--\1</TT>%;
#     # ~
#     $line =~ s%([^\\]{1})~%$1&nbsp;%g;
#     # Undo the --TILDE--
#     $line =~ s%--TILDE--%~%;
#     # {\tt ... }
#     if ($announce_oldstyle && /\\tt /) {
#         print STDERR "line $line_count: \\tt in $original_line";
#     }
#     $line =~ s%{\\tt([^}]*)}%<TT>$1</TT>%g;
#     # {\it ... }
#     if ($announce_oldstyle && /\\it /) {
#         print STDERR "line $line_count: \\it in $original_line";
#     }
#     $line =~ s%{\\it([^}]*)}%<EM>$1</EM>%g;
#     # \~{ }
#     $line =~ s%\\~\{\s*\}%~%g;
#     # \\code.  May contain <> &, (without \), so fix those up.
#     while ($line =~ /\\code{([^\}]*)}/) {
# 	$codearg = $1;
# 	$codearg =~ s%\&%&amp;%g;
#         $codearg =~ s%<%&lt;%g;
#         $codearg =~ s%>%&gt;%g;
# 	$line =~ s%\\code{[^\}]*}%<TT>$codearg</TT>%;
#     }
# #    $line =~ s%\\code{([^\}]*)}%<TT>\1</TT>%g;
#     # \\ (linebreak)
#     $line =~ s%\\\\%<BR>%;
#     # \o
#     $line =~ s%\\o([^A-Za-z]{1})%&oslash;$1%g;
#     # \O
#     $line =~ s%\\O([^A-Za-z]{1})%&Oslash;$1%g;
#     # _{} -> <SUB>...</SUB>
#     # ^{} -> <SUP>...</SUP>
#     # \(.*\) -> <EM>...</EM>
#     # \'{letter} {} is optional
#     $line =~ s%\\'\{([AEIOUYaeiouy]{1})\}%&$1acute;%;
#     $line =~ s%\\'([AEIOUYaeiouy]{1})%&$1acute;%;
#     # \~
#     $line =~ s%\\~\{([ANOano]{1})\}%&$1tilde;%;
#     $line =~ s%\\~([ANOano]{1})%&$1tilde;%;
#     # \"
#     $line =~ s%\\"\{([AEIOUaeiou]{1})\}%&$1uml;%;
#     $line =~ s%\\"([AEIOUYaeiouy]{1})%&$1uml;%;
#     # \`
#     $line =~ s%\\`\{([AEIOUaeiou]{1})\}%&$1grave;%;
#     $line =~ s%\\`([AEIOUaeiou]{1})%&$1grave;%;
#     #
#     # \.
#     $line =~ s%\\`\{([AEIOUaeiou]{1})\}%&$1circ;%;
#     $line =~ s%\\`([AEIOUaeiou]{1})%&$1circ;%;
#     # --- -> &mdash;
#     $line =~ s%---%&mdash;%g if $special_entity;
#     # -- -> &ndash;
#     $line =~ s%--%&ndash;%g if $special_entity;
    
#     # Turn URLs into links in $_
#     s%(http:[^ }"]*)%<A HREF="$1">$1</A>%g;
#     s%(ftp:[^ }"]*)%<A HREF="$1">$1</A>%g;

#     # Process \mpich and \ 
#     $line =~ s%\\mpich%MPICH%g;
#     $line =~ s%\\ % %g;

    return $line;
}
