#######################################################################
#                             HTMLTOTEX                               #
#                                                                     #
#              converts html files to plain TeX files                 #
#                                                                     #
#                   AUTHOR: Abhijit Das (Barda)                       #
#           Department of Computer Science and Automation             #
#                   Indian Institute of Science                       #
#                    Bangalore 560 012  India                         #
#                 e-mail: abhij@csa.iisc.ernet.in                     #
#            URL: http://www2.csa.iisc.ernet.in/~abhij/               #
#                                                                     #
#                          VERSION: 1.1                               #
#                    LAST MODIFIED: Dec 8 1997                        #
#######################################################################
sub helpMessage {
print STDERR <<EOM;
Usage:
       htmltotex [-a] [-b base_url] [-c] [-d|-g] [-f]  [-F]  [-h]
       [-i|-I]  [-ip  macro_file]  [-L lib_dir] [-lf left_footer]
       [-lh left_header] [-m image_dir] [-o output_file] [-p num]
       [-P]   [-pt   num]   [-r   num]  [-rf  right_footer]  [-rh
       right_header]  [-t  temp_dir]  [-u]  [-v]  [-V]  [-w  num]
       input_file
For detailed help run "htmltotex -h"
EOM
exit(1);
}

sub detailedHelpMessage {
print STDERR <<EOM;
Usage: htmltotex [Options] input_file
Options:
-a          show details of applet tags
-b BASEURL  set base URL to BASEURL (default: file:<input_file>)
            (overwritten by the BASE tag in the input file)
-c          retain html comments in TeX file
-d          convert images in black-and-white dithered mode
-f          show details of the form tags
-F          use scaled versions of 10pt computer modern fonts
-g          convert images in gray scale
-h          print this help message
-i          do not put in-line images, show the argument to ALT
-I          do not put in-line images, do not show the argument to ALT
-ip FILE    input TeX macro/preamble file
-L LIBDIR   append LIBDIR to the list of directories for searching
            the library files
-lf LFTR    set left-footer to LFTR
-lh LHDR    set left-header to LHDR
-m IMGDIR   put postscript files for in-line images in IMGDIR
            (default: directory of the input file)
-o OUTFILE  output TeX file to OUTFILE (default: STDOUT)
-p NUM      set starting page number to NUM
-P          suppress page numbering
-pt NUM     set point size of plain text to NUM (default: 10)
-r 0|1|2|3  set running mode of output TeX file (default: 0)
-rf RFTR    set right footer to RFTR
-rh RHDR    set right header to RHDR
-t TMPDIR   set temp directory for intermediate files (default: /tmp/)
-u          underline anchors
-v          verbose mode
-V          print version and quit
-w NUM      set cell width in tables to NUM centimeters
EOM
exit(1);
}

sub initialize {
    # default parameter values
   ($appletDetails, $formDetails, $includeComments) = (0,0,0);
   ($baseURL, $baseDir, $baseProtocol) = ("", "./", "file");;
   ($imageMode, $imageCol) = (0,0);
   $figno = 0;
   ($leftFooter, $leftHeader, $rightFooter, $rightHeader) = ("","","","");
   ($tmpDir, $imgDir) = ("/tmp/","./");
   $startPage = 1;
   ($showPage, $ulAnchors, $verbose) = (1,0,0);
   $normalSize = 10; $cellWidth="3cm"; $useScaledFonts = 0;
   *OUTFILE = *STDOUT;
   ($prmbFile, $outputFile, $inputFile) = ("","","");
   $libPath = "/usr/local/lib/htmltotex:/usr/local/htmltotex:~/.htmltotex:.";
   $runMode = 0; $infinity = 20000; $imbalance = 0;

   # default resource values
   $httpdHome = "/usr/local/etc/httpd/htdocs/";
   $pubHtmlDir = "public_html/";
   $localHost = `uname -n`; chop($localHost);
}

sub splitURL {
   local $URL = $_[0];
   local $protocol = $baseProtocol;
   local $dir = $baseDir;
   local $file = $URL;
   local $nextIndex;
   local $serverName = "";
   local $userName = "";
   $nextIndex = index($URL,":",0);
   if ($nextIndex != -1) {
      $protocol = substr($URL,0,$nextIndex);
      $file = substr($URL,$nextIndex + 1);
   }
   if ($protocol eq "http") {
      if ($file =~ /^\/\//) {
         $file = substr($file,2);
         $nextIndex = index($file,"/");
         if ($nextIndex == -1) {
            $serverName = $file;
            $file = $httpdHome;
         } else {
            $serverName = substr($file,0,$nextIndex);
            $file = substr($file, $nextIndex + 1);
            if (index($file,"~") == 0) {
               $nextIndex = index($file,"/");
               if ($nextIndex == -1) {
                  $userName = $file;
                  $file = "";
               } else {
                  $userName = substr($file,0,$nextIndex);
                  $file = substr($file,$nextIndex + 1);
               }
               $userDir = `dirname $userName/junk`;
               chop $userDir;
               $file = "$userDir/$pubHtmlDir$file";
            } else {
               $file = $httpdHome . $file;
            }
         }
         unless ($localHost =~ /(^|:)$serverName(:|$)/i) {
            print STDERR "Remote files from \"$serverName\" are not loaded\n";
            return ($baseProtocol, $baseDir, $file);
         }
      } else {
         if (substr($file,0,1) eq "~") {
            $nextIndex = index($file,"/");
            if ($nextIndex == -1) {
               $userName = $file;
               $file = "";
            } else {
               $userName = substr($file,0,$nextIndex);
               $file = substr($file,$nextIndex + 1);
            }
            $userDir = `dirname $userName/junk`;
            chop $userDir;
            $file = "$userDir/$pubHtmlDir$file";
         } elsif (substr($file,0,1) eq "/") {
            $file = $httpdHome . substr($file,1);
         } else {
            $file = $baseDir . $file;
         }
      }
   } elsif ($protocol eq "file") {
      if (index($file,"/",0) != 0) {
         if (index($file,"~",0) == 0) {
            $file =~ /(~.*?)($|\/)/;
            $userName = $1;
            $userDir = `dirname $userName/junk`;
            chop $userDir;
            $file =~ s/~.*?($|\/)/$userDir\//;
         } else {
            $file = $baseDir . $file;
         }
      }
   } else {
      print STDERR "WARNING: Unknown protocol \"$protocol\"\n";
      return ($baseProtocol, $baseDir, $file);
   }
   if ($file =~ /\/$/) {
      return ($protocol, $file, "");
   }
   $nextIndex = rindex($file,"/");
   if ($nextIndex == -1) {
      if (index($file,"~") == 0) {
        return ($protocol, "$file/", "");
      }
      $dir = "./";
   } else {
      $dir = substr($file,0,$nextIndex + 1);
      $file = substr($file,$nextIndex + 1);
   }
   if ((-e "$dir$file") && (-d "$dir$file")) {
      return ($protocol, "$dir$file/", "");
   }
   return ($protocol, $dir, $file);
}

sub processCmdLine {
   if (!($ARGV[0])) {
      print STDERR "Error: Too few arguments\n";
      helpMessage;
   }
   $nargs = $#ARGV + 1;
   for ($i=0; $i<$nargs; $i++) {
      if (substr($ARGV[$i],0,1) eq "-") {
         $option = substr($ARGV[$i],1);
         if ($option eq "a") {
            $appletDetails = 1;
         } elsif ($option eq "c") {
            $includeComments = 1;
         } elsif ($option eq "d") {
            if ($imageCol == 1) {
               print STDERR "Error: You must not specify -d and -g simultaineously\n";
               exit(1);
            } else {
               $imageCol = 2;
            }
         } elsif ($option eq "f") {
            $formDetails = 1;
         } elsif ($option eq "F") {
            $useScaledFonts = 1;
         } elsif ($option eq "g") {
            if ($imageCol == 2) {
               print STDERR "Error: You must not specify -d and -g simultaineously\n";
               exit(1);
            } else {
               $imageCol = 1;
            }
         } elsif ($option eq "h") {
            detailedHelpMessage;
         } elsif ($option eq "i") {
            if ($imageMode == 2) {
               print STDERR "Error: You must not specify -i and -I simultaineously\n";
               exit(1);
            } else {
               $imageMode = 1;
            }
         } elsif ($option eq "I") {
            if ($imageMode == 1) {
               print STDERR "Error: You must not specify -i and -I simultaineously\n";
               exit(1);
            } else {
               $imageMode = 2;
            }
         } elsif ($option eq "P") {
            $showPage = 0;
         } elsif ($option eq "u") {
            $ulAnchors = 1;
         } elsif ($option eq "v") {
            $verbose = 1;
         } elsif ($option eq "V") {
            print STDERR "htmltotex: Version 1.1 ...\n";
            print STDERR "Author: Abhijit Das (abhij\@csa.iisc.ernet.in)\n";
            print STDERR "Last modified: Dec 8 1997\n";
            exit(0);
         } elsif ($option eq "b") {
            if ($i == $nargs - 1) {
               print STDERR "Error: No base URL specified for option -b\n";
               helpMessage;
            } else {
               $baseURL = $ARGV[++$i];
            }
         } elsif ($option eq "ip") {
            if ($i == $nargs - 1) {
               print STDERR "Error: No input file specified for option -ip\n";
               helpMessage;
            } else {
               $prmbFile = $ARGV[++$i];
            }
         } elsif ($option eq "L") {
            if ($i == $nargs - 1) {
               print STDERR "Error: No directory specified for option -L\n";
               helpMessage;
            } else {
               $libPath = $libPath . ":" . $ARGV[++$i];
            }
         } elsif ($option eq "lf") {
            if ($i == $nargs - 1) {
               print STDERR "Error: No left footer specified for option -lf\n";
               helpMessage;
            } else {
               $leftFooter = $ARGV[++$i];
            }
         } elsif ($option eq "lh") {
            if ($i == $nargs - 1) {
               print STDERR "Error: No left header specified for option -lh\n";
               helpMessage;
            } else {
               $leftHeader = $ARGV[++$i];
            }
         } elsif ($option eq "m") {
            if ($i == $nargs - 1) {
               print STDERR "Error: No directory specified for option -m\n";
               helpMessage;
            } else {
               $imgDir = $ARGV[++$i];
               unless ($imgDir =~ /\/$/) {
                  $imgDir = $imgDir . "/";
               }
            }
         } elsif ($option eq "o") {
            if ($i == $nargs - 1) {
               print STDERR "Error: No file specified for option -o\n";
               helpMessage;
            } else {
               $outputFile = $ARGV[++$i];
            }
         } elsif ($option eq "p") {
            if ($i == $nargs - 1) {
               print STDERR "Error: Page number not specified for option -p\n";
               helpMessage;
            } else {
               $startPage = $ARGV[++$i];
            }
         } elsif ($option eq "pt") {
            if ($i == $nargs - 1) {
               print STDERR "Error: Default font size not specified for option -pt\n";
               helpMessage;
            } else {
               $normalSize = $ARGV[++$i];
            }
         } elsif ($option eq "r") {
            if ($i == $nargs - 1) {
               print STDERR "Error: TeX running mode not specified for option -r\n";
            } else {
               $runMode = $ARGV[++$i];
            }
         } elsif ($option eq "rf") {
            if ($i == $nargs - 1) {
               print STDERR "Error: No right footer specified for option -rf\n";
               helpMessage;
            } else {
               $rightFooter = $ARGV[++$i];
            }
         } elsif ($option eq "rh") {
            if ($i == $nargs - 1) {
               print STDERR "Error: No right header specified for option -rh\n";
               helpMessage;
            } else {
               $rightHeader = " " . $ARGV[++$i];
            }
         } elsif ($option eq "t") {
            if ($i == $nargs - 1) {
               print STDERR "Error: No tmp directory specified\n";
               helpMessage;
            } else {
               $tmpDir = $ARGV[++$i];
            }
         } elsif ($option eq "w") {
            if ($i == $nargs - 1) {
               print STDERR "Error: No cell width specified\n";
               helpMessage;
            } else {
               $cellWidth = "$ARGV[++$i]cm";
            }
         } else {
            print STDERR "Error: Invalid option -$option\n";
            helpMessage;
         }
      } else {
         if ($i == $nargs - 1) {
            $inputFile = $ARGV[$i];
         } else {
            print STDERR "Error: Too many arguments\n";
            helpMessage;
         }
      }
      if (($i == $nargs - 1) && ($inputFile eq "")) {
         print STDERR "ERROR: No input file specified\n";
         helpMessage;
      }
   }
}

sub processOptions {
   $jobName = $inputFile;
   $jobExtn = "";
   $jobPath = "./";
   $slashIndex = rindex($inputFile,"/");
   if ($slashIndex != -1) {
      $jobPath = substr($inputFile,0,$slashIndex + 1);
      $jobName = substr($inputFile,$slashIndex + 1);
   }
   $dotIndex = rindex($jobName,".");
   if ($dotIndex != -1) {
      $jobExtn = substr($jobName,$dotIndex + 1);
      $jobName = substr($jobName,0,$dotIndex);
   }
   if ($outputFile ne "") {
      $slashIndex = rindex($outputFile,"/");
      if ($slashIndex != -1) {
         $outPath = substr($outputFile,0,$slashIndex + 1);
      } else {
         $outPath = "./";
      }
   }
   if ((!(-e $inputFile)) || (!(-r $inputFile)) || (!(-f $inputFile))) {
      print STDERR "Error: unable to read input file\n";
      exit(1);
   }
   open(INFILE,"<$inputFile");
   if ((!(-d $tmpDir)) || (!(-w $tmpDir))) {
      print STDERR "Error: $tmpDir not writable\n";
      exit(1);
   }
   if (($imageMode == 0) && ((!(-d $imgDir)) || (!(-w $imgDir)))) {
      print STDERR "Error: $imgDir not writable\n";
      exit(1);
   }
   if ($outputFile ne "") {
      if ((!(-d $outPath)) || (!(-w $outPath))) {
         print STDERR "Error: cannot write output file $outputFile\n";
         exit(1);
      }
      if (-e $outputFile) {
         if ($verbose) {
            print "File $outputFile exists. Overwrite (y/n) ? ";
            $answer = <STDIN>; chop($answer);
            if (($answer ne "y") && ($answer ne "Y")) {
               print STDERR "Okay ... quitting !\n";
               exit(1);
            }
         }
         `rm $outputFile`;
      }
      open(OUTFILE,">$outputFile");
   }
   if (!$useScaledFonts) {
      ($sSize, $tSize) = ($normalSize - 3, $normalSize - 5);
      ($nSkip, $sSkip, $tSkip) = ($normalSize + 2, $normalSize - 1, $normalSize - 3);
      ($lSkip, $LSkip, $LLSkip, $hSkip) = 
           (int(1.4 * $normalSize), int(1.7 * $normalSize), 2 * $normalSize, int(2.5 * $normalSize));
   }
   if ($verbose) {
      $verboseOption = "-v";
   } else {
      $verboseOption = "";
   }
   if ($imageCol == 0) {
      $colorOption = "";
   } elsif ($imageCol == 1) {
      $colorOption = "-g";
   } elsif ($imageCol == 2) {
      $colorOption = "-d";
   }
}

sub readResources {
   $rcsLoaded = 0;
   $tmpLibPath = $libPath;
   while ($tmpLibPath ne "") {
      $colonIndex = index($tmpLibPath,":");
      if ($colonIndex == -1) {
         $tmpLibDir = $tmpLibPath;
         $tmpLibPath = "";
      } else {
         $tmpLibDir = substr($tmpLibPath,0,$colonIndex);
         $tmpLibPath = substr($tmpLibPath,$colonIndex + 1);
      }
      if (!($tmpLibDir =~ /\/$/)) {
         $tmpLibDir = $tmpLibDir . "/";
      }
      $rcFile = $tmpLibDir . "htmltotex.rc";
      $rcDir = `dirname $rcFile`; chop($rcDir);
      $rcFile = "$rcDir/htmltotex.rc";
      if ((-e $rcFile) && (-r $rcFile) && (!($rcsLoaded))) {
         open(RFILE,"<$rcFile");
         while ($nextLine = <RFILE>) {
            chop($nextLine);
            $equalIndex = index($nextLine,"=");
            if ($equalIndex != -1) {
               $rcName = substr($nextLine,0,$equalIndex);
               $rcValue = substr($nextLine,$equalIndex + 1);
               if ((uc $rcName) eq "HTTPD_HOME") {
                  $httpdHome = $rcValue;
               } elsif ((uc $rcName) eq "PUBLIC_HTML_DIR") {
                  $pubHtmlDir = $rcValue;
               } elsif ((uc $rcName) eq "LOCAL_HOST") {
                  $localHost = $rcValue;
               }
            }
         }
         close(RFILE);
         $rcsLoaded = 1;
         if ($verbose) {
            print STDERR "Resource file read ...\n";
         }
      }
   }
   if (!($rcsLoaded)) {
      print STDERR "WARNING: Unable to read resource file ... using defaults\n";
      print STDERR "         But you may have problems later ...\n";
   }
   if ($baseURL ne "") {
      ($baseProtocol, $baseDir, $junk) = splitURL($baseURL);
   }
}

sub readSpecialChars {
   %splCharMap = ();
   $splCharsLoaded = 0;
   $tmpLibPath = $libPath;
   while ( ($tmpLibPath ne "") && (!$splCharsLoaded) ) {
      $colonIndex = index($tmpLibPath,":");
      if ($colonIndex == -1) {
         $tmpLibDir = $tmpLibPath;
         $tmpLibPath = "";
      } else {
         $tmpLibDir = substr($tmpLibPath,0,$colonIndex);
         $tmpLibPath = substr($tmpLibPath,$colonIndex + 1);
      }
      if (!($tmpLibDir =~ /\/$/)) {
         $tmpLibDir = $tmpLibDir . "/";
      }
      $splCharFile = $tmpLibDir . "spl-chars";
      $splCharDir = `dirname $splCharFile`; chop($splCharDir);
      $splCharFile = "$splCharDir/spl-chars";
      if ((-e $splCharFile) && (-r $splCharFile)) {
         open(SFILE,"<$splCharFile");
         while ($nextLine = <SFILE>) {
            chop($nextLine);
            $equalIndex = index($nextLine,"=");
            if ($equalIndex != -1) {
               $charName = substr($nextLine,0,$equalIndex);
               $charValue = substr($nextLine,$equalIndex + 1);
               $splCharMap{$charName} = $charValue;
            }
         }
         close(SFILE);
         $splCharsLoaded = 1;
         if ($verbose) {
            print STDERR "Special characters loaded ...\n";
         }
      }
   }
   if (!($splCharsLoaded)) {
      print STDERR "WARNING: Unable to read special character maps ... ignoring\n";
      print STDERR "         But you may have problems later ...\n";
   }
}

sub writePreamble {
   $fontsLoaded = 0;
   $miscMacrosLoaded = 0;
   $tmpLibPath = $libPath;
   while ( ($tmpLibPath ne "") && ((!$fontsLoaded) || (!miscMacrosLoaded)) ) {
      $colonIndex = index($tmpLibPath,":");
      if ($colonIndex == -1) {
         $tmpLibDir = $tmpLibPath;
         $tmpLibPath = "";
      } else {
         $tmpLibDir = substr($tmpLibPath,0,$colonIndex);
         $tmpLibPath = substr($tmpLibPath,$colonIndex + 1);
      }
      if (!($tmpLibDir =~ /\/$/)) {
         $tmpLibDir = $tmpLibDir . "/";
      }
      if (!$fontsLoaded) {
         if ($useScaledFonts) {
            if ($normalSize == 11) { $fontFile = "fonts11.mac"; }
            elsif ($normalSize == 12) { $fontFile = "fonts12.mac"; }
            else {
               if ($normalSize != 10) {
                  print STDERR "Point size must be 10, 11 or 12 with the -F option ... using defaults\n";
               }
               $fontFile = "fonts10.mac";
            }
         } else {
            $fontFile = "fonts.mac";
         }
         $preambleFile = $tmpLibDir . $fontFile;
         $preambleDir = `dirname $preambleFile`; chop($preambleDir);
         $preambleFile = "$preambleDir/$fontFile";
         if ((-e $preambleFile) && (-r $preambleFile)) {
            open(PFILE,"<$preambleFile");
            while ($nextLine = <PFILE>) {
               unless ($useScaledFonts) {
                  $nextLine =~ s/NORMALSIZE/$normalSize/g;
                  $nextLine =~ s/SMALLSIZE/$sSize/g;
                  $nextLine =~ s/TINYSIZE/$tSize/g;
                  $nextLine =~ s/NORMALSKIP/$nSkip/g;
                  $nextLine =~ s/SMALLSKIP/$sSkip/g;
                  $nextLine =~ s/TINYSKIP/$tSkip/g;
                  $nextLine =~ s/largeSKIP/$lSkip/g;
                  $nextLine =~ s/LargeSKIP/$LSkip/g;
                  $nextLine =~ s/LARGESKIP/$LLSkip/g;
                  $nextLine =~ s/hugeSKIP/$hSkip/g;
               }
               print OUTFILE $nextLine;
            }
            close(PFILE);
            $fontsLoaded = 1;
            if ($verbose) {
               print STDERR "Font macros loaded ...\n";
            }
         }
      }
      if (!$miscMacrosLoaded) {
         $preambleFile = $tmpLibDir . "misc.mac";
         $preambleDir = `dirname $preambleFile`; chop($preambleDir);
         $preambleFile = "$preambleDir/misc.mac";
         if ((-e $preambleFile) && (-r $preambleFile)) {
            print OUTFILE "\\def\\lhdr{$leftHeader}\n";
            print OUTFILE "\\def\\lftr{$leftFooter}\n";
            print OUTFILE "\\def\\rhdr{$rightHeader}\n";
            print OUTFILE "\\def\\rftr{$rightFooter}\n";
            if ($showPage) {
               print OUTFILE "\\def\\thispage{-- \\folio\\ --}\n";
            } else {
               print OUTFILE "\\def\\thispage{}\n";
            }
            if ($startPage != 1) {
               print OUTFILE "\\pageno=" . $startPage . "\n";
            }
            open(PFILE,"<$preambleFile");
            while ($nextLine = <PFILE>) {
               print OUTFILE $nextLine;
            }
            close(PFILE);
            $miscMacrosLoaded = 1;
            if ($verbose) {
               print STDERR "Miscellaneous macros loaded ...\n";
            }
         }
      }
   }
   if (($fontsLoaded == 0) || ($miscMacrosLoaded == 0)) {
      print STDERR "Error: Unable to load library\n";
      exit(1);
   }
   if ($runMode == 1) {
      print OUTFILE "\\batchmode\n";
   } elsif ($runMode == 2) {
      print OUTFILE "\\scrollmode\n";
   } elsif ($runMode == 3) {
      print OUTFILE "\\nonstopmode\n";
   } elsif ($runMode != 0) {
      print STDERR "WARNING: Invalid TeX running mode specified ... using default\n";
   }
   if ($prmbFile ne "") {
      print OUTFILE "\\input $prmbFile\n";
   }
   if ($imageMode == 0) { print OUTFILE "\\input epsf.sty\n"; }
   if ($ulAnchors) {
      print OUTFILE "\\tolerance=10000\n";
   }
   if ($verbose) {
      print STDERR "Preamble written ...\n";
      print STDERR "Processing input ... Please wait\n";
   }
}

sub substSplChars {
   $_ = $_[0];
   $thisLength = length $_;
   $index = 0;
   while (substr($_,$index) =~
             /[^(\w|\s|\/|\?<|>|\{|\}|\[|\]|!|@|#|\$|%|\^|&|\*|\(|\)|_|-|\+|=|\\|\||:|;|"|'|,|\.|`|~)]/s) {
      $thisChar = $&;
      $index = index($_,$thisChar,$index) + 1;
      $thisOrd = ord $thisChar;
      if ($thisOrd > 127) {
         $thisSymb = "&#" . $thisOrd . ";";
         $thisMap = $splCharMap{$thisSymb};
         $index-- if ($thisMap eq "");
         s/$thisChar/$thisMap/gs;
      }
   }
   s/&#\d*?;/$splCharMap{$&}/gs;
   s/&\w*?;/$splCharMap{$&}/gs;
   s/(&#\d*?)$/$splCharMap{$1 . ";"}/g;
   s/(&\w*?)$/$splCharMap{$1 . ";"}/g;
   s/(&#\d*?)\s/$splCharMap{$1 . ";"}/gs;
   s/(&\w*?)\s/$splCharMap{$1 . ";"}/gs;
   return $_;
}

sub substTexSplChars {
   $_ = $_[0];
   $offset = 0;
   $bsi = index($_,"\\",$offset);
   $lbi = index($_,"{",$offset);
   $rbi = index($_,"}",$offset);
   $min = $infinity;
   if ($bsi != -1) {
      $min = $bsi;
   }
   if (($lbi != -1) && ($lbi < $min)) {
      $min = $lbi;
   }
   if (($rbi != -1) && ($rbi < $min)) {
      $min = $rbi;
   }
   while ($min < $infinity) {
      $thisChar = substr($_,$min,1);
      if ($min > 0) {
         $beforeChar = substr($_,0,$min);
      } else {
         $beforeChar = "";
      }
      $afterChar = substr($_,$min + 1);
      if ($thisChar eq "\\") {
         $_ = $beforeChar . "{\\backslash}" . $afterChar;
         $offset = $min + 12;
      } elsif ($thisChar eq "{") {
         $_ = $beforeChar . "{\\lbrace}" . $afterChar;
         $offset = $min + 9;
      } elsif ($thisChar eq "}") {
         $_ = $beforeChar . "{\\rbrace}" . $afterChar;
         $offset = $min + 9;
      }
      $bsi = index($_,"\\",$offset);
      $lbi = index($_,"{",$offset);
      $rbi = index($_,"}",$offset);
      $min = $infinity;
      if ($bsi != -1) {
         $min = $bsi;
      }
      if (($lbi != -1) && ($lbi < $min)) {
         $min = $lbi;
      }
      if (($rbi != -1) && ($rbi < $min)) {
         $min = $rbi;
      }
   }
   s/\$/{\\dollar}/gs;
   s/%/{\\percent}/gs;
   s/_/{\\underscore}/gs;
   s/\^/{\\caret}/gs;
   s/~/{\\tilde}/gs;
   s/\|/{\\vertbar}/gs;
   return $_;
}

sub substOtherTexSplChars {
   $_ = $_[0];
   s/#/{\\hash}/gs;
   s/</{\\ltsign}/gs;
   s/>/{\\gtsign}/gs;
   return $_;
}

sub substFonts {
   $_ = $_[0];
   s/<BLINK>//is;
   s/<B>/{\\bf /is;
   s/<CITE>/{\\sl /is;
   s/<CODE>/{\\tt /is;
   s/<DFN>/{\\tt /is;
   s/<EM>/{\\it /is;
   s/<I>/{\\it /is;
   s/<KBD>/{\\tt /is;
   s/<SAMP>/{\\tt /is;
   s/<STRONG>/{\\bf /is;
   s/<TT>/{\\tt /is;
   s/<U>/\\underbar{/is;
   s/<VAR>/{\\sl /is;
   s/<\/BLINK>//is;
   s/<\/B>/}/is;
   s/<\/CITE>/}/is;
   s/<\/CODE>/}/is;
   s/<\/DFN>/}/is;
   s/<\/EM>/}/is;
   s/<\/I>/}/is;
   s/<\/KBD>/}/is;
   s/<\/SAMP>/}/is;
   s/<\/STRONG>/}/is;
   s/<\/TT>/}/is;
   s/<\/U>/}/is;
   s/<\/VAR>/}/is;
   s/<FONT>/{/is;
   if (/<FONT(\s[^>]*)>/is) {
      $args = $1;
      if ($args =~ /(\s|")SIZE="(\d+?)(\s|"|$)/is) {
         $farg = $2;
         s/<FONT\s[^>]*>/{\\fontsize{$farg}/is;
      } elsif ($args =~ /(\s|")SIZE=(\d+?)(\s|"|$)/is) {
         $farg = $2;
         s/<FONT\s[^>]*>/{\\fontsize{$farg}/is;
      } elsif ($args =~ /(\s|")SIZE="((\+|-)\d+?)(\s|"|$)/is) {
         $farg = $2;
         s/<FONT\s[^>]*>/{\\fontsizeplus{A}{$farg}/is;
      } elsif ($args =~ /(\s|")SIZE=((\+|-)\d+?)(\s|"|$)/is) {
         $farg = $2;
         s/<FONT\s[^>]*>/{\\fontsizeplus{A}{$farg}/is;
      } else {
         s/<FONT\s[^>]*>/{/is;
      }
   }
   s/<\/FONT>/}/is;
   s/<BIG>/{\\fontsizeplus{R}{1}/is;
   s/<\/BIG>/}/is;
   s/<SMALL>/{\\fontsizeplus{R}{-1}/is;
   s/<\/SMALL>/}/is;
   return $_;
}

sub substHeadings {
   $_ = $_[0];
   s/<H1>/\\medbreak\\beginflushleft\\LARGE\\bf /is;
   s/<H2>/\\medbreak\\beginflushleft\\Large\\bf /is;
   s/<H3>/\\medbreak\\beginflushleft\\large\\bf /is;
   s/<H4>/\\medbreak\\beginflushleft\\normalsize\\bf /is;
   s/<H5>/\\medbreak\\beginflushleft\\small\\bf /is;
   s/<H6>/\\medbreak\\beginflushleft\\tiny\\bf /is;
   if (/<H1(\s[^>]*)>/is) {
      $args = $1;
      if ($args =~ /\sALIGN="?CENTER(\s|$|")/is) { s/<H1\s[^>]*>/\\medbreak\\begincenter\\LARGE\\bf /is; }
      elsif ($args =~ /\sALIGN="?LEFT(\s|$|")/is) { s/<H1\s[^>]*>/\\medbreak\\beginflushleft\\LARGE\\bf /is; }
      elsif ($args =~ /\sALIGN="?RIGHT(\s|$|")/is) { s/<H1\s[^>]*>/\\medbreak\\beginflushright\\LARGE\\bf /is; }
      else { s/<H1\s[^>]*>/\\medbreak\\beginflushleft\\LARGE\\bf /is; }
   }
   if (/<H2(\s[^>]*)>/is) {
      $args = $1;
      if ($args =~ /\sALIGN="?CENTER(\s|$|")/is) { s/<H2\s[^>]*>/\\medbreak\\begincenter\\Large\\bf /is; }
      elsif ($args =~ /\sALIGN="?LEFT(\s|$|")/is) { s/<H2\s[^>]*>/\\medbreak\\beginflushleft\\Large\\bf /is; }
      elsif ($args =~ /\sALIGN="?RIGHT(\s|$|")/is) { s/<H2\s[^>]*>/\\medbreak\\beginflushright\\Large\\bf /is; }
      else { s/<H2\s[^>]*>/\\medbreak\\beginflushleft\\Large\\bf /is; }
   }
   if (/<H3(\s[^>]*)>/is) {
      $args = $1;
      if ($args =~ /\sALIGN="?CENTER(\s|$|")/is) { s/<H3\s[^>]*>/\\medbreak\\begincenter\\large\\bf /is; }
      elsif ($args =~ /\sALIGN="?LEFT(\s|$|")/is) { s/<H3\s[^>]*>/\\medbreak\\beginflushleft\\large\\bf /is; }
      elsif ($args =~ /\sALIGN="?RIGHT(\s|$|")/is) { s/<H3\s[^>]*>/\\medbreak\\beginflushright\\large\\bf /is; }
      else { s/<H3\s[^>]*>/\\medbreak\\beginflushleft\\large\\bf /is; }
   }
   if (/<H4(\s[^>]*)>/is) {
      $args = $1;
      if ($args =~ /\sALIGN="?CENTER(\s|$|")/is) { s/<H4\s[^>]*>/\\medbreak\\begincenter\\normalsize\\bf /is; }
      elsif ($args =~ /\sALIGN="?LEFT(\s|$|")/is) { s/<H4\s[^>]*>/\\medbreak\\beginflushleft\\normalsize\\bf /is; }
      elsif ($args =~ /\sALIGN="?RIGHT(\s|$|")/is) { s/<H4\s[^>]*>/\\medbreak\\beginflushright\\normalsize\\bf /is; }
      else { s/<H4\s[^>]*>/\\medbreak\\beginflushleft\\normalsize\\bf /is; }
   }
   if (/<H5(\s[^>]*)>/is) {
      $args = $1;
      if ($args =~ /\sALIGN="?CENTER(\s|$|")/is) { s/<H5\s[^>]*>/\\medbreak\\begincenter\\small\\bf /is; }
      elsif ($args =~ /\sALIGN="?LEFT(\s|$|")/is) { s/<H5\s[^>]*>/\\medbreak\\beginflushleft\\small\\bf /is; }
      elsif ($args =~ /\sALIGN="?RIGHT(\s|$|")/is) { s/<H5\s[^>]*>/\\medbreak\\beginflushright\\small\\bf /is; }
      else { s/<H5\s[^>]*>/\\medbreak\\beginflushleft\\small\\bf /is; }
   }
   if (/<H6(\s[^>]*)>/is) {
      $args = $1;
      if ($args =~ /\sALIGN="?CENTER(\s|$|")/is) { s/<H6\s[^>]*>/\\medbreak\\begincenter\\tiny\\bf /is; }
      elsif ($args =~ /\sALIGN="?LEFT(\s|$|")/is) { s/<H6\s[^>]*>/\\medbreak\\beginflushleft\\tiny\\bf /is; }
      elsif ($args =~ /\sALIGN="?RIGHT(\s|$|")/is) { s/<H6\s[^>]*>/\\medbreak\\beginflushright\\tiny\\bf /is; }
      else { s/<H6\s[^>]*>/\\medbreak\\beginflushleft\\tiny\\bf /is; }
   }
   s/<\/H1>/\\par\\endgroup\\medskip/is;
   s/<\/H2>/\\par\\endgroup\\medskip/is;
   s/<\/H3>/\\par\\endgroup\\medskip/is;
   s/<\/H4>/\\par\\endgroup\\medskip/is;
   s/<\/H5>/\\par\\endgroup\\medskip/is;
   s/<\/H6>/\\par\\endgroup\\medskip/is;
   return $_;
}

sub substLists {
   $_ = $_[0];
   s/<LI>/\\item /is;
   if (/<LI(\s[^>]*)>/is) {
      $args = $1;
      if ($args =~ /\sTYPE="?(\w+)("|$|\s)/is) {
         $markerType = $1;
         $markerCode = 0;
         $markerCode = 1 if (uc($markerType) eq "DISC");
         $markerCode = 2 if (uc($markerType) eq "CIRCLE");
         $markerCode = 3 if (uc($markerType) eq "SQUARE");
         s/<LI\s[^>]*>/\\splitem{U}{$markerCode}/is;
      } elsif ($args =~ /\sVALUE="?(\d+)("|$|\s)/is) {
         $markerVal = $1;
         s/<LI\s[^>]*>/\\splitem{O}{$markerVal}/is;
      } else {
         s/<LI\s[^>]*>/\\item /is;
      }
   }
   s/<\/LI>//is;
   s/<UL>/\\beginitemize{0}/is;
   if (/<UL(\s[^>]*)>/is) {
      $args = $1;
      if ($args =~ /\sTYPE="?(\w+)("|$|\s)/is) {
         $markerType = $1;
         $markerCode = 0;
         $markerCode = 1 if (uc($markerType) eq "DISC");
         $markerCode = 2 if (uc($markerType) eq "CIRCLE");
         $markerCode = 3 if (uc($markerType) eq "SQUARE");
         s/<UL\s[^>]*>/\\beginitemize{$markerCode}/is;
      } else {
         s/<UL\s[^>]*>/\\beginitemize{0}/is;
      }
   }
   s/<\/UL>/\\par\\enditemize /is;
   s/<DIR>/\\beginitemize{0}/is;
   s/<\/DIR>/\\par\\enditemize /is;
   s/<MENU>/\\beginitemize{0}/is;
   s/<\/MENU>/\\par\\enditemize /is;
   s/<OL>/\\beginenumerate{1}{1}/is;
   if (/<OL(\s[^>]*)>/is) {
      $args = $1;
      $enumType = "1";
      $enumStart = "1";
      if ($args =~ /\sTYPE="?(\w)("|$|\s)/is) { $enumType = $1; }
      if ($args =~ /\sSTART="?(\d+)("|$|\s)/is) { $enumStart = $1; }
      s/<OL\s[^>]*>/\\beginenumerate{$enumStart}{$enumType}/is;
   }
   s/<\/OL>/\\par\\endenumerate /is;
   s/<DL>/\\begindefinition{F}/is;
   s/<DL\s+COMPACT[^>]*>/\\begindefinition{T}/is;
   s/<DL\s[^>]*>/\\begindefinition{F}/is;
   s/<\/DL>/\\par\\enddefinition /is;
   s/<DT>/\\par\\hglue -30pt /is;
   s/<\/DT>//is;
   s/<DD>/\\descr /is;
   s/<\/DD>//is;
   return $_;
}

sub substTables {
   $_ = $_[0];
   s/<TABLE>/\\halign{\\span\\lcol&&\\span\\pcol{$cellWidth}\\quad/is;
   s/<TABLE\s[^>]*?>/\\halign{\\span\\lcol&&\\span\\pcol{$cellWidth}\\quad/is;
   s/<TR>/\\cr/is;
   s/<TR\s[^>]*?>/\\cr/is;
   s/<TD>/ &\\flushleft /is;
   s/<TD\s[^>]*\sALIGN=LEFT[^>]*>/ &\\flushleft /is;
   s/<TD\s[^>]*\sALIGN=RIGHT[^>]*>/ &\\flushright /is;
   s/<TD\s[^>]*\sALIGN=CENTER[^>]*>/ &\\center /is;
   s/<TD\s+ALIGN=LEFT[^>]*>/ &\\flushleft /is;
   s/<TD\s+ALIGN=RIGHT[^>]*>/ &\\flushright /is;
   s/<TD\s+ALIGN=CENTER[^>]*>/ &\\center /is;
   s/<TD\s[^>]*?>/ &\\flushleft /is;
   s/<\/TD>//is;
   s/<TH>/ & \\center\\bf /is;
   s/<TH\s[^>]*\sALIGN=LEFT[^>]*>/ &\\flushleft\\bf /is;
   s/<TH\s[^>]*\sALIGN=RIGHT[^>]*>/ &\\flushright\\bf /is;
   s/<TH\s[^>]*\sALIGN=CENTER[^>]*>/ &\\center\\bf /is;
   s/<TH\s+ALIGN=LEFT[^>]*>/ &\\flushleft\\bf /is;
   s/<TH\s+ALIGN=RIGHT[^>]*>/ &\\flushright\\bf /is;
   s/<TH\s+ALIGN=CENTER[^>]*>/ &\\center\\bf /is;
   s/<TH\s[^>]*?>/ & \\center\\bf /is;
   s/<\/TH>//is;
   s/<\/TABLE>/\\cr}/is;
   return $_;
}

sub substBlocks {
   $_ = $_[0];
   if (/<A>/is) {
      if ($ulAnchors) {
         s/<A>/\\underbar{/is;
      } else {
         s/<A>//is;
      }
   }
   if (/<A\s[^>]*?>/is) {
      if ($ulAnchors) {
         s/<A\s[^>]*?>/\\underbar{/is;
      } else {
         s/<A\s[^>]*?>//is;
      }
   }
   if (/<\/A>/is) {
      if ($ulAnchors) {
         s/<\/A>/}/is;
      } else {
         s/<\/A>//is;
      }
   }
   s/<P>/\\par /is;
   s/<P\s[^>]*>/\\par /is;
   s/<\/P>/\\par /is;
   s/<BR>/\\\\/is;
   s/<BR\s[^>]*>/\\\\/is;
   s/<HR>/\\medskip\\hrule width \\hsize /is;
   s/<HR\s[^>]*>/\\medskip\\hrule width \\hsize /is;
   s/<BLOCKQUOTE>/\\beginquote /is;
   s/<\/BLOCKQUOTE>/\\endquote /is;
   s/<PRE>/\\beginpreformat /is;
   s/<PRE\s[^>]*>/\\beginpreformat /is;
   s/<\/PRE>/\\endpreformat /is;
   s/<ADDRESS>/\\par{\\sl /is;
   s/<\/ADDRESS>/}\\par /is;
   s/<HTML>//is;
   s/<\/HTML>//is;
   s/<BODY>//is;
   s/<BODY\s[^>]*>//is;
   s/<\/BODY>//is;
   s/<CENTER>/\\begincenter /is;
   s/<\/CENTER>/\\par\\endcenter /is;
   s/<DIV>/\\beginflushleft /is;
   s/<DIV\s+ALIGN="?LEFT("|\s)[^>]*>/\\beginflushleft /is;
   s/<DIV\s+ALIGN="?RIGHT("|\s)[^>]*>/\\beginflushright /is;
   s/<DIV\s+ALIGN="?CENTER("|\s)[^>]*>/\\begincenter /is;
   s/<DIV\s+ALIGN="?LEFT"?>/\\beginflushleft /is;
   s/<DIV\s+ALIGN="?RIGHT"?>/\\beginflushright /is;
   s/<DIV\s+ALIGN="?CENTER"?>/\\begincenter /is;
   s/<\/DIV>/\\par\\endgroup /is;
   return $_;
}

sub substForms {
   $_ = $_[0];
   if ($formDetails) {
      s/<FORM>/\\par\\underbar{\\large\\bf Form} /is;
      s/<FORM\s[^>]*>/\\par\\underbar{\\large\\bf Form} /is;
      $rows = "5em"; $cols = "20em"; $size="20em";
      s/<TEXTAREA>/\\rectangle{$cols}{$rows}/is;
      if (/<TEXTAREA(\s[^>]*)>/is) {
         $args = $1;
         if ($args =~ /(\s|")ROWS=(\d+)("|\s|$)/is) { $rows = $2 . "ex"; }
         if ($args =~ /(\s|")COLS=(\d+)("|\s|$)/is) { $cols = $2 . "ex"; }
         s/<TEXTAREA\s[^>]*>/\\rectangle{$cols}{$rows}/is;
      }
      s/<\/TEXTAREA>//gis;
      s/<INPUT>/\\stline{$size}/is;
      if (/<INPUT(\s[^>]*)>/is) {
         $args = $1;
         if ($args =~ /(\s|")SIZE="?(\d+)("|\s|$)/is) { $size = $2 . "ex"; }
         if ($args =~ /(\s|")TYPE="?TEXT("|\s|$)/is) {
            s/<INPUT\s[^>]*>/\\stline{$size}/is;
         } elsif ($args =~ /(\s|")TYPE="?CHECKBOX("|\s|$)/is) {
            s/<INPUT\s[^>]*>/\\checkbox /is;
         } elsif ($args =~ /(\s|")TYPE="?RADIO("|\s|$)/is) {
            s/<INPUT\s[^>]*>/\$\\diamond\$ /is;
         } elsif ($args =~ /(\s|")TYPE="?RESET("|\s|$)/is) {
            $resetVal = "Reset";
            if ($args =~ /(\s|")VALUE=(\w+)("|\s|$)/is) { $resetVal = $2; }
            if ($args =~ /(\s|")VALUE="(.+?)("|$)/is) { $resetVal = $2; }
            s/<INPUT\s[^>]*>/\\button{$resetVal}/is;
         }  elsif ($args =~ /(\s|")TYPE="?SUBMIT("|\s|$)/is) {
            $submitVal = "Submit Query";
            if ($args =~ /(\s|")VALUE=(\w+)("|\s|$)/is) { $submitVal = $2; }
            if ($args =~ /(\s|")VALUE="(.+?)("|$)/is) { $submitVal = $2; }
            s/<INPUT\s[^>]*>/\\button{$submitVal}/is;
         } elsif ($args =~ /(\s|")TYPE="?HIDDEN("|\s|$)/is) {
            s/<INPUT\s[^>]*>//is;
         } else {
            s/<INPUT\s[^>]*>/\\stline{$size}/is;
         }
      }
      s/<\/INPUT>//is;
      s/<SELECT>/\\leavevmode\\raise 0.5em \\vtop{\\offinterlineskip\\halign{&\\strut\\vrule\\quad\\span\\lcol\\quad\\vrule/is;
      s/<SELECT\s[^>]*>/\\leavevmode\\raise 0.5em \\vtop{\\offinterlineskip\\halign{&\\strut\\vrule\\quad\\span\\lcol\\quad\\vrule/is;
      s/<\/SELECT>/\\cr\\noalign{\\hrule}}}/is;
      s/<OPTION>/\\cr\\noalign{\\hrule}/is;
      s/<OPTION [^>]*>/\\cr\\noalign{\\hrule}/is;
      s/<\/OPTION>//is;
   } else {
      s/<FORM>//is;
      s/<FORM\s[^>]*>//is;
      s/<TEXTAREA>//is;
      s/<TEXTAREA\s[^>]*>//is;
      s/<\/TEXTAREA>//is;
      s/<INPUT>//is;
      s/<INPUT\s[^>]*>//is;
      s/<\/INPUT>//is;
      s/<SELECT>//is;
      s/<SELECT\s[^>]*>//is;
      s/<\/SELECT>//is;
      s/<OPTION>//is;
      s/<OPTION\s[^>]*>//is;
      s/<\/OPTION>//is;
   }
   s/<\/FORM>//is;
   return $_;
}

sub substApplets {
   $_ = $_[0];
   if ($appletDetails) {
      s/<APPLET>/\\par\\underbar{\\large\\bf Applet} \\par\\vtop{\\halign{&\\span\\lcol\\quad\\cr\\bf Parameter& \\bf Value /is;
      while (/<APPLET(\s[^>]*)>/is) {
         $args = $1; $appletCode = "";
         if ($args =~ /(\s|")CODE="(.+?)("|$)/is) {
            $appletCode = $2;
            s/<APPLET\s[^>]*>/\\par\\underbar{\\large\\bf Applet} {\\sl $appletCode}\\par\\vtop{\\halign{&\\span\\lcol\\quad\\cr\\bf Parameter& \\bf Value /is;
         }
         if ($args =~ /(\s|")CODE=(\S+?)("|\s|$)/is) {
            $appletCode = $2;
            s/<APPLET\s[^>]*>/\\par\\underbar{\\large\\bf Applet} {\\sl $appletCode}\\par\\vtop{\\halign{&\\span\\lcol\\quad\\cr\\bf Parameter& \\bf Value /is;
         }
      }
      s/<\/APPLET>/\\cr}}/is;
      s/<PARAM>//is;
      while (/<PARAM(\s[^>]*)>/is) {
         $args = $1; $paramName = ""; $paramVal = "";
         if ($args =~ /(\s|")NAME=(\w+)("|\s|$)/is) { $paramName = $2; }
         if ($args =~ /(\s|")VALUE=(\S+?)("|\s|$)/is) { $paramVal = $2; }
         if ($args =~ /(\s|")VALUE="(.+?)("|$)/is) { $paramVal = $2; }
         s/<PARAM\s[^>]*>/\\cr $paramName & $paramVal /is;
      }
      s/<\/PARAM>//is;
   } else {
      s/<APPLET>//is;
      s/<APPLET\s[^>]*>//is;
      s/<\/APPLET>//is;
      s/<PARAM>//is;
      s/<PARAM\s[^>]*>//is;
      s/<\/PARAM>//is;
   }
   return $_;
}

sub substScripts {
   $_ = $_[0];
   s/<SUB>/{\\beginsub /is;
   s/<SUP>/{\\beginsup /is;
   s/<\/SUB>/\\endsub}/is;
   s/<\/SUP>/\\endsup}/is;
   return $_;
}

sub substImages {
   $_ = $_[0];
   s/<IMG>//is;
   if ($imageMode == 2) {
      s/<IMG\s[^>]*>//is;
      return $_;
   }
   if (/<IMG(\s[^>]*)>/is) {
      $args = $1; $imgsrc = ""; $imgwd = 0; $imght = 0; $altText = "";
      if ($args =~ /(\s|")WIDTH="?(\d+)("|\s|$)/i) { $imgwd = $2; }
      if ($args =~ /(\s|")HEIGHT="?(\d+)("|\s|$)/i) { $imght = $2; }
      if ($args =~ /(\s|")SRC="(\S+?)("|\s|$)/i) { $imgsrc = $2; }
      if (($imgsrc eq "") && ($args =~ /(\s|")SRC=(\S+?)("|\s|$)/i)) { $imgsrc = $2; }
      if ($args =~ /(\s|")ALT="(.*?)("|$)/i) { $altText = $2; }
      if (($altText eq "") && ($args =~ /(\s|")ALT=(.*?)("|\s|$)/i)) { $altText = $2; }
      if ($imageMode == 1) {
         if ($altText eq "") {
            s/<IMG\s[^>]*>/[Image]/is;
         } else {
            s/<IMG\s[^>]*>/[Image: $altText]/is;
         }
      } else {
         $imgsrc =~ s/{\\tilde}/~/g;
         $imgsrc =~ s/{\\underscore}/_/g;
         ($protocol, $imagePath, $imageName) = splitURL($imgsrc);
         $imageFile = $imagePath . $imageName;
         if ((-e $imageFile) && (-r $imageFile) && (-f $imageFile)) {
            $figno++; $psFile = $imgDir . "Fig" . $figno . ".ps";
            `imgtops $verboseOption $colorOption -t $tmpDir -o $psFile $imageFile`;
            $xSize = ""; $ySize = "";
            if ($imgwd > 0) {$xSize = "\\epsfxsize=$imgwd" . "pt ";}
            if ($imght > 0) {$ySize = "\\epsfysize=$imght" . "pt ";}
            s/<IMG\s[^>]*>/$xSize$ySize\\epsfbox{$psFile}/is;
         } else {
            print STDERR "WARNING: Image $imageFile cannot be loaded\n";
            if ($altText eq "") {
               s/<IMG\s[^>]*>/[Image]/is;
            } else {
               s/<IMG\s[^>]*>/[Image: $altText]/is;
            }
         }
      }
   }
   return $_;
}

sub substUnknownTags {
   $_ = $_[0];
   s/<TITLE>/\\forgetit{/is;
   s/<SCRIPT>/\\forgetit{/is;
   s/<STYLE>/\\forgetit{/is;
   s/<CAPTION>/\\forgetit{/is;
   s/<\/TITLE>/}/is;
   s/<\/SCRIPT>/}/is;
   s/<\/STYLE>/}/is;
   s/<\/CAPTION>/}/is;
   s/<[^>]*>//is;
   return $_;
}

sub processLine {
   $thisLine = $_[0];
   $thisLine = substTexSplChars($thisLine);
   $thisLine = substSplChars($thisLine);
   $thisLine =~  s/&/{\\ampersand}/gs;
   while ($thisLine =~ /<[^>]*>/s) {
      $thisTag = $&;
      $thisTag = substFonts($thisTag);
      $thisTag = substBlocks($thisTag) if (substr($thisTag,0,1) eq "<");
      $thisTag = substHeadings($thisTag) if (substr($thisTag,0,1) eq "<");
      $thisTag = substImages($thisTag) if (substr($thisTag,0,1) eq "<");
      $thisTag = substLists($thisTag) if (substr($thisTag,0,1) eq "<");
      $thisTag = substTables($thisTag) if (substr($thisTag,0,1) eq "<");
      $thisTag = substForms($thisTag) if (substr($thisTag,0,1) eq "<");
      $thisTag = substApplets($thisTag) if (substr($thisTag,0,1) eq "<");
      $thisTag = substScripts($thisTag) if (substr($thisTag,0,1) eq "<");
      $thisTag = substUnknownTags($thisTag) if (substr($thisTag,0,1) eq "<");
      $thisLine =~ s/<[^>]*>/$thisTag/s;
   }
   $thisLine = substOtherTexSplChars($thisLine);
   return($thisLine);
}

sub occ {
   $nocc = 0; $offset = 0;
   $ips = $_[0];
   $ss = $_[1];
   $ssIndex = index($ips,$ss,$offset);
   while ($ssIndex != -1) {
      $nocc++;
      $offset = $ssIndex + 1;
      $ssIndex = index($ips,$ss,$offset);
   }
   return $nocc;
}

sub getTagEnd {
   $tagLine = $_[0];
   $ltocc = occ($tagLine,"<");
   if ($ltocc == 0) { return -1; }
   $gtocc = occ($tagLine,">");
   if ($gtocc == 0) { return -1; }
   $tagStart = index($tagLine,"<");
   $tempLine = substr($tagLine,$tagStart);
   $offset = 0;
   for ($i=0; $i<$gtocc; $i++) {
      $gtIndex = index($tempLine,">",$offset);
      $toCheck = substr($tempLine,0,$gtIndex + 1);
      $ltOcc = occ($toCheck,"<");
      $gtOcc = occ($toCheck,">");
      if ($ltOcc == $gtOcc) {
         return $tagStart + $gtIndex;
      }
      $offset = $gtIndex + 1;
   }
   return -1;
}

sub processXMP {
   $_ = $_[0];
   $bsIndex = index($_,"\\",0);
   while ($bsIndex != -1) {
      if ($bsIndex > 0) {
         $beforeChar = substr($_,0,$bsIndex);
      } else {
         $beforeChar = "";
      }
      $afterChar = substr($_,$bsIndex + 1);
      $_ = $beforeChar . "\\\\" . $afterChar;
      $bsIndex = index($_,"\\",$bsIndex + 2);
   }
   $thisLength = length $_;
   for ($i=0; $i<$thisLength; $i++) {
      $thisChar = substr($_,$i,1);
      $thisOrd = ord $thisChar;
      $thisSymb = "&#" . $thisOrd . ";";
      if ($thisOrd > 127) {
         s/$thisChar/$thisSymb/gs;
         $thisLength = length $_;
      }
   }
  return $_;
}

sub readLine {
   unless ((eof INFILE) && ($unprocessedLine eq "")) {
      $nextLine = "";
      do {
         if ($unprocessedLine eq "") {
            $anotherLine = <INFILE>;
            $anotherLine =~ s/<(?=[^(\w|!|\/)])/&lt;/;
         } else {
            $anotherLine = $unprocessedLine;
            $unprocessedLine = "";
         }
         $anotherLine =~ s/<LISTING>/<XMP>/gis;
         $anotherLine =~ s/<\/LISTING>/<\/XMP>/gis;
         $nextLine .= $anotherLine;
         $lenal = length $anotherLine;
         for ($i=0; $i<$lenal; $i++) {
            $imbalance++ if (substr($anotherLine,$i,1) eq "<");
            $imbalance-- if ((substr($anotherLine,$i,1) eq ">") && ($imbalance > 0));
         }
      } while (($imbalance > 0) && (!(eof INFILE)));
      $commentIndex = index($nextLine,"<!--");
      $XMPIndex = index(uc $nextLine,"<XMP>");
      $headIndex = index(uc $nextLine,"<HEAD>");
      if (($XMPIndex == -1) && ($commentIndex == -1) && ($headIndex == -1)) {
         $nextLine = processLine($nextLine);
         $unprocessedLine = "";
         return $nextLine;
      }
      $min = $infinity;
      if ($commentIndex != -1) {
         $min = $commentIndex;
         $blockType = "comment";
      }
      if (($XMPIndex != -1) && ($XMPIndex < $min)) {
         $min = $XMPIndex;
         $blockType = "XMP";
      }
      if (($headIndex != -1) && ($headIndex < $min)) {
         $blockType = "head";
      }
      if ($blockType eq "XMP") {
         $firstPart = processLine(substr($nextLine,0,$XMPIndex));
         $nextLine = substr($nextLine,$XMPIndex + 5);
         $endXMPIndex = index(uc $nextLine,"</XMP>");
         while (($endXMPIndex == -1) && (!(eof(INFILE)))) {
            $blockLine = <INFILE>;
            $blockLine =~ s/<\/LISTING>/<\/XMP>/gis;
            $nextLine = $nextLine . $blockLine;
            $endXMPIndex = index(uc $nextLine,"</XMP>");
         }
         $unprocessedLine = "\n";
         if ($endXMPIndex != -1) {
            $unprocessedLine = substr($nextLine,$endXMPIndex + 6);
            $nextLine = substr($nextLine,0,$endXMPIndex);
         }
         $nextLine = processXMP($nextLine);
         $nextLine = $firstPart . "\\beginXMP " . $nextLine . "\\endXMP\n";
      }

      if ($blockType eq "head") {
         $firstPart = processLine(substr($nextLine,0,$headIndex));
         $nextLine = substr($nextLine,$headIndex + 6);
         $endHeadIndex = index(uc $nextLine,"</HEAD>");
         while (($endHeadIndex == -1) && (!(eof(INFILE)))) {
            $blockLine = <INFILE>;
            $nextLine = $nextLine . $blockLine;
            $endHeadIndex = index(uc $nextLine,"</HEAD>");
         }
         $unprocessedLine = "\n";
         if ($endHeadIndex != -1) {
            $unprocessedLine = substr($nextLine,$endHeadIndex + 7);
         }
         $headLine = substr($nextLine,0,$endHeadIndex);
         $headLine =~ s/\n/ /gs;
         if (($rightHeader eq "") && ($headLine =~ /<TITLE>(.*?)<\/TITLE>/i)) {
            $rightHeader = $1;
            $rightHeader = processLine($rightHeader);
            print OUTFILE "\\def\\rhdr{$rightHeader}\n";
            print OUTFILE "\\headline{\\normalsize\\raise 5pt \\rlap{\\lhdr}\\hrulefill\\raise 5pt \\llap{\\rhdr}}\n";
         }
         if (($baseURL eq "") && ($headLine =~ /<BASE\s.*?HREF="?(\S*?)("|\s|$)/is)) {
            $baseURL = $1;
            ($baseProtocol, $baseDir, $junk) = splitURL($baseURL);
         }
         $nextLine = $firstPart . "\n";
      }
      
      if ($blockType eq "comment") {
         $firstPart = processLine(substr($nextLine,0,$commentIndex));
         $nextLine = substr($nextLine,$commentIndex);
         $endCommentIndex = getTagEnd($nextLine);
         while (($endCommentIndex == -1) && (!(eof(INFILE)))) {
            $blockLine = <INFILE>;
            $nextLine = $nextLine . $blockLine;
            $endCommentIndex = getTagEnd($nextLine);
         }
         $unprocessedLine = "\n";
         if ($endCommentIndex != -1) {
            $unprocessedLine = substr($nextLine,$endCommentIndex + 1);
            $nextLine = substr($nextLine,0,$endCommentIndex + 1);
         }
         if ($includeComments) {
            $nextLine =~ s/\n/\n%/gs;
         } else {
            $nextLine = "";
         }
         $nextLine = $firstPart . "%" . $nextLine . "\n";
      }
      return $nextLine;
   }
   return "";
}

sub processInput {
   do {
      $line = readLine;
      if ($line =~ /\S/s) {
         print OUTFILE "$line";
      }
   } while ($line);
}

sub windup {
   close(INFILE);
   print OUTFILE "\\bye\n";
   close(OUTFILE);
}

initialize;
processCmdLine;
processOptions;
readResources;
readSpecialChars;
writePreamble;
processInput;
windup;
