source: git/doc/texi2html @ 4c79e7

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