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