home *** CD-ROM | disk | FTP | other *** search
/ Best Tools for JAVA / Best Tools for JAVA.iso / CONVERTR / TXT2HTML / TXT2HTML.PL < prev   
Encoding:
Perl Script  |  1995-09-09  |  22.6 KB  |  861 lines

  1. : # use perl
  2.     eval 'exec perl -S $0 "$@"'
  3.     if $runnning_under_some_shell;
  4. #
  5. # txt2html.pl
  6. # Convert raw text to something with a little HTML formatting
  7. #
  8. # Written by Seth Golub <seth@cs.wustl.edu> 
  9. #            http://www.cs.wustl.edu/~seth/txt2html/
  10. #
  11. # $Revision: 1.10 $
  12. # $Date: 1994/12/28 20:10:25 $
  13. # $Author: seth $
  14. #
  15. #
  16. # $Log: txt2html.pl,v $
  17. # Revision 1.10  1994/12/28  20:10:25  seth
  18. #  * Added --extract, etc.
  19. #
  20. # Revision 1.9  94/12/13  15:16:23  15:16:23  seth (Seth Golub)
  21. #  * Changed from #!/usr/local/bin/perl to the more clever version in
  22. #    the man page.  (How did I manage not to read this for so long?)
  23. #  * Swapped hrule & header back to handle double lines.  Why should
  24. #    this order screw up headers?
  25. # Revision 1.8  1994/11/30  21:07:03  seth
  26. #  * put mail_anchor back in.  (Why did I take this out?)
  27. #  * Finally added handling of lettered lists (ordered lists marked with
  28. #    letters)
  29. #  * Added title option (--title, -t)
  30. #  * Shortline now looks at how long the line was before txt2html
  31. #    started adding tags.   ($line_length)
  32. #  * Changed list references to scalars where appropriate.  (@foo[0] -> $foo[0])
  33. #  * Added untabify() to homogenize leading indentation for list
  34. #    prefixes and functions that use line length
  35. #  * Added "underline tolerance" for when underlines are not exactly the
  36. #    same length as what they underline.
  37. #  * Added error message for unrecognized options
  38. #  * removed \w matching on --capstag
  39. #  * Tagline now removes leading & trailing whitespace before tagging
  40. #  * swapped order of caps & heading in main loop
  41. #  * Cleaned up code for speed and to get rid of warnings
  42. #  * Added more restrictions to something being a mail header
  43. #  * Added indentation for lists, just to make the output more readable.
  44. #  * Fixed major bug in lists: $OL and $UL were never set, so when a
  45. #    list was ended "</UL>" was *always* used!
  46. #  * swapped order of hrule & header to properly handle long underlines
  47. #
  48. # Revision 1.7  94/10/28  13:16:11  13:16:11  seth (Seth Golub)
  49. #  * Added to comments in options section
  50. #  * renamed blank to is_blank
  51. #  * Page break is converted to horizontal rule <HR>
  52. #  * moved usage subroutine up top so people who look through code see
  53. #    it sooner
  54. # Revision 1.6  94/10/28  12:43:46  12:43:46  seth (Seth Golub)
  55. #  * Creates anchors at each heading
  56. # Revision 1.5  94/07/14  17:43:59  17:43:59  seth (Seth Golub)
  57. #  * Fixed minor bug in Headers
  58. #  * Preformatting can be set to only start/stop when TWO lines of
  59. #    [non]formatted-looking-text are encountered.  Old behavior is still
  60. #    possible through command line options (-pb 1 -pe 1).
  61. #  * Can preformat entire document (-pb 0) or disable preformatting
  62. #    completely (-pe 0).
  63. #  * Fixed minor bug in CAPS handling (paragraph breaks broke)
  64. #  * Puts paragraph tags *before* paragraphs, not just between them.
  65. # Revision 1.4  94/06/20  16:42:55  16:42:55  seth (Seth Golub)
  66. #  * Allow ':' for numbered lists (e.g. "1: Figs")
  67. #  * Whitespace at end of line will not start or end preformatting
  68. #  * Mailmode is now off by default
  69. #  * Doesn't break short lines if they are the first line in a list
  70. #    item.  It *should* break them anyway if the next line is a
  71. #    continuation of the list item, but I haven't dealt with this yet.
  72. #  * Added action on lines that are all capital letters.  You can change
  73. #    how these lines get tagged, as well as the mininum number of
  74. #    consecutive capital letters required to fire off this action.
  75. # Revision 1.3  94/05/17  15:58:58  15:58:58  seth (Seth Golub)
  76. # * Tiny bugfix in unhyphenation
  77. # Revision 1.2  94/05/16  18:15:16  18:15:16  seth (Seth Golub)
  78. #  * Added unhyphenation
  79. # Revision 1.1  94/05/16  16:19:03  16:19:03  seth (Seth Golub)
  80. # Initial revision
  81. #
  82. # 1.02  Allow '-' in mail headers
  83. #       Added handling for multiline mail headers
  84. #
  85. #
  86. #
  87. # Oscar Nierstrasz has a nice script for hypertextifying URLs.
  88. # It is available at:
  89. #   http://cuiwww.unige.ch/ftp/PUBLIC/oscar/scripts/html.pl
  90. #
  91.  
  92. #########################
  93. # Configurable options
  94. #
  95.  
  96. # [-s <n>    ] | [--shortline <n>                 ]
  97. $short_line_length = 40;        # Lines this short (or shorter) must be
  98.                 # intentionally broken and are kept
  99.                 # that short. <BR>
  100.  
  101. # [-p <n>    ] | [--prewhite <n>                  ]
  102. $preformat_whitespace_min = 5;  # Minimum number of consecutive leading
  103.                                 # whitespace characters to trigger 
  104.                                 # preformatting.  
  105.                 # NOTE: Tabs are now expanded to
  106.                 # spaces before this check is made.
  107.                 # That means if $tab_width is 8 and
  108.                 # this is 5, then one tab is expanded
  109.                 # to 8 spaces, which is enough to
  110.                 # trigger preformatting.
  111.  
  112. # [-pb <n>   ] | [--prebegin <n>                  ]
  113. $preformat_trigger_lines = 2;    # How many lines of preformatted-looking
  114.                 # text are needed to switch to <PRE>
  115.                 # <= 0 : Preformat entire document
  116.                 #    1 : one line triggers
  117.                 # >= 2 : two lines trigger
  118.  
  119. # [-pe <n>   ] | [--preend <n>                    ]
  120. $endpreformat_trigger_lines = 2; # How many lines of unpreformatted-looking
  121.                  # text are needed to switch from <PRE>
  122.                                  # <= 0 : Never preformat within document
  123.                  #    1 : one line triggers
  124.                  # >= 2 : two lines trigger
  125. # NOTE for --prebegin and --preend:
  126. # A zero takes precedence.  If one is zero, the other is ignored.
  127. # If both are zero, entire document is preformatted.
  128.  
  129.  
  130. # [-r <n>    ] | [--hrule <n>                     ]
  131. $hrule_min = 4;            # Min number of ---s for an HRule.
  132.  
  133. # [-c <n>    ] | [--caps <n>                      ]
  134. $min_caps_length = 3;        # min sequential CAPS for an all-caps line
  135.  
  136. # [-ct <tag> ] | [--capstag <tag>                 ]
  137. $caps_tag = "STRONG";        # Tag to put around all-caps lines
  138.  
  139. # [-m/+m     ] | [--mail        / --nomail        ]
  140. $mailmode = 0;            # Deal with mail headers & quoted text
  141.  
  142. # [-u/+u     ] | [--unhyphenate / --nounhyphenate ]
  143. $unhyphenation = 1;        # Enables unhyphenation of text.
  144.  
  145. # [-a <file> ] | [--append <file>                 ]
  146. # [+a        ] | [--noappend                      ]
  147. $append_file = 0;        # If you want something appended by 
  148.                 # default, put the filename here.
  149.                 # The appended text will not be
  150.                 # processed at all, so make sure it's
  151.                 # plain text or decent HTML.  i.e. do
  152.                 # not have things like:
  153.                 #   Seth Golub <seth@cs.wustl.edu>
  154.                 # but instead, have:
  155.                 #   Seth Golub <seth@cs.wustl.edu>
  156.  
  157. # [-t <title>] | [--title <title>                 ]
  158. $title = 0;            # You can specify a title.
  159.                 # Otherwise it won't put one in.
  160.  
  161. # [-ul <n>   ] | [--underlinelong <n>             ]
  162. $underline_tolerance_long = 1;    # How much longer can underlines 
  163.                 # be and still be underlines?
  164.  
  165. # [-us <n>   ] | [--underlineshort <n>            ]
  166. $underline_tolerance_short = 1;    # How much shorter can underlines 
  167.                 # be and still be underlines?
  168.  
  169. # [-tw <n>   ] | [--tabwidth <n>                  ]
  170. $tab_width = 8;            # How many spaces equal a tab?
  171.  
  172.  
  173. # [-iw <n>   ] | [--indent <n>                    ]
  174. $indent_width = 2;        # Indents this many spaces for each 
  175.                 # level of a list
  176.  
  177. # [-/+e      ] | [--extract / --noextract         ]
  178. $extract = 0;            # Extract Mode (suitable for inserting)
  179.  
  180. # END OF CONFIGURABLE OPTIONS
  181. ########################################
  182.  
  183.  
  184. ########################################
  185. # Definitions  (Don't change these)
  186. #
  187. $NONE       =   0;
  188. $LIST       =   1;
  189. $HRULE      =   2;
  190. $PAR        =   4;
  191. $PRE        =   8;
  192. $END        =  16;
  193. $BREAK      =  32;
  194. $HEADER     =  64;
  195. $MAILHEADER = 128;
  196. $MAILQUOTE  = 256;
  197. $CAPS       = 512;
  198.  
  199. $OL = 1;
  200. $UL = 2;
  201.  
  202. sub usage
  203. {
  204.     $0 =~ s#.*/##;
  205.     local($s) = " " x length($0);
  206.     print STDERR <<EOF;
  207.  
  208. Usage: $0 [options]
  209.  
  210. where options are:
  211.        $s [-v        ] | [--version                       ]
  212.        $s [-h        ] | [--help                          ]
  213.        $s [-s <n>    ] | [--shortline <n>                 ]
  214.        $s [-p <n>    ] | [--prewhite <n>                  ]
  215.        $s [-pb <n>   ] | [--prebegin <n>                  ]
  216.        $s [-pe <n>   ] | [--preend <n>                    ]
  217.        $s [-e/+e     ] | [--extract / --noextract         ]
  218.        $s [-r <n>    ] | [--hrule <n>                     ]
  219.        $s [-c <n>    ] | [--caps <n>                      ]
  220.        $s [-ct <tag> ] | [--capstag <tag>                 ]
  221.        $s [-m/+m     ] | [--mail     / --nomail           ]
  222.        $s [-u/+u     ] | [--unhyphen / --nounhyphen       ]
  223.        $s [-a <file> ] | [--append <file>                 ]
  224.        $s [+a        ] | [--noappend                      ]
  225.        $s [-t <title>] | [--title <title>                 ]
  226.        $s [-tw <n>   ] | [--tabwidth <n>                  ]
  227.        $s [-iw <n>   ] | [--indent <n>                    ]
  228.        $s [-ul <n>   ] | [--underlinelong <n>             ]
  229.        $s [-us <n>   ] | [--underlineshort <n>            ]
  230.  
  231.   More complete explanations of these options can be found in 
  232.   comments near the beginning of the script.
  233.  
  234. EOF
  235. }
  236.  
  237.  
  238. sub deal_with_options
  239. {
  240.     while ($ARGV[0] =~ /^[-+].+/)
  241.     {
  242.     if (($ARGV[0] eq "-r" || $ARGV[0] eq "--hrule") &&
  243.         $ARGV[1] =~ /^%d+$/)
  244.     {
  245.         $hrule_min = $ARGV[1];
  246.         shift @ARGV;
  247.         next;
  248.     }
  249.  
  250.     if (($ARGV[0] eq "-s" || $ARGV[0] eq "--shortline") &&
  251.         $ARGV[1] =~ /^\d+$/)
  252.     {
  253.         $short_line_length = $ARGV[1];
  254.         shift @ARGV;
  255.         next;
  256.     }
  257.  
  258.     if (($ARGV[0] eq "-p" || $ARGV[0] eq "--prewhite") &&
  259.         $ARGV[1] =~ /^\d+$/)
  260.     {
  261.         $preformat_whitespace_min = $ARGV[1];
  262.         shift @ARGV;
  263.         next;
  264.     }
  265.  
  266.     if (($ARGV[0] eq "-pb" || $ARGV[0] eq "--prebegin") &&
  267.         $ARGV[1] =~ /^\d+$/)
  268.     {
  269.         $preformat_trigger_lines = $ARGV[1];
  270.         shift @ARGV;
  271.         next;
  272.     }
  273.     
  274.     if (($ARGV[0] eq "-pe" || $ARGV[0] eq "--preend") &&
  275.         $ARGV[1] =~ /^\d+$/)
  276.     {
  277.         $endpreformat_trigger_lines = $ARGV[1];
  278.         shift @ARGV;
  279.         next;
  280.     }
  281.  
  282.     if (($ARGV[0] eq "-e" || $ARGV[0] eq "--extract"))
  283.     {
  284.         $extract = 1;
  285.         shift @ARGV;
  286.         next;
  287.     }
  288.  
  289.     if (($ARGV[0] eq "+e" || $ARGV[0] eq "--noextract"))
  290.     {
  291.         $extract = 0;
  292.         shift @ARGV;
  293.         next;
  294.     }
  295.  
  296.     if (($ARGV[0] eq "-c" || $ARGV[0] eq "--caps") &&
  297.         $ARGV[1] =~ /^\d+$/)
  298.     {
  299.         $min_caps_length = $ARGV[1];
  300.         shift @ARGV;
  301.         next;
  302.     }
  303.  
  304.     if (($ARGV[0] eq "-ct" || $ARGV[0] eq "--capstag") &&
  305.         $ARGV[1])
  306.     {
  307.         $caps_tag = $ARGV[1];
  308.         shift @ARGV;
  309.         next;
  310.     }
  311.  
  312.     if ($ARGV[0] eq "-m" || $ARGV[0] eq "--mail")
  313.     {
  314.         $mailmode = 1;
  315.         next;
  316.     }
  317.  
  318.     if ($ARGV[0] eq "+m" || $ARGV[0] eq "--nomail")
  319.     {
  320.         $mailmode = 0;
  321.         next;
  322.     }
  323.  
  324.     if ($ARGV[0] eq "-u" || $ARGV[0] eq "--unhyphen")
  325.     {
  326.         $unhyphenation = 1;
  327.         next;
  328.     }
  329.  
  330.     if ($ARGV[0] eq "+u" || $ARGV[0] eq "--nounhyphen")
  331.     {
  332.         $unhyphenation = 0;
  333.         next;
  334.     }
  335.  
  336.     if (($ARGV[0] eq "-a" || $ARGV[0] eq "--append") &&
  337.         $ARGV[1])
  338.     {
  339.         if (-r $ARGV[1]) {
  340.         $append_file = $ARGV[1];
  341.         } else {
  342.         print STDERR "Can't find or read $ARGV[1].\n";
  343.         }
  344.         shift @ARGV;
  345.         next;
  346.     }
  347.  
  348.     if ($ARGV[0] eq "+a" || $ARGV[0] eq "--noappend")
  349.     {
  350.         $append_file = 0;
  351.         next;
  352.     }
  353.  
  354.     if (($ARGV[0] eq "-t" || $ARGV[0] eq "--title") &&
  355.         $ARGV[1])
  356.     {
  357.         $title = $ARGV[1];
  358.         shift @ARGV;
  359.         next;
  360.     }
  361.  
  362.     if (($ARGV[0] eq "-ul" || $ARGV[0] eq "--underlinelong") &&
  363.         $ARGV[1] =~ /^\d+$/)
  364.     {
  365.         $underline_tolerance_long = $ARGV[1];
  366.         shift @ARGV;
  367.         next;
  368.     }
  369.  
  370.     if (($ARGV[0] eq "-us" || $ARGV[0] eq "--underlineshort") &&
  371.         $ARGV[1] =~ /^\d+$/)
  372.     {
  373.         $underline_tolerance_short = $ARGV[1];
  374.         shift @ARGV;
  375.         next;
  376.     }
  377.  
  378.     if (($ARGV[0] eq "-tw" || $ARGV[0] eq "--tabwidth") &&
  379.         $ARGV[1] =~ /^\d+$/)
  380.     {
  381.         $tab_width = $ARGV[1];
  382.         shift @ARGV;
  383.         next;
  384.     }
  385.  
  386.     if (($ARGV[0] eq "-iw" || $ARGV[0] eq "--indentwidth") &&
  387.         $ARGV[1] =~ /^\d+$/)
  388.     {
  389.         $indent_width = $ARGV[1];
  390.         shift @ARGV;
  391.         next;
  392.     }
  393.  
  394.     if ($ARGV[0] eq "-v" || $ARGV[0] eq "--version")
  395.     {
  396.         print '$Header: /users/hilco/seth/projects/txt2html/txt2html.pl,v 1.10 1994/12/28 20:10:25 seth Exp seth $ ';
  397.         print "\n";
  398.         exit;
  399.     }
  400.  
  401.     if ($ARGV[0] eq "-h" || $ARGV[0] eq "--help")
  402.     {
  403.         &usage;
  404.         exit;
  405.     }
  406.  
  407.     print STDERR "Unrecognized option: $ARGV[0]\n";
  408.     print STDERR " or bad paramater: $ARGV[1]\n" if($ARGV[1]);
  409.  
  410.     &usage;
  411.     exit(1);
  412.  
  413.     } continue {
  414.  
  415.     shift @ARGV;
  416.     }
  417.  
  418.     $preformat_trigger_lines = 0 if ($preformat_trigger_lines < 0);
  419.     $preformat_trigger_lines = 2 if ($preformat_trigger_lines > 2);
  420.  
  421.     $endpreformat_trigger_lines = 1 if ($preformat_trigger_lines == 0);
  422.     $endpreformat_trigger_lines = 0 if ($endpreformat_trigger_lines < 0);
  423.     $endpreformat_trigger_lines = 2 if ($endpreformat_trigger_lines > 2);
  424.  
  425.     $underline_tolerance_long  = 0 if $underline_tolerance_long < 0;
  426.     $underline_tolerance_short = 0 if $underline_tolerance_short < 0;
  427. }
  428.  
  429. sub is_blank
  430. {
  431.     return $_[0] =~ /^\s*$/;
  432. }
  433.  
  434. sub escape
  435. {
  436.     $line =~ s/&/&/g;
  437.     $line =~ s/>/>/g;
  438.     $line =~ s/</</g;
  439.     $line =~ s/\014/\n<HR>\n/g;    # Linefeeds become horizontal rules
  440. }
  441.  
  442. sub hrule
  443. {
  444.     if ($line =~ /^\s*([-_~=\*]\s*){$hrule_min,}$/)
  445.     {
  446.     $line = "<HR>\n";
  447.     $prev =~ s/<p>//;
  448.     $line_action |= $HRULE;
  449.     }
  450. }
  451.  
  452. sub shortline
  453. {
  454.     if (!($mode & $PRE) &&
  455.     !&is_blank($line) &&
  456.     ($line_length < $short_line_length) && 
  457.     !&is_blank($nextline) &&
  458.     !($line_action & ($HEADER | $HRULE | $BREAK | $LIST)))
  459.     {
  460.     $line =~ s/$/<BR>/;
  461.     $line_action |= $BREAK;
  462.     }
  463. }
  464.  
  465. sub mailstuff
  466. {
  467.     if ((($line =~ /^\w*>/) || # Handle "FF> Werewolves."
  468.      ($line =~ /^\w*\|/))&&  # Handle "Igor| There wolves."
  469.     !&is_blank($nextline))
  470.     {
  471.     $line =~ s/$/<BR>/;
  472.     $line_action |= $BREAK | $MAILQUOTE;
  473.     } elsif (($line =~ /^[\w\-]*:/) # Handle "Some-Header: blah"
  474.          && (($previous_action & $MAILHEADER) || &is_blank($prev))
  475.          && !&is_blank($nextline))
  476.     {
  477.     &anchor_mail if !($previous_action & $MAILHEADER);
  478.     $line =~ s/$/<BR>/;
  479.     $line_action |= $BREAK | $MAILHEADER;
  480.     } elsif (($line =~ /^\s+\S/) &&   # Handle multi-line mail headers
  481.          ($previous_action & $MAILHEADER) &&
  482.          !&is_blank($nextline))
  483.     {
  484.     $line =~ s/$/<BR>/;
  485.     $line_action |= $BREAK | $MAILHEADER;
  486.     }
  487. }
  488.  
  489. sub paragraph
  490. {
  491.     $prev .= "<p>\n";
  492.     $line_action |= $PAR;
  493. }
  494.  
  495. sub listprefix
  496. {
  497.     local($line) = @_;
  498.     local($prefix, $number, $rawprefix);
  499.  
  500.     return (0,0,0) if (!($line =~ /^\s*[-=\*o]\s+\S/ ) &&
  501.                !($line =~ /^\s*(\d+|[a-zA-Z])[\.\)\]:]\s+\S/ ));
  502.  
  503.     ($number) = $line =~ /^\s*(\d+|[a-zA-Z])/;
  504.  
  505.     # That slippery exception of "o" as a bullet
  506.     # (This ought to be determined more through the context of what lists
  507.     #  we have in progress, but this will probably work well enough.)
  508.     if($line =~ /^\s*o\s/)
  509.     {
  510.     $number = 0;
  511.     }
  512.  
  513.     if ($number)
  514.     {
  515.     ($rawprefix) = $line =~ /^(\s*(\d+|[a-zA-Z]).)/;
  516.     $prefix = $rawprefix;
  517.     $prefix =~ s/(\d+|[a-zA-Z])//;    # Take the number out
  518.     } else {
  519.     ($rawprefix) = $line =~ /^(\s*[-=o\*].)/;
  520.     $prefix = $rawprefix;
  521.     }
  522.     ($prefix, $number, $rawprefix);
  523. }
  524.  
  525. sub startlist
  526. {
  527.     local($prefix, $number, $rawprefix) = @_;
  528.  
  529.     $listprefix[$listnum] = $prefix;
  530.     if($number)
  531.     {
  532.     # It doesn't start with 1,a,A.  Let's not screw with it.
  533.     if (($number != 1) && ($number ne "a") && ($number ne "A"))
  534.     {
  535.         return;
  536.     }
  537.     $prev .= "$list_indent<OL>\n";
  538.     $list[$listnum] = $OL;
  539.     } else {
  540.     $prev .= "$list_indent<UL>\n";
  541.     $list[$listnum] = $UL;
  542.     }
  543.     $listnum++;
  544.     $list_indent = " " x $listnum x $indent_width;
  545.     $line_action |= $LIST;
  546.     $mode |= $LIST;
  547. }
  548.  
  549.  
  550. sub endlist            # End N lists
  551. {
  552.     local($n) = @_;
  553.     for(; $n > 0; $n--, $listnum--)
  554.     {
  555.     $list_indent = " " x ($listnum-1) x $indent_width;
  556.     if($list[$listnum-1] == $UL)
  557.     {
  558.         $prev .= "$list_indent</UL>\n";
  559.     } elsif($list[$listnum-1] == $OL)
  560.     {
  561.         $prev .= "$list_indent</OL>\n";
  562.     } else
  563.     {
  564.         print STDERR "Encountered list of unknown type\n";
  565.     }
  566.     }
  567.     $line_action |= $END;
  568.     $mode ^= ($LIST & $mode) if (!$listnum);
  569. }
  570.  
  571. sub continuelist
  572. {
  573.     $line =~ s/^\s*[-=o\*]\s*/$list_indent<LI> / if $list[$listnum-1] == $UL;
  574.     $line =~ s/^\s*(\d+|[a-zA-Z]).\s*/$list_indent<LI> /    if $list[$listnum-1] == $OL;
  575.     $line_action |= $LIST;
  576. }
  577.  
  578. sub liststuff
  579. {
  580.     local($i);
  581.  
  582.     local($prefix, $number, $rawprefix) = &listprefix($line);
  583.  
  584.     $i = $listnum;
  585.     if (!$prefix)
  586.     {
  587.     return if !&is_blank($prev); # inside a list item
  588.  
  589.     # This ain't no list.  We'll want to end all of them.
  590.     return if !($mode & $LIST);    # This just speeds up the inevitable
  591.     $i = 0;
  592.     } else 
  593.     {
  594.     # Maybe we're going back up to a previous list
  595.     $i-- while (($prefix ne $listprefix[$i-1]) && ($i >= 0));
  596.     }
  597.  
  598.     if (($i >= 0) && ($i != $listnum))
  599.     { 
  600.     &endlist($listnum - $i); 
  601.     } elsif (!$listnum || $i != $listnum)
  602.     { 
  603.     &startlist($prefix, $number, $rawprefix);
  604.     }
  605.  
  606.     &continuelist($prefix, $number, $rawprefix) if ($mode & $LIST);
  607. }
  608.  
  609. sub endpreformat
  610. {
  611.     if(!($line =~ /\s{$preformat_whitespace_min,}\S+/) && 
  612.        ($endpreformat_trigger_lines == 1 ||
  613.     !($nextline =~ /\s{$preformat_whitespace_min,}\S+/)))
  614.     {
  615.     $prev =~ s#$#\n</PRE>#;
  616.     $mode ^= ($PRE & $mode);
  617.     $line_action |= $END;
  618.     }
  619. }
  620.  
  621. sub preformat
  622. {
  623.     if($preformat_trigger_lines == 0 ||
  624.        (($line =~ /\s{$preformat_whitespace_min,}\S+/) &&
  625.     ($preformat_trigger_lines == 1 || 
  626.      $nextline =~ /\s{$preformat_whitespace_min,}\S+/)))
  627.     {
  628.     $line =~ s/^/<PRE>\n/;
  629.     $prev =~ s/<p>//;
  630.     $mode |= $PRE;
  631.     $line_action |= $PRE;
  632.     }
  633. }
  634.  
  635. sub make_new_anchor
  636. {
  637.     $anchor++;
  638.     $anchor;
  639. }
  640.  
  641. sub anchor_mail
  642. {
  643.     local($text) = $line =~ /\S+: *(.*) *$/;
  644.     local($anchor) = &make_new_anchor($text);
  645.     $line =~ s/(.*)/<A NAME="$anchor">$1<\/A>/;
  646. }
  647.  
  648. sub anchor_heading
  649. {
  650.     local($heading) = @_;
  651.     local($anchor) = &make_new_anchor($heading);
  652.     $line =~ s/(<H.>.*<\/H.>)/<A NAME="$anchor">$1<\/A>/;
  653. }
  654.  
  655. sub heading
  656. {
  657.     local($hindent, $heading) = $line =~ /^(\s*)(.+)$/;
  658.     $hindent = 0;        # This isn't used yet, but Perl warns of
  659.                 # "possible typo" if I declare a var
  660.                 # and never reference it.
  661.  
  662.     # This is now taken care of in main()
  663. #    $heading =~ s/\s+$//;    # get rid of trailing whitespace.
  664.  
  665.     local($underline) = $nextline =~ /^\s*(\S+)\s*$/;
  666.     
  667.     if((length($heading) > (length($underline) + $underline_tolerance_short))
  668.        || (length($heading) < (length($underline) -$underline_tolerance_long)))
  669.     {
  670.     return;
  671.     }
  672.  
  673. #    $underline =~ s/(^.).*/$1/;     # Could I do this any less efficiently?
  674.     $underline = substr($underline,0,1);
  675.  
  676.     local($hlevel);
  677.     $hlevel = 1 if $underline eq "*";
  678.     $hlevel = 2 if $underline eq "=";
  679.     $hlevel = 3 if $underline eq "+";
  680.     $hlevel = 4 if $underline eq "-";
  681.     $hlevel = 5 if $underline eq "~";
  682.     $hlevel = 6 if $underline eq ".";
  683.     return if !$hlevel;
  684.  
  685.     $nextline = <STDIN>;    # Eat the underline
  686.     &tagline("H${hlevel}");
  687.     &anchor_heading($heading);
  688.     $line_action |= $HEADER;
  689. }
  690.  
  691. sub unhyphenate
  692. {
  693.     local($second);
  694.  
  695.     # This looks hairy because of all the quoted characters.
  696.     # All I'm doing is pulling out the word that begins the next line.
  697.     # Along with it, I pull out any punctuation that follows.
  698.     # Preceding whitespace is preserved.  We don't want to screw up
  699.     # our own guessing systems that rely on indentation.
  700.     ($second) = $nextline =~ /^\s*([a-zA-Z]+[\)\}\]\.,:;\'\"\>]*\s*)/; # "
  701.     $nextline =~ s/^(\s*)[a-zA-Z]+[\)\}\]\.,:;\'\"\>]*\s*/$1/; # "
  702.     # (The silly comments are for my less-than-perfect code hilighter)
  703.  
  704.     $line =~ s/\-\s*$/$second/;
  705.     $line .= "\n";
  706. }
  707.  
  708. sub untabify
  709. {
  710.     local($oldws) = $line =~ /^([ \011]+)/;
  711.     local($oldlen) = (length($oldws));
  712.  
  713.     local($i, $column);
  714.     for($i=0, $column = 0; $i < $oldlen; $i++)
  715.     {
  716.     if(substr($oldws, $i, 1) eq " ")
  717.     {            # Space
  718.         $column++;
  719.     } else {        # Tab
  720.         $column += $tab_width - ($column % $tab_width);
  721.     }
  722.     }
  723.     $line = (" " x $column) . substr($line, $oldlen);
  724. }
  725.  
  726. sub tagline
  727. {
  728.     local($tag) = @_;
  729.     $line =~ s/^\s*(.*)\s*$/<$tag>$1<\/$tag>\n/;
  730. }
  731.  
  732. sub caps
  733. {
  734.     if($line =~ /^[^a-z<]*[A-Z]{$min_caps_length,}[^a-z<]*$/)
  735.     {
  736.     &tagline($caps_tag);
  737.     $line_action |= $CAPS;
  738.     }
  739. }
  740.  
  741.  
  742.  
  743. sub main
  744. {
  745.     &deal_with_options;
  746.  
  747.     if(!$extract)
  748.     {
  749.     print "<HTML>\n";
  750.     print "<HEAD>\n";
  751.  
  752.     # It'd be nice if we could guess a title from the first header,
  753.     # but even that would be too late if we're doing this in one pass.
  754.     print "<TITLE>$title</TITLE>\n" if($title);
  755.  
  756.     print "</HEAD>\n";
  757.                 
  758.     print "<BODY>\n";
  759.     }
  760.  
  761.     $prev     = "";
  762.     $line     = <STDIN>;
  763.     $nextline = <STDIN>;
  764.     do 
  765.     {
  766.     $line =~ s/[ \011]*$//;    # Chop trailing whitespace
  767.  
  768.     &untabify;        # Change leading whitespace into spaces
  769.  
  770.     $line_length = length($line); # Do this before tags go in
  771.  
  772.     &escape;
  773.  
  774.     &endpreformat if (($mode & $PRE) && ($preformat_trigger_lines != 0));
  775.  
  776.     &hrule if !($mode & $PRE);
  777.  
  778.     &heading   if (!($mode & $PRE) && 
  779.                $nextline =~ /^\s*[=\-\*\.~\+]+$/);
  780.  
  781.     &caps if  !($mode & $PRE);
  782.  
  783.     &liststuff if (!($mode & $PRE) && 
  784.                !&is_blank($line));
  785.  
  786.     &mailstuff if ($mailmode && 
  787.                !($mode & $PRE) && 
  788.                !($line_action & $HEADER));
  789.  
  790.     &preformat if (!($line_action & ($HEADER | $LIST | $MAILHEADER)) && 
  791.                !($mode & ($LIST | $PRE)) &&
  792.                ($endpreformat_trigger_lines != 0));
  793.  
  794.     ¶graph if ((&is_blank($prev) || ($line_action & $END)) && 
  795.                !&is_blank($line) &&
  796.                !($mode & ($LIST | $PRE)) && # paragraphs in lists
  797.                                     # *should* be allowed.
  798.                (!$line_action || 
  799.             ($line_action & ($CAPS | $END | $MAILQUOTE))));
  800.  
  801.     &shortline;
  802.  
  803.     &unhyphenate if ($unhyphenation && 
  804.              ($line =~ /[a-zA-Z]\-$/) && # ends in hyphen
  805.              # next line starts w/letters
  806.              ($nextline =~ /^\s*[a-zA-Z]/) && 
  807.              !($mode & ($PRE | $HEADER | $MAILHEADER | $BREAK)));
  808.  
  809.  
  810.     # Print it out and move on.
  811.  
  812.     print $prev;
  813.  
  814.     if (!&is_blank($nextline))
  815.     {
  816.         $previous_action = $line_action;
  817.         $line_action     = $NONE;
  818.     }
  819.  
  820.     $prev = $line;
  821.     $line = $nextline;
  822.     $nextline = <STDIN>;
  823.     } until (!$nextline && !$line && !$prev);
  824.  
  825.     $prev = "";
  826.     &endlist($listnum) if ($mode & $LIST); # End all lists
  827.     print $prev;
  828.  
  829.     print "\n";
  830.  
  831.     print "</PRE>\n" if ($mode & $PRE);
  832.  
  833.     if ($append_file)
  834.     {
  835.     if(-r $append_file)
  836.     {
  837.         open(APPEND, $append_file);
  838.         print while <APPEND>;
  839.     } else {
  840.         print STDERR "Can't find or read file $append_file to append.\n";
  841.     }
  842.     }
  843.  
  844.     if(!$extract)
  845.     {
  846.     print "</BODY>\n";
  847.     print "</HTML>\n";
  848.     }
  849. }
  850.  
  851. &main();
  852.  
  853.