home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 2 / goldfish_vol2_cd1.bin / files / docs / misc / amigafaqg / bin / texi2html
Text File  |  1994-07-28  |  41KB  |  1,570 lines

  1. #!/usr/local/dist/bin/perl
  2. 'di';
  3. 'ig00';
  4. #+##############################################################################
  5. #                                                                              #
  6. # File: texi2html                                                              #
  7. #                                                                              #
  8. # Description: Program to transform most Texinfo documents to HTML             #
  9. #                                                                              #
  10. #-##############################################################################
  11.  
  12. # @(#)texi2html    1.29 04/21/94    Written by Lionel Cons, Lionel.Cons@cern.ch
  13.  
  14. # texi2html 1.29af 08.08.94   by Hans Maurer
  15. # Made some modifications for better compatability with AmigaFAQ
  16.  
  17. # The man page for this program is included at the end of this file and can be
  18. # viewed using the command 'nroff -man texi2html'.
  19. # Please read the copyright at the end of the man page.
  20.  
  21. #+++############################################################################
  22. #                                                                              #
  23. # Constants                                                                    #
  24. #                                                                              #
  25. #---############################################################################
  26.  
  27. $DEBUG_TOC = 1;
  28. $DEBUG_INDEX = 2;
  29. $DEBUG_BIB = 4;
  30. $DEBUG_GLOSS = 8;
  31. $DEBUG_DEF = 16;
  32.  
  33. $BIBRE = '\[[\w\/]+\]';            # RE for a bibliography reference
  34. $FILERE = '[\/\w.+-]+';            # RE for a file name
  35. $VARRE = '[^\s\{\}]+';            # RE for a variable name
  36. $NODERE = '[^@{}:\'`",]+';        # RE for a node name
  37. $NODESRE = '[^@{}:\'`"]+';        # RE for a list of node names
  38. $XREFRE = '[^@{}]+';            # RE for a xref (should use NODERE)
  39.  
  40. $THISPROG = "texi2html 1.29af";            # program name and version
  41. $TODAY = &pretty_date;            # like "20 September 1993"
  42. $SPLITTAG = "<!-- SPLIT HERE -->\n";    # tag to know where to split
  43. $PROTECTTAG = "_ThisIsProtected_";    # tag to recognize protected sections
  44.  
  45. #
  46. # language dependent constants
  47. #
  48. $LDC =
  49.     (
  50.      'xrefstring',     'see',
  51.      'Xrefstring',     'See',
  52.      'Footnotestring', 'Footnote',
  53.      'Chapterstring',  'Chapter',
  54.      'Appendixstring', 'Appendix',
  55.      'Sectionstring',  'Section',
  56.      'sectionstring',  'section',
  57.      'pagestring',     'page',
  58.      );
  59.  
  60. #
  61. # texinfo section names to level
  62. #
  63. %sec2level = (
  64.           'top', 0,
  65.           'chapter', 1,
  66.           'unnumbered', 1,
  67.           'majorheading', 1,
  68.           'chapheading', 1,
  69.           'appendix', 1,
  70.           'section', 2,
  71.           'unnumberedsec', 2,
  72.           'heading', 2,
  73.           'appendixsec', 2,
  74.           'appendixsection', 2,
  75.           'subsection', 3,
  76.           'unnumberedsubsec', 3,
  77.           'subheading', 3,
  78.           'appendixsubsec', 3,
  79.           'subsubsection', 4,
  80.           'unnumberedsubsubsec', 4,
  81.           'subsubheading', 4,
  82.           'appendixsubsubsec', 4,
  83.           );
  84.  
  85. #
  86. # texinfo "simple things" (@foo) to HTML ones
  87. #
  88. %simple_map = (
  89.            # cf. makeinfo.c
  90.            "*", "<BR>",        # HTML+
  91.            " ", " ",
  92.            "\n", "\n",
  93.            "|", "",
  94.            # spacing commands
  95.            ":", "",
  96.            "!", "!",
  97.            "?", "?",
  98.            ".", ".",
  99.            );
  100.  
  101. #
  102. # texinfo "things" (@foo{}) to HTML ones
  103. #
  104. %things_map = (
  105.            'TeX', 'TeX',
  106.            'br', '<P>',        # paragraph break
  107.            'bullet', '*',
  108.            'copyright', '(C)',
  109.            'dots', '...',
  110.            'equiv', '==',
  111.            'error', 'error-->',
  112.            'expansion', '==>',
  113.            'minus', '-',
  114.            'point', '-!-',
  115.            'print', '-|',
  116.            'result', '=>',
  117.            'today', $TODAY,
  118.            );
  119.  
  120. #
  121. # texinfo styles (@foo{bar}) to HTML ones
  122. #
  123. %style_map = (
  124.           'asis', '',
  125.           'b', 'B',
  126.           'cite', 'CITE',
  127.           'code', 'CODE',
  128.           'ctrl', '&do_ctrl',    # special case
  129.           'dfn', 'DFN',
  130.           'dmn', '',        # useless
  131.           'emph', 'EM',
  132.           'file', '"TT',        # will put quotes, cf. &apply_style
  133.           'i', 'I',
  134.           'kbd', 'KBD',
  135.           'key', 'KBD',
  136.           'r', '',            # unsupported
  137.           'samp', '"SAMP',        # will put quotes, cf. &apply_style
  138.           'sc', '&do_sc',        # special case
  139.           'subtitle', 'H2',
  140.           'strong', 'STRONG',
  141.           't', 'TT',
  142.           'title', 'H1',
  143.           'titlefont', '',        # useless
  144.           'var', 'VAR',
  145.           'w', '',            # unsupported
  146.           );
  147.  
  148. #
  149. # texinfo format (@foo/@end foo) to HTML ones
  150. #
  151. %format_map = (
  152.            'display', 'PRE',
  153.            'example', 'PRE',
  154.            'format', 'PRE',
  155.            'lisp', 'PRE',
  156.            'quotation', 'BLOCKQUOTE',
  157.            'smallexample', 'PRE',
  158.            'smalllisp', 'PRE',
  159.            # lists
  160.            'itemize', 'UL',
  161.            'enumerate', 'OL',
  162.            # poorly supported
  163.            'flushleft', 'PRE',
  164.            'flushright', 'PRE',
  165.            );
  166.  
  167. #
  168. # texinfo definition shortcuts to real ones
  169. #
  170. %def_map = (
  171.         # basic commands
  172.         'deffn', 0,
  173.         'defvr', 0,
  174.         'deftypefn', 0,
  175.         'deftypevr', 0,
  176.         'defcv', 0,
  177.         'defop', 0,
  178.         'deftp', 0,
  179.         # basic x commands
  180.         'deffnx', 0,
  181.         'defvrx', 0,
  182.         'deftypefnx', 0,
  183.         'deftypevrx', 0,
  184.         'defcvx', 0,
  185.         'defopx', 0,
  186.         'deftpx', 0,
  187.         # shortcuts
  188.         'defun', 'deffn Function',
  189.         'defmac', 'deffn Macro',
  190.         'defspec', 'deffn {Special Form}',
  191.         'defvar', 'defvr Variable',
  192.         'defopt', 'defvr {User Option}',
  193.         'deftypefun', 'deftypefn Function',
  194.         'deftypevar', 'deftypevr Variable',
  195.         'defivar', 'defcv {Instance Variable}',
  196.         'defmethod', 'defop Method',
  197.         # x shortcuts
  198.         'defunx', 'deffnx Function',
  199.         'defmacx', 'deffnx Macro',
  200.         'defspecx', 'deffnx {Special Form}',
  201.         'defvarx', 'defvrx Variable',
  202.         'defoptx', 'defvrx {User Option}',
  203.         'deftypefunx', 'deftypefnx Function',
  204.         'deftypevarx', 'deftypevrx Variable',
  205.         'defivarx', 'defcvx {Instance Variable}',
  206.         'defmethodx', 'defopx Method',
  207.         );
  208.  
  209. #
  210. # things to skip
  211. #
  212. %to_skip = (
  213.         # comments
  214.         'c', 1,
  215.         'comment', 1,
  216.         # useless
  217.         'contents', 1,
  218.         'shortcontents', 1,
  219.         'summarycontents', 1,
  220.         'footnotestyle', 1,
  221.         'end ifclear', 1,
  222.         'end ifset', 1,
  223.         'iftex', 1,
  224.         'end iftex', 1,
  225.         'parskip', 1,
  226.         'titlepage', 1,
  227.         'end titlepage', 1,
  228.         # unsupported commands (formatting)
  229.         'afourpaper', 1,
  230.         'cropmarks', 1,
  231.         'finalout', 1,
  232.         'headings', 1,
  233.         'need', 1,
  234.         'page', 1,
  235.         'setchapternewpage', 1,
  236.         'everyheading', 1,
  237.         'everyfooting', 1,
  238.         'evenheading', 1,
  239.         'evenfooting', 1,
  240.         'oddheading', 1,
  241.         'oddfooting', 1,
  242.         'smallbook', 1,
  243.         'vskip', 1,
  244.         # unsupported formats
  245.         'cartouche', 1,
  246.         'end cartouche', 1,
  247.         'group', 1,
  248.         'end group', 1,
  249.         # misc unsupported commands
  250.             'defindex', 1,
  251.         );
  252.  
  253. #+++############################################################################
  254. #                                                                              #
  255. # Argument parsing, initialisation                                             #
  256. #                                                                              #
  257. #---############################################################################
  258.  
  259. $invisible_mark = '';
  260. $use_bibliography = 1;
  261. $usage = <<EOT;
  262. This is $THISPROG
  263. To convert a Texinfo file to HMTL: $0 [options] file
  264.   where options can be:
  265.     -glossary      : handle a glossary
  266.     -invisible name: use name as an invisible anchor
  267.     -menu          : handle menus
  268.     -split_chapter : split on main sections
  269.     -split_node    : split on nodes
  270.     -usage         : print usage instructions
  271.     -verbose       : verbose output
  272. To check converted files: $0 -check [-verbose] files
  273. EOT
  274.  
  275. while ($_ = $ARGV[0], /^-/) {
  276.     shift;
  277.     if (/^-d(ebug)?(\d+)?$/) { $debug = $2 || shift; next; }
  278.     if (/^-c(heck)?$/)       { $check = 1; next; }
  279.     if (/^-g(lossary)?$/)    { $use_glossary = 1; next; }
  280.     if (/^-i(nvisible)?$/)   { $invisible_mark = shift; next; }
  281.     if (/^-iso$/)            { $use_iso = 1; next; }
  282.     if (/^-m(enu)?$/)        { $show_menu = 1; next; }
  283.     if (/^-s(plit)?_?(n(ode)?|c(hapter)?)?$/) {
  284.     if ($2 =~ /^n/) {
  285.         $split_node = 1;
  286.     } else {
  287.         $split_chapter = 1;
  288.     }
  289.     next;
  290.     }
  291.     if (/^-v(erbose)?$/)     { $verbose = 1; next; }
  292.     die $usage;
  293. }
  294.  
  295. if ($check) {
  296.     die $usage unless @ARGV > 0;
  297.     ✓
  298.     exit;
  299. }
  300.  
  301. $invisible_mark = '<IMG SRC="invisible.xbm">' if $invisible_mark eq 'xbm';
  302. die $usage unless @ARGV == 1;
  303. $docu = shift(@ARGV);
  304. if ($docu =~ /.*\//) {
  305.     chop($docu_dir = $&);
  306.     $docu_name = $';
  307. } else {
  308.     $docu_dir = '.';
  309.     $docu_name = $docu;
  310. }
  311. $docu_name =~ s/\.te?x(i|info)?$//;    # basename of the document
  312.  
  313. $docu_toc = $docu_doc = $docu_foot = $docu_name;
  314. $docu_toc  .= '_toc.html';        # document's table of contents
  315. $docu_doc  .= '.html';            # document's contents
  316. $docu_foot .= '_foot.html';        # document's footnotes
  317.  
  318. #
  319. # variables
  320. #
  321. %value = ();                # hold texinfo variables
  322. $value{'html'} = 1;            # predefine html (the output format)
  323. $value{'texi2html'} = '1.29';        # predefine texi2html (the translator)
  324. %node2sec = ();                # node to section name
  325. %node2href = ();            # node to HREF
  326. %bib2href = ();                # bibliography reference to HREF
  327. %gloss2href = ();            # glossary term to HREF
  328. @sections = ();                # list of sections
  329. %tag2pro = ();                # protected sections
  330.  
  331. #
  332. # initial indexes
  333. #
  334. $bib_num = 0;
  335. $foot_num = 0;
  336. $gloss_num = 0;
  337. $idx_num = 0;
  338. $sec_num = 0;
  339. $doc_num = 0;
  340. $html_num = 0;
  341.  
  342. #
  343. # can I use ISO8879 characters? (HTML+)
  344. #
  345. if ($use_iso) {
  346.     $things_map{'bullet'} = "•";
  347.     $things_map{'copyright'} = "©";
  348.     $things_map{'dots'} = "…";
  349.     $things_map{'equiv'} = "≡";
  350.     $things_map{'expansion'} = "→";
  351.     $things_map{'point'} = "∗";
  352.     $things_map{'result'} = "⇒";
  353. }
  354.  
  355. #
  356. # read texi2html extensions (if any)
  357. #
  358. $extensions = 'texi2html.ext'; # extensions in working directory
  359. if (-f $extensions) {
  360.     print "# reading extensions from $extensions\n" if $verbose;
  361.     require($extensions);
  362. }
  363. ($progdir = $0) =~ s/[^\/]+$//;
  364. if ($progdir && ($progdir ne './')) {
  365.     $extensions = "${progdir}texi2html.ext"; # extensions in texi2html directory
  366.     if (-f $extensions) {
  367.     print "# reading extensions from $extensions\n" if $verbose;
  368.     require($extensions);
  369.     }
  370. }
  371.  
  372. print "# reading from $docu\n" if $verbose;
  373.  
  374. #+++############################################################################
  375. #                                                                              #
  376. # Pass 1: read source, handle command, variable, simple substitution           #
  377. #                                                                              #
  378. #---############################################################################
  379.  
  380. @lines = ();                # whole document
  381. @toc_lines = ();            # table of contents
  382. $curlevel = 0;                # current level in TOC
  383. $node = '';                # current node name
  384. $in_table = 0;                # am I inside a table
  385. $table_type = '';            # type of table ('', 'f', 'v')
  386. $in_bibliography = 0;            # am I inside a bibliography
  387. $in_glossary = 0;            # am I inside a glossary
  388. $in_top = 0;                # am I inside the top node
  389. $in_pre = 0;                # am I inside a preformatted section
  390. $in_html = 0;                # am I inside an HTML section
  391. $first_line = 1;                # is it the first line
  392. $dont_html = 0;                # don't protect HTML on this line
  393. $split_num = 0;                # split index
  394.  
  395. # build code for simple substitutions
  396. # the maps used (%simple_map and %things_map) MUST be aware of this
  397. # watch out for regexps, / and escaped characters!
  398. $subst_code = '';
  399. for (keys(%simple_map)) {
  400.     ($re = $_) =~ s/(\W)/\\$1/g; # protect regexp chars
  401.     $subst_code .= "s/\\@$re/$simple_map{$_}/g && study;\n";
  402. }
  403. for (keys(%things_map)) {
  404.     $subst_code .= "s/\\@$_\\{\\}/$things_map{$_}/g && study;\n";
  405. }
  406.  
  407. &init_input;
  408. while ($_ = &next_line) {
  409.     #
  410.     # remove \input on the first lines
  411.     #
  412.     if ($first_line && /^\\input/) {
  413.     next;
  414.     }
  415.     else {
  416.     $first_line = 0;
  417.     }
  418.     #
  419.     # parse texinfo tags
  420.     #
  421.     $tag = '';
  422.     $end_tag = '';
  423.     if (/^\@end\s+(\w+)\b/) {
  424.     $end_tag = $1;
  425.     } elsif (/^\@(\w+)\b/) {
  426.     $tag = $1;
  427.     }
  428.     #
  429.     # handle @ifhtml / @end ifhtml
  430.     #
  431.     if ($in_html) {
  432.     if ($end_tag eq 'ifhtml') {
  433.         $in_html = 0;
  434.     } else {
  435.         $tag2pro{$in_html} .= $_;
  436.     }
  437.     next;
  438.     } elsif ($tag eq 'ifhtml') {
  439.     $in_html = $PROTECTTAG . ++$html_num;
  440.     push(@lines, $in_html);
  441.     next;
  442.     }
  443.     #
  444.     # try to skip the line
  445.     #
  446.     if ($end_tag) {
  447.     next if $to_skip{"end $end_tag"};
  448.     } elsif ($tag) {
  449.     next if $to_skip{$tag};
  450.     last if $tag eq 'bye';
  451.     }
  452.     if ($in_top) {
  453.     # parsing the top node
  454.     if ($tag eq 'node' || $tag eq 'include' || $sec2level{$tag}) {
  455.         # no more in top
  456.         $in_top = 0;
  457.     } else {
  458.         # skip it
  459.         next;
  460.     }
  461.     }
  462.     #
  463.     # try to remove inlined comments
  464.     # syntax from tex-mode.el comment-start-skip
  465.     #
  466.     s/((^|[^\@])(\@\@)*)\@c(omment)? .*/\1/;
  467.     #
  468.     # analyze the tag
  469.     #
  470.     if ($tag) {
  471.     # skip lines
  472.     &skip_until($tag), next if $tag eq 'ignore';
  473.     &skip_until($tag), next if $tag eq 'ifinfo';
  474.     &skip_until($tag), next if $tag eq 'tex';
  475.     # handle special tables
  476.     if ($tag eq 'table') {
  477.         $table_type = '';
  478.     } elsif ($tag eq 'ftable') {
  479.         $tag = 'table';
  480.         $table_type = 'f';
  481.     } elsif ($tag eq 'vtable') {
  482.         $tag = 'table';
  483.         $table_type = 'v';
  484.     }
  485.     # special cases
  486.     if ($tag eq 'top' || ($tag eq 'node' && /^\@node\s+top\s*,/i)) {
  487.         $in_top = 1;
  488.         @lines = (); # ignore all lines before top (title page garbage)
  489.         next;
  490.     } elsif ($tag eq 'node') {
  491.         $in_top = 0;
  492.         &protect_html;    # if node contains '&' for instance
  493.         warn "Bad node line: $_" unless $_ =~ /^\@node\s$NODESRE$/o;
  494.         s/^\@node\s+//;
  495.         ($node) = split(/,/);
  496.         $node =~ s/\s+/ /g; # normalize
  497.         $node =~ s/ $//;
  498.         if ($split_node) {
  499.         &next_doc;
  500.         push(@lines, $SPLITTAG) if $split_num++;
  501.         push(@sections, $node);
  502.         }
  503.         next;
  504.     } elsif ($tag eq 'include') {
  505.         if (/^\@include\s+($FILERE)\s*$/o) {
  506.         $file = $1;
  507.         $file = "$docu_dir/$file" unless -e $file;
  508.         if (-e $file) {
  509.             &open($file);
  510.             print "# including $file\n" if $verbose;
  511.         } else {
  512.             warn "Can't find $file, skipping";
  513.         }
  514.         } else {
  515.         warn "Bad include line: $_";
  516.         }
  517.         next;
  518.     } elsif ($tag eq 'ifclear') {
  519.         if (/^\@ifclear\s+($VARRE)\s*$/o) {
  520.         next unless defined($value{$1});
  521.         &skip_until($tag);
  522.         } else {
  523.         warn "Bad ifclear line: $_";
  524.         }
  525.         next;
  526.     } elsif ($tag eq 'ifset') {
  527.         if (/^\@ifset\s+($VARRE)\s*$/o) {
  528.         next if defined($value{$1});
  529.         &skip_until($tag);
  530.         } else {
  531.         warn "Bad ifset line: $_";
  532.         }
  533.         next;
  534.     } elsif ($tag eq 'menu' && ! $show_menu) {
  535.         &skip_until($tag);
  536.         next;
  537.     } elsif ($format_map{$tag}) {
  538.         $in_pre = 1 if $format_map{$tag} eq 'PRE';
  539.         push(@lines, "<$format_map{$tag}>\n");
  540.         next;
  541.     } elsif ($tag eq 'table') {
  542.         if (/^\@[fv]?table\s+\@(\w+)\s*$/) {
  543.         $in_table = $1;
  544.         push(@lines, "<DL COMPACT>\n");
  545.         } else {
  546.         warn "Bad table line: $_";
  547.         }
  548.         next;
  549.     } elsif ($tag eq 'synindex' || $tag eq 'syncodeindex') {
  550.         if (/^\@$tag\s+(\w)\w\s+(\w)\w\s*$/) {
  551.         eval("*${1}index = *${2}index");
  552.         } else {
  553.         warn "Bad syn*index line: $_";
  554.         }
  555.         next;
  556.     } elsif ($tag eq 'sp') {
  557.         push(@lines, "<P>\n");
  558.         next;
  559.     } elsif (defined($def_map{$tag})) {
  560.         if ($def_map{$tag}) {
  561.         s/^\@$tag\s+//;
  562.         $tag = $def_map{$tag};
  563.         $_ = "\@$tag $_";
  564.         $tag =~ s/\s.*//;
  565.         }
  566.     }
  567.     if (defined($def_map{$tag})) {
  568.         s/^\@$tag\s+//;
  569.         $tag =~ s/x$//;
  570.         1 while s/(\{[^\}]*)\s+([^\{]*\})/$1$;9$2/; # protect spaces inside {}
  571.         @args = split(/\s+/, $_);
  572.         for (@args) {s/$;9/ /g;} # unprotect spaces
  573.         $type = shift(@args);
  574.         $type =~ s/^\{(.*)\}$/$1/;
  575.         print "# def ($tag): {$type} ", join(', ', @args), "\n"
  576.         if $debug & $DEBUG_DEF;
  577.         $type .= ':'; # it's nicer like this
  578.         $name = shift(@args);
  579.         $name =~ s/^\{(.*)\}$/$1/;
  580.         if ($tag eq 'deffn' || $tag eq 'defvr' || $tag eq 'deftp') {
  581.         $_ = "<U>$type</U> <B>$name</B>";
  582.         $_ .= " <I>@args</I>" if @args;
  583.         $_ .= "<P>\n";
  584.         } elsif ($tag eq 'deftypefn' || $tag eq 'deftypevr'
  585.              || $tag eq 'defcv' || $tag eq 'defop') {
  586.         $ftype = $name;
  587.         $name = shift(@args);
  588.         $name =~ s/^\{(.*)\}$/$1/;
  589.         $_ = "<U>$type</U> $ftype <B>$name</B>";
  590.         $_ .= " <I>@args</I>" if @args;
  591.         $_ .= "<P>\n";
  592.         } else {
  593.         warn "Unknown definition type: $tag\n";
  594.         $_ = "<U>$type</U> <B>$name</B>";
  595.         $_ .= " <I>@args</I>" if @args;
  596.         $_ .= "<P>\n";
  597.         }
  598.         if ($tag eq 'deffn' || $tag eq 'deftypefn' || $tag eq 'defop') {
  599.         unshift(@input_spool, "\@findex $name\n");
  600.         } elsif ($tag eq 'defvr' || $tag eq 'deftypevr' || $tag eq 'defcv') {
  601.         unshift(@input_spool, "\@vindex $name\n");
  602.         } else {
  603.         unshift(@input_spool, "\@tindex $name\n");
  604.         }
  605.         $dont_html = 1;
  606.     }
  607.     } elsif ($end_tag) {
  608.     if ($format_map{$end_tag}) {
  609.         $in_pre = 0 if $format_map{$end_tag} eq 'PRE';
  610.         push(@lines, "</$format_map{$end_tag}>\n");
  611.     } elsif ($end_tag eq 'table' ||
  612.          $end_tag eq 'ftable' ||
  613.          $end_tag eq 'vtable') {
  614.         $in_table = 0;
  615.         push(@lines, "</DL>\n");
  616.     } elsif (defined($def_map{$end_tag})) {
  617.         push(@lines, "<P>\n");
  618.     } elsif ($end_tag eq 'menu') {
  619.         push(@lines, $_); # must keep it for pass 2
  620.     }
  621.     next;
  622.     }
  623.     #
  624.     # misc things
  625.     #
  626.     # protect texi and HTML things
  627.     &protect_texi;
  628.     &protect_html unless $dont_html;
  629.     $dont_html = 0;
  630.     # non-@ substitutions cf. texinfmt.el
  631.     s/``/"/g && study;
  632.     s/''/"/g && study;
  633.     s/([\w ])---([\w ])/$1--$2/g && study;
  634.     # substitution (unsupported things)
  635.     s/^\@center\s+//g && study;
  636.     s/^\@exdent\s+//g && study;
  637.     s/\@noindent\s+//g && study;
  638.     s/\@refill\s+//g && study;
  639.     # other substitutions
  640.     eval($subst_code);
  641.     s/\@value{($VARRE)}/$value{$1}/eg;
  642.     s/\@footnote\{/\@footnote$docu_doc\{/g; # mark footnotes, cf. pass 4
  643.     #
  644.     # analyze the tag again
  645.     #
  646.     if ($tag) {
  647.     if ($sec2level{$tag} > 0) {
  648.         if (/^\@$tag\s+(.+)$/) {
  649.         $name = $1;
  650.         $name =~ s/\s+$//;
  651.         $level = $sec2level{$tag};
  652.         if ($tag =~ /heading$/) {
  653.             $_ = "<H$level>$name</H$level>\n";
  654.             print "# heading, section $name, level $level\n"
  655.             if $debug & $DEBUG_TOC;
  656.         } else {
  657.             if ($split_chapter && $level == 1) {
  658.             &next_doc;
  659.             push(@lines, $SPLITTAG) if $split_num++;
  660.             push(@sections, $name);
  661.             }
  662.             $id = 'SEC' . ++$sec_num;
  663.             # check biblio and glossary
  664.             $in_bibliography = ($name =~ /^bibliography$/i);
  665.             $in_glossary = ($name =~ /^glossary$/i);
  666.             # check node
  667.             if ($node) {
  668.             if ($node2sec{$node}) {
  669.                 warn "Duplicate node found: $node\n";
  670.             } else {
  671.                 $node2sec{$node} = $name;
  672.                 $node2href{$node} = "$docu_doc#$id";
  673.                 print "# node $node, section $name, level $level\n"
  674.                 if $debug & $DEBUG_TOC;
  675.             }
  676.             $node = '';
  677.             } else {
  678.             print "# no node, section $name, level $level\n"
  679.                 if $debug & $DEBUG_TOC;
  680.             }
  681.             # update TOC
  682.             while ($level > $curlevel) {
  683.             $curlevel++;
  684.             push(@toc_lines, "<UL>\n");
  685.             }
  686.             while ($level < $curlevel) {
  687.             $curlevel--;
  688.             push(@toc_lines, "</UL>\n");
  689.             }
  690.             $_ = "<LI>" . &anchor($id, "$docu_doc#$id", $name, 1);
  691.             push(@toc_lines, &substitute_style($_));
  692.             # update DOC
  693.             $_ =  "<H$level>" . &anchor($id, "$docu_toc#$id", $name) . "</H$level>\n";
  694.         }
  695.         # update DOC
  696.         push(@lines, $_);
  697.         next;
  698.         } else {
  699.         warn "Bad section line: $_";
  700.         }
  701.     } else {
  702.         # track variables
  703.         $value{$1} = $2, next if /^\@set\s+($VARRE)\s+(.*)$/o;
  704.         delete $value{$1}, next if /^\@clear\s+($VARRE)\s*$/o;
  705.         # store things
  706.         $value{'filename'} = $1, next if /^\@setfilename\s+(.*)$/;
  707.         $value{'author'} .= "$1\n", next if /^\@author\s+(.*)$/;
  708.         $value{'subtitle'} .= "$1\n", next if /^\@subtitle\s+(.*)$/;
  709.         $value{'title'} = $1, next if /^\@settitle\s+(.*)$/;
  710.         $value{'title'} = $1, next if /^\@title\s+(.*)$/;
  711.         # index
  712.         if (/^\@(.index)\s+/) {
  713.         $id = 'IDX' . ++$idx_num;
  714.         $index = $1;
  715.         $what = &substitute_style($');
  716.         $what =~ s/\s+$//;
  717.         print "# found $index for '$what' id $id\n"
  718.             if $debug & $DEBUG_INDEX;
  719.         eval("\$$index\{\$what\} = \"$docu_doc#$id\"");
  720.         # check last line
  721.         if ($lines[$#lines] =~ /^\</) {
  722.             # we can safely (?) insert the index before the last line
  723.             splice(@lines, -1, 0, &anchor($id, '', $invisible_mark, 1));
  724.         } else {
  725.             # it's safer to append the index
  726.             push(@lines, &anchor($id, '', $invisible_mark, !$in_pre));
  727.         }
  728.         next;
  729.         }
  730.         # list item
  731.         if (/^\@itemx?\s+/) {
  732.         $what = $';
  733.         $what =~ s/\s+$//;
  734.         if ($in_bibliography && $use_bibliography) {
  735.             if ($what =~ /^$BIBRE$/o) {
  736.             $id = 'BIB' . ++$bib_num;
  737.             $bib2href{$what} = "$docu_doc#$id";
  738.             print "# found bibliography for '$what' id $id\n"
  739.                 if $debug & $DEBUG_BIB;
  740.             $what = &anchor($id, '', $what);
  741.             }
  742.         } elsif ($in_glossary && $use_glossary) {
  743.             $id = 'GLOSS' . ++$gloss_num;
  744.             $entry = $what;
  745.             $entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/;
  746.             $gloss2href{$entry} = "$docu_doc#$id";
  747.             print "# found glossary for '$entry' id $id\n"
  748.             if $debug & $DEBUG_GLOSS;
  749.             $what = &anchor($id, '', $what);
  750.         }
  751.         if ($in_table) {
  752.             if ($things_map{$in_table} && !$what) {
  753.             # special case to allow @table @bullet for instance
  754.             push(@lines, "<DT>$things_map{$in_table}\n<DD>");
  755.             } else {
  756.             push(@lines, "<DT>\@$in_table{$what}\n<DD>");
  757.             }
  758.             if ($table_type) { # add also an index
  759.             unshift(@input_spool, "\@${table_type}index $what\n");
  760.             }
  761.         } else {
  762.             push(@lines, "<LI>$what\n");
  763.         }
  764.         next;
  765.         }
  766.     }
  767.     }
  768.     # paragraph separator
  769.     $_ = "<P>\n" if $_ eq "\n" && ! $in_pre;
  770.     # otherwise
  771.     push(@lines, $_);
  772. }
  773.  
  774. # finish TOC
  775. $level = 0;
  776. while ($level < $curlevel) {
  777.     $curlevel--;
  778.     push(@toc_lines, "</UL>\n");
  779. }
  780.  
  781. print "# end of pass 1\n" if $verbose;
  782.  
  783. #+++############################################################################
  784. #                                                                              #
  785. # Pass 2/3: handle style, menu, index, cross-reference                         #
  786. #                                                                              #
  787. #---############################################################################
  788.  
  789. @lines2 = ();                # whole document (2nd pass)
  790. @lines3 = ();                # whole document (3rd pass)
  791. $in_menu = 0;                # am I inside a menu
  792.  
  793. while (@lines) {
  794.     $_ = shift(@lines);
  795.     #
  796.     # special case (protected sections)
  797.     #
  798.     if (/^$PROTECTTAG/o) {
  799.     push(@lines2, $_);
  800.     next;
  801.     }
  802.     #
  803.     # menu
  804.     #
  805.     $in_menu = 1, push(@lines2, "<UL>\n"), next if /^\@menu\b/;
  806.     $in_menu = 0, push(@lines2, "</UL>\n"), next if /^\@end\s+menu\b/;
  807.     if ($in_menu) {
  808.     if (/^\*\s+($NODERE)::/o) {
  809.         $descr = $';
  810.         chop($descr);
  811.         &menu_entry($1, $1, $descr);
  812.     } elsif (/^\*\s+(.+):\s+([^\t,\.\n]+)[\t,\.\n]/) {
  813.         $descr = $';
  814.         chop($descr);
  815.         &menu_entry($1, $2, $descr);
  816.     } elsif (/^\*/) {
  817.         warn "Bad menu line: $_";
  818.     } else { # description continued?
  819.         push(@lines2, $_);
  820.     }
  821.     next;
  822.     }
  823.     #
  824.     # printindex
  825.     #
  826.     if (/^\@printindex\s+(\w)\w\b/) {
  827.     eval("*ary = *$1index");
  828.     @keys = keys(%ary);
  829.     for $key (@keys) {
  830.         $_ = $key;
  831.         1 while s/<(\w+)>\`(.*)\'<\/\1>/$2/; # remove HTML tags with quotes
  832.         1 while s/<(\w+)>(.*)<\/\1>/$2/; # remove HTML tags
  833.         &unprotect_html;
  834.         &unprotect_texi;
  835.         tr/A-Z/a-z/; # lowercase
  836.         $key2alpha{$key} = $_;
  837.         print "# index $key sorted as $_\n"
  838.         if $key ne $_ && $debug & $DEBUG_INDEX;
  839.     }
  840.     $last_letter = '';
  841.     push(@lines2, "<DIR>\n");
  842.     for (sort(byalpha @keys)) {
  843.         $letter = substr($key2alpha{$_}, 0, 1);
  844.         $letter = substr($key2alpha{$_}, 0, 2) if $letter eq $;;
  845.         if ($letter ne $last_letter) {
  846.         local($_) = $letter;
  847.         &protect_html;
  848.         push(@lines2, "<H2>$_</H2>\n");
  849.         $last_letter = $letter;
  850.         }
  851.         push(@lines2, "<LI>" . &anchor('', $ary{$_}, $_, 1));
  852.     }
  853.     push(@lines2, "</DIR>\n");
  854.     next;
  855.     }
  856.     #
  857.     # simple style substitutions
  858.     #
  859.     $_ = &substitute_style($_);
  860.     #
  861.     # xref
  862.     #
  863.     while (/\@(x|px|info|)ref{($XREFRE)(}?)/o) {
  864.     # note: Texinfo may accept other characters
  865.     ($type, $nodes, $full) = ($1, $2, $3);
  866.     ($before, $after) = ($`, $');
  867.     if (! $full && $after) {
  868.         warn "* Bad xref (no ending } on line): $_";
  869.         $_ = "$before$;0${type}ref\{$nodes$after";
  870.         next; # while xref
  871.     }
  872.     if ($type eq 'x') {
  873.         $type = ($value{'Xrefstring'} || $LDC{'Xrefstring'}).' ';
  874.     } elsif ($type eq 'px') {
  875.         $type = ($value{'xrefstring'} || $LDC{'xrefstring'}).' ';
  876.     } elsif ($type eq 'info') {
  877.         $type = 'See Info';    ### TODO (hm)
  878.     } else {
  879.         $type = '';
  880.     }
  881.     unless ($full) {
  882.         $next = shift(@lines);
  883.         chop($nodes); # remove final newline
  884.         if ($next =~ /\}/) { # splitted on 2 lines
  885.         $nodes .= " $`";
  886.         $after = $';
  887.         } else {
  888.         $nodes .= " $next";
  889.         $next = shift(@lines);
  890.         chop($nodes);
  891.         if ($next =~ /\}/) { # splitted on 3 lines
  892.             $nodes .= " $`";
  893.             $after = $';
  894.         } else {
  895.             warn "* Bad xref (no ending }): $_";
  896.             $_ = "$before$;0xref\{$nodes$after";
  897.             unshift(@lines, $next);
  898.             next; # while xref
  899.         }
  900.         }
  901.     }
  902.     $nodes =~ s/\s+/ /g; # normalize
  903.     @args = split(/\s*,\s*/, $nodes);
  904.     $node = $args[0]; # the node is always the first arg
  905.     $sec = $node2sec{$node};
  906.     if (@args == 5) { # reference to another manual
  907.         $sec = $args[2] || $node;
  908.         $man = $args[4] || $args[3];
  909.         $_ = "${before}${type}".($value{'sectionstring'}||$LC{'sectionstring'})." `$sec' in \@cite{$man}$after"; ### TODO (hm)
  910.     } elsif ($type =~ /Info/) { # inforef
  911.         warn "Wrong number of arguments: $_" unless @args == 3;
  912.         ($nn, $rn, $in) = @args;
  913.         $_ = "${before}${type} file `$in', node `$nn'$after"; ### TODO (hm)
  914.     } elsif ($sec) {
  915.         $href = $node2href{$node};
  916.         $_ = "${before}${type}".($value{'sectionstring'}||$LC{'sectionstring'})." " . &anchor('', $href, $sec) . $after;
  917.     } else {
  918.         warn "Undefined node ($node): $_";
  919.         $_ = "$before$;0xref{$nodes}$after";
  920.     }
  921.     }
  922.     #
  923.     # try to guess bibliography references or glossary terms
  924.     #
  925.     unless (/^<H\d><A NAME=\"SEC\d/) {
  926.     if ($use_bibliography) {
  927.         $done = '';
  928.         while (/$BIBRE/o) {
  929.         ($pre, $what, $post) = ($`, $&, $');
  930.         $href = $bib2href{$what};
  931.         if (defined($href) && $post !~ /^[^<]*<\/A>/) {
  932.             $done .= $pre . &anchor('', $href, $what);
  933.         } else {
  934.             $done .= "$pre$what";
  935.         }
  936.         $_ = $post;
  937.         }
  938.         $_ = $done . $_;
  939.     }
  940.     if ($use_glossary) {
  941.         $done = '';
  942.         while (/\b\w+\b/) {
  943.         ($pre, $what, $post) = ($`, $&, $');
  944.         $entry = $what;
  945.         $entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/;
  946.         $href = $gloss2href{$entry};
  947.         if (defined($href) && $post !~ /^[^<]*<\/A>/) {
  948.             $done .= $pre . &anchor('', $href, $what);
  949.         } else {
  950.             $done .= "$pre$what";
  951.         }
  952.         $_ = $post;
  953.         }
  954.         $_ = $done . $_;
  955.     }
  956.     }
  957.     # otherwise
  958.     push(@lines2, $_);
  959. }
  960. print "# end of pass 2\n" if $verbose;
  961.  
  962. #
  963. # splitted style substitutions
  964. #
  965. while (@lines2) {
  966.     $_ = shift(@lines2);
  967.     #
  968.     # special case (protected sections)
  969.     #
  970.     if (/^$PROTECTTAG/o) {
  971.     push(@lines3, $_);
  972.     next;
  973.     }
  974.     #
  975.     # splitted style substitutions
  976.     #
  977.     $old = '';
  978.     while ($old ne $_) {
  979.         $old = $_;
  980.     if (/\@(\w+)\{/) {
  981.         ($before, $style, $after) = ($`, $1, $');
  982.         if (defined($style_map{$style})) {
  983.         $_ = $after;
  984.         $text = '';
  985.         $after = '';
  986.         $failed = 1;
  987.         while (@lines2) {
  988.             if (/\}/) {
  989.             $text .= $`;
  990.             $after = $';
  991.             $failed = 0;
  992.             last;
  993.             } else {
  994.             $text .= $_;
  995.             $_ = shift(@lines2);
  996.             }
  997.         }
  998.         if ($failed) {
  999.             die "* Bad syntax (\@$style) after: $before\n";
  1000.         } else {
  1001.             $text = &apply_style($style, $text);
  1002.             $_ = "$before$text$after";
  1003.         }
  1004.         }
  1005.     }
  1006.     }
  1007.     # otherwise
  1008.     push(@lines3, $_);
  1009. }
  1010. print "# end of pass 3\n" if $verbose;
  1011.  
  1012. #+++############################################################################
  1013. #                                                                              #
  1014. # Pass 4: foot notes, final cleanup                                            #
  1015. #                                                                              #
  1016. #---############################################################################
  1017.  
  1018. @lines4 = ();                # whole document (4th pass)
  1019. @foot_lines = ();            # footnotes
  1020. @doc_lines = ();            # final document
  1021. $end_of_para = 0;            # true if last line is <P>
  1022.  
  1023. while (@lines3) {
  1024.     $_ = shift(@lines3);
  1025.     #
  1026.     # special case (protected sections)
  1027.     #
  1028.     if (/^$PROTECTTAG/o) {
  1029.     push(@doc_lines, $_);
  1030.     $end_of_para = 0;
  1031.     next;
  1032.     }
  1033.     #
  1034.     # footnotes
  1035.     #
  1036.     while (/\@footnote([^\{\s]+)\{/) {
  1037.     ($before, $d, $after) = ($`, $1, $');
  1038.     $_ = $after;
  1039.     $text = '';
  1040.     $after = '';
  1041.     $failed = 1;
  1042.     while (@lines3) {
  1043.         if (/\}/) {
  1044.         $text .= $`;
  1045.         $after = $';
  1046.         $failed = 0;
  1047.         last;
  1048.         } else {
  1049.         $text .= $_;
  1050.         $_ = shift(@lines3);
  1051.         }
  1052.     }
  1053.     if ($failed) {
  1054.         die "* Bad syntax (@footnote) after: $before\n";
  1055.     } else {
  1056.         $id = 'FOOT' . ++$foot_num;
  1057.         $foot = "($foot_num)";
  1058.         push(@foot_lines, "<H3>" . &anchor($id, "$d#$id", $foot) . "</H3>\n");
  1059.         push(@foot_lines, "$text\n");
  1060.         $_ = $before . &anchor($id, "$docu_foot#$id", $foot) . $after;
  1061.     }
  1062.     }
  1063.     #
  1064.     # remove unnecessary <P>
  1065.     #
  1066.     if ($_ eq "<P>\n") {
  1067.     next if $end_of_para++;
  1068.     } else {
  1069.     $end_of_para = 0;
  1070.     }
  1071.     # otherwise
  1072.     push(@doc_lines, $_);
  1073. }
  1074. print "# end of pass 4\n" if $verbose;
  1075.  
  1076. #+++############################################################################
  1077. #                                                                              #
  1078. # Pass 5: print things                                                         #
  1079. #                                                                              #
  1080. #---############################################################################
  1081.  
  1082. $header = <<EOT;
  1083. <!-- This HTML file has been created by $THISPROG
  1084.      from $docu on $TODAY -->
  1085. EOT
  1086.  
  1087. $_ = &substitute_style($value{'title'} || "Untitled Document");
  1088. &unprotect_texi;
  1089. $title = $_;
  1090.  
  1091. #
  1092. # print TOC
  1093. #
  1094. if (open(FILE, "> $docu_toc")) {
  1095.     print "# creating $docu_toc...\n" if $verbose;
  1096.     print FILE "$header\n";
  1097.     print FILE "<TITLE>$title - Table of Contents</TITLE>\n";
  1098.     print FILE "<H1>$title</H1>\n";
  1099.     if ($value{'subtitle'}) {
  1100.     chop($value{'subtitle'}); # rmv last \n
  1101.     foreach (split(/\n/, $value{'subtitle'})) {
  1102.         $_ = &substitute_style($_);
  1103.         &unprotect_texi;
  1104.         print FILE "<H2>$_</H2>\n";
  1105.     }
  1106.     }
  1107.     if ($value{'author'}) {
  1108.     chop($value{'author'}); # rmv last \n
  1109.     foreach (split(/\n/, $value{'author'})) {
  1110.         $_ = &substitute_style($_);
  1111.         &unprotect_texi;
  1112.         print FILE "<ADDRESS>$_</ADDRESS>\n";
  1113.     }
  1114.     }
  1115.     print FILE "<P>\n";
  1116.     &print(*toc_lines, FILE);
  1117.     close(FILE);
  1118. } else {
  1119.     warn "Can't write to $docu_toc: $!\n";
  1120. }
  1121.  
  1122. #
  1123. # print document
  1124. #
  1125. if ($split_chapter || $split_node) {
  1126.     $doc_num = 0;
  1127.     foreach $section (@sections) {
  1128.     &next_doc;
  1129.     if (open(FILE, "> $docu_doc")) {
  1130.         print "# creating $docu_doc...\n" if $verbose;
  1131.         $prev_doc = &doc_name($doc_num - 1);
  1132.         $prev_doc_title = $sections[$doc_num - 2];
  1133.         $prev_doc = '' if $doc_num == 1;
  1134.         $next_doc = &doc_name($doc_num + 1);
  1135.         $next_doc_title = $sections[$doc_num];
  1136.         $next_doc = '' if $doc_num > $#sections;
  1137.         print FILE "$header\n";
  1138.         print FILE "<TITLE>$title - $section</TITLE>\n\n";
  1139.         $navigation = '';
  1140.         $navigation .= '<< ' . &anchor('', $prev_doc, $prev_doc_title) . "\n" if $prev_doc;
  1141.         $navigation .= '>> ' . &anchor('', $next_doc, $next_doc_title) . "\n" if $next_doc;
  1142.         print FILE $navigation&&"<PRE><I>\n$navigation<HR>\n</I></PRE>\n\n";
  1143.         # find corresponding lines
  1144.             @tmp_lines = ();
  1145.             while (@doc_lines) {
  1146.         $_ = shift(@doc_lines);
  1147.         last if ($_ eq $SPLITTAG);
  1148.         push(@tmp_lines, $_);
  1149.         }
  1150.             &print(*tmp_lines, FILE);
  1151.         print FILE $navigation&&"\n<PRE><I>\n<HR>\n$navigation</I></PRE>\n";
  1152.         close(FILE);
  1153.     } else {
  1154.         warn "Can't write to $docu_doc: $!\n";
  1155.     }
  1156.     }
  1157. } else {
  1158.     if (open(FILE, "> $docu_doc")) {
  1159.     print "# creating $docu_doc...\n" if $verbose;
  1160.     print FILE <<EOT;
  1161. $header
  1162. <TITLE>$title</TITLE>
  1163. <H1>$title</H1>
  1164. EOT
  1165.         &print(*doc_lines, FILE);
  1166.     close(FILE);
  1167.     } else {
  1168.     warn "Can't write to $docu_doc: $!\n";
  1169.     }
  1170. }
  1171.  
  1172. #
  1173. # print footnotes
  1174. #
  1175. if (@foot_lines) {
  1176.     if (open(FILE, "> $docu_foot")) {
  1177.     print "# creating $docu_foot...\n" if $verbose;
  1178.     print FILE <<EOT;
  1179. $header
  1180. <TITLE>$title - Footnotes</TITLE>
  1181. <H1>$title</H1>
  1182. EOT
  1183.         &print(*foot_lines, FILE);
  1184.     close(FILE);
  1185.     } else {
  1186.     warn "Can't write to $docu_foot: $!\n";
  1187.     }
  1188. }
  1189.  
  1190. print "# that's all folks\n" if $verbose;
  1191.  
  1192. #+++############################################################################
  1193. #                                                                              #
  1194. # Low level functions                                                          #
  1195. #                                                                              #
  1196. #---############################################################################
  1197.  
  1198. sub check {
  1199.     local($_, %seen, %context, $before, $match, $after);
  1200.  
  1201.     while (<>) {
  1202.     if (/\@(\*|\.|\:|\@|\{|\})/) {
  1203.         $seen{$&}++;
  1204.         $context{$&} .= "> $_" if $verbose;
  1205.         $_ = "$`XX$'";
  1206.         redo;
  1207.     }
  1208.     if (/\@(\w+)/) {
  1209.         ($before, $match, $after) = ($`, $&, $');
  1210.         if ($before =~ /\b[\w-]+$/ && $after =~ /^[\w-.]*\b/) { # e-mail address
  1211.         $seen{'e-mail address'}++;
  1212.         $context{'e-mail address'} .= "> $_" if $verbose;
  1213.         } else {
  1214.         $seen{$match}++;
  1215.         $context{$match} .= "> $_" if $verbose;
  1216.         }
  1217.         $match =~ s/^\@/X/;
  1218.         $_ = "$before$match$after";
  1219.         redo;
  1220.     }
  1221.     }
  1222.  
  1223.     for (sort(keys(%seen))) {
  1224.     if ($verbose) {
  1225.         print "$_\n";
  1226.         print $context{$_};
  1227.     } else {
  1228.         print "$_ ($seen{$_})\n";
  1229.     }
  1230.     }
  1231. }
  1232.  
  1233. sub open {
  1234.     local($name) = @_;
  1235.  
  1236.     ++$fh_name;
  1237.     if (open($fh_name, $name)) {
  1238.     unshift(@fhs, $fh_name);
  1239.     } else {
  1240.     warn "Can't read file $name: $!\n";
  1241.     }
  1242. }
  1243.  
  1244. sub init_input {
  1245.     @fhs = ();            # hold the file handles to read
  1246.     @input_spool = ();        # spooled lines to read
  1247.     $fh_name = 'FH000';
  1248.     &open($docu);
  1249. }
  1250.  
  1251. sub next_line {
  1252.     local($fh, $line);
  1253.  
  1254.     if (@input_spool) {
  1255.     $line = shift(@input_spool);
  1256.     return($line);
  1257.     }
  1258.     while (@fhs) {
  1259.     $fh = $fhs[0];
  1260.     $line = <$fh>;
  1261.     return($line) if $line;
  1262.     close($fh);
  1263.     shift(@fhs);
  1264.     }
  1265.     return(undef);
  1266. }
  1267.  
  1268. # used in pass 1, use &next_line
  1269. sub skip_until {
  1270.     local($tag) = @_;
  1271.     local($_);
  1272.  
  1273.     while ($_ = &next_line) {
  1274.     return if /^\@end\s+$tag\s*$/;
  1275.     }
  1276.     die "* Failed to find '$tag' after: " . $lines[$#lines];
  1277. }
  1278.  
  1279. sub menu_entry {
  1280.     local($entry, $node, $descr) = @_;
  1281.     local($href);
  1282.  
  1283.     $href = $node2href{$node};
  1284.     if ($href) {
  1285.     $descr =~ s/^\s+//;
  1286.     $descr = ": $descr" if $descr;
  1287.     push(@lines2, "<LI>" . &anchor('', $href, $entry) . "$descr\n");
  1288.     } else {
  1289.     warn "Undefined node ($node): $_";
  1290.     }
  1291. }
  1292.  
  1293. sub do_ctrl { "^$_[0]" }
  1294.  
  1295. sub do_sc { "\U$_[0]\E" }
  1296.  
  1297. sub apply_style {
  1298.     local($texi_style, $text) = @_;
  1299.     local($style);
  1300.  
  1301.     $style = $style_map{$texi_style};
  1302.     if (defined($style)) { # known style
  1303.     if ($style =~ /^\"/) { # add quotes
  1304.         $style = $';
  1305.         $text = "\`$text\'";
  1306.     }
  1307.     if ($style =~ /^\&/) { # custom
  1308.         $style = $';
  1309.         $text = &$style($text);
  1310.     } elsif ($style) { # good style
  1311.         $text = "<$style>$text</$style>";
  1312.     } else { # no style
  1313.     }
  1314.     } else { # unknown style
  1315.     $text = undef;
  1316.     }
  1317.     return($text);
  1318. }
  1319.  
  1320. sub substitute_style {
  1321.     local($_) = @_;
  1322.     local($changed, $done, $style, $text);
  1323.  
  1324.     $changed = 1;
  1325.     while ($changed) {
  1326.     $changed = 0;
  1327.     $done = '';
  1328.     while (/\@(\w+){([^\{\}]+)}/) {
  1329.         $text = &apply_style($1, $2);
  1330.         if ($text) {
  1331.         $_ = "$`$text$'";
  1332.         $changed = 1;
  1333.         } else {
  1334.         $done .= "$`\@$1";
  1335.         $_ = "{$2}$'";
  1336.         }
  1337.     }
  1338.         $_ = $done . $_;
  1339.     }
  1340.     return($_);
  1341. }
  1342.  
  1343. sub anchor {
  1344.     local($name, $href, $text, $newline) = @_;
  1345.     local($result);
  1346.  
  1347.     $result = "<A";
  1348.     $result .= " NAME=\"$name\"" if $name;
  1349.     $result .= " HREF=\"$href\"" if $href;
  1350.     $result .= ">$text</A>";
  1351.     $result .= "\n" if $newline;
  1352.     return($result);
  1353. }
  1354.  
  1355. sub pretty_date {
  1356.     local(@MoY, $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);
  1357.  
  1358.     @MoY = ('January', 'Febuary', 'March', 'April', 'May', 'June',
  1359.         'July', 'August', 'September', 'October', 'November', 'December');
  1360.     ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
  1361.     $year += ($year < 70) ? 2000 : 1900;
  1362.     return("$mday $MoY[$mon] $year");
  1363. }
  1364.  
  1365. sub doc_name {
  1366.     local($num) = @_;
  1367.  
  1368.     return("${docu_name}_$num.html");
  1369. }
  1370.  
  1371. sub next_doc {
  1372.     $docu_doc = &doc_name(++$doc_num);
  1373. }
  1374.  
  1375. sub print {
  1376.     local(*lines, $fh) = @_;
  1377.     local($_);
  1378.  
  1379.     while (@lines) {
  1380.     $_ = shift(@lines);
  1381.     if (/^$PROTECTTAG/o) {
  1382.         $_ = $tag2pro{$_};
  1383.     } else {
  1384.         &unprotect_texi;
  1385.     }
  1386.     print $fh $_;
  1387.     }
  1388. }
  1389.  
  1390. sub protect_texi {
  1391.     # protect @ { } ` '
  1392.     s/\@\@/$;0/go && study;
  1393.     s/\@\{/$;1/go && study;
  1394.     s/\@\}/$;2/go && study;
  1395.     s/\@\`/$;3/go && study;
  1396.     s/\@\'/$;4/go && study;
  1397. }
  1398.  
  1399. sub protect_html {
  1400.     # protect & < >
  1401.     s/\&/\&\#38;/g && study;
  1402.     s/\</\&\#60;/g && study;
  1403.     s/\>/\&\#62;/g && study;
  1404.     s/\&\#60;\/A\&\#62;/<\/A>/g && study; # assume </A> is HTML
  1405.     s/\&\#60;A ([^\&]+)\&\#62;/<A $1>/g && study; # assume <A [^&]+> is HTML
  1406. }
  1407.  
  1408. # we should use this:
  1409. #
  1410. #  sub unprotect_texi {
  1411. #      s/$;0/\@/go && study;
  1412. #      s/$;1/\{/go && study;
  1413. #      s/$;2/\}/go && study;
  1414. #      s/$;3/\`/go && study;
  1415. #      s/$;4/\'/go && study;
  1416. #  }
  1417. #
  1418. #  sub unprotect_html {
  1419. #      s/\&\#38;/\&/g && study;
  1420. #      s/\&\#60;/\</g && study;
  1421. #      s/\&\#62;/\>/g && study;
  1422. #  }
  1423. #
  1424. # but Perl 4.036 bugs on it (Perl 5 is OK)
  1425.  
  1426. sub unprotect_texi {
  1427.     s/$;0/\@/go;
  1428.     s/$;1/\{/go;
  1429.     s/$;2/\}/go;
  1430.     s/$;3/\`/go;
  1431.     s/$;4/\'/go;
  1432. }
  1433.  
  1434. sub unprotect_html {
  1435.     s/\&\#38;/\&/g;
  1436.     s/\&\#60;/\</g;
  1437.     s/\&\#62;/\>/g;
  1438. }
  1439.  
  1440. sub byalpha {
  1441.     $key2alpha{$a} cmp $key2alpha{$b};
  1442. }
  1443.  
  1444. ##############################################################################
  1445.  
  1446.     # These next few lines are legal in both Perl and nroff.
  1447.  
  1448. .00;            # finish .ig
  1449.  
  1450. 'di            \" finish diversion--previous line must be blank
  1451. .nr nl 0-1        \" fake up transition to first page again
  1452. .nr % 0            \" start at page 1
  1453. '; __END__ ############# From here on it's a standard manual page ############
  1454. .TH TEXI2HTML 1 "04/21/94"
  1455. .AT 3
  1456. .SH NAME
  1457. texi2html \- a Texinfo to HTML converter
  1458. .SH SYNOPSIS
  1459. .B texi2html [options] file
  1460. .PP
  1461. .B texi2html -check [-verbose] files
  1462. .SH DESCRIPTION
  1463. .I Texi2html
  1464. converts the given Texinfo file to a set of HTML files. It tries to handle
  1465. most of Texinfo commands. It creates hypertext links for cross-references,
  1466. footnotes...
  1467. .PP
  1468. It also tries to add links from a reference to its corresponding entry in the
  1469. bibliography (if any). It may also handle a glossary (see the
  1470. .B \-glossary
  1471. option).
  1472. .PP
  1473. .I Texi2html
  1474. creates several files depending on the contents of the Texinfo file and on
  1475. the chosen options (see FILES).
  1476. .PP
  1477. The HTML files created by
  1478. .I texi2html
  1479. are closer to TeX than to Info, what's why
  1480. .I texi2html
  1481. convert @iftex sections and not @ifinfo ones.
  1482. .SH OPTIONS
  1483. .TP 12
  1484. .B \-check
  1485. Check the given file and give the list of all things that may be Texinfo commands.
  1486. This may be used to check the output of
  1487. .I texi2html
  1488. to find the Texinfo commands that have been left in the HTML file.
  1489. .TP
  1490. .B \-glossary
  1491. Use the section named 'Glossary' to build a list of terms and put links in the HTML
  1492. document from each term toward its definition.
  1493. .TP
  1494. .B \-invisible \fIname\fP
  1495. Use \fIname\fP to create invisible destination anchors for index links. This is a workaround
  1496. for a known bug of many WWW browsers, including xmosaic.
  1497. .TP
  1498. .B \-menu
  1499. Show the Texinfo menus; by default they are ignored.
  1500. .TP
  1501. .B \-split_chapter
  1502. Split the output into several HTML files (one per main section:
  1503. chapter, appendix...).
  1504. .TP
  1505. .B \-split_node
  1506. Split the output into several HTML files (one per node).
  1507. .TP
  1508. .B \-usage
  1509. Print usage instructions, listing the current available command-line options.
  1510. .TP
  1511. .B \-verbose
  1512. Give a verbose output. Can be used with the
  1513. .B \-check
  1514. option.
  1515. .PP
  1516. .SH FILES
  1517. By default
  1518. .I texi2html
  1519. creates the following files (foo being the name of the Texinfo file):
  1520. .TP 16
  1521. .B foo_toc.html
  1522. The table of contents.
  1523. .TP
  1524. .B foo.html
  1525. The document's contents.
  1526. .TP
  1527. .B foo_foot.html
  1528. The footnotes (if any).
  1529. .PP
  1530. When used with the
  1531. .B \-split
  1532. option, it creates several files (one per chapter or node), named
  1533. .B foo_n.html
  1534. (n being the indice of the chapter or node), instead of the single
  1535. .B foo.html
  1536. file.
  1537. .SH VARIABLES
  1538. .I texi2html
  1539. predefines the following variables: \fBhtml\fP, \fBtexi2html\fP.
  1540. .SH ADDITIONAL COMMANDS
  1541. .I texi2html
  1542. implements the following non-Texinfo commands:
  1543. .TP 16
  1544. .B @ifhtml
  1545. This indicates the start of an HTML section, this section will passed through
  1546. without any modofication.
  1547. .TP
  1548. .B @end ifhtml
  1549. This indcates the end of an HTML section.
  1550. .SH VERSION
  1551. This is \fItexi2html\fP version 1.29, 04/21/94.
  1552. .SH AUTHOR
  1553. Lionel Cons, CERN CN/DCI/UWS, Lionel.Cons@cern.ch
  1554. .SH COPYRIGHT
  1555. This program is the intellectual property of the European
  1556. Laboratory for Particle Physics (known as CERN). No guarantee whatsoever is
  1557. provided by CERN. No liability whatsoever is accepted for any loss or damage
  1558. of any kind resulting from any defect or inaccuracy in this information or
  1559. code.
  1560. .PP
  1561. CERN, 1211 Geneva 23, Switzerland
  1562. .SH "SEE ALSO"
  1563. GNU Texinfo Documentation Format,
  1564. HyperText Markup Language (HTML),
  1565. World Wide Web (WWW).
  1566. .SH BUGS
  1567. This program does not understand all Texinfo commands (yet).
  1568. .ex
  1569.  
  1570.