source: git/doc/texi2html @ 5222d6d

spielwiese
Last change on this file since 5222d6d was 5222d6d, checked in by Olaf Bachmann <obachman@…>, 26 years ago
* last minute changes git-svn-id: file:///usr/local/Singular/svn/trunk@2224 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 63.0 KB
Line 
1#!/usr/bin/perl
2'di ';
3'ig 00 ';
4# $Id: texi2html,v 1.7 1998-06-19 15:55:28 obachman Exp $
5# Description: Program to transform most Texinfo documents to HTML.
6# The plan is for the next version of makeinfo to support HTML output
7# directly, but until then ...
8
9$THISPROG = "texi2html 1.54";                   # program name and version
10# This version of texi2html is currently maintained at
11# ftp://ftp.cs.umb.edu/pub/tex/texi2html by kb@cs.umb.edu.
12
13# The man page for this program is included at the end of this file and can be
14# viewed using the command 'nroff -man texi2html'.
15# Please read the copyright at the end of the man page.
16
17# Fixme:
18# deal with @macro @unmacro @shorttitlepage @detailmenu @image
19# [plus more fixmes below]
20# Use <link>s for Up, Index, Glossary?
21# Inserting copyright links: Having texinfo markup for the online copyright
22#  would allow a link to that from wherever.
23
24#+++############################################################################
25#                                                                              #
26# Constants                                                                    #
27#                                                                              #
28#---############################################################################
29
30$DEBUG_TOC   =  1;
31$DEBUG_INDEX =  2;
32$DEBUG_BIB   =  4;
33$DEBUG_GLOSS =  8;
34$DEBUG_DEF   = 16;
35$DEBUG_HTML  = 32;
36$DEBUG_USER  = 64;
37
38#$IMG_FIRST_ACTIVE  = "<IMG SRC=\"first-b.gif\">";
39#$IMG_FIRST_PASSIVE = "<IMG SRC=\"first-t.gif\">";
40#$IMG_LAST_ACTIVE   = "<IMG SRC=\"last-b.gif\">";
41#$IMG_LAST_PASSIVE  = "<IMG SRC=\"last-t.gif\">";
42#$IMG_NEXT_ACTIVE   = "<IMG SRC=\"next-b.gif\">";
43#$IMG_NEXT_PASSIVE  = "<IMG SRC=\"next-t.gif\">";
44#$IMG_PREV_ACTIVE   = "<IMG SRC=\"previous-b.gif\">";
45#$IMG_PREV_PASSIVE  = "<IMG SRC=\"previous-t.gif\">";
46#$IMG_TOC           = "<IMG SRC=\"toc-b.gif\">";
47$IMG_FIRST_ACTIVE  = "";
48$IMG_FIRST_PASSIVE = "";
49$IMG_LAST_ACTIVE   = "";
50$IMG_LAST_PASSIVE  = "";
51$IMG_NEXT_ACTIVE   = "<IMG SRC=\"images/next_motif.gif\">";
52$IMG_NEXT_PASSIVE  = "<IMG SRC=\"images/next_motif_gr.gif\">";
53$IMG_PREV_ACTIVE   = "<IMG SRC=\"images/previous_motif.gif\">";
54$IMG_PREV_PASSIVE  = "<IMG SRC=\"images/previous_motif_gr.gif\">";
55$IMG_TOC           = "<IMG SRC=\"images/contents_motif.gif\">";
56$IMG_LEFT          = "images/bg_left.gif";
57$IMG_RIGHT         = "images/bg_right.gif";
58
59$BIBRE = '\[[\w\/]+\]';                 # RE for a bibliography reference
60$FILERE = '[\/\w.+-]+';                 # RE for a file name
61$VARRE = '[^\s\{\}]+';                  # RE for a variable name
62$NODERE = '[^@{}:\'`",]+';              # RE for a node name
63$NODESRE = '[^@{}:\'`"]+';              # RE for a list of node names
64$XREFRE = '[^@{}]+';                    # RE for a xref (should use NODERE)
65
66$ERROR = "***";                         # prefix for errors and warnings
67$HOMEPAGE = "http://wwwcn.cern.ch/dci/texi2html/"; # program home page
68$TODAY = &pretty_date;                  # like "20 September 1993"
69$SPLITTAG = "<!-- SPLIT HERE -->\n";    # tag to know where to split
70$PROTECTTAG = "_ThisIsProtected_";      # tag to recognize protected sections
71$TOPTAG = "<!--top-->";         # tag to mark first node (end of preamble)
72$html2_doctype = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0 Strict Level 2//EN">';
73
74#
75# language dependent constants
76#
77#$LDC_SEE = 'see';
78#$LDC_SECTION = 'section';
79#$LDC_IN = 'in';
80#$LDC_TOC = 'Table of Contents';
81#$LDC_GOTO = 'Go to the';
82#$LDC_FOOT = 'Footnotes';
83# TODO: @def* shortcuts
84
85#
86# pre-defined indices
87#
88%predefined_index = (
89                    'cp', 'c',
90                    'fn', 'f',
91                    'vr', 'v',
92                    'ky', 'k',
93                    'pg', 'p',
94                    'tp', 't',
95                    );
96
97#
98# valid indices
99#
100%valid_index = (
101                    'c', 1,
102                    'f', 1,
103                    'v', 1,
104                    'k', 1,
105                    'p', 1,
106                    't', 1,
107                );
108
109#
110# texinfo section names to level
111#
112%sec2level = (
113              'top', 0,
114              'chapter', 1,
115              'unnumbered', 1,
116              'majorheading', 1,
117              'chapheading', 1,
118              'appendix', 1,
119              'section', 2,
120              'unnumberedsec', 2,
121              'heading', 2,
122              'appendixsec', 2,
123              'appendixsection', 2,
124              'subsection', 3,
125              'unnumberedsubsec', 3,
126              'subheading', 3,
127              'appendixsubsec', 3,
128              'subsubsection', 4,
129              'unnumberedsubsubsec', 4,
130              'subsubheading', 4,
131              'appendixsubsubsec', 4,
132              );
133
134#
135# accent map, TeX command to ISO name
136#
137%accent_map = (
138               '"',  'uml',
139               '~',  'tilde',
140               '^',  'circ',
141               '`',  'grave',
142               '\'', 'acute',
143               ',',  'cedil',
144               # fixme: (not Latin1) = H d dotaccent dotless ringaccent
145               # tieaccent u ubaraccent v
146               );
147
148#
149# texinfo "simple things" (@foo) to HTML ones
150#
151%simple_map = (
152               # cf. makeinfo.c
153               "*", "<BR>",             # HTML+
154               " ", "&#160;",   # nbsp
155               "\n", "\n",
156               "|", "",
157               # spacing commands
158               ":", "",
159               "!", "!",
160               "?", "?",
161               ".", ".",
162               "\t", " ",
163               "-", "&#173;",   # soft hyphen
164               'tab', '<TD>',
165               '-', '',
166               );
167
168#
169# texinfo "things" (@foo{}) to HTML ones
170#
171%things_map = (
172               'TeX', 'TeX',
173               'br', '<P>',             # paragraph break.  Gone from texinfo 3.9
174               'bullet', '*',
175               'copyright', '&#169;',
176               'dots', '...',
177               'enddots', '....',
178               'equiv', '==',
179               'error', 'error-->',
180               'expansion', '==>',
181               'minus', '-',
182               'point', '-!-',
183               'print', '-|',
184               'result', '=>',
185               'today', $TODAY,
186               # fixme: output these Latin1 characters as such rather
187               # than as entities?
188               'pounds', '&#163;',
189               'questiondown', '&#191;',
190               'ss', '&#223;',
191               'exclamdown', '&#161;',
192               'AA', '&#197;',
193               'AE', '&#198;',
194               'aa', '&#229;',
195               'ae', '&#230;',
196               'O', '&#216;',
197               'o', '&#248;',
198               # follow info rendering:
199               'L', 'L\/',
200               'l', 'l\/',
201               'OE', 'OE',
202               'oe', 'oe',
203               );
204
205#
206# texinfo styles (@foo{bar}) to HTML ones
207#
208%style_l_map = (
209              'center', 'CENTER',
210              );
211
212%style_map = (
213              'asis', '',               # ??
214              'b', 'B',
215              'cite', 'CITE',
216              'code', 'CODE',
217              'ctrl', '&do_ctrl',       # special case (obsolete)
218              'dfn', 'STRONG',          # DFN tag is illegal in the standard
219              'dmn', '',                # useless
220              'emph', 'EM',
221              'email', '&do_email',     # new special case
222              'file', '"TT',            # will put quotes, cf. &apply_style
223              'i', 'I',
224              'image', '&do_image',     # in-line images
225              'kbd', 'KBD',
226              'key', 'KBD',             # fixme: probably not <KBD>; possibly
227                                        # enclose in angles like makeinfo now does
228              'r', '',                  # unsupported
229              'samp', '"SAMP',          # will put quotes, cf. &apply_style
230              'sc', '&do_sc',           # special case
231              'strong', 'STRONG',
232              't', 'TT',
233              'titlefont', 'B',         # make it distinctive, at least
234              'uref', '&do_uref',       # new special case
235              'url', '&do_url',         # new special case
236              'var', 'VAR',
237              'w', '',                  # unsupported
238#             'math', 'I',              # not very useful, but at least italicize
239              'math', '',               # don't want italic numbers
240              );
241
242#
243# texinfo format (@foo/@end foo) to HTML ones
244#
245%format_map = (
246               'display', 'PRE',
247               'example', 'PRE',
248               'format', 'PRE', # fixme: shouldn't use tt, but can't avoid?
249               'lisp', 'PRE',
250               'quotation', 'BLOCKQUOTE',
251               'smallexample', 'PRE',
252               'smalllisp', 'PRE',
253               # lists
254               'itemize', 'UL',
255               'enumerate', 'OL',
256               # poorly supported
257               'flushleft', 'PRE',
258               'flushright', 'PRE',
259               );
260
261#
262# texinfo definition shortcuts to real ones
263#
264%def_map = (
265            # basic commands
266            'deffn', 0,
267            'defvr', 0,
268            'deftypefn', 0,
269            'deftypevr', 0,
270            'defcv', 0,
271            'defop', 0,
272            'deftp', 0,
273            # basic x commands
274            'deffnx', 0,
275            'defvrx', 0,
276            'deftypefnx', 0,
277            'deftypevrx', 0,
278            'defcvx', 0,
279            'defopx', 0,
280            'deftpx', 0,
281            # shortcuts
282            'defun', 'deffn Function',
283            'defmac', 'deffn Macro',
284            'defspec', 'deffn {Special Form}',
285            'defvar', 'defvr Variable',
286            'defopt', 'defvr {User Option}',
287            'deftypefun', 'deftypefn Function',
288            'deftypevar', 'deftypevr Variable',
289            'defivar', 'defcv {Instance Variable}',
290            'defmethod', 'defop Method',
291            # x shortcuts
292            'defunx', 'deffnx Function',
293            'defmacx', 'deffnx Macro',
294            'defspecx', 'deffnx {Special Form}',
295            'defvarx', 'defvrx Variable',
296            'defoptx', 'defvrx {User Option}',
297            'deftypefunx', 'deftypefnx Function',
298            'deftypevarx', 'deftypevrx Variable',
299            'defivarx', 'defcvx {Instance Variable}',
300            'defmethodx', 'defopx Method',
301            );
302
303#
304# things to skip
305#
306%to_ignore = (
307            'manual', 1,
308            'end manual', 1,
309            );
310
311%to_skip = (
312            # comments
313            'c', 1,
314            'comment', 1,
315            # useless
316            'contents', 1,
317            'shortcontents', 1,
318            'summarycontents', 1,
319            'footnotestyle', 1,
320            'end ifclear', 1,
321            'end ifset', 1,
322            'titlepage', 1,
323            'end titlepage', 1,
324            'dircategory', 1,
325            # unsupported commands (formatting)
326            'afourpaper', 1,
327            'cropmarks', 1,
328            'finalout', 1,
329            'headings', 1,
330            'need', 1,
331            'page', 1,
332            'setchapternewpage', 1,
333            'everyheading', 1,
334            'everyfooting', 1,
335            'evenheading', 1,
336            'evenfooting', 1,
337            'oddheading', 1,
338            'oddfooting', 1,
339            'smallbook', 1,
340            'vskip', 1,
341            'filbreak', 1,
342            'centerchap', 1,
343            'setchapterstyle', 1,
344            'hyphenation', 1,
345            # unsupported formats
346            'cartouche', 1,
347            'end cartouche', 1,
348            'group', 1,
349            'end group', 1,
350            );
351
352%append2num = (
353               'A', 1,
354               'B', 2,
355               'C', 3,
356               'D', 4,
357               'E', 5,
358               'F', 6,
359               'G', 7,
360               'H', 8,
361               'I', 9,
362               'J', 10,
363               );
364#+++############################################################################
365#                                                                              #
366# Argument parsing, initialisation                                             #
367#                                                                              #
368#---############################################################################
369
370$use_bibliography = 1;
371$use_acc = 0;
372$debug = 0;
373$doctype = '';
374$check = 0;
375$expandinfo = 0;
376$use_glossary = 0;
377$invisible_mark = '';
378$use_iso = 0;
379@include_dirs = ();
380$show_menu = 0;
381$number_sections = 0;
382$split_node = 0;
383$split_chapter = 0;
384$monolithic = 0;
385$verbose = 0;
386$make_entry_page = 1;
387$make_menu_page = 1;
388$section_type = 0;
389$ignore_part = 0;
390$usage = <<EOT;
391This is $THISPROG
392To convert a Texinfo file to HMTL: $0 [options] file
393  where options can be:
394    -expandinfo    : use \@ifinfo sections, not \@iftex
395    -glossary      : handle a glossary
396    -invisible name: use 'name' as an invisible anchor
397    -I dir         : search also for files in 'dir'
398    -menu          : handle menus and don\'t do the ToC
399    -monolithic    : output only one file including ToC
400    -number        : number sections
401    -split_chapter : split on main sections
402    -split_node    : split on nodes
403    -check         : check given file for possible Texinfo commands
404    -usage         : print usage instructions
405    -verbose       : verbose output
406To check converted files: $0 -check [-verbose] files
407EOT
408
409while ($#ARGV >= 0 && $ARGV[0] =~ /^-/) {
410    $_ = shift(@ARGV);
411    if (/^-acc$/)            { $use_acc = 1; next; }
412    if (/^-d(ebug)?(\d+)?$/) { $debug = $2 || shift(@ARGV); next; }
413    if (/^-doctype$/)        { $doctype = shift(@ARGV); next; }
414    if (/^-c(heck)?$/)       { $check = 1; next; }
415    if (/^-e(xpandinfo)?$/)  { $expandinfo = 1; next; }
416    if (/^-g(lossary)?$/)    { $use_glossary = 1; next; }
417    if (/^-i(nvisible)?$/)   { $invisible_mark = shift(@ARGV); next; }
418    if (/^-iso$/)            { $use_iso = 1; next; }
419    if (/^-I(.+)?$/)         { push(@include_dirs, $1 || shift(@ARGV)); next; }
420    if (/^-m(enu)?$/)        { $show_menu = 1; next; }
421    if (/^-mono(lithic)?$/)  { $monolithic = 1; next; }
422    if (/^-n(umber)?$/)      { $number_sections = 1; next; }
423    if (/^-s(plit)?_?(n(ode)?|c(hapter)?)?$/) {
424        if ($2 =~ /^n/) {
425            $split_node = 1;
426        } else {
427            $split_chapter = 1;
428        }
429        next;
430    }
431    if (/^-v(erbose)?$/)     { $verbose = 1; next; }
432    die $usage;
433}
434if ($check) {
435    die $usage unless @ARGV > 0;
436    &check;
437    exit;
438}
439
440if (($split_node || $split_chapter) && $monolithic) {
441    warn "Can't use -monolithic with -split, -monolithic ignored.\n";
442    $monolithic = 0;
443}
444if ($expandinfo) {
445    $to_skip{'ifinfo'}++;
446    $to_skip{'end ifinfo'}++;
447} else {
448    $to_skip{'iftex'}++;
449    $to_skip{'end iftex'}++;
450}
451$invisible_mark = '<IMG SRC="images/invisible.xbm" ALT="">' if $invisible_mark eq 'xbm';
452die $usage unless @ARGV == 1;
453$docu = shift(@ARGV);
454if ($docu =~ /.*\//) {
455    chop($docu_dir = $&);
456    $docu_name = $';
457} else {
458    $docu_dir = '.';
459    $docu_name = $docu;
460}
461unshift(@include_dirs, $docu_dir);
462$docu_name =~ s/\.te?x(i|info)?$//;     # basename of the document
463
464$docu_doc = "$docu_name.html";          # document's contents
465if ($monolithic) {
466    $docu_toc = $docu_foot = $docu_doc;
467} else {
468    $docu_toc  = "${docu_name}_toc.html";  # document's table of contents
469    $docu_foot = "${docu_name}_foot.html"; # document's footnotes
470    $docu_left = "${docu_name}_left.html";
471    $docu_main = "index.html";
472}
473
474#
475# variables
476#
477%value = ();                            # hold texinfo variables
478$value{'html'} = 1;                     # predefine html (the output format)
479$value{'texi2html'} = '1.51a';          # predefine texi2html (the translator)
480# _foo: internal to track @foo
481foreach ('_author', '_title', '_subtitle',
482         '_settitle', '_setfilename') {
483    $value{$_} = '';                    # prevent -w warnings
484}
485%node2sec = ();                         # node to section name
486%node2href = ();                        # node to HREF
487%bib2href = ();                         # bibliography reference to HREF
488%gloss2href = ();                       # glossary term to HREF
489@sections = ();                         # list of sections
490@left_index = ();
491%tag2pro = ();                          # protected sections
492
493#
494# initial indexes
495#
496$bib_num = 0;
497$foot_num = 0;
498$gloss_num = 0;
499$idx_num = 0;
500$sec_num = 0;
501$doc_num = 0;
502$html_num = 0;
503
504#
505# can I use ISO8879 characters? (HTML+)
506#
507if ($use_iso) {
508    $things_map{'bullet'} = "&bull;";
509    $things_map{'copyright'} = "&copy;";
510    $things_map{'dots'} = "&hellip;";
511    $things_map{'equiv'} = "&equiv;";
512    $things_map{'expansion'} = "&rarr;";
513    $things_map{'point'} = "&lowast;";
514    $things_map{'result'} = "&rArr;";
515}
516
517#
518# read texi2html extensions (if any)
519#
520$extensions = 'texi2html.ext'; # extensions in working directory
521if (-f $extensions) {
522    print "# reading extensions from $extensions\n" if $verbose;
523    require($extensions);
524}
525($progdir = $0) =~ s/[^\/]+$//;
526if ($progdir && ($progdir ne './')) {
527    $extensions = "${progdir}texi2html.ext"; # extensions in texi2html directory
528    if (-f $extensions) {
529        print "# reading extensions from $extensions\n" if $verbose;
530        require($extensions);
531    }
532}
533
534print "# reading from $docu\n" if $verbose;
535
536#+++############################################################################
537#                                                                              #
538# Pass 1: read source, handle command, variable, simple substitution           #
539#                                                                              #
540#---############################################################################
541
542@lines = ();                            # whole document
543@toc_lines = ();                        # table of contents
544@top_lines = ();                        # contents of top node
545@menu_lines = ();
546$toplevel = 0;                          # top level seen in hierarchy
547$curlevel = 0;                          # current level in TOC
548$node = '';                             # current node name
549$in_table = 0;                          # am I inside a table
550$table_type = '';                       # type of table ('', 'f', 'v')
551@tables = ();                           # nested table support
552$in_bibliography = 0;                   # am I inside a bibliography
553$in_glossary = 0;                       # am I inside a glossary
554$in_top = 0;                            # am I inside the top node
555$in_pre = 0;                            # am I inside a preformatted section
556$in_list = 0;                           # am I inside a list
557$in_html = 0;                           # am I inside an HTML section (@ifhtml)
558$in_raw_html = 0;                       # am I inside an HTML section (@html)
559$in_preamble = 1;                       # am I before the top node
560$first_line = 1;                        # is it the first line
561$dont_html = 0;                         # don't protect HTML on this line
562$split_num = 0;                         # split index
563$deferred_ref = '';                     # deferred reference for indexes
564@html_stack = ();                       # HTML elements stack
565$html_element = '';                     # current HTML element
566&html_reset;
567@raw_html = ();
568
569# build code for simple substitutions
570# the maps used (%simple_map and %things_map) MUST be aware of this
571# watch out for regexps, / and escaped characters!
572$subst_code = '';
573foreach (keys(%simple_map)) {
574    ($re = $_) =~ s/(\W)/\\$1/g; # protect regexp chars
575    $subst_code .= "s/\\\@$re/$simple_map{$_}/g;\n";
576}
577foreach (keys(%things_map)) {
578    $subst_code .= "s/\\\@$_\\{\\}/$things_map{$_}/g;\n";
579}
580if ($use_acc) {
581    # accentuated characters
582    foreach (keys(%accent_map)) {
583        if ($_ eq "`") {
584            $subst_code .= "s/$;3";
585        } elsif ($_ eq "'") {
586            $subst_code .= "s/$;4";
587        } else {
588            $subst_code .= "s/\\\@\\$_";
589        }
590        $subst_code .= "([aeiou])/&\${1}$accent_map{$_};/gi;\n";
591    }
592}
593eval("sub simple_substitutions { $subst_code }");
594
595&init_input;
596while ($_ = &next_line) {
597    #
598    # remove \input on the first lines only
599    #
600    if ($first_line) {
601        next if /^\\input/;
602        $first_line = 0;
603    }
604    #
605    # parse texinfo tags
606    #
607    $tag = '';
608    $end_tag = '';
609    if (/^\@end\s+(\w+)\b/) {
610        $end_tag = $1;
611    } elsif (/^\@(\w+)\b/) {
612        $tag = $1;
613    }
614    #
615    # handle @ifhtml / @end ifhtml
616    #
617    if ($in_html) {
618        if ($end_tag eq 'ifhtml') {
619            $in_html = 0;
620        } else {
621            $tag2pro{$in_html} .= $_;
622        }
623        next;
624    } elsif ($tag eq 'ifhtml') {
625        $in_html = $PROTECTTAG . ++$html_num;
626        push(@raw_html, $in_html);
627        next;
628    }
629    #
630    # do raw HTML (no escapes)
631    #
632    if ($in_raw_html) {
633        if ($end_tag eq 'html') {
634            $in_raw_html = 0;
635        } else {
636            push (@raw_html, $_);
637        }
638        next;
639    } elsif ($tag eq 'html') {
640        $in_raw_html = 1;
641    }
642    #
643    # try to skip the line
644    #
645    if ($end_tag) {
646        next if $to_skip{"end $end_tag"};
647    } elsif ($tag) {
648        next if $to_skip{$tag};
649        last if $tag eq 'bye';
650    }
651
652    if ($end_tag) {
653        if ($to_ignore{"end $end_tag"}) {
654            $ignore_part = 0;
655            next;
656        }
657    } elsif ($tag) {
658        if ($to_ignore{$tag}) {
659            $ignore_part = 1;
660        }
661    }
662    next if $ignore_part;
663
664    #
665    # try to remove inlined comments
666    # syntax from tex-mode.el comment-start-skip
667    #
668    s/((^|[^\@])(\@\@)*)\@c(omment)? .*/$1/;
669    # non-@ substitutions cf. texinfmt.el
670    s/``/\"/g;
671    s/''/\"/g;
672    s/([\w ])---([\w ])/$1--$2/g;
673    #
674    # analyze the tag
675    #
676    if ($tag) {
677        # skip lines
678        &skip_until($tag), next if $tag eq 'ignore';
679        if ($expandinfo) {
680            &skip_until($tag), next if $tag eq 'iftex';
681        } else {
682            &skip_until($tag), next if $tag eq 'ifinfo' &&
683                ! $in_preamble; # we want the contents of the top node
684        }
685        &skip_until($tag), next if $tag eq 'tex';
686        # handle special tables
687        if ($tag eq 'table') {
688            $table_type = '';
689        } elsif ($tag eq 'ftable') {
690            $tag = 'table';
691            $table_type = 'f';
692        } elsif ($tag eq 'vtable') {
693            $tag = 'table';
694            $table_type = 'v';
695        } elsif ($tag eq 'multitable') {
696            $tag = 'table';
697            $table_type = '';
698        }
699        # special cases
700        if ($tag eq 'top' || ($tag eq 'node' && /^\@node\s+Top\s*,/i)) {
701            # We want to stash the contents of the top node (including
702            # @ifinfo bits).
703            $in_top = 1;
704            $in_preamble = 0;
705            #@lines = (); # ignore all lines before top (title page garbage)
706            @lines = @raw_html;
707            next;
708        } elsif ($tag eq 'node') {
709            push (@lines, "$TOPTAG") if ($in_top); # Mark end of top node
710            $in_top = 0;
711            $in_preamble = 0;
712            warn "$ERROR Bad node line: $_" unless $_ =~ /^\@node\s$NODESRE$/o;
713            $_ = &protect_html($_); # if node contains '&' for instance
714            s/^\@node\s+//;
715            ($node) = split(/,/);
716            &normalise_node($node);
717            if ($split_node) {
718                &next_doc;
719                push(@lines, $SPLITTAG) if $split_num++;
720                push(@sections, $node);
721            }
722            next;
723        } elsif ($tag eq 'include') {
724            if (/^\@include\s+($FILERE)\s*$/o) {
725                $file = $1;
726                unless (-e $file) {
727                    foreach $dir (@include_dirs) {
728                        $file = "$dir/$1";
729                        last if -e $file;
730                    }
731                }
732                if (-e $file) {
733                    &open($file);
734                    print "# including $file\n" if $verbose;
735                } else {
736                    warn "$ERROR Can't find $file, skipping";
737                }
738            } else {
739                warn "$ERROR Bad include line: $_";
740            }
741            next;
742        } elsif ($tag eq 'ifclear') {
743            if (/^\@ifclear\s+($VARRE)\s*$/o) {
744                next unless defined($value{$1});
745                &skip_until($tag);
746            } else {
747                warn "$ERROR Bad ifclear line: $_";
748            }
749            next;
750        } elsif ($tag eq 'ifset') {
751            if (/^\@ifset\s+($VARRE)\s*$/o) {
752                next if defined($value{$1});
753                &skip_until($tag);
754            } else {
755                warn "$ERROR Bad ifset line: $_";
756            }
757            next;
758        } elsif ($tag eq 'menu') {
759            unless ($show_menu) {
760                &skip_until($tag);
761                next;
762            }
763            &html_push_if($tag);
764            push(@lines, &html_debug("\n", __LINE__));
765        } elsif ($format_map{$tag}) {
766            $in_pre = 1 if $format_map{$tag} eq 'PRE';
767            &html_push_if($format_map{$tag});
768            push(@lines, &html_debug("\n", __LINE__));
769            $in_list++ if $format_map{$tag} eq 'UL' || $format_map{$tag} eq 'OL' ;
770            push(@lines, &debug("<$format_map{$tag}>\n", __LINE__));
771            next;
772        } elsif ($tag eq 'table') {
773            if (/^\@[fv]?table\s+\@(\w+)\s*$/) {
774                $in_table = $1;
775                unshift(@tables, join($;, $table_type, $in_table));
776                push(@lines, &debug("<DL COMPACT>\n", __LINE__));
777                &html_push_if('DL');
778                push(@lines, &html_debug("\n", __LINE__));
779            } elsif (/^\@multitable\s+/) {
780                # Note descent to HTML 3.2 necessary for multitable.
781                $in_table = ' ';
782                unshift(@tables, join($;, $table_type, $in_table));
783                push(@lines, &debug("<TABLE>\n", __LINE__));
784                &html_push_if('TABLE');
785                push(@lines, &html_debug("\n", __LINE__));
786            } else {
787                warn "$ERROR Bad table line: $_";
788            }
789            next;
790        } elsif ($tag eq 'synindex' || $tag eq 'syncodeindex') {
791            if (/^\@$tag\s+(\w)\w\s+(\w)\w\s*$/) {
792                eval("*${1}index = *${2}index");
793            } else {
794                warn "$ERROR Bad syn*index line: $_";
795            }
796            next;
797        } elsif ($tag eq 'sp') {
798            push(@lines, &debug("<P>\n", __LINE__));
799            next;
800        } elsif ($tag eq 'setref') {
801            &protect_html; # if setref contains '&' for instance
802            if (/^\@$tag\s*{($NODERE)}\s*$/) {
803                $setref = $1;
804                $setref =~ s/\s+/ /g; # normalize
805                $setref =~ s/ $//;
806                $node2sec{$setref} = $name;
807                $node2href{$setref} = "$docu_doc#$docid";
808            } else {
809                warn "$ERROR Bad setref line: $_";
810            }
811            next;
812        } elsif ($tag eq 'defindex' || $tag eq 'defcodeindex') {
813            if (/^\@$tag\s+(\w\w)\s*$/) {
814                $valid_index{$1} = 1;
815            } else {
816                warn "$ERROR Bad defindex line: $_";
817            }
818            next;
819        } elsif ($tag eq 'direntry') {
820            &skip_until ($tag);
821            next;
822        } elsif (defined($def_map{$tag})) {
823            if ($def_map{$tag}) {
824                s/^\@$tag\s+//;
825                $tag = $def_map{$tag};
826                $_ = "\@$tag $_";
827                $tag =~ s/\s.*//;
828            }
829        } elsif (defined($user_sub{$tag})) {
830            s/^\@$tag\s+//;
831            $sub = $user_sub{$tag};
832            print "# user $tag = $sub, arg: $_" if $debug & $DEBUG_USER;
833            if (defined(&$sub)) {
834                chop($_);
835                &$sub($_);
836            } else {
837                warn "$ERROR Bad user sub for $tag: $sub\n";
838            }
839            next;
840        }
841        if (defined($def_map{$tag})) {
842            s/^\@$tag\s+//;
843            if ($tag =~ /x$/) {
844                # extra definition line
845                $tag = $`;
846                $is_extra = 1;
847            } else {
848                $is_extra = 0;
849            }
850            while (/\{([^\{\}]*)\}/) {
851                # this is a {} construct
852                ($before, $contents, $after) = ($`, $1, $');
853                # protect spaces
854                $contents =~ s/\s+/$;9/g;
855                # restore $_ protecting {}
856                $_ = "$before$;7$contents$;8$after";
857            }
858            @args = split(/\s+/, &protect_html($_));
859            foreach (@args) {
860                s/$;9/ /g;      # unprotect spaces
861                s/$;7/\{/g;     # ... {
862                s/$;8/\}/g;     # ... }
863            }
864            $type = shift(@args);
865            $type =~ s/^\{(.*)\}$/$1/;
866            print "# def ($tag): {$type} ", join(', ', @args), "\n"
867                if $debug & $DEBUG_DEF;
868            $type .= ':'; # it's nicer like this
869            $name = shift(@args);
870            $name =~ s/^\{(.*)\}$/$1/;
871            if ($is_extra) {
872                $_ = &debug("<DT>", __LINE__);
873            } else {
874                $_ = &debug("<DL>\n<DT>", __LINE__);
875            }
876            if ($tag eq 'deffn' || $tag eq 'defvr' || $tag eq 'deftp') {
877                $_ .= "<U>$type</U> <B>$name</B>";
878                $_ .= " <I>@args</I>" if @args;
879            } elsif ($tag eq 'deftypefn' || $tag eq 'deftypevr'
880                     || $tag eq 'defcv' || $tag eq 'defop') {
881                $ftype = $name;
882                $name = shift(@args);
883                $name =~ s/^\{(.*)\}$/$1/;
884                $_ .= "<U>$type</U> $ftype <B>$name</B>";
885                $_ .= " <I>@args</I>" if @args;
886            } else {
887                warn "$ERROR Unknown definition type: $tag\n";
888                $_ .= "<U>$type</U> <B>$name</B>";
889                $_ .= " <I>@args</I>" if @args;
890            }
891            $_ .= &debug("\n<DD>", __LINE__);
892            $name = &unprotect_html($name);
893            if ($tag eq 'deffn' || $tag eq 'deftypefn') {
894                unshift(@input_spool, "\@findex $name\n");
895            } elsif ($tag eq 'defop') {
896                unshift(@input_spool, "\@findex $name on $ftype\n");
897            } elsif ($tag eq 'defvr' || $tag eq 'deftypevr' || $tag eq 'defcv') {
898                unshift(@input_spool, "\@vindex $name\n");
899            } else {
900                unshift(@input_spool, "\@tindex $name\n");
901            }
902            $dont_html = 1;
903        }
904    } elsif ($end_tag) {
905        if ($format_map{$end_tag}) {
906            $in_pre = 0 if $format_map{$end_tag} eq 'PRE';
907            $in_list-- if $format_map{$end_tag} eq 'UL' || $format_map{$end_tag} eq 'OL' ;
908            &html_pop_if('LI', 'P');
909            &html_pop_if();
910            push(@lines, &debug("</$format_map{$end_tag}>\n", __LINE__));
911            push(@lines, &html_debug("\n", __LINE__));
912        } elsif ($end_tag eq 'table' ||
913                 $end_tag eq 'ftable' ||
914                 $end_tag eq 'vtable' ||
915                 $end_tag eq 'multitable') {
916            shift(@tables);
917            if (@tables) {
918                ($table_type, $in_table) = split($;, $tables[0]);
919            } else {
920                $in_table = 0;
921            }
922            if ($end_tag eq 'multitable') {
923                push(@lines, "</TABLE>\n");
924                &html_pop_if('TABLE');
925            } else {
926            push(@lines, "</DL>\n");
927            &html_pop_if('DD');
928            }
929            &html_pop_if();
930        } elsif (defined($def_map{$end_tag})) {
931            push(@lines, &debug("</DL>\n", __LINE__));
932        } elsif ($end_tag eq 'menu') {
933            &html_pop_if();
934            push(@lines, $_); # must keep it for pass 2
935        }
936        next;
937    }
938    #
939    # misc things
940    #
941    # protect texi and HTML things
942    &protect_texi;
943    $_ = &protect_html($_) unless $dont_html;
944    $dont_html = 0;
945    # substitution (unsupported things)
946    # s/^\@center\s+//g;                # fixme: use <center> or <div align=center>?
947    s/^\@exdent\s+//g;
948    s/\@noindent\s+//g;
949    s/\@refill\s+//g;
950    # other substitutions
951    &simple_substitutions;
952    s/\@value{($VARRE)}/$value{$1}/eg;
953    s/\@footnote\{/\@footnote$docu_doc\{/g; # mark footnotes, cf. pass 4
954    #
955    # analyze the tag again
956    #
957    if ($tag) {
958        if (defined($sec2level{$tag}) && $sec2level{$tag} > 0) {
959            if (/^\@$tag\s+(.+)$/) {
960                $name = $1;
961                $name =~ s/\s+$//;
962                $level = $sec2level{$tag};
963#               print "+++==>$tag<\n";
964                if ($number_sections && $tag !~ /heading$/) {
965                    $name = &update_sec_num($tag, $level) . "  $name";
966                    push(@left_index, $name);
967                }
968#               $name = &update_sec_num($tag, $level) . "  $name"
969#                   if $number_sections && $tag !~ /heading$/;
970#                   if $number_sections && $tag !~ /^unnumbered/;
971                if ($tag =~ /heading$/) {
972                    push(@lines, &html_debug("\n", __LINE__));
973                    if ($html_element ne 'body') {
974                        # We are in a nice pickle here. We are trying to get a H? heading
975                        # even though we are not in the body level. So, we convert it to a
976                        # nice, bold, line by itself.
977                        $_ = &debug("\n\n<P><STRONG>$name</STRONG></P>\n\n", __LINE__);
978                    } else {
979                        $_ = &debug("<H$level>$name</H$level>\n", __LINE__);
980                        &html_push_if('body');
981                    }
982                    print "# heading, section $name, level $level\n"
983                        if $debug & $DEBUG_TOC;
984                } else {
985                    if ($split_chapter) {
986                        unless ($toplevel) {
987                            # first time we see a "section"
988                            unless ($level == 1) {
989                                warn "$ERROR The first section found is not of level 1: $_";
990                                warn "$ERROR I'll split on sections of level $level...\n";
991                            }
992                            $toplevel = $level;
993                        }
994                        if ($level == $toplevel) {
995                            &next_doc;
996                            push(@lines, $SPLITTAG) if $split_num++;
997                            push(@sections, $name);
998                        }
999                    }
1000                    $sec_num++;
1001                    $docid = "SEC$sec_num";
1002                    $tocid = "TOC$sec_num";
1003                    # check biblio and glossary
1004                    $in_bibliography = ($name =~ /^([A-Z]|\d+)?(\.\d+)*\s*bibliography$/i);
1005                    $in_glossary = ($name =~ /^([A-Z]|\d+)?(\.\d+)*\s*glossary$/i);
1006                    # check node
1007                    if ($node) {
1008                        if ($node2sec{$node}) {
1009                            warn "$ERROR Duplicate node found: $node\n";
1010                        } else {
1011                            $node2sec{$node} = $name;
1012                            $node2href{$node} = "$docu_doc#$docid";
1013                            print "# node $node, section $name, level $level\n"
1014                                if $debug & $DEBUG_TOC;
1015                        }
1016                        $node = '';
1017                    } else {
1018                        print "# no node, section $name, level $level\n"
1019                            if $debug & $DEBUG_TOC;
1020                    }
1021                    # update TOC
1022                    while ($level > $curlevel) {
1023                        $curlevel++;
1024                        push(@toc_lines, "<UL>\n");
1025                    }
1026                    while ($level < $curlevel) {
1027                        $curlevel--;
1028                        push(@toc_lines, "</UL>\n");
1029                    }
1030                    $_ = "<LI>" . &anchor($tocid, "$docu_doc#$docid", '', $name, 1);
1031                    push(@toc_lines, &substitute_style($_));
1032                    # update DOC
1033                    push(@lines, &html_debug("\n", __LINE__));
1034                    &html_reset;
1035                    $_ =  "<H$level>".&anchor($docid, "$docu_toc#$tocid", '', $name)."</H$level>\n";
1036                    $_ = &debug($_, __LINE__);
1037                    push(@lines, &html_debug("\n", __LINE__));
1038                }
1039                # update DOC
1040                foreach $line (split(/\n+/, $_)) {
1041                    push(@lines, "$line\n");
1042                }
1043                next;
1044            } else {
1045                warn "$ERROR Bad section line: $_";
1046            }
1047        } else {
1048            # track variables
1049            $value{$1} = $2, next if /^\@set\s+($VARRE)\s+(.*)$/o;
1050            delete $value{$1}, next if /^\@clear\s+($VARRE)\s*$/o;
1051            # store things
1052            $value{'_setfilename'}   = $1, next if /^\@setfilename\s+(.*)$/;
1053            $value{'_settitle'}      = $1, next if /^\@settitle\s+(.*)$/;
1054            $value{'_author'}   .= "$1\n", next if /^\@author\s+(.*)$/;
1055            $value{'_subtitle'} .= "$1\n", next if /^\@subtitle\s+(.*)$/;
1056            $value{'_title'}    .= "$1\n", next if /^\@title\s+(.*)$/;
1057            # index
1058            if (/^\@(..?)index\s+/) {
1059                unless ($valid_index{$1}) {
1060                    warn "$ERROR Undefined index command: $_";
1061                    next;
1062                }
1063                $id = 'IDX' . ++$idx_num;
1064                $index = $1 . 'index';
1065                $what = &substitute_style($');
1066                $what =~ s/\s+$//;
1067                print "# found $index for '$what' id $id\n"
1068                    if $debug & $DEBUG_INDEX;
1069                eval(<<EOC);
1070                if (defined(\$$index\{\$what\})) {
1071                    \$$index\{\$what\} .= "$;$docu_doc#$id";
1072                } else {
1073                    \$$index\{\$what\} = "$docu_doc#$id";
1074                }
1075EOC
1076                #
1077                # dirty hack to see if I can put an invisible anchor...
1078                #
1079                if ($html_element eq 'P' ||
1080                    $html_element eq 'LI' ||
1081                    $html_element eq 'DT' ||
1082                    $html_element eq 'DD' ||
1083                    $html_element eq 'ADDRESS' ||
1084                    $html_element eq 'B' ||
1085                    $html_element eq 'BLOCKQUOTE' ||
1086                    $html_element eq 'PRE' ||
1087                    $html_element eq 'SAMP') {
1088                    push(@lines, &anchor($id, '', '', $invisible_mark, !$in_pre));
1089                } elsif ($html_element eq 'body') {
1090                    push(@lines, &debug("<P>\n", __LINE__));
1091                    push(@lines, &anchor($id, '', '', $invisible_mark, !$in_pre));
1092                    &html_push('P');
1093                } elsif ($html_element eq 'DL' ||
1094                         $html_element eq 'UL' ||
1095                         $html_element eq 'OL' ) {
1096                    $deferred_ref .= &anchor($id, '', '', $invisible_mark, !$in_pre) . " ";
1097                }
1098                next;
1099            }
1100            # list item
1101            if (/^\@itemx?\s+/) {
1102                $what = $';
1103                $what =~ s/\s+$//;
1104                if ($in_bibliography && $use_bibliography) {
1105                    if ($what =~ /^$BIBRE$/o) {
1106                        $id = 'BIB' . ++$bib_num;
1107                        $bib2href{$what} = "$docu_doc#$id";
1108                        print "# found bibliography for '$what' id $id\n"
1109                            if $debug & $DEBUG_BIB;
1110                        $what = &anchor($id, '', '', $what);
1111                    }
1112                } elsif ($in_glossary && $use_glossary) {
1113                    $id = 'GLOSS' . ++$gloss_num;
1114                    $entry = $what;
1115                    $entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/;
1116                    $gloss2href{$entry} = "$docu_doc#$id";
1117                    print "# found glossary for '$entry' id $id\n"
1118                        if $debug & $DEBUG_GLOSS;
1119                    $what = &anchor($id, '', '', $what);
1120                }
1121                &html_pop_if('P');
1122                if ($html_element eq 'DL' || $html_element eq 'DD') {
1123                    if ($things_map{$in_table} && !$what) {
1124                        # special case to allow @table @bullet for instance
1125                        push(@lines, &debug("<DT>$things_map{$in_table}\n", __LINE__));
1126                    } else {
1127                        push(@lines, &debug("<DT>\@$in_table\{$what\}\n", __LINE__));
1128                    }
1129                    push(@lines, "<DD>");
1130                    &html_push('DD') unless $html_element eq 'DD';
1131                    if ($table_type) { # add also an index
1132                        unshift(@input_spool, "\@${table_type}index $what\n");
1133                    }
1134                } elsif ($html_element eq 'TABLE' || $html_element eq 'TR') {
1135                    # Add <br> at ends of rows for non-tables browsers.
1136                    push(@lines, "<BR>\n") if $html_element eq 'TR';
1137                    push(@lines, "<TR>$what");
1138                    &html_push('TR') unless $html_element eq 'TR';
1139                } else {
1140                    push(@lines, &debug("<LI>$what\n", __LINE__));
1141                    &html_push('LI') unless $html_element eq 'LI';
1142                }
1143                push(@lines, &html_debug("\n", __LINE__));
1144                if ($deferred_ref) {
1145                    push(@lines, &debug("$deferred_ref\n", __LINE__));
1146                    $deferred_ref = '';
1147                }
1148                next;
1149            }
1150        }
1151    }
1152    # paragraph separator
1153    if ($_ eq "\n") {
1154        next if $#lines >= 0 && $lines[$#lines] eq "\n";
1155        if ($html_element eq 'P') {
1156            push(@lines, "\n");
1157            $_ = &debug("</P>\n", __LINE__);
1158            &html_pop;
1159        }
1160    } elsif ($html_element eq 'body' || $html_element eq 'BLOCKQUOTE') {
1161        push(@lines, "<P>\n");
1162        &html_push('P');
1163        $_ = &debug($_, __LINE__);
1164    }
1165    # otherwise
1166    push(@lines, $_);
1167}
1168
1169# finish TOC
1170$level = 0;
1171while ($level < $curlevel) {
1172    $curlevel--;
1173    push(@toc_lines, "</UL>\n");
1174}
1175
1176print "# end of pass 1\n" if $verbose;
1177
1178#+++############################################################################
1179#                                                                              #
1180# Pass 2/3: handle style, menu, index, cross-reference                         #
1181#                                                                              #
1182#---############################################################################
1183
1184@lines2 = ();                           # whole document (2nd pass)
1185@lines3 = ();                           # whole document (3rd pass)
1186$in_menu = 0;                           # am I inside a menu
1187$in_top = 1;
1188
1189while (@lines) {
1190    $_ = shift(@lines);
1191    #
1192    # special case (protected sections)
1193    #
1194    if (/^$PROTECTTAG/o) {
1195        push(@lines2, $_);
1196        next;
1197    }
1198    if ($in_top && $_ eq "$TOPTAG") {
1199        $in_top = 0;
1200        while(@lines2) {
1201            $_ = shift(@lines2);
1202            if (/\@(\w+)\ /) {
1203                ($before, $style, $after) = ($`, $1, $');
1204                if (defined($style_l_map{$style})) {
1205                    $_ = $after;
1206                    $text = '';
1207                    $after = '';
1208                    $failed = 1;
1209                    while (@lines2) {
1210                        if (/\n/) {
1211                            $text .= $`;
1212                            $after = $';
1213                            $failed = 0;
1214                            last;
1215                        } else {
1216                            $text .= $_;
1217                            $_ = shift(@lines2);
1218                        }
1219                    }
1220                    if ($failed) {
1221                        die "* Bad syntax (\@$style) after: $before\n";
1222                    } else {
1223                        $text = &apply_l_style($style, $text);
1224                        $_ = "$before$text$after\n";
1225                    }
1226                }
1227            }
1228            push(@top_lines, $_);
1229        }
1230        #@top_lines = @lines2;  # Contents of the top node.
1231        @lines2 = ();           # Don't use them in place.
1232        next;
1233    }
1234    #
1235    # menu
1236    #
1237    $in_menu = 1, push(@lines2, &debug("<UL>\n", __LINE__)), next if /^\@menu\b/;
1238    $in_menu = 0, push(@lines2, &debug("</UL>\n", __LINE__)), next if /^\@end\s+menu\b/;
1239    if ($in_menu) {
1240        if (/^\*\s+($NODERE)::/o) {
1241            $descr = $';
1242            chop($descr);
1243            &menu_entry($1, $1, $descr);
1244        } elsif (/^\*\s+(.+):\s+([^\t,\.\n]+)[\t,\.\n]/) {
1245            $descr = $';
1246            chop($descr);
1247            &menu_entry($1, $2, $descr);
1248        } elsif (/^\*/) {
1249            warn "$ERROR Bad menu line: $_";
1250        } else { # description continued?
1251            push(@lines2, $_);
1252        }
1253        next;
1254    }
1255    #
1256    # printindex
1257    #
1258    if (/^\@printindex\s+(\w\w)\b/) {
1259        local($index, *ary, @keys, $key, $letter, $last_letter, @refs);
1260        if ($predefined_index{$1}) {
1261            $index = $predefined_index{$1} . 'index';
1262        } else {
1263            $index = $1 . 'index';
1264        }
1265        eval("*ary = *$index");
1266        @keys = keys(%ary);
1267        foreach $key (@keys) {
1268            $_ = $key;
1269            1 while s/<(\w+)>\`(.*)\'<\/\1>/$2/; # remove HTML tags with quotes
1270            1 while s/<(\w+)>(.*)<\/\1>/$2/;     # remove HTML tags
1271            $_ = &unprotect_html($_);
1272            &unprotect_texi;
1273            tr/A-Z/a-z/; # lowercase
1274            $key2alpha{$key} = $_;
1275            print "# index $key sorted as $_\n"
1276                if $key ne $_ && $debug & $DEBUG_INDEX;
1277        }
1278        $last_letter = undef;
1279        foreach $key (sort byalpha @keys) {
1280            $letter = substr($key2alpha{$key}, 0, 1);
1281            $letter = substr($key2alpha{$key}, 0, 2) if $letter eq $;;
1282            if (!defined($last_letter) || $letter ne $last_letter) {
1283                push(@lines2, "</DIR>\n") if defined($last_letter);
1284                push(@lines2, "<H2>" . &protect_html($letter) . "</H2>\n");
1285                push(@lines2, "<DIR>\n");
1286                $last_letter = $letter;
1287            }
1288            @refs = ();
1289            foreach (split(/$;/, $ary{$key})) {
1290                push(@refs, &anchor('', $_, '', $key, 0));
1291            }
1292            push(@lines2, "<LI>" . join(", ", @refs) . "\n");
1293        }
1294        push(@lines2, "</DIR>\n") if defined($last_letter);
1295        next;
1296    }
1297    #
1298    # simple style substitutions
1299    #
1300    $_ = &substitute_style($_);
1301    #
1302    # xref
1303    #
1304    while (/\@(x|px|info|)ref{($XREFRE)(}?)/o) {
1305        # note: Texinfo may accept other characters
1306        ($type, $nodes, $full) = ($1, $2, $3);
1307        ($before, $after) = ($`, $');
1308        $ref_where = "Section";
1309        if (! $full && $after) {
1310            warn "$ERROR Bad xref (no ending } on line): $_";
1311            $_ = "$before$;0${type}ref\{$nodes$after";
1312            next; # while xref
1313        }
1314        if ($type eq 'x') {
1315            $type = 'See ';
1316        } elsif ($type eq 'px') {
1317            $type = 'see ';
1318        } elsif ($type eq 'info') {
1319            $type = 'See Info';
1320        } else {
1321            $type = '';
1322        }
1323        unless ($full) {
1324            $next = shift(@lines);
1325            $next = &substitute_style($next);
1326            chop($nodes); # remove final newline
1327            if ($next =~ /\}/) { # split on 2 lines
1328                $nodes .= " $`";
1329                $after = $';
1330            } else {
1331                $nodes .= " $next";
1332                $next = shift(@lines);
1333                $next = &substitute_style($next);
1334                chop($nodes);
1335                if ($next =~ /\}/) { # split on 3 lines
1336                    $nodes .= " $`";
1337                    $after = $';
1338                } else {
1339                    warn "$ERROR Bad xref (no ending }): $_";
1340                    $_ = "$before$;0xref\{$nodes$after";
1341                    unshift(@lines, $next);
1342                    next; # while xref
1343                }
1344            }
1345        }
1346        $nodes =~ s/\s+/ /g; # remove useless spaces
1347        @args = split(/\s*,\s*/, $nodes);
1348        $node = $args[0]; # the node is always the first arg
1349        &normalise_node($node);
1350        $sec = $node2sec{$node};
1351        $_ = $sec;
1352        if (/^[A-Z]/) {
1353            $ref_where = "Appendix";
1354        }
1355        if (@args == 5) { # reference to another manual
1356            $sec = $args[2] || $node;
1357            $man = $args[4] || $args[3];
1358            $_ = "${before}${type}$ref_where `$sec' in \@cite{$man}$after";
1359        } elsif ($type =~ /Info/) { # inforef
1360            warn "$ERROR Wrong number of arguments: $_" unless @args == 3;
1361            ($nn, $_, $in) = @args;
1362            $_ = "${before}${type} file `$in', node `$nn'$after";
1363        } elsif ($sec) {
1364            $href = $node2href{$node};
1365            $_ = "${before}${type}" . &anchor('', $href, '', "$ref_where $sec") . $after;
1366        } else {
1367            warn "$ERROR Undefined node ($node): $_";
1368            $_ = "$before$;0xref{$nodes}$after";
1369        }
1370    }
1371    #
1372    # try to guess bibliography references or glossary terms
1373    #
1374    unless (/^<H\d><A NAME=\"SEC\d/) {
1375        if ($use_bibliography) {
1376            $done = '';
1377            while (/$BIBRE/o) {
1378                ($pre, $what, $post) = ($`, $&, $');
1379                $href = $bib2href{$what};
1380                if (defined($href) && $post !~ /^[^<]*<\/A>/) {
1381                    $done .= $pre . &anchor('', $href, '', $what);
1382                } else {
1383                    $done .= "$pre$what";
1384                }
1385                $_ = $post;
1386            }
1387            $_ = $done . $_;
1388        }
1389        if ($use_glossary) {
1390            $done = '';
1391            while (/\b\w+\b/) {
1392                ($pre, $what, $post) = ($`, $&, $');
1393                $entry = $what;
1394                $entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/;
1395                $href = $gloss2href{$entry};
1396                if (defined($href) && $post !~ /^[^<]*<\/A>/) {
1397                    $done .= $pre . &anchor('', $href, '', $what);
1398                } else {
1399                    $done .= "$pre$what";
1400                }
1401                $_ = $post;
1402            }
1403            $_ = $done . $_;
1404        }
1405    }
1406    # otherwise
1407    push(@lines2, $_);
1408}
1409print "# end of pass 2\n" if $verbose;
1410
1411#
1412# split style substitutions
1413#
1414while (@lines2) {
1415    $_ = shift(@lines2);
1416    #
1417    # special case (protected sections)
1418    #
1419    if (/^$PROTECTTAG/o) {
1420        push(@lines3, $_);
1421        next;
1422    }
1423    #
1424    # split style substitutions
1425    #
1426    $old = '';
1427    while ($old ne $_) {
1428        $old = $_;
1429        if (/\@(\w+)\{/) {
1430            ($before, $style, $after) = ($`, $1, $');
1431            if (defined($style_map{$style})) {
1432                $_ = $after;
1433                $text = '';
1434                $after = '';
1435                $failed = 1;
1436                while (@lines2) {
1437                    if (/\}/) {
1438                        $text .= $`;
1439                        $after = $';
1440                        $failed = 0;
1441                        last;
1442                    } else {
1443                        $text .= $_;
1444                        $_ = shift(@lines2);
1445                    }
1446                }
1447                if ($failed) {
1448                    die "* Bad syntax (\@$style) after: $before\n";
1449                } else {
1450                    $text = &apply_style($style, $text);
1451                    $_ = "$before$text$after";
1452                }
1453            }
1454        }
1455        if (/\@(\w+)\ /) {
1456            ($before, $style, $after) = ($`, $1, $');
1457            if (defined($style_l_map{$style})) {
1458                $_ = $after;
1459                $text = '';
1460                $after = '';
1461                $failed = 1;
1462                while (@lines2) {
1463                    if (/\n/) {
1464                        $text .= $`;
1465                        $after = $';
1466                        $failed = 0;
1467                        last;
1468                    } else {
1469                        $text .= $_;
1470                        $_ = shift(@lines2);
1471                    }
1472                }
1473                if ($failed) {
1474                    die "* Bad syntax (\@$style) after: $before\n";
1475                } else {
1476                    $text = &apply_l_style($style, $text);
1477                    $_ = "$before$text$after";
1478                }
1479            }
1480        }
1481    }
1482    # otherwise
1483    push(@lines3, $_);
1484}
1485print "# end of pass 3\n" if $verbose;
1486
1487#+++############################################################################
1488#                                                                              #
1489# Pass 4: foot notes, final cleanup                                            #
1490#                                                                              #
1491#---############################################################################
1492
1493@foot_lines = ();                       # footnotes
1494@doc_lines = ();                        # final document
1495$end_of_para = 0;                       # true if last line is <P>
1496
1497while (@lines3) {
1498    $_ = shift(@lines3);
1499    #
1500    # special case (protected sections)
1501    #
1502    if (/^$PROTECTTAG/o) {
1503        push(@doc_lines, $_);
1504        $end_of_para = 0;
1505        next;
1506    }
1507    #
1508    # footnotes
1509    #
1510    while (/\@footnote([^\{\s]+)\{/) {
1511        ($before, $d, $after) = ($`, $1, $');
1512        $_ = $after;
1513        $text = '';
1514        $after = '';
1515        $failed = 1;
1516        while (@lines3) {
1517            if (/\}/) {
1518                $text .= $`;
1519                $after = $';
1520                $failed = 0;
1521                last;
1522            } else {
1523                $text .= $_;
1524                $_ = shift(@lines3);
1525            }
1526        }
1527        if ($failed) {
1528            die "* Bad syntax (\@footnote) after: $before\n";
1529        } else {
1530            $foot_num++;
1531            $docid  = "DOCF$foot_num";
1532            $footid = "FOOT$foot_num";
1533            $foot = "($foot_num)";
1534            push(@foot_lines, "<H3>" . &anchor($footid, "$d#$docid", '', $foot) . "</H3>\n");
1535            $text = "<P>$text" unless $text =~ /^\s*<P>/;
1536            push(@foot_lines, "$text\n");
1537            $_ = $before . &anchor($docid, "$docu_foot#$footid", '', $foot) . $after;
1538        }
1539    }
1540    #
1541    # remove unnecessary <P>
1542    #
1543    if (/^\s*<P>\s*$/) {
1544        next if $end_of_para++;
1545    } else {
1546        $end_of_para = 0;
1547    }
1548    # otherwise
1549    push(@doc_lines, $_);
1550}
1551print "# end of pass 4\n" if $verbose;
1552
1553push(@menu_lines, "<BODY BACKGROUND=\"$IMG_LEFT\">\n");
1554push(@menu_lines, "<A HREF=\"http://www.mathematik.uni-kl.de/~zca/Singular\" TARGET=\"_parent\">");
1555push(@menu_lines, "<IMG SRC=\"images/singular-small.jpg\"></A><P>\n");
1556#push(@menu_lines, "<BODY BACKGROUND=\"/rock.gif\" TEXT=\"yellow\"");
1557#push(@menu_lines, " LINK=#FFFFFF ALINK=#FF00FF VLINK=\"#00FF00\">\n");
1558#push(@menu_lines, "<NOBR>\n");
1559push(@menu_lines, "<OL>\n");
1560foreach (@left_index) {
1561    $entry = $_;
1562    @part = split(/\ /);
1563    $name = join(' ', @part[1..$#part]);
1564    if (!/^[A-Z0-9]\./) {
1565        &left_menu_entry($part[0], $name);
1566    }
1567}
1568push(@menu_lines, "</OL>\n");
1569print "# end of pass 5\n" if $verbose;
1570
1571#+++############################################################################
1572#                                                                              #
1573# Pass 6: print things                                                         #
1574#                                                                              #
1575#---############################################################################
1576
1577$header = <<EOT;
1578<!-- This HTML file has been created by $THISPROG
1579     from $docu on $TODAY -->
1580EOT
1581
1582$full_title = $value{'_title'} || $value{'_settitle'} || "Untitled Document";
1583$title = $value{'_settitle'} || $full_title;
1584$_ = &substitute_style($full_title);
1585&unprotect_texi;
1586s/\n$//; # rmv last \n (if any)
1587$full_title = "<H1>" . join("</H1>\n<H1>", split(/\n/, $_)) . "</H1>\n";
1588
1589#
1590# print ToC
1591#
1592# ... unless using menus instead.  Make the TOC lines empty rather than
1593# null so we get a ToC page with the top node (including menu).
1594@toc_lines = ("") if $show_menu;
1595
1596if (!$monolithic && @toc_lines) {
1597    if (open(FILE, "> $docu_toc")) {
1598        print "# creating $docu_toc...\n" if $verbose;
1599        &print_header("$title - Table of Contents", "", 0);
1600        # &print_toplevel_header("$title - Table of Contents");
1601        &print_ruler;
1602        &print (*top_lines, FILE); # Contents of the top node before the TOC.
1603        &print(*toc_lines, FILE);
1604        &print_toplevel_footer;
1605        close(FILE);
1606    } else {
1607        warn "$ERROR Can't write to $docu_toc: $!\n";
1608    }
1609}
1610
1611#
1612# print footnotes
1613#
1614if (!$monolithic && @foot_lines) {
1615    if (open(FILE, "> $docu_foot")) {
1616        print "# creating $docu_foot...\n" if $verbose;
1617        &print_toplevel_header("$title - Footnotes");
1618        &print_ruler;
1619        &print(*foot_lines, FILE);
1620        &print_toplevel_footer;
1621        close(FILE);
1622    } else {
1623        warn "$ERROR Can't write to $docu_foot: $!\n";
1624    }
1625}
1626
1627#
1628#
1629#
1630if (!$monolithic && $make_entry_page) {
1631    if(open(FILE, "> $docu_main")) {
1632        &print_header("$title - $docu_name", "", 1);
1633        print "# creating $docu_main...\n" if $verbose;
1634        #&print_frame($docu_name . "_1.html");
1635        &print_frame($docu_toc);
1636        &print_toplevel_footer;
1637        close(FILE);
1638    } else {
1639        warn "$ERROR Can't write to $docu_main: $!\n";
1640    }
1641}
1642
1643#
1644#
1645#
1646if (!$monolithic && $make_menu_page && @menu_lines) {
1647    if(open(FILE, "> $docu_left")) {
1648        &print_header("$title - $docu_left", "", 1);
1649        print "# creating $docu_left...\n" if $verbose;
1650        &print(*menu_lines, FILE);
1651        &print_footer;
1652        close(FILE);
1653    } else {
1654        warn "$ERROR Can't write to $docu_main: $!\n";
1655    }
1656}
1657
1658#
1659# print document
1660#
1661if ($split_chapter || $split_node) { # split
1662    $doc_num = 0;
1663    $last_num = scalar(@sections);
1664    $first_doc = &doc_name(1);
1665    $last_doc = &doc_name($last_num);
1666    while (@sections) {
1667        $section = shift(@sections);
1668        &next_doc;
1669        if (open(FILE, "> $docu_doc")) {
1670            print "# creating $docu_doc...\n" if $verbose;
1671            $prev_doc = ($doc_num == 1 ? undef : &doc_name($doc_num - 1));
1672            $next_doc = ($doc_num == $last_num ? undef : &doc_name($doc_num + 1));
1673            $links = ($next_doc ? "<link href=\"$next_doc\" rel=Next>\n" : "");
1674            $links .= ($prev_doc ? "<link href=\"$prev_doc\" rel=Previous>\n" : "");
1675            $links .= "<link href=\"$docu_toc\" rel=ToC>\n";
1676            # fixme: try rel=Index too?
1677            &print_header("$title - $section", $links, 0);
1678
1679            #$navigation = "<p>Go to the ";
1680            $navigation = "<p>";
1681            if ($IMG_FIRST_ACTIVE ne "") {
1682                $navigation .= ($prev_doc ? &anchor('', $first_doc, '', 
1683                             $IMG_FIRST_ACTIVE) : $IMG_FIRST_PASSIVE);
1684                $navigation .= " ";
1685            }
1686            $navigation .= ($prev_doc ? &anchor('', $prev_doc, '', $IMG_PREV_ACTIVE) : $IMG_PREV_PASSIVE);
1687            $navigation .= " ";
1688            $navigation .= ($next_doc ? &anchor('', $next_doc, '', $IMG_NEXT_ACTIVE) : $IMG_NEXT_PASSIVE);
1689            if ($IMG_LAST_ACTIVE ne "") {
1690                $navigation .= " ";
1691                $navigation .= ($next_doc ? &anchor('', $last_doc, '',
1692                             $IMG_LAST_ACTIVE) : $IMG_LAST_PASSIVE);
1693            }
1694            #$navigation .= " section, " . &anchor('', $docu_toc, '', "<IMG SRC=\"toc-b.gif\">") . ".\n";
1695            $navigation .= " " . &anchor('', $docu_toc, '', $IMG_TOC) . "\n";
1696            print FILE $navigation;
1697            &print_ruler;
1698            # find corresponding lines
1699            @tmp_lines = ();
1700            while (@doc_lines) {
1701                $_ = shift(@doc_lines);
1702                last if ($_ eq $SPLITTAG);
1703                push(@tmp_lines, $_);
1704            }
1705            &print(*tmp_lines, FILE);
1706            &print_ruler;
1707            print FILE $navigation;
1708            &print_footer;
1709            close(FILE);
1710        } else {
1711            warn "$ERROR Can't write to $docu_doc: $!\n";
1712        }
1713    }
1714} else { # not split
1715    if (open(FILE, "> $docu_doc")) {
1716        print "# creating $docu_doc...\n" if $verbose;
1717        if ($monolithic || !@toc_lines) {
1718            &print_toplevel_header($title);
1719        } else {
1720            &print_header($title, "", 0);
1721            print FILE $full_title;
1722        }
1723        if ($monolithic && @toc_lines) {
1724            &print_ruler;
1725            print FILE "<H1>Table of Contents</H1>\n";
1726            &print(*toc_lines, FILE);
1727        }
1728        &print_ruler;
1729        &print(*doc_lines, FILE);
1730        if ($monolithic && @foot_lines) {
1731            &print_ruler;
1732            print FILE "<H1>Footnotes</H1>\n";
1733            &print(*foot_lines, FILE);
1734        }
1735        if ($monolithic || !@toc_lines) {
1736            &print_toplevel_footer;
1737        } else {
1738            &print_footer;
1739        }
1740        close(FILE);
1741    } else {
1742        warn "$ERROR Can't write to $docu_doc: $!\n";
1743    }
1744}
1745
1746print "# that's all folks\n" if $verbose;
1747
1748#+++############################################################################
1749#                                                                              #
1750# Low level functions                                                          #
1751#                                                                              #
1752#---############################################################################
1753
1754sub update_sec_num {
1755    local($name, $level) = @_;
1756
1757    $level--; # here we start at 0
1758    if (($name =~ /^appendix/) || ($section_type)) {
1759        # appendix style
1760        $section_type = 1;
1761        if (defined(@appendix_sec_num)) {
1762            &incr_sec_num($level, @appendix_sec_num);
1763        } else {
1764            @appendix_sec_num = ('A', 0, 0, 0);
1765        }
1766        return(join('.', @appendix_sec_num[0..$level]));
1767    } else {
1768        # normal style
1769        $section_type = 0;
1770        if (defined(@normal_sec_num)) {
1771            &incr_sec_num($level, @normal_sec_num);
1772        } else {
1773            @normal_sec_num = (1, 0, 0, 0);
1774        }
1775        return(join('.', @normal_sec_num[0..$level]));
1776    }
1777}
1778
1779sub incr_sec_num {
1780    local($level, $l);
1781    $level = shift(@_);
1782    $_[$level]++;
1783    foreach $l ($level+1 .. 3) {
1784        $_[$l] = 0;
1785    }
1786}
1787
1788sub check {
1789    local($_, %seen, %context, $before, $match, $after);
1790
1791    while (<>) {
1792        if (/\@(\*|\.|\:|\@|\{|\})/) {
1793            $seen{$&}++;
1794            $context{$&} .= "> $_" if $verbose;
1795            $_ = "$`XX$'";
1796            redo;
1797        }
1798        if (/\@(\w+)/) {
1799            ($before, $match, $after) = ($`, $&, $');
1800            if ($before =~ /\b[\w-]+$/ && $after =~ /^[\w-.]*\b/) { # e-mail address
1801                $seen{'e-mail address'}++;
1802                $context{'e-mail address'} .= "> $_" if $verbose;
1803            } else {
1804                $seen{$match}++;
1805                $context{$match} .= "> $_" if $verbose;
1806            }
1807            $match =~ s/^\@/X/;
1808            $_ = "$before$match$after";
1809            redo;
1810        }
1811    }
1812   
1813    foreach (sort(keys(%seen))) {
1814        if ($verbose) {
1815            print "$_\n";
1816            print $context{$_};
1817        } else {
1818            print "$_ ($seen{$_})\n";
1819        }
1820    }
1821}
1822
1823sub open {
1824    local($name) = @_;
1825
1826    ++$fh_name;
1827    if (open($fh_name, $name)) {
1828        unshift(@fhs, $fh_name);
1829    } else {
1830        warn "$ERROR Can't read file $name: $!\n";
1831    }
1832}
1833
1834sub init_input {
1835    @fhs = ();                  # hold the file handles to read
1836    @input_spool = ();          # spooled lines to read
1837    $fh_name = 'FH000';
1838    &open($docu);
1839}
1840
1841sub next_line {
1842    local($fh, $line);
1843
1844    if (@input_spool) {
1845        $line = shift(@input_spool);
1846        return($line);
1847    }
1848    while (@fhs) {
1849        $fh = $fhs[0];
1850        $line = <$fh>;
1851        return($line) if $line;
1852        close($fh);
1853        shift(@fhs);
1854    }
1855    return(undef);
1856}
1857
1858# used in pass 1, use &next_line
1859sub skip_until {
1860    local($tag) = @_;
1861    local($_);
1862
1863    while ($_ = &next_line) {
1864        return if /^\@end\s+$tag\s*$/;
1865    }
1866    die "* Failed to find '$tag' after: " . $lines[$#lines];
1867}
1868
1869#
1870# HTML stacking to have a better HTML output
1871#
1872
1873sub html_reset {
1874    @html_stack = ('html');
1875    $html_element = 'body';
1876}
1877
1878sub html_push {
1879    local($what) = @_;
1880    push(@html_stack, $html_element);
1881    $html_element = $what;
1882}
1883
1884sub html_push_if {
1885    local($what) = @_;
1886    push(@html_stack, $html_element)
1887        if ($html_element && $html_element ne 'P');
1888    $html_element = $what;
1889}
1890
1891sub html_pop {
1892    $html_element = pop(@html_stack);
1893}
1894
1895sub html_pop_if {
1896    local($elt);
1897
1898    if (@_) {
1899        foreach $elt (@_) {
1900            if ($elt eq $html_element) {
1901                $html_element = pop(@html_stack) if @html_stack;
1902                last;
1903            }
1904        }
1905    } else {
1906        $html_element = pop(@html_stack) if @html_stack;
1907    }
1908}
1909
1910sub html_debug {
1911    local($what, $line) = @_;
1912    return("<!-- $line @html_stack, $html_element -->$what")
1913        if $debug & $DEBUG_HTML;
1914    return($what);
1915}
1916
1917# to debug the output...
1918sub debug {
1919    local($what, $line) = @_;
1920    return("<!-- $line -->$what")
1921        if $debug & $DEBUG_HTML;
1922    return($what);
1923}
1924
1925sub normalise_node {
1926    $_[0] =~ s/\s+/ /g;
1927    $_[0] =~ s/ $//;
1928    $_[0] =~ s/^ //;
1929}
1930
1931sub left_menu_entry {
1932    local($secnum, $entry) = @_;
1933    local($_);
1934    local($href, $descr, $oltype,$value);
1935
1936    $_ = $secnum;
1937    $value = $secnum;
1938    if (/[A-Z]/) { 
1939        $oltype = "<LI TYPE=A";
1940        $value = $append2num{$secnum};
1941    } else {
1942        $oltype = "<LI";
1943    }
1944    $_ = $entry;
1945    print "===>($secnum): $entry\n";
1946    #s/^[0-9A-Z.]+ //;
1947    $_ = $entry;
1948    &normalise_node($_);
1949    $href = $node2href{$_};
1950    if ($href) {
1951        $descr =~ s/^\s+//;
1952        $descr = ": $descr" if $descr;
1953        push(@menu_lines, "$oltype VALUE=$value>" . &anchor('', $href, "Main", $entry) . "$descr\n");
1954        push(@menu_lines, "<P>\n");
1955    } else {
1956        warn "$ERROR Undefined node ($node): $_";
1957    }
1958}
1959
1960sub menu_entry {
1961    local($entry, $node, $descr) = @_;
1962    local($href);
1963
1964    &normalise_node($node);
1965    $href = $node2href{$node};
1966    if ($href) {
1967        $descr =~ s/^\s+//;
1968        $descr = ": $descr" if $descr;
1969        push(@lines2, "<LI>" . &anchor('', $href, '', $entry) . "$descr\n");
1970    } else {
1971        warn "$ERROR Undefined node ($node): $_";
1972    }
1973}
1974
1975sub do_email {
1976    my($address,$text);
1977    ($address,$text) = split(/,/, "$_[0]");
1978    $text =~ s/(^\s+)|(\s+$)//; # trim leading and trailing white space
1979    $text = $address unless $text;
1980    &anchor('', "mailto:${address}", '', "<TT>${text}</TT>")
1981}
1982
1983sub do_image {
1984    my($base,$width,$height,$image);
1985    ($base,$width,$height) = split(/,/,"$_[0]");
1986    if ( -f "${base}.jpg" ) {
1987        $image = "${base}.jpg";
1988    } elsif ( -f "${base}.gif" ) {
1989        $image = "${base}.gif";
1990    } else {
1991        $image = $base;
1992        warn "$ERROR image not found for ($base): $_";
1993    }
1994    "<BR><IMG SRC=\"${image}\"><BR>";
1995}
1996
1997sub do_uref {
1998  my($href,$text);
1999  ($href,$text) = split(/,/,"$_[0]");
2000  $text =~ s/(^\s+)|(\s+$)//;   # trim leading and trailing white space
2001  $text = $href unless $text;
2002# args to anchor() are: ($name, $href, $text, $newline)
2003  &anchor('', "$href", '', "<TT>$text</TT>")
2004}
2005
2006sub do_url {
2007    my($address,$text);
2008    ($address,$text) = split(/,/, "$_[0]");
2009    $text =~ s/(^\s+)|(\s+$)//; # trim leading and trailing white space
2010    $text = $address unless $text;
2011    $address =~ s/&#173;//g;
2012    &anchor('', "${address}", '_parent', "<TT>${text}</TT>")
2013}
2014
2015sub do_ctrl { "^$_[0]" }
2016
2017sub do_sc { "\U$_[0]\E" }
2018
2019sub apply_style {
2020    local($texi_style, $text) = @_;
2021    local($style);
2022
2023    $style = $style_map{$texi_style};
2024    if (defined($style)) { # known style
2025        if ($style =~ /^\"/) { # add quotes
2026            $style = $';
2027            $text = "\`$text\'";
2028        }
2029        if ($style =~ /^\&/) { # custom
2030            $style = $';
2031            $text = &$style($text);
2032        } elsif ($style) { # good style
2033            $text = "<$style>$text</$style>";
2034        } else { # no style
2035        }
2036    } else { # unknown style
2037        $text = undef;
2038    }
2039    return($text);
2040}
2041
2042sub apply_l_style {
2043    local($texi_style, $text) = @_;
2044    local($style);
2045
2046    $style = $style_l_map{$texi_style};
2047    if (defined($style)) { # known style
2048        if ($style =~ /^\"/) { # add quotes
2049            $style = $';
2050            $text = "\`$text\'";
2051        }
2052        if ($style =~ /^\&/) { # custom
2053            $style = $';
2054            $text = &$style($text);
2055        } elsif ($style) { # good style
2056            $text = "<$style>$text</$style>";
2057        } else { # no style
2058        }
2059    } else { # unknown style
2060        $text = undef;
2061    }
2062    return($text);
2063}
2064
2065# remove Texinfo styles
2066sub remove_style {
2067    local($_) = @_;
2068    s/\@\w+{([^\{\}]+)}/$1/g;
2069    return($_);
2070}
2071
2072sub substitute_style {
2073    local($_) = @_;
2074    local($changed, $done, $style, $text);
2075
2076    $changed = 1;
2077    while ($changed) {
2078        $changed = 0;
2079        $done = '';
2080        while (/\@(\w+){([^\{\}]+)}/) {
2081            $text = &apply_style($1, $2);
2082            if ($text) {
2083                $_ = "$`$text$'";
2084                $changed = 1;
2085            } else {
2086                $done .= "$`\@$1";
2087                $_ = "{$2}$'";
2088            }
2089        }
2090        $_ = $done . $_;
2091    }
2092    return($_);
2093}
2094
2095sub anchor {
2096    local($name, $href, $target, $text, $newline) = @_;
2097    local($result);
2098
2099    $result = "<A";
2100    $result .= " NAME=\"$name\"" if $name;
2101    $result .= " HREF=\"$href\"" if $href;
2102    $result .= " TARGET=\"$target\"" if $target;
2103    $result .= ">$text</A>";
2104    $result .= "\n" if $newline;
2105    return($result);
2106}
2107
2108sub pretty_date {
2109    local(@MoY, $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);
2110
2111    @MoY = ('January', 'Febuary', 'March', 'April', 'May', 'June',
2112            'July', 'August', 'September', 'October', 'November', 'December');
2113    ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
2114    $year += ($year < 70) ? 2000 : 1900;
2115    return("$mday $MoY[$mon] $year");
2116}
2117
2118sub doc_name {
2119    local($num) = @_;
2120
2121    return("${docu_name}_$num.html");
2122}
2123
2124sub next_doc {
2125    $docu_doc = &doc_name(++$doc_num);
2126}
2127
2128sub print {
2129    local(*lines, $fh) = @_;
2130    local($_);
2131
2132    while (@lines) {
2133        $_ = shift(@lines);
2134        if (/^$PROTECTTAG/o) {
2135            $_ = $tag2pro{$_};
2136        } else {
2137            &unprotect_texi;
2138        }
2139        print $fh $_;
2140    }
2141}
2142
2143sub print_ruler {
2144    print FILE "<P><HR><P>\n";
2145}
2146
2147sub print_frame {
2148    print FILE <<EOT;
2149<FRAMESET COLS="20%,*" BORDER=0>
2150<FRAME SRC="$docu_left" NAME="Links">
2151<FRAME SRC="$_[0]" NAME="Main">
2152</FRAMESET>
2153
2154EOT
2155}
2156
2157sub print_header {
2158    local($_);
2159
2160    $links = $_[1];
2161    $is_frame = $_[2];
2162    # clean the title
2163    $_ = &remove_style($_[0]);
2164    &unprotect_texi;
2165    # print the header
2166    if ($doctype eq 'html2') {
2167        print FILE $html2_doctype; # Wrong if any multitable used
2168    } elsif ($doctype) {
2169        print FILE $doctype;
2170    }
2171    print FILE <<EOT;
2172<HTML>
2173<HEAD>
2174$header
2175<TITLE>$_</TITLE>
2176$links
2177</HEAD>
2178EOT
2179    if(!$is_frame) { print FILE "<BODY background=\"$IMG_RIGHT\">\n"; }
2180}
2181
2182sub print_toplevel_header {
2183    local($_);
2184
2185    &print_header ($_[0], "", 0);
2186    print FILE $full_title;
2187    if ($value{'_subtitle'}) {
2188        $value{'_subtitle'} =~ s/\n+$//;
2189        foreach (split(/\n/, $value{'_subtitle'})) {
2190            $_ = &substitute_style($_);
2191            &unprotect_texi;
2192            print FILE "<H2>$_</H2>\n";
2193        }
2194    }
2195    if ($value{'_author'}) {
2196        $value{'_author'} =~ s/\n+$//;
2197        foreach (split(/\n/, $value{'_author'})) {
2198            $_ = &substitute_style($_);
2199            &unprotect_texi;
2200#           s/[\w.-]+\@[\w.-]+/<A HREF="mailto:$&">$&<\/A>/g;
2201            print FILE "<ADDRESS>$_</ADDRESS>\n";
2202        }
2203    }
2204    print FILE "<P>\n";
2205}
2206
2207sub print_footer {
2208    print FILE <<EOT;
2209</BODY>
2210</HTML>
2211EOT
2212}
2213
2214sub print_toplevel_footer {
2215    &print_ruler;
2216    print FILE <<EOT;
2217<H6>This document was generated on $TODAY using the
2218<A HREF=\"$HOMEPAGE\" TARGET=\"_parent\">texi2html</A>
2219translator version 1.51a.</H6>
2220<H6>Modified by the Singular-Team 19.6.1998</H6>
2221EOT
2222    &print_footer;
2223}
2224
2225sub protect_texi {
2226    # protect @ { } ` '
2227    s/\@\@/$;0/go;
2228    s/\@\{/$;1/go;
2229    s/\@\}/$;2/go;
2230    s/\@\`/$;3/go;
2231    s/\@\'/$;4/go;
2232}
2233
2234sub protect_html {
2235    local($what) = @_;
2236    # protect & < >
2237    $what =~ s/\&/\&\#38;/g;
2238    $what =~ s/\</\&\#60;/g;
2239    $what =~ s/\>/\&\#62;/g;
2240    # but recognize some HTML things
2241    $what =~ s/\&\#60;\/A\&\#62;/<\/A>/g;             # </A>
2242    $what =~ s/\&\#60;A ([^\&]+)\&\#62;/<A $1>/g;     # <A [^&]+>
2243    $what =~ s/\&\#60;IMG ([^\&]+)\&\#62;/<IMG $1>/g; # <IMG [^&]+>
2244    return($what);
2245}
2246
2247sub unprotect_texi {
2248    s/$;0/\@/go;
2249    s/$;1/\{/go;
2250    s/$;2/\}/go;
2251    s/$;3/\`/go;
2252    s/$;4/\'/go;
2253}
2254
2255sub unprotect_html {
2256    local($what) = @_;
2257    $what =~ s/\&\#38;/\&/g;
2258    $what =~ s/\&\#60;/\</g;
2259    $what =~ s/\&\#62;/\>/g;
2260    return($what);
2261}
2262
2263sub byalpha {
2264    $key2alpha{$a} cmp $key2alpha{$b};
2265}
2266
2267##############################################################################
2268
2269        # These next few lines are legal in both Perl and nroff.
2270
2271.00 ;                   # finish .ig
2272 
2273'di                     \" finish diversion--previous line must be blank
2274.nr nl 0-1              \" fake up transition to first page again
2275.nr % 0                 \" start at page 1
2276'; __END__ ############# From here on it's a standard manual page ############
2277.TH TEXI2HTML 1 "08/12/97"
2278.AT 3
2279.SH NAME
2280texi2html \- a Texinfo to HTML converter
2281.SH SYNOPSIS
2282.B texi2html [OPTION]... FILE
2283.PP
2284.B texi2html -check [-verbose] FILE...
2285.SH DESCRIPTION
2286.I Texi2html
2287converts the given Texinfo file to a set of HTML files. It tries to handle
2288most of the Texinfo commands. It creates hypertext links for cross-references,
2289footnotes...
2290.PP
2291It also tries to add links from a reference to its corresponding entry in the
2292bibliography (if any). It may also handle a glossary (see the
2293.B \-glossary
2294option).
2295.PP
2296.I Texi2html
2297creates several files depending on the contents of the Texinfo file and on
2298the chosen options (see FILES).
2299.PP
2300The HTML files created by
2301.I texi2html
2302are closer to TeX than to Info, that's why
2303.I texi2html
2304converts @iftex sections and not @ifinfo ones by default. You can reverse
2305this with the \-expandinfo option.
2306.SH OPTIONS
2307.TP 12
2308.B \-check
2309Check the given file and give the list of all things that may be Texinfo commands.
2310This may be used to check the output of
2311.I texi2html
2312to find the Texinfo commands that have been left in the HTML file.
2313.TP
2314.B \-expandinfo
2315Expand @ifinfo sections, not @iftex ones.
2316.TP
2317.B \-glossary
2318Use the section named 'Glossary' to build a list of terms and put links in the HTML
2319document from each term toward its definition.
2320.TP
2321.B \-invisible \fIname\fP
2322Use \fIname\fP to create invisible destination anchors for index links. This is a workaround
2323for a known bug of many WWW browsers, including xmosaic.
2324.TP
2325.B \-I \fIdir\fP
2326Look also in \fIdir\fP to find included files.
2327.TP
2328.B \-menu
2329Show the Texinfo menus; by default they are ignored.
2330.TP
2331.B \-monolithic
2332Output only one file, including the table of contents and footnotes.
2333.TP
2334.B \-number
2335Number the sections.
2336.TP
2337.B \-split_chapter
2338Split the output into several HTML files (one per main section:
2339chapter, appendix...).
2340.TP
2341.B \-split_node
2342Split the output into several HTML files (one per node).
2343.TP
2344.B \-usage
2345Print usage instructions, listing the current available command-line options.
2346.TP
2347.B \-verbose
2348Give a verbose output. Can be used with the
2349.B \-check
2350option.
2351.PP
2352.SH FILES
2353By default
2354.I texi2html
2355creates the following files (foo being the name of the Texinfo file):
2356.TP 16
2357.B foo_toc.html
2358The table of contents.
2359.TP
2360.B foo.html
2361The document's contents.
2362.TP
2363.B foo_foot.html
2364The footnotes (if any).
2365.PP
2366When used with the
2367.B \-split
2368option, it creates several files (one per chapter or node), named
2369.B foo_n.html
2370(n being the indice of the chapter or node), instead of the single
2371.B foo.html
2372file.
2373.PP
2374When used with the
2375.B \-monolithic
2376option, it creates only one file:
2377.B foo.html
2378.SH VARIABLES
2379.I texi2html
2380predefines the following variables: \fBhtml\fP, \fBtexi2html\fP.
2381.SH ADDITIONAL COMMANDS
2382.I texi2html
2383implements the following non-Texinfo commands:
2384.TP 16
2385.B @ifhtml
2386This indicates the start of an HTML section, this section will passed through
2387without any modofication.
2388.TP
2389.B @end ifhtml
2390This indcates the end of an HTML section.
2391.SH VERSION
2392This is \fItexi2html\fP version 1.54, 1998-01-17
2393.PP
2394The latest version of \fItexi2html\fP can be found at
2395ftp://ftp.cs.umb.edu/pub/tex/texi2html
2396.SH AUTHOR
2397The main author is Lionel Cons, CERN CN/DCI/UWS.
2398This version is maintained at ftp://ftp.cs.umb.edu/pub/tex/texi2html
2399by kb@cs.umb.edu.
2400Many other people around the net contributed to this program.
2401.SH COPYRIGHT
2402This program is the intellectual property of the European
2403Laboratory for Particle Physics (known as CERN). No guarantee whatsoever is
2404provided by CERN. No liability whatsoever is accepted for any loss or damage
2405of any kind resulting from any defect or inaccuracy in this information or
2406code.
2407.PP
2408CERN, 1211 Geneva 23, Switzerland
2409.SH "SEE ALSO"
2410GNU Texinfo Documentation Format,
2411HyperText Markup Language (HTML),
2412World Wide Web (WWW).
2413.SH BUGS
2414This program does not understand all Texinfo commands (yet).
2415.PP
2416TeX specific commands (normally enclosed in @iftex) will be
2417passed u
Note: See TracBrowser for help on using the repository browser.