]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - readline/doc/texi2html
Initial creation of sourceware repository
[thirdparty/binutils-gdb.git] / readline / doc / texi2html
CommitLineData
d60d9f65
SS
1#!/usr/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;
303This is $THISPROG
304To 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
317To check converted files: $0 -check [-verbose] files
318EOT
319
320while ($#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}
345if ($check) {
346 die $usage unless @ARGV > 0;
347 &check;
348 exit;
349}
350
351if (($split_node || $split_chapter) && $monolithic) {
352 warn "Can't use -monolithic with -split, -monolithic ignored.\n";
353 $monolithic = 0;
354}
355if ($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';
363die $usage unless @ARGV == 1;
364$docu = shift(@ARGV);
365if ($docu =~ /.*\//) {
366 chop($docu_dir = $&);
367 $docu_name = $';
368} else {
369 $docu_dir = '.';
370 $docu_name = $docu;
371}
372unshift(@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
376if ($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
390foreach ('_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#
415if ($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
429if (-f $extensions) {
430 print "# reading extensions from $extensions\n" if $verbose;
431 require($extensions);
432}
433($progdir = $0) =~ s/[^\/]+$//;
434if ($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
442print "# 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 = '';
476foreach (keys(%simple_map)) {
477 ($re = $_) =~ s/(\W)/\\$1/g; # protect regexp chars
478 $subst_code .= "s/\\\@$re/$simple_map{$_}/g;\n";
479}
480foreach (keys(%things_map)) {
481 $subst_code .= "s/\\\@$_\\{\\}/$things_map{$_}/g;\n";
482}
483if ($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}
496eval("sub simple_substitutions { $subst_code }");
497
498&init_input;
499while ($_ = &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 }
930EOC
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;
1021while ($level < $curlevel) {
1022 $curlevel--;
1023 push(@toc_lines, "</UL>\n");
1024}
1025
1026print "# 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
1038while (@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}
1217print "# end of pass 2\n" if $verbose;
1218
1219#
1220# split style substitutions
1221#
1222while (@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}
1267print "# 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
1279while (@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}
1333print "# 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 -->
1344EOT
1345
1346$full_title = $value{'_title'} || $value{'_settitle'} || "Untitled Document";
1347$title = $value{'_settitle'} || $full_title;
1348$_ = &substitute_style($full_title);
1349&unprotect_texi;
1350s/\n$//; # rmv last \n (if any)
1351$full_title = "<H1>" . join("</H1>\n<H1>", split(/\n/, $_)) . "</H1>\n";
1352
1353#
1354# print ToC
1355#
1356if (!$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#
1372if (!$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#
1388if ($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
1460print "# that's all folks\n" if $verbose;
1461
1462#+++############################################################################
1463# #
1464# Low level functions #
1465# #
1466#---############################################################################
1467
1468sub 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
1491sub incr_sec_num {
1492 local($level, $l);
1493 $level = shift(@_);
1494 $_[$level]++;
1495 foreach $l ($level+1 .. 3) {
1496 $_[$l] = 0;
1497 }
1498}
1499
1500sub 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
1535sub 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
1546sub 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
1553sub 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
1571sub 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
1585sub html_reset {
1586 @html_stack = ('html');
1587 $html_element = 'body';
1588}
1589
1590sub html_push {
1591 local($what) = @_;
1592 push(@html_stack, $html_element);
1593 $html_element = $what;
1594}
1595
1596sub 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
1603sub html_pop {
1604 $html_element = pop(@html_stack);
1605}
1606
1607sub 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
1622sub 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...
1630sub debug {
1631 local($what, $line) = @_;
1632 return("<!-- $line -->$what")
1633 if $debug & $DEBUG_HTML;
1634 return($what);
1635}
1636
1637sub normalise_node {
1638 $_[0] =~ s/\s+/ /g;
1639 $_[0] =~ s/ $//;
1640 $_[0] =~ s/^ //;
1641}
1642
1643sub 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
1658sub do_ctrl { "^$_[0]" }
1659
1660sub do_sc { "\U$_[0]\E" }
1661
1662sub 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
1686sub remove_style {
1687 local($_) = @_;
1688 s/\@\w+{([^\{\}]+)}/$1/g;
1689 return($_);
1690}
1691
1692sub 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
1715sub 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
1727sub 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
1737sub doc_name {
1738 local($num) = @_;
1739
1740 return("${docu_name}_$num.html");
1741}
1742
1743sub next_doc {
1744 $docu_doc = &doc_name(++$doc_num);
1745}
1746
1747sub 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
1762sub print_ruler {
1763 print FILE "<P><HR><P>\n";
1764}
1765
1766sub 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>
1785EOT
1786}
1787
1788sub 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
1813sub print_footer {
1814 print FILE <<EOT;
1815</BODY>
1816</HTML>
1817EOT
1818}
1819
1820sub print_toplevel_footer {
1821 &print_ruler;
1822 print FILE <<EOT;
1823This document was generated on $TODAY using the
1824<A HREF=\"$HOMEPAGE\">texi2html</A>
1825translator version 1.51.</P>
1826EOT
1827 &print_footer;
1828}
1829
1830sub 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
1839sub 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
1852sub unprotect_texi {
1853 s/$;0/\@/go;
1854 s/$;1/\{/go;
1855 s/$;2/\}/go;
1856 s/$;3/\`/go;
1857 s/$;4/\'/go;
1858}
1859
1860sub 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
1868sub 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
1885texi2html \- 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
1892converts the given Texinfo file to a set of HTML files. It tries to handle
1893most of the Texinfo commands. It creates hypertext links for cross-references,
1894footnotes...
1895.PP
1896It also tries to add links from a reference to its corresponding entry in the
1897bibliography (if any). It may also handle a glossary (see the
1898.B \-glossary
1899option).
1900.PP
1901.I Texi2html
1902creates several files depending on the contents of the Texinfo file and on
1903the chosen options (see FILES).
1904.PP
1905The HTML files created by
1906.I texi2html
1907are closer to TeX than to Info, that's why
1908.I texi2html
1909converts @iftex sections and not @ifinfo ones by default. You can reverse
1910this with the \-expandinfo option.
1911.SH OPTIONS
1912.TP 12
1913.B \-check
1914Check the given file and give the list of all things that may be Texinfo commands.
1915This may be used to check the output of
1916.I texi2html
1917to find the Texinfo commands that have been left in the HTML file.
1918.TP
1919.B \-expandinfo
1920Expand @ifinfo sections, not @iftex ones.
1921.TP
1922.B \-glossary
1923Use the section named 'Glossary' to build a list of terms and put links in the HTML
1924document from each term toward its definition.
1925.TP
1926.B \-invisible \fIname\fP
1927Use \fIname\fP to create invisible destination anchors for index links. This is a workaround
1928for a known bug of many WWW browsers, including xmosaic.
1929.TP
1930.B \-I \fIdir\fP
1931Look also in \fIdir\fP to find included files.
1932.TP
1933.B \-menu
1934Show the Texinfo menus; by default they are ignored.
1935.TP
1936.B \-monolithic
1937Output only one file, including the table of contents and footnotes.
1938.TP
1939.B \-number
1940Number the sections.
1941.TP
1942.B \-split_chapter
1943Split the output into several HTML files (one per main section:
1944chapter, appendix...).
1945.TP
1946.B \-split_node
1947Split the output into several HTML files (one per node).
1948.TP
1949.B \-usage
1950Print usage instructions, listing the current available command-line options.
1951.TP
1952.B \-verbose
1953Give a verbose output. Can be used with the
1954.B \-check
1955option.
1956.PP
1957.SH FILES
1958By default
1959.I texi2html
1960creates the following files (foo being the name of the Texinfo file):
1961.TP 16
1962.B foo_toc.html
1963The table of contents.
1964.TP
1965.B foo.html
1966The document's contents.
1967.TP
1968.B foo_foot.html
1969The footnotes (if any).
1970.PP
1971When used with the
1972.B \-split
1973option, 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
1977file.
1978.PP
1979When used with the
1980.B \-monolithic
1981option, it creates only one file:
1982.B foo.html
1983.SH VARIABLES
1984.I texi2html
1985predefines the following variables: \fBhtml\fP, \fBtexi2html\fP.
1986.SH ADDITIONAL COMMANDS
1987.I texi2html
1988implements the following non-Texinfo commands:
1989.TP 16
1990.B @ifhtml
1991This indicates the start of an HTML section, this section will passed through
1992without any modofication.
1993.TP
1994.B @end ifhtml
1995This indcates the end of an HTML section.
1996.SH VERSION
1997This is \fItexi2html\fP version 1.51, 09/10/96.
1998.PP
1999The latest version of \fItexi2html\fP can be found in WWW, cf. URL
2000http://wwwcn.cern.ch/dci/texi2html/
2001.SH AUTHOR
2002The main author is Lionel Cons, CERN CN/DCI/UWS, Lionel.Cons@cern.ch.
2003Many other people around the net contributed to this program.
2004.SH COPYRIGHT
2005This program is the intellectual property of the European
2006Laboratory for Particle Physics (known as CERN). No guarantee whatsoever is
2007provided by CERN. No liability whatsoever is accepted for any loss or damage
2008of any kind resulting from any defect or inaccuracy in this information or
2009code.
2010.PP
2011CERN, 1211 Geneva 23, Switzerland
2012.SH "SEE ALSO"
2013GNU Texinfo Documentation Format,
2014HyperText Markup Language (HTML),
2015World Wide Web (WWW).
2016.SH BUGS
2017This program does not understand all Texinfo commands (yet).
2018.PP
2019TeX specific commands (normally enclosed in @iftex) will be
2020passed unmodified.
2021.ex