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