Fix and extend the definition of mapatom
[maxima.git] / archive / info / texi2html
blob6255fd8594fbbce3b857cbfe21673bb8b2ea9fd1
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 #-##############################################################################
12 $THISPROG = "texi2html 1.52"; # program name and version
13 # This version of texi2html is currently maintained at
14 # ftp://ftp.cs.umb.edu/pub/tex/texi2html by kb@cs.umb.edu.
16 # w schelter: made minor changes to allow the @anchor construct. so
17 # you can do "See @ref{FACTOR} and @ref{GFACTOR}." if you put in
18 # @anchor{FACTOR} just before the definition of FACTOR.. the new
19 # texi2html by olaf does @anchor, but it uses tables so heavily that
20 # netmath cannot view its output properly. Also I like the way the
21 # index is done here as one file, and several other features.
23 # The man page for this program is included at the end of this file and can be
24 # viewed using the command 'nroff -man texi2html'.
25 # Please read the copyright at the end of the man page.
27 # Fixme:
28 # deal with @macro @unmacro @shorttitlepage @detailmenu @image
29 # [plus more fixmes below]
30 # Use <link>s for Up, Index, Glossary?
31 # Inserting copyright links: Having texinfo markup for the online copyright
32 # would allow a link to that from wherever.
34 #+++############################################################################
35 # #
36 # Constants #
37 # #
38 #---############################################################################
40 $DEBUG_TOC = 1;
41 $DEBUG_INDEX = 2;
42 $DEBUG_BIB = 4;
43 $DEBUG_GLOSS = 8;
44 $DEBUG_DEF = 16;
45 $DEBUG_HTML = 32;
46 $DEBUG_USER = 64;
48 $BIBRE = '\[[\w\/]+\]'; # RE for a bibliography reference
49 $FILERE = '[\/\w.+-]+'; # RE for a file name
50 $VARRE = '[^\s\{\}]+'; # RE for a variable name
51 $NODERE = '[^@{}:\'`",]+'; # RE for a node name
52 $NODESRE = '[^@{}:\'`"]+'; # RE for a list of node names
53 $XREFRE = '[^@{}]+'; # RE for a xref (should use NODERE)
55 $ERROR = "***"; # prefix for errors and warnings
56 $HOMEPAGE = "http://wwwcn.cern.ch/dci/texi2html/"; # program home page
57 $TODAY = &pretty_date; # like "20 September 1993"
58 $SPLITTAG = "<!-- SPLIT HERE -->\n"; # tag to know where to split
59 $PROTECTTAG = "_ThisIsProtected_"; # tag to recognize protected sections
60 $TOPTAG = "<!--top-->"; # tag to mark first node (end of preamble)
61 $html2_doctype = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0 Strict Level 2//EN">';
64 # language dependent constants
66 #$LDC_SEE = 'see';
67 #$LDC_SECTION = 'section';
68 #$LDC_IN = 'in';
69 #$LDC_TOC = 'Table of Contents';
70 #$LDC_GOTO = 'Go to the';
71 #$LDC_FOOT = 'Footnotes';
72 # TODO: @def* shortcuts
75 # pre-defined indices
77 %predefined_index = (
78 'cp', 'c',
79 'fn', 'f',
80 'vr', 'v',
81 'ky', 'k',
82 'pg', 'p',
83 'tp', 't',
87 # valid indices
89 %valid_index = (
90 'c', 1,
91 'f', 1,
92 'v', 1,
93 'k', 1,
94 'p', 1,
95 't', 1,
99 # texinfo section names to level
101 %sec2level = (
102 'top', 0,
103 'chapter', 1,
104 'unnumbered', 1,
105 'majorheading', 1,
106 'chapheading', 1,
107 'appendix', 1,
108 'section', 2,
109 'unnumberedsec', 2,
110 'heading', 2,
111 'appendixsec', 2,
112 'appendixsection', 2,
113 'subsection', 3,
114 'unnumberedsubsec', 3,
115 'subheading', 3,
116 'appendixsubsec', 3,
117 'subsubsection', 4,
118 'unnumberedsubsubsec', 4,
119 'subsubheading', 4,
120 'appendixsubsubsec', 4,
124 # accent map, TeX command to ISO name
126 %accent_map = (
127 '"', 'uml',
128 '~', 'tilde',
129 '^', 'circ',
130 '`', 'grave',
131 '\'', 'acute',
132 ',', 'cedil',
133 # fixme: (not Latin1) = H d dotaccent dotless ringaccent
134 # tieaccent u ubaraccent v
138 # texinfo "simple things" (@foo) to HTML ones
140 %simple_map = (
141 # cf. makeinfo.c
142 "*", "<BR>", # HTML+
143 " ", "&#160;", # nbsp
144 "\n", "\n",
145 "|", "",
146 # spacing commands
147 ":", "",
148 "!", "!",
149 "?", "?",
150 ".", ".",
151 "\t", " ",
152 "-", "&#173;", # soft hyphen
153 'tab', '<TD>',
157 # texinfo "things" (@foo{}) to HTML ones
159 %things_map = (
160 'TeX', 'TeX',
161 'br', '<P>', # paragraph break. Gone from texinfo 3.9
162 'bullet', '*',
163 'copyright', '&#169;',
164 'dots', '...',
165 'enddots', '....',
166 'equiv', '==',
167 'error', 'error-->',
168 'expansion', '==>',
169 'minus', '-',
170 'point', '-!-',
171 'print', '-|',
172 'result', '=>',
173 'today', $TODAY,
174 # fixme: output these Latin1 characters as such rather
175 # than as entities?
176 'pounds', '&#163;',
177 'questiondown', '&#191;',
178 'ss', '&#223;',
179 'exclamdown', '&#161;',
180 'AA', '&#197;',
181 'AE', '&#198;',
182 'aa', '&#229;',
183 'ae', '&#230;',
184 'O', '&#216;',
185 'o', '&#248;',
186 # follow info rendering:
187 'L', 'L\/',
188 'l', 'l\/',
189 'OE', 'OE',
190 'oe', 'oe',
194 # texinfo styles (@foo{bar}) to HTML ones
196 %style_map = (
197 'asis', '', # ??
198 'b', 'B',
199 'cite', 'CITE',
200 'code', 'CODE',
201 'ctrl', '&do_ctrl', # special case (obsolete)
202 'dfn', 'STRONG', # DFN tag is illegal in the standard
203 'dmn', '', # useless
204 'emph', 'EM',
205 'email', '&do_email', # new special case
206 'file', '"TT', # will put quotes, cf. &apply_style
207 'i', 'I',
208 'kbd', 'KBD',
209 'key', 'KBD', # fixme: probably not <KBD>; possibly
210 # enclose in angles like makeinfo now does
211 'r', '', # unsupported
212 'samp', '"SAMP', # will put quotes, cf. &apply_style
213 'sc', '&do_sc', # special case
214 'strong', 'STRONG',
215 't', 'TT',
216 'titlefont', 'B', # make it distinctive, at least
217 'uref', '&do_url', # new special case
218 'url', 'CODE', # new special case
219 'var', 'VAR',
220 'w', '', # unsupported
221 # 'math', 'I', # not very useful, but at least italicize
222 'math', '', # don't want italic numbers
226 # texinfo format (@foo/@end foo) to HTML ones
228 %format_map = (
229 'display', 'PRE',
230 'example', 'PRE',
231 'format', 'PRE', # fixme: shouldn't use tt, but can't avoid?
232 'lisp', 'PRE',
233 'quotation', 'BLOCKQUOTE',
234 'smallexample', 'PRE',
235 'smalllisp', 'PRE',
236 # lists
237 'itemize', 'UL',
238 'enumerate', 'OL',
239 # poorly supported
240 'flushleft', 'PRE',
241 'flushright', 'PRE',
245 # texinfo definition shortcuts to real ones
247 %def_map = (
248 # basic commands
249 'deffn', 0,
250 'defvr', 0,
251 'deftypefn', 0,
252 'deftypevr', 0,
253 'defcv', 0,
254 'defop', 0,
255 'deftp', 0,
256 # basic x commands
257 'deffnx', 0,
258 'defvrx', 0,
259 'deftypefnx', 0,
260 'deftypevrx', 0,
261 'defcvx', 0,
262 'defopx', 0,
263 'deftpx', 0,
264 # shortcuts
265 'defun', 'deffn Function',
266 'defmac', 'deffn Macro',
267 'defspec', 'deffn {Special Form}',
268 'defvar', 'defvr Variable',
269 'defopt', 'defvr {User Option}',
270 'deftypefun', 'deftypefn Function',
271 'deftypevar', 'deftypevr Variable',
272 'defivar', 'defcv {Instance Variable}',
273 'defmethod', 'defop Method',
274 # x shortcuts
275 'defunx', 'deffnx Function',
276 'defmacx', 'deffnx Macro',
277 'defspecx', 'deffnx {Special Form}',
278 'defvarx', 'defvrx Variable',
279 'defoptx', 'defvrx {User Option}',
280 'deftypefunx', 'deftypefnx Function',
281 'deftypevarx', 'deftypevrx Variable',
282 'defivarx', 'defcvx {Instance Variable}',
283 'defmethodx', 'defopx Method',
287 # things to skip
289 %to_skip = (
290 # comments
291 'c', 1,
292 'comment', 1,
293 # useless
294 'contents', 1,
295 'shortcontents', 1,
296 'summarycontents', 1,
297 'footnotestyle', 1,
298 'end ifclear', 1,
299 'end ifset', 1,
300 'titlepage', 1,
301 'end titlepage', 1,
302 'dircategory', 1,
303 # unsupported commands (formatting)
304 'afourpaper', 1,
305 'cropmarks', 1,
306 'finalout', 1,
307 'headings', 1,
308 'need', 1,
309 'page', 1,
310 'setchapternewpage', 1,
311 'everyheading', 1,
312 'everyfooting', 1,
313 'evenheading', 1,
314 'evenfooting', 1,
315 'oddheading', 1,
316 'oddfooting', 1,
317 'smallbook', 1,
318 'vskip', 1,
319 'filbreak', 1,
320 'centerchap', 1,
321 'setchapterstyle', 1,
322 'hyphenation', 1,
323 # unsupported formats
324 'cartouche', 1,
325 'end cartouche', 1,
326 'group', 1,
327 'end group', 1,
330 #+++############################################################################
332 # Argument parsing, initialisation #
334 #---############################################################################
336 $use_bibliography = 1;
337 $use_acc = 0;
338 $debug = 0;
339 $doctype = '';
340 $check = 0;
341 $expandinfo = 0;
342 $use_glossary = 0;
343 $invisible_mark = '';
344 $use_iso = 0;
345 @include_dirs = ();
346 $show_menu = 0;
347 $number_sections = 0;
348 $split_node = 0;
349 $split_chapter = 0;
350 $monolithic = 0;
351 $verbose = 0;
352 $usage = <<EOT;
353 This is $THISPROG
354 To convert a Texinfo file to HMTL: $0 [options] file
355 where options can be:
356 -expandinfo : use \@ifinfo sections, not \@iftex
357 -glossary : handle a glossary
358 -invisible name: use 'name' as an invisible anchor
359 -I dir : search also for files in 'dir'
360 -menu : handle menus and don\'t do the ToC
361 -monolithic : output only one file including ToC
362 -number : number sections
363 -split_chapter : split on main sections
364 -split_node : split on nodes
365 -check : check given file for possible Texinfo commands
366 -usage : print usage instructions
367 -verbose : verbose output
368 To check converted files: $0 -check [-verbose] files
371 while ($#ARGV >= 0 && $ARGV[0] =~ /^-/) {
372 $_ = shift(@ARGV);
373 if (/^-acc$/) { $use_acc = 1; next; }
374 if (/^-d(ebug)?(\d+)?$/) { $debug = $2 || shift(@ARGV); next; }
375 if (/^-doctype$/) { $doctype = shift(@ARGV); next; }
376 if (/^-c(heck)?$/) { $check = 1; next; }
377 if (/^-e(xpandinfo)?$/) { $expandinfo = 1; next; }
378 if (/^-g(lossary)?$/) { $use_glossary = 1; next; }
379 if (/^-i(nvisible)?$/) { $invisible_mark = shift(@ARGV); next; }
380 if (/^-iso$/) { $use_iso = 1; next; }
381 if (/^-I(.+)?$/) { push(@include_dirs, $1 || shift(@ARGV)); next; }
382 if (/^-m(enu)?$/) { $show_menu = 1; next; }
383 if (/^-mono(lithic)?$/) { $monolithic = 1; next; }
384 if (/^-n(umber)?$/) { $number_sections = 1; next; }
385 if (/^-s(plit)?_?(n(ode)?|c(hapter)?)?$/) {
386 if ($2 =~ /^n/) {
387 $split_node = 1;
388 } else {
389 $split_chapter = 1;
391 next;
393 if (/^-v(erbose)?$/) { $verbose = 1; next; }
394 die $usage;
396 if ($check) {
397 die $usage unless @ARGV > 0;
398 &check;
399 exit;
402 if (($split_node || $split_chapter) && $monolithic) {
403 warn "Can't use -monolithic with -split, -monolithic ignored.\n";
404 $monolithic = 0;
406 if ($expandinfo) {
407 $to_skip{'ifinfo'}++;
408 $to_skip{'end ifinfo'}++;
409 } else {
410 $to_skip{'iftex'}++;
411 $to_skip{'end iftex'}++;
413 $invisible_mark = '<IMG SRC="invisible.xbm" ALT="">' if $invisible_mark eq 'xbm';
414 die $usage unless @ARGV == 1;
415 $docu = shift(@ARGV);
416 if ($docu =~ /.*\//) {
417 chop($docu_dir = $&);
418 $docu_name = $';
419 } else {
420 $docu_dir = '.';
421 $docu_name = $docu;
423 unshift(@include_dirs, $docu_dir);
424 $docu_name =~ s/\.te?x(i|info)?$//; # basename of the document
426 $docu_doc = "$docu_name.html"; # document's contents
427 if ($monolithic) {
428 $docu_toc = $docu_foot = $docu_doc;
429 } else {
430 $docu_toc = "${docu_name}_toc.html"; # document's table of contents
431 $docu_foot = "${docu_name}_foot.html"; # document's footnotes
435 # variables
437 %value = (); # hold texinfo variables
438 $value{'html'} = 1; # predefine html (the output format)
439 $value{'texi2html'} = '1.51a'; # predefine texi2html (the translator)
440 # _foo: internal to track @foo
441 foreach ('_author', '_title', '_subtitle',
442 '_settitle', '_setfilename') {
443 $value{$_} = ''; # prevent -w warnings
445 %node2sec = (); # node to section name
446 %node2href = (); # node to HREF
447 %anchor2href = (); # anchor to HREF
448 %bib2href = (); # bibliography reference to HREF
449 %gloss2href = (); # glossary term to HREF
450 @sections = (); # list of sections
451 %tag2pro = (); # protected sections
454 # initial indexes
456 $bib_num = 0;
457 $foot_num = 0;
458 $gloss_num = 0;
459 $idx_num = 0;
460 $sec_num = 0;
461 $doc_num = 0;
462 $html_num = 0;
465 # can I use ISO8879 characters? (HTML+)
467 if ($use_iso) {
468 $things_map{'bullet'} = "&bull;";
469 $things_map{'copyright'} = "&copy;";
470 $things_map{'dots'} = "&hellip;";
471 $things_map{'equiv'} = "&equiv;";
472 $things_map{'expansion'} = "&rarr;";
473 $things_map{'point'} = "&lowast;";
474 $things_map{'result'} = "&rArr;";
478 # read texi2html extensions (if any)
480 $extensions = 'texi2html.ext'; # extensions in working directory
481 if (-f $extensions) {
482 print "# reading extensions from $extensions\n" if $verbose;
483 require($extensions);
485 ($progdir = $0) =~ s/[^\/]+$//;
486 if ($progdir && ($progdir ne './')) {
487 $extensions = "${progdir}texi2html.ext"; # extensions in texi2html directory
488 if (-f $extensions) {
489 print "# reading extensions from $extensions\n" if $verbose;
490 require($extensions);
494 print "# reading from $docu\n" if $verbose;
496 #+++############################################################################
498 # Pass 1: read source, handle command, variable, simple substitution #
500 #---############################################################################
502 @lines = (); # whole document
503 @toc_lines = (); # table of contents
504 @top_lines = (); # contents of top node
505 $toplevel = 0; # top level seen in hierarchy
506 $curlevel = 0; # current level in TOC
507 $node = ''; # current node name
508 $in_table = 0; # am I inside a table
509 $table_type = ''; # type of table ('', 'f', 'v')
510 @tables = (); # nested table support
511 $in_bibliography = 0; # am I inside a bibliography
512 $in_glossary = 0; # am I inside a glossary
513 $in_top = 0; # am I inside the top node
514 $in_pre = 0; # am I inside a preformatted section
515 $in_list = 0; # am I inside a list
516 $in_html = 0; # am I inside an HTML section (@ifhtml)
517 $in_raw_html = 0; # am I inside an HTML section (@html)
518 $in_preamble = 1; # am I before the top node
519 $first_line = 1; # is it the first line
520 $dont_html = 0; # don't protect HTML on this line
521 $split_num = 0; # split index
522 $deferred_ref = ''; # deferred reference for indexes
523 @html_stack = (); # HTML elements stack
524 $html_element = ''; # current HTML element
525 &html_reset;
527 # build code for simple substitutions
528 # the maps used (%simple_map and %things_map) MUST be aware of this
529 # watch out for regexps, / and escaped characters!
530 $subst_code = '';
531 foreach (keys(%simple_map)) {
532 ($re = $_) =~ s/(\W)/\\$1/g; # protect regexp chars
533 $subst_code .= "s/\\\@$re/$simple_map{$_}/g;\n";
535 foreach (keys(%things_map)) {
536 $subst_code .= "s/\\\@$_\\{\\}/$things_map{$_}/g;\n";
538 if ($use_acc) {
539 # accentuated characters
540 foreach (keys(%accent_map)) {
541 if ($_ eq "`") {
542 $subst_code .= "s/$;3";
543 } elsif ($_ eq "'") {
544 $subst_code .= "s/$;4";
545 } else {
546 $subst_code .= "s/\\\@\\$_";
548 $subst_code .= "([aeiou])/&\${1}$accent_map{$_};/gi;\n";
551 eval("sub simple_substitutions { $subst_code }");
553 &init_input;
554 while ($_ = &next_line) {
556 # remove \input on the first lines only
558 if ($first_line) {
559 next if /^\\input/;
560 $first_line = 0;
563 # parse texinfo tags
565 $tag = '';
566 $end_tag = '';
567 if (/^\@end\s+(\w+)\b/) {
568 $end_tag = $1;
569 } elsif (/^\@(\w+)\b/) {
570 $tag = $1;
573 # handle @ifhtml / @end ifhtml
575 if ($in_html) {
576 if ($end_tag eq 'ifhtml') {
577 $in_html = 0;
578 } else {
579 $tag2pro{$in_html} .= $_;
581 next;
582 } elsif ($tag eq 'ifhtml') {
583 $in_html = $PROTECTTAG . ++$html_num;
584 push(@lines, $in_html);
585 next;
588 # do raw HTML (no escapes)
590 if ($in_raw_html) {
591 if ($end_tag eq 'html') {
592 $in_raw_html = 0;
593 } else {
594 push (@lines, $_);
596 next;
597 } elsif ($tag eq 'html') {
598 $in_raw_html = 1;
601 # try to skip the line
603 if ($end_tag) {
604 next if $to_skip{"end $end_tag"};
605 } elsif ($tag) {
606 next if $to_skip{$tag};
607 last if $tag eq 'bye';
610 # try to remove inlined comments
611 # syntax from tex-mode.el comment-start-skip
613 s/((^|[^\@])(\@\@)*)\@c(omment)? .*/$1/;
614 # non-@ substitutions cf. texinfmt.el
615 s/``/\"/g;
616 s/''/\"/g;
617 s/([\w ])---([\w ])/$1--$2/g;
619 # analyze the tag
621 if ($tag) {
622 # skip lines
623 &skip_until($tag), next if $tag eq 'ignore';
624 if ($expandinfo) {
625 &skip_until($tag), next if $tag eq 'iftex';
626 } else {
627 &skip_until($tag), next if $tag eq 'ifinfo' &&
628 ! $in_preamble; # we want the contents of the top node
630 &skip_until($tag), next if $tag eq 'tex';
631 # handle special tables
632 if ($tag eq 'table') {
633 $table_type = '';
634 } elsif ($tag eq 'ftable') {
635 $tag = 'table';
636 $table_type = 'f';
637 } elsif ($tag eq 'vtable') {
638 $tag = 'table';
639 $table_type = 'v';
640 } elsif ($tag eq 'multitable') {
641 $tag = 'table';
642 $table_type = '';
644 # special cases
645 if ($tag eq 'top' || ($tag eq 'node' && /^\@node\s+Top\s*,/i)) {
646 # We want to stash the contents of the top node (including
647 # @ifinfo bits).
648 $in_top = 1;
649 $in_preamble = 0;
650 @lines = (); # ignore all lines before top (title page garbage)
651 next;
652 } elsif ($tag eq 'node') {
653 push (@lines, "$TOPTAG") if ($in_top); # Mark end of top node
654 $in_top = 0;
655 $in_preamble = 0;
656 warn "$ERROR Bad node line: $_" unless $_ =~ /^\@node\s$NODESRE$/o;
657 $_ = &protect_html($_); # if node contains '&' for instance
658 s/^\@node\s+//;
659 ($node) = split(/,/);
660 &normalise_node($node);
661 if ($split_node) {
662 &next_doc;
663 push(@lines, $SPLITTAG) if $split_num++;
664 push(@sections, $node);
666 next;
667 } elsif ($tag eq 'include') {
668 if (/^\@include\s+($FILERE)\s*$/o) {
669 $file = $1;
670 unless (-e $file) {
671 foreach $dir (@include_dirs) {
672 $file = "$dir/$1";
673 last if -e $file;
676 if (-e $file) {
677 &open($file);
678 print "# including $file\n" if $verbose;
679 } else {
680 warn "$ERROR Can't find $file, skipping";
682 } else {
683 warn "$ERROR Bad include line: $_";
685 next;
686 } elsif ($tag eq 'ifclear') {
687 if (/^\@ifclear\s+($VARRE)\s*$/o) {
688 next unless defined($value{$1});
689 &skip_until($tag);
690 } else {
691 warn "$ERROR Bad ifclear line: $_";
693 next;
694 } elsif ($tag eq 'ifset') {
695 if (/^\@ifset\s+($VARRE)\s*$/o) {
696 next if defined($value{$1});
697 &skip_until($tag);
698 } else {
699 warn "$ERROR Bad ifset line: $_";
701 next;
702 } elsif ($tag eq 'menu') {
703 unless ($show_menu) {
704 &skip_until($tag);
705 next;
707 &html_push_if($tag);
708 push(@lines, &html_debug("\n", __LINE__));
709 } elsif ($format_map{$tag}) {
710 $in_pre = 1 if $format_map{$tag} eq 'PRE';
711 &html_push_if($format_map{$tag});
712 push(@lines, &html_debug("\n", __LINE__));
713 $in_list++ if $format_map{$tag} eq 'UL' || $format_map{$tag} eq 'OL' ;
714 push(@lines, &debug("<$format_map{$tag}>\n", __LINE__));
715 next;
716 } elsif ($tag eq 'table') {
717 if (/^\@[fv]?table\s+\@(\w+)\s*$/) {
718 $in_table = $1;
719 unshift(@tables, join($;, $table_type, $in_table));
720 push(@lines, &debug("<DL COMPACT>\n", __LINE__));
721 &html_push_if('DL');
722 push(@lines, &html_debug("\n", __LINE__));
723 } elsif (/^\@multitable\s+/) {
724 # Note descent to HTML 3.2 necessary for multitable.
725 $in_table = ' ';
726 unshift(@tables, join($;, $table_type, $in_table));
727 push(@lines, &debug("<TABLE>\n", __LINE__));
728 &html_push_if('TABLE');
729 push(@lines, &html_debug("\n", __LINE__));
730 } else {
731 warn "$ERROR Bad table line: $_";
733 next;
734 } elsif ($tag eq 'synindex' || $tag eq 'syncodeindex') {
735 if (/^\@$tag\s+(\w)\w\s+(\w)\w\s*$/) {
736 eval("*${1}index = *${2}index");
737 } else {
738 warn "$ERROR Bad syn*index line: $_";
740 next;
741 } elsif ($tag eq 'sp') {
742 push(@lines, &debug("<P>\n", __LINE__));
743 next;
744 } elsif ($tag eq 'anchor') {
745 if (/^\@$tag\s*{($NODERE)}\s*$/) {
746 $anchor = $1;
747 push(@lines,&debug("<a name=\"$anchor\"></a>", __LINE__));
749 # warn "$anchor,hello,bib2href=$bib2href{$anchor},$gloss2href{$anchor},";
750 $anchor2href{$anchor} = "$docu_doc#$anchor";
752 next ;
753 } elsif ($tag eq 'setref') {
754 &protect_html; # if setref contains '&' for instance
755 if (/^\@$tag\s*{($NODERE)}\s*$/) {
756 $setref = $1;
757 $setref =~ s/\s+/ /g; # normalize
758 $setref =~ s/ $//;
759 $node2sec{$setref} = $name;
760 $node2href{$setref} = "$docu_doc#$docid";
761 } else {
762 warn "$ERROR Bad setref line: $_";
764 next;
765 } elsif ($tag eq 'defindex' || $tag eq 'defcodeindex') {
766 if (/^\@$tag\s+(\w\w)\s*$/) {
767 $valid_index{$1} = 1;
768 } else {
769 warn "$ERROR Bad defindex line: $_";
771 next;
772 } elsif ($tag eq 'direntry') {
773 &skip_until ($tag);
774 next;
775 } elsif (defined($def_map{$tag})) {
776 if ($def_map{$tag}) {
777 s/^\@$tag\s+//;
778 $tag = $def_map{$tag};
779 $_ = "\@$tag $_";
780 $tag =~ s/\s.*//;
782 } elsif (defined($user_sub{$tag})) {
783 s/^\@$tag\s+//;
784 $sub = $user_sub{$tag};
785 print "# user $tag = $sub, arg: $_" if $debug & $DEBUG_USER;
786 if (defined(&$sub)) {
787 chop($_);
788 &$sub($_);
789 } else {
790 warn "$ERROR Bad user sub for $tag: $sub\n";
792 next;
794 if (defined($def_map{$tag})) {
795 s/^\@$tag\s+//;
796 if ($tag =~ /x$/) {
797 # extra definition line
798 $tag = $`;
799 $is_extra = 1;
800 } else {
801 $is_extra = 0;
803 while (/\{([^\{\}]*)\}/) {
804 # this is a {} construct
805 ($before, $contents, $after) = ($`, $1, $');
806 # protect spaces
807 $contents =~ s/\s+/$;9/g;
808 # restore $_ protecting {}
809 $_ = "$before$;7$contents$;8$after";
811 @args = split(/\s+/, &protect_html($_));
812 foreach (@args) {
813 s/$;9/ /g; # unprotect spaces
814 s/$;7/\{/g; # ... {
815 s/$;8/\}/g; # ... }
817 $type = shift(@args);
818 $type =~ s/^\{(.*)\}$/$1/;
819 print "# def ($tag): {$type} ", join(', ', @args), "\n"
820 if $debug & $DEBUG_DEF;
821 $type .= ':'; # it's nicer like this
822 $name = shift(@args);
823 $name =~ s/^\{(.*)\}$/$1/;
824 if ($is_extra) {
825 $_ = &debug("<DT>", __LINE__);
826 } else {
827 $_ = &debug("<DL>\n<DT>", __LINE__);
829 if ($tag eq 'deffn' || $tag eq 'defvr' || $tag eq 'deftp') {
830 $_ .= "<U>$type</U> <B>$name</B>";
831 $_ .= " <I>@args</I>" if @args;
832 } elsif ($tag eq 'deftypefn' || $tag eq 'deftypevr'
833 || $tag eq 'defcv' || $tag eq 'defop') {
834 $ftype = $name;
835 $name = shift(@args);
836 $name =~ s/^\{(.*)\}$/$1/;
837 $_ .= "<U>$type</U> $ftype <B>$name</B>";
838 $_ .= " <I>@args</I>" if @args;
839 } else {
840 warn "$ERROR Unknown definition type: $tag\n";
841 $_ .= "<U>$type</U> <B>$name</B>";
842 $_ .= " <I>@args</I>" if @args;
844 $_ .= &debug("\n<DD>", __LINE__);
845 $name = &unprotect_html($name);
846 if ($tag eq 'deffn' || $tag eq 'deftypefn') {
847 unshift(@input_spool, "\@findex $name\n");
848 } elsif ($tag eq 'defop') {
849 unshift(@input_spool, "\@findex $name on $ftype\n");
850 } elsif ($tag eq 'defvr' || $tag eq 'deftypevr' || $tag eq 'defcv') {
851 unshift(@input_spool, "\@vindex $name\n");
852 } else {
853 unshift(@input_spool, "\@tindex $name\n");
855 $dont_html = 1;
857 } elsif ($end_tag) {
858 if ($format_map{$end_tag}) {
859 $in_pre = 0 if $format_map{$end_tag} eq 'PRE';
860 $in_list-- if $format_map{$end_tag} eq 'UL' || $format_map{$end_tag} eq 'OL' ;
861 &html_pop_if('LI', 'P');
862 &html_pop_if();
863 push(@lines, &debug("</$format_map{$end_tag}>\n", __LINE__));
864 push(@lines, &html_debug("\n", __LINE__));
865 } elsif ($end_tag eq 'table' ||
866 $end_tag eq 'ftable' ||
867 $end_tag eq 'vtable' ||
868 $end_tag eq 'multitable') {
869 shift(@tables);
870 if (@tables) {
871 ($table_type, $in_table) = split($;, $tables[0]);
872 } else {
873 $in_table = 0;
875 if ($end_tag eq 'multitable') {
876 push(@lines, "</TABLE>\n");
877 &html_pop_if('TABLE');
878 } else {
879 push(@lines, "</DL>\n");
880 &html_pop_if('DD');
882 &html_pop_if();
883 } elsif (defined($def_map{$end_tag})) {
884 push(@lines, &debug("</DL>\n", __LINE__));
885 } elsif ($end_tag eq 'menu') {
886 &html_pop_if();
887 push(@lines, $_); # must keep it for pass 2
889 next;
892 # misc things
894 # protect texi and HTML things
895 &protect_texi;
896 $_ = &protect_html($_) unless $dont_html;
897 $dont_html = 0;
898 # substitution (unsupported things)
899 s/^\@center\s+//g; # fixme: use <center> or <div align=center>?
900 s/^\@exdent\s+//g;
901 s/\@noindent\s+//g;
902 s/\@refill\s+//g;
903 # other substitutions
904 &simple_substitutions;
905 s/\@value{($VARRE)}/$value{$1}/eg;
906 s/\@footnote\{/\@footnote$docu_doc\{/g; # mark footnotes, cf. pass 4
907 s/\@image\{([^,\}]+)[^\}]*\}/\<img src="$1"\>/g;
909 # analyze the tag again
911 if ($tag) {
912 if (defined($sec2level{$tag}) && $sec2level{$tag} > 0) {
913 if (/^\@$tag\s+(.+)$/) {
914 $name = $1;
915 $name =~ s/\s+$//;
916 $level = $sec2level{$tag};
917 $name = &update_sec_num($tag, $level) . " $name"
918 if $number_sections && $tag !~ /^unnumbered/;
919 if ($tag =~ /heading$/) {
920 push(@lines, &html_debug("\n", __LINE__));
921 if ($html_element ne 'body') {
922 # We are in a nice pickle here. We are trying to get a H? heading
923 # even though we are not in the body level. So, we convert it to a
924 # nice, bold, line by itself.
925 $_ = &debug("\n\n<P><STRONG>$name</STRONG></P>\n\n", __LINE__);
926 } else {
927 $_ = &debug("<H$level>$name</H$level>\n", __LINE__);
928 &html_push_if('body');
930 print "# heading, section $name, level $level\n"
931 if $debug & $DEBUG_TOC;
932 } else {
933 if ($split_chapter) {
934 unless ($toplevel) {
935 # first time we see a "section"
936 unless ($level == 1) {
937 warn "$ERROR The first section found is not of level 1: $_";
938 warn "$ERROR I'll split on sections of level $level...\n";
940 $toplevel = $level;
942 if ($level == $toplevel) {
943 &next_doc;
944 push(@lines, $SPLITTAG) if $split_num++;
945 push(@sections, $name);
948 $sec_num++;
949 $docid = "SEC$sec_num";
950 $tocid = "TOC$sec_num";
951 # check biblio and glossary
952 $in_bibliography = ($name =~ /^([A-Z]|\d+)?(\.\d+)*\s*bibliography$/i);
953 $in_glossary = ($name =~ /^([A-Z]|\d+)?(\.\d+)*\s*glossary$/i);
954 # check node
955 if ($node) {
956 if ($node2sec{$node}) {
957 warn "$ERROR Duplicate node found: $node\n";
958 } else {
959 $node2sec{$node} = $name;
960 $node2href{$node} = "$docu_doc#$docid";
961 print "# node $node, section $name, level $level\n"
962 if $debug & $DEBUG_TOC;
964 $node = '';
965 } else {
966 print "# no node, section $name, level $level\n"
967 if $debug & $DEBUG_TOC;
969 # update TOC
970 while ($level > $curlevel) {
971 $curlevel++;
972 push(@toc_lines, "<UL>\n");
974 while ($level < $curlevel) {
975 $curlevel--;
976 push(@toc_lines, "</UL>\n");
978 $_ = "<LI>" . &anchor($tocid, "$docu_doc#$docid", $name, 1);
979 push(@toc_lines, &substitute_style($_));
980 # update DOC
981 push(@lines, &html_debug("\n", __LINE__));
982 &html_reset;
983 $_ = "<H$level>".&anchor($docid, "$docu_toc#$tocid", $name)."</H$level>\n";
984 $_ = &debug($_, __LINE__);
985 push(@lines, &html_debug("\n", __LINE__));
987 # update DOC
988 foreach $line (split(/\n+/, $_)) {
989 push(@lines, "$line\n");
991 next;
992 } else {
993 warn "$ERROR Bad section line: $_";
995 } else {
996 # track variables
997 $value{$1} = $2, next if /^\@set\s+($VARRE)\s+(.*)$/o;
998 delete $value{$1}, next if /^\@clear\s+($VARRE)\s*$/o;
999 # store things
1000 $value{'_setfilename'} = $1, next if /^\@setfilename\s+(.*)$/;
1001 $value{'_settitle'} = $1, next if /^\@settitle\s+(.*)$/;
1002 $value{'_author'} .= "$1\n", next if /^\@author\s+(.*)$/;
1003 $value{'_subtitle'} .= "$1\n", next if /^\@subtitle\s+(.*)$/;
1004 $value{'_title'} .= "$1\n", next if /^\@title\s+(.*)$/;
1005 # index
1006 if (/^\@(..?)index\s+/) {
1007 unless ($valid_index{$1}) {
1008 warn "$ERROR Undefined index command: $_";
1009 next;
1011 $id = 'IDX' . ++$idx_num;
1012 $index = $1 . 'index';
1013 $what = &substitute_style($');
1014 $what =~ s/\s+$//;
1015 print "# found $index for '$what' id $id\n"
1016 if $debug & $DEBUG_INDEX;
1017 eval(<<EOC);
1018 if (defined(\$$index\{\$what\})) {
1019 \$$index\{\$what\} .= "$;$docu_doc#$id";
1020 } else {
1021 \$$index\{\$what\} = "$docu_doc#$id";
1025 # dirty hack to see if I can put an invisible anchor...
1027 if ($html_element eq 'P' ||
1028 $html_element eq 'LI' ||
1029 $html_element eq 'DT' ||
1030 $html_element eq 'DD' ||
1031 $html_element eq 'ADDRESS' ||
1032 $html_element eq 'B' ||
1033 $html_element eq 'BLOCKQUOTE' ||
1034 $html_element eq 'PRE' ||
1035 $html_element eq 'SAMP') {
1036 push(@lines, &anchor($id, '', $invisible_mark, !$in_pre));
1037 } elsif ($html_element eq 'body') {
1038 push(@lines, &debug("<P>\n", __LINE__));
1039 push(@lines, &anchor($id, '', $invisible_mark, !$in_pre));
1040 &html_push('P');
1041 } elsif ($html_element eq 'DL' ||
1042 $html_element eq 'UL' ||
1043 $html_element eq 'OL' ) {
1044 $deferred_ref .= &anchor($id, '', $invisible_mark, !$in_pre) . " ";
1046 next;
1048 # list item
1049 if (/^\@itemx?\s+/) {
1050 $what = $';
1051 $what =~ s/\s+$//;
1052 if ($in_bibliography && $use_bibliography) {
1053 if ($what =~ /^$BIBRE$/o) {
1054 $id = 'BIB' . ++$bib_num;
1055 $bib2href{$what} = "$docu_doc#$id";
1056 print "# found bibliography for '$what' id $id\n"
1057 if $debug & $DEBUG_BIB;
1058 $what = &anchor($id, '', $what);
1060 } elsif ($in_glossary && $use_glossary) {
1061 $id = 'GLOSS' . ++$gloss_num;
1062 $entry = $what;
1063 $entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/;
1064 $gloss2href{$entry} = "$docu_doc#$id";
1065 print "# found glossary for '$entry' id $id\n"
1066 if $debug & $DEBUG_GLOSS;
1067 $what = &anchor($id, '', $what);
1069 &html_pop_if('P');
1070 if ($html_element eq 'DL' || $html_element eq 'DD') {
1071 if ($things_map{$in_table} && !$what) {
1072 # special case to allow @table @bullet for instance
1073 push(@lines, &debug("<DT>$things_map{$in_table}\n", __LINE__));
1074 } else {
1075 push(@lines, &debug("<DT>\@$in_table\{$what\}\n", __LINE__));
1077 push(@lines, "<DD>");
1078 &html_push('DD') unless $html_element eq 'DD';
1079 if ($table_type) { # add also an index
1080 unshift(@input_spool, "\@${table_type}index $what\n");
1082 } elsif ($html_element eq 'TABLE' || $html_element eq 'TR') {
1083 # Add <br> at ends of rows for non-tables browsers.
1084 push(@lines, "<BR>\n") if $html_element eq 'TR';
1085 push(@lines, "<TR>$what");
1086 &html_push('TR') unless $html_element eq 'TR';
1087 } else {
1088 push(@lines, &debug("<LI>$what\n", __LINE__));
1089 &html_push('LI') unless $html_element eq 'LI';
1091 push(@lines, &html_debug("\n", __LINE__));
1092 if ($deferred_ref) {
1093 push(@lines, &debug("$deferred_ref\n", __LINE__));
1094 $deferred_ref = '';
1096 next;
1100 # paragraph separator
1101 if ($_ eq "\n") {
1102 next if $#lines >= 0 && $lines[$#lines] eq "\n";
1103 if ($html_element eq 'P') {
1104 push(@lines, "\n");
1105 $_ = &debug("</P>\n", __LINE__);
1106 &html_pop;
1108 } elsif ($html_element eq 'body' || $html_element eq 'BLOCKQUOTE') {
1109 push(@lines, "<P>\n");
1110 &html_push('P');
1111 $_ = &debug($_, __LINE__);
1113 # otherwise
1114 push(@lines, $_);
1117 # finish TOC
1118 $level = 0;
1119 while ($level < $curlevel) {
1120 $curlevel--;
1121 push(@toc_lines, "</UL>\n");
1124 print "# end of pass 1\n" if $verbose;
1126 #+++############################################################################
1128 # Pass 2/3: handle style, menu, index, cross-reference #
1130 #---############################################################################
1132 @lines2 = (); # whole document (2nd pass)
1133 @lines3 = (); # whole document (3rd pass)
1134 $in_menu = 0; # am I inside a menu
1135 $in_top = 1;
1137 while (@lines) {
1138 $_ = shift(@lines);
1140 # special case (protected sections)
1142 if (/^$PROTECTTAG/o) {
1143 push(@lines2, $_);
1144 next;
1146 if ($in_top && $_ eq "$TOPTAG") {
1147 $in_top = 0;
1148 @top_lines = @lines2; # Contents of the top node.
1149 @lines2 = (); # Don't use them in place.
1150 next;
1153 # menu
1155 $in_menu = 1, push(@lines2, &debug("<UL>\n", __LINE__)), next if /^\@menu\b/;
1156 $in_menu = 0, push(@lines2, &debug("</UL>\n", __LINE__)), next if /^\@end\s+menu\b/;
1157 if ($in_menu) {
1158 if (/^\*\s+($NODERE)::/o) {
1159 $descr = $';
1160 chop($descr);
1161 &menu_entry($1, $1, $descr);
1162 } elsif (/^\*\s+(.+):\s+([^\t,\.\n]+)[\t,\.\n]/) {
1163 $descr = $';
1164 chop($descr);
1165 &menu_entry($1, $2, $descr);
1166 } elsif (/^\*/) {
1167 warn "$ERROR Bad menu line: $_";
1168 } else { # description continued?
1169 push(@lines2, $_);
1171 next;
1174 # printindex
1176 if (/^\@printindex\s+(\w\w)\b/) {
1177 local($index, *ary, @keys, $key, $letter, $last_letter, @refs);
1178 if ($predefined_index{$1}) {
1179 $index = $predefined_index{$1} . 'index';
1180 } else {
1181 $index = $1 . 'index';
1183 eval("*ary = *$index");
1184 @keys = keys(%ary);
1185 foreach $key (@keys) {
1186 $_ = $key;
1187 1 while s/<(\w+)>\`(.*)\'<\/\1>/$2/; # remove HTML tags with quotes
1188 1 while s/<(\w+)>(.*)<\/\1>/$2/; # remove HTML tags
1189 $_ = &unprotect_html($_);
1190 &unprotect_texi;
1191 tr/A-Z/a-z/; # lowercase
1192 $key2alpha{$key} = $_;
1193 print "# index $key sorted as $_\n"
1194 if $key ne $_ && $debug & $DEBUG_INDEX;
1196 $last_letter = undef;
1197 foreach $key (sort byalpha @keys) {
1198 $letter = substr($key2alpha{$key}, 0, 1);
1199 $letter = substr($key2alpha{$key}, 0, 2) if $letter eq $;;
1200 if (!defined($last_letter) || $letter ne $last_letter) {
1201 push(@lines2, "</DIR>\n") if defined($last_letter);
1202 push(@lines2, "<H2>" . &protect_html($letter) . "</H2>\n");
1203 push(@lines2, "<DIR>\n");
1204 $last_letter = $letter;
1206 @refs = ();
1207 foreach (split(/$;/, $ary{$key})) {
1208 push(@refs, &anchor('', $_, $key, 0));
1210 push(@lines2, "<LI>" . join(", ", @refs) . "\n");
1212 push(@lines2, "</DIR>\n") if defined($last_letter);
1213 next;
1217 # simple style substitutions
1219 $_ = &substitute_style($_);
1221 # xref
1223 while (/\@(x|px|info|)ref{($XREFRE)(}?)/o) {
1224 # note: Texinfo may accept other characters
1225 ($type, $nodes, $full) = ($1, $2, $3);
1226 ($before, $after) = ($`, $');
1227 if (! $full && $after) {
1228 warn "$ERROR Bad xref (no ending } on line): $_";
1229 $_ = "$before$;0${type}ref\{$nodes$after";
1230 next; # while xref
1232 if ($type eq 'x') {
1233 $type = 'See ';
1234 } elsif ($type eq 'px') {
1235 $type = 'see ';
1236 } elsif ($type eq 'info') {
1237 $type = 'See Info';
1238 } else {
1239 $type = '';
1241 unless ($full) {
1242 $next = shift(@lines);
1243 $next = &substitute_style($next);
1244 chop($nodes); # remove final newline
1245 if ($next =~ /\}/) { # split on 2 lines
1246 $nodes .= " $`";
1247 $after = $';
1248 } else {
1249 $nodes .= " $next";
1250 $next = shift(@lines);
1251 $next = &substitute_style($next);
1252 chop($nodes);
1253 if ($next =~ /\}/) { # split on 3 lines
1254 $nodes .= " $`";
1255 $after = $';
1256 } else {
1257 warn "$ERROR Bad xref (no ending }): $_";
1258 $_ = "$before$;0xref\{$nodes$after";
1259 unshift(@lines, $next);
1260 next; # while xref
1264 $nodes =~ s/\s+/ /g; # remove useless spaces
1265 @args = split(/\s*,\s*/, $nodes);
1266 $node = $args[0]; # the node is always the first arg
1267 &normalise_node($node);
1268 $sec = $node2sec{$node};
1269 $href = $anchor2href{$node};
1270 if (@args == 5) { # reference to another manual
1271 $sec = $args[2] || $node;
1272 $man = $args[4] || $args[3];
1273 $_ = "${before}${type}section `$sec' in \@cite{$man}$after";
1274 } elsif ($type =~ /Info/) { # inforef
1275 warn "$ERROR Wrong number of arguments: $_" unless @args == 3;
1276 ($nn, $_, $in) = @args;
1277 $_ = "${before}${type} file `$in', node `$nn'$after";
1279 } elsif ($sec) {
1280 $href = $node2href{$node};
1281 $_ = "${before}${type}section " . &anchor('', $href, $sec) . $after;
1282 } elsif ($href) {
1283 $_ = "${before}${type} " . &anchor('', $href, $node) . $after;
1284 } else {
1285 warn "$ERROR Undefined node ($node) href=$href: $_";
1286 $_ = "$before$;0xref{$nodes}$after";
1290 # try to guess bibliography references or glossary terms
1292 unless (/^<H\d><A NAME=\"SEC\d/) {
1293 if ($use_bibliography) {
1294 $done = '';
1295 while (/$BIBRE/o) {
1296 ($pre, $what, $post) = ($`, $&, $');
1297 $href = $bib2href{$what};
1298 if (defined($href) && $post !~ /^[^<]*<\/A>/) {
1299 $done .= $pre . &anchor('', $href, $what);
1300 } else {
1301 $done .= "$pre$what";
1303 $_ = $post;
1305 $_ = $done . $_;
1307 if ($use_glossary) {
1308 $done = '';
1309 while (/\b\w+\b/) {
1310 ($pre, $what, $post) = ($`, $&, $');
1311 $entry = $what;
1312 $entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/;
1313 $href = $gloss2href{$entry};
1314 if (defined($href) && $post !~ /^[^<]*<\/A>/) {
1315 $done .= $pre . &anchor('', $href, $what);
1316 } else {
1317 $done .= "$pre$what";
1319 $_ = $post;
1321 $_ = $done . $_;
1324 # otherwise
1325 push(@lines2, $_);
1327 print "# end of pass 2\n" if $verbose;
1330 # split style substitutions
1332 while (@lines2) {
1333 $_ = shift(@lines2);
1335 # special case (protected sections)
1337 if (/^$PROTECTTAG/o) {
1338 push(@lines3, $_);
1339 next;
1342 # split style substitutions
1344 $old = '';
1345 while ($old ne $_) {
1346 $old = $_;
1347 if (/\@(\w+)\{/) {
1348 ($before, $style, $after) = ($`, $1, $');
1349 if (defined($style_map{$style})) {
1350 $_ = $after;
1351 $text = '';
1352 $after = '';
1353 $failed = 1;
1354 while (@lines2) {
1355 if (/\}/) {
1356 $text .= $`;
1357 $after = $';
1358 $failed = 0;
1359 last;
1360 } else {
1361 $text .= $_;
1362 $_ = shift(@lines2);
1365 if ($failed) {
1366 die "* Bad syntax (\@$style) after: $before\n";
1367 } else {
1368 $text = &apply_style($style, $text);
1369 $_ = "$before$text$after";
1374 # otherwise
1375 push(@lines3, $_);
1377 print "# end of pass 3\n" if $verbose;
1379 #+++############################################################################
1381 # Pass 4: foot notes, final cleanup #
1383 #---############################################################################
1385 @foot_lines = (); # footnotes
1386 @doc_lines = (); # final document
1387 $end_of_para = 0; # true if last line is <P>
1389 while (@lines3) {
1390 $_ = shift(@lines3);
1392 # special case (protected sections)
1394 if (/^$PROTECTTAG/o) {
1395 push(@doc_lines, $_);
1396 $end_of_para = 0;
1397 next;
1400 # footnotes
1402 while (/\@footnote([^\{\s]+)\{/) {
1403 ($before, $d, $after) = ($`, $1, $');
1404 $_ = $after;
1405 $text = '';
1406 $after = '';
1407 $failed = 1;
1408 while (@lines3) {
1409 if (/\}/) {
1410 $text .= $`;
1411 $after = $';
1412 $failed = 0;
1413 last;
1414 } else {
1415 $text .= $_;
1416 $_ = shift(@lines3);
1419 if ($failed) {
1420 die "* Bad syntax (\@footnote) after: $before\n";
1421 } else {
1422 $foot_num++;
1423 $docid = "DOCF$foot_num";
1424 $footid = "FOOT$foot_num";
1425 $foot = "($foot_num)";
1426 push(@foot_lines, "<H3>" . &anchor($footid, "$d#$docid", $foot) . "</H3>\n");
1427 $text = "<P>$text" unless $text =~ /^\s*<P>/;
1428 push(@foot_lines, "$text\n");
1429 $_ = $before . &anchor($docid, "$docu_foot#$footid", $foot) . $after;
1433 # remove unnecessary <P>
1435 if (/^\s*<P>\s*$/) {
1436 next if $end_of_para++;
1437 } else {
1438 $end_of_para = 0;
1440 # otherwise
1441 push(@doc_lines, $_);
1443 print "# end of pass 4\n" if $verbose;
1445 #+++############################################################################
1447 # Pass 5: print things #
1449 #---############################################################################
1451 $header = <<EOT;
1452 <!-- This HTML file has been created by $THISPROG
1453 from $docu on $TODAY -->
1456 $full_title = $value{'_title'} || $value{'_settitle'} || "Untitled Document";
1457 $title = $value{'_settitle'} || $full_title;
1458 $_ = &substitute_style($full_title);
1459 &unprotect_texi;
1460 s/\n$//; # rmv last \n (if any)
1461 $full_title = "<H1>" . join("</H1>\n<H1>", split(/\n/, $_)) . "</H1>\n";
1464 # print ToC
1466 # ... unless using menus instead. Make the TOC lines empty rather than
1467 # null so we get a ToC page with the top node (including menu).
1468 @toc_lines = ("") if $show_menu;
1470 if (!$monolithic && @toc_lines) {
1471 if (open(FILE, "> $docu_toc")) {
1472 print "# creating $docu_toc...\n" if $verbose;
1473 &print_toplevel_header("$title - Table of Contents");
1474 &print_ruler;
1475 &print (*top_lines, FILE); # Contents of the top node before the TOC.
1476 &print(*toc_lines, FILE);
1477 &print_toplevel_footer;
1478 close(FILE);
1479 } else {
1480 warn "$ERROR Can't write to $docu_toc: $!\n";
1485 # print footnotes
1487 if (!$monolithic && @foot_lines) {
1488 if (open(FILE, "> $docu_foot")) {
1489 print "# creating $docu_foot...\n" if $verbose;
1490 &print_toplevel_header("$title - Footnotes");
1491 &print_ruler;
1492 &print(*foot_lines, FILE);
1493 &print_toplevel_footer;
1494 close(FILE);
1495 } else {
1496 warn "$ERROR Can't write to $docu_foot: $!\n";
1501 # print document
1503 if ($split_chapter || $split_node) { # split
1504 $doc_num = 0;
1505 $last_num = scalar(@sections);
1506 $first_doc = &doc_name(1);
1507 $last_doc = &doc_name($last_num);
1508 while (@sections) {
1509 $section = shift(@sections);
1510 &next_doc;
1511 if (open(FILE, "> $docu_doc")) {
1512 print "# creating $docu_doc...\n" if $verbose;
1513 $prev_doc = ($doc_num == 1 ? undef : &doc_name($doc_num - 1));
1514 $next_doc = ($doc_num == $last_num ? undef : &doc_name($doc_num + 1));
1515 $links = ($next_doc ? "<link href=\"$next_doc\" rel=Next>\n" : "");
1516 $links .= ($prev_doc ? "<link href=\"$prev_doc\" rel=Previous>\n" : "");
1517 $links .= "<link href=\"$docu_toc\" rel=ToC>\n";
1518 # fixme: try rel=Index too?
1519 &print_header("$title - $section", $links);
1521 $navigation = "<p>Go to the ";
1522 $navigation .= ($prev_doc ? &anchor('', $first_doc, "first") : "first");
1523 $navigation .= ", ";
1524 $navigation .= ($prev_doc ? &anchor('', $prev_doc, "previous") : "previous");
1525 $navigation .= ", ";
1526 $navigation .= ($next_doc ? &anchor('', $next_doc, "next") : "next");
1527 $navigation .= ", ";
1528 $navigation .= ($next_doc ? &anchor('', $last_doc, "last") : "last");
1529 $navigation .= " section, " . &anchor('', $docu_toc, "table of contents") . ".\n";
1530 print FILE $navigation;
1531 &print_ruler;
1532 # find corresponding lines
1533 @tmp_lines = ();
1534 while (@doc_lines) {
1535 $_ = shift(@doc_lines);
1536 last if ($_ eq $SPLITTAG);
1537 push(@tmp_lines, $_);
1539 &print(*tmp_lines, FILE);
1540 &print_ruler;
1541 print FILE $navigation;
1542 &print_footer;
1543 close(FILE);
1544 } else {
1545 warn "$ERROR Can't write to $docu_doc: $!\n";
1548 } else { # not split
1549 if (open(FILE, "> $docu_doc")) {
1550 print "# creating $docu_doc...\n" if $verbose;
1551 if ($monolithic || !@toc_lines) {
1552 &print_toplevel_header($title);
1553 } else {
1554 &print_header($title, "");
1555 print FILE $full_title;
1557 if ($monolithic && @toc_lines) {
1558 &print_ruler;
1559 print FILE "<H1>Table of Contents</H1>\n";
1560 &print(*toc_lines, FILE);
1562 &print_ruler;
1563 &print(*doc_lines, FILE);
1564 if ($monolithic && @foot_lines) {
1565 &print_ruler;
1566 print FILE "<H1>Footnotes</H1>\n";
1567 &print(*foot_lines, FILE);
1569 if ($monolithic || !@toc_lines) {
1570 &print_toplevel_footer;
1571 } else {
1572 &print_footer;
1574 close(FILE);
1575 } else {
1576 warn "$ERROR Can't write to $docu_doc: $!\n";
1580 print "# that's all folks\n" if $verbose;
1582 #+++############################################################################
1584 # Low level functions #
1586 #---############################################################################
1588 sub update_sec_num {
1589 local($name, $level) = @_;
1591 $level--; # here we start at 0
1592 if ($name =~ /^appendix/) {
1593 # appendix style
1594 if (defined(@appendix_sec_num)) {
1595 &incr_sec_num($level, @appendix_sec_num);
1596 } else {
1597 @appendix_sec_num = ('A', 0, 0, 0);
1599 return(join('.', @appendix_sec_num[0..$level]));
1600 } else {
1601 # normal style
1602 if (defined(@normal_sec_num)) {
1603 &incr_sec_num($level, @normal_sec_num);
1604 } else {
1605 @normal_sec_num = (1, 0, 0, 0);
1607 return(join('.', @normal_sec_num[0..$level]));
1611 sub incr_sec_num {
1612 local($level, $l);
1613 $level = shift(@_);
1614 $_[$level]++;
1615 foreach $l ($level+1 .. 3) {
1616 $_[$l] = 0;
1620 sub check {
1621 local($_, %seen, %context, $before, $match, $after);
1623 while (<>) {
1624 if (/\@(\*|\.|\:|\@|\{|\})/) {
1625 $seen{$&}++;
1626 $context{$&} .= "> $_" if $verbose;
1627 $_ = "$`XX$'";
1628 redo;
1630 if (/\@(\w+)/) {
1631 ($before, $match, $after) = ($`, $&, $');
1632 if ($before =~ /\b[\w-]+$/ && $after =~ /^[\w-.]*\b/) { # e-mail address
1633 $seen{'e-mail address'}++;
1634 $context{'e-mail address'} .= "> $_" if $verbose;
1635 } else {
1636 $seen{$match}++;
1637 $context{$match} .= "> $_" if $verbose;
1639 $match =~ s/^\@/X/;
1640 $_ = "$before$match$after";
1641 redo;
1645 foreach (sort(keys(%seen))) {
1646 if ($verbose) {
1647 print "$_\n";
1648 print $context{$_};
1649 } else {
1650 print "$_ ($seen{$_})\n";
1655 sub open {
1656 local($name) = @_;
1658 ++$fh_name;
1659 if (open($fh_name, $name)) {
1660 unshift(@fhs, $fh_name);
1661 } else {
1662 warn "$ERROR Can't read file $name: $!\n";
1666 sub init_input {
1667 @fhs = (); # hold the file handles to read
1668 @input_spool = (); # spooled lines to read
1669 $fh_name = 'FH000';
1670 &open($docu);
1673 sub next_line {
1674 local($fh, $line);
1676 if (@input_spool) {
1677 $line = shift(@input_spool);
1678 return($line);
1680 while (@fhs) {
1681 $fh = $fhs[0];
1682 $line = <$fh>;
1683 return($line) if $line;
1684 close($fh);
1685 shift(@fhs);
1687 return(undef);
1690 # used in pass 1, use &next_line
1691 sub skip_until {
1692 local($tag) = @_;
1693 local($_);
1695 while ($_ = &next_line) {
1696 return if /^\@end\s+$tag\s*$/;
1698 die "* Failed to find '$tag' after: " . $lines[$#lines];
1702 # HTML stacking to have a better HTML output
1705 sub html_reset {
1706 @html_stack = ('html');
1707 $html_element = 'body';
1710 sub html_push {
1711 local($what) = @_;
1712 push(@html_stack, $html_element);
1713 $html_element = $what;
1716 sub html_push_if {
1717 local($what) = @_;
1718 push(@html_stack, $html_element)
1719 if ($html_element && $html_element ne 'P');
1720 $html_element = $what;
1723 sub html_pop {
1724 $html_element = pop(@html_stack);
1727 sub html_pop_if {
1728 local($elt);
1730 if (@_) {
1731 foreach $elt (@_) {
1732 if ($elt eq $html_element) {
1733 $html_element = pop(@html_stack) if @html_stack;
1734 last;
1737 } else {
1738 $html_element = pop(@html_stack) if @html_stack;
1742 sub html_debug {
1743 local($what, $line) = @_;
1744 return("<!-- $line @html_stack, $html_element -->$what")
1745 if $debug & $DEBUG_HTML;
1746 return($what);
1749 # to debug the output...
1750 sub debug {
1751 local($what, $line) = @_;
1752 return("<!-- $line -->$what")
1753 if $debug & $DEBUG_HTML;
1754 return($what);
1757 sub normalise_node {
1758 $_[0] =~ s/\s+/ /g;
1759 $_[0] =~ s/ $//;
1760 $_[0] =~ s/^ //;
1763 sub menu_entry {
1764 local($entry, $node, $descr) = @_;
1765 local($href);
1767 &normalise_node($node);
1768 $href = $node2href{$node};
1769 if ($href) {
1770 $descr =~ s/^\s+//;
1771 $descr = ": $descr" if $descr;
1772 push(@lines2, "<LI>" . &anchor('', $href, $entry) . "$descr\n");
1773 } else {
1774 warn "$ERROR Undefined node ($node): $_";
1779 sub do_email { "&#60;" . &anchor('', "mailto:$_[0]", "<TT>$_[0]</TT>") . "&#62;" }
1781 sub do_url { &anchor('', "$_[0]", "<TT>$_[0]</TT>") }
1783 sub do_ctrl { "^$_[0]" }
1785 sub do_sc { "\U$_[0]\E" }
1787 sub apply_style {
1788 local($texi_style, $text) = @_;
1789 local($style);
1791 $style = $style_map{$texi_style};
1792 if (defined($style)) { # known style
1793 if ($style =~ /^\"/) { # add quotes
1794 $style = $';
1795 $text = "\`$text\'";
1797 if ($style =~ /^\&/) { # custom
1798 $style = $';
1799 $text = &$style($text);
1800 } elsif ($style) { # good style
1801 $text = "<$style>$text</$style>";
1802 } else { # no style
1804 } else { # unknown style
1805 $text = undef;
1807 return($text);
1810 # remove Texinfo styles
1811 sub remove_style {
1812 local($_) = @_;
1813 s/\@\w+{([^\{\}]+)}/$1/g;
1814 return($_);
1817 sub substitute_style {
1818 local($_) = @_;
1819 local($changed, $done, $style, $text);
1821 $changed = 1;
1822 while ($changed) {
1823 $changed = 0;
1824 $done = '';
1825 while (/\@(\w+){([^\{\}]+)}/) {
1826 $text = &apply_style($1, $2);
1827 if ($text) {
1828 $_ = "$`$text$'";
1829 $changed = 1;
1830 } else {
1831 $done .= "$`\@$1";
1832 $_ = "{$2}$'";
1835 $_ = $done . $_;
1837 return($_);
1840 sub anchor {
1841 local($name, $href, $text, $newline) = @_;
1842 local($result);
1844 $result = "<A";
1845 $result .= " NAME=\"$name\"" if $name;
1846 $result .= " HREF=\"$href\"" if $href;
1847 $result .= ">$text</A>";
1848 $result .= "\n" if $newline;
1849 return($result);
1852 sub pretty_date {
1853 local(@MoY, $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);
1855 @MoY = ('January', 'Febuary', 'March', 'April', 'May', 'June',
1856 'July', 'August', 'September', 'October', 'November', 'December');
1857 ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
1858 $year += ($year < 70) ? 2000 : 1900;
1859 return("$mday $MoY[$mon] $year");
1862 sub doc_name {
1863 local($num) = @_;
1865 return("${docu_name}_$num.html");
1868 sub next_doc {
1869 $docu_doc = &doc_name(++$doc_num);
1872 sub print {
1873 local(*lines, $fh) = @_;
1874 local($_);
1876 while (@lines) {
1877 $_ = shift(@lines);
1878 if (/^$PROTECTTAG/o) {
1879 $_ = $tag2pro{$_};
1880 } else {
1881 &unprotect_texi;
1883 print $fh $_;
1887 sub print_ruler {
1888 print FILE "<P><HR><P>\n";
1891 sub print_header {
1892 local($_);
1894 $links = $_[1];
1895 # clean the title
1896 $_ = &remove_style($_[0]);
1897 &unprotect_texi;
1898 # print the header
1899 if ($doctype eq 'html2') {
1900 print FILE $html2_doctype; # Wrong if any multitable used
1901 } elsif ($doctype) {
1902 print FILE $doctype;
1904 print FILE <<EOT;
1905 <HTML>
1906 <HEAD>
1907 $header
1908 <TITLE>$_</TITLE>
1909 $links
1910 </HEAD>
1911 <BODY>
1915 sub print_toplevel_header {
1916 local($_);
1918 &print_header ($_[0], "");
1919 print FILE $full_title;
1920 if ($value{'_subtitle'}) {
1921 $value{'_subtitle'} =~ s/\n+$//;
1922 foreach (split(/\n/, $value{'_subtitle'})) {
1923 $_ = &substitute_style($_);
1924 &unprotect_texi;
1925 print FILE "<H2>$_</H2>\n";
1928 if ($value{'_author'}) {
1929 $value{'_author'} =~ s/\n+$//;
1930 foreach (split(/\n/, $value{'_author'})) {
1931 $_ = &substitute_style($_);
1932 &unprotect_texi;
1933 # s/[\w.-]+\@[\w.-]+/<A HREF="mailto:$&">$&<\/A>/g;
1934 print FILE "<ADDRESS>$_</ADDRESS>\n";
1937 print FILE "<P>\n";
1940 sub print_footer {
1941 print FILE <<EOT;
1942 </BODY>
1943 </HTML>
1947 sub print_toplevel_footer {
1948 &print_ruler;
1949 print FILE <<EOT;
1950 This document was generated on $TODAY using the
1951 <A HREF=\"$HOMEPAGE\">texi2html</A>
1952 translator version 1.51a.</P>
1954 &print_footer;
1957 sub protect_texi {
1958 # protect @ { } ` '
1959 s/\@\@/$;0/go;
1960 s/\@\{/$;1/go;
1961 s/\@\}/$;2/go;
1962 s/\@\`/$;3/go;
1963 s/\@\'/$;4/go;
1966 sub protect_html {
1967 local($what) = @_;
1968 # protect & < >
1969 $what =~ s/\&/\&\#38;/g;
1970 $what =~ s/\</\&\#60;/g;
1971 $what =~ s/\>/\&\#62;/g;
1972 # but recognize some HTML things
1973 $what =~ s/\&\#60;\/A\&\#62;/<\/A>/g; # </A>
1974 $what =~ s/\&\#60;A ([^\&]+)\&\#62;/<A $1>/g; # <A [^&]+>
1975 $what =~ s/\&\#60;IMG ([^\&]+)\&\#62;/<IMG $1>/g; # <IMG [^&]+>
1976 return($what);
1979 sub unprotect_texi {
1980 s/$;0/\@/go;
1981 s/$;1/\{/go;
1982 s/$;2/\}/go;
1983 s/$;3/\`/go;
1984 s/$;4/\'/go;
1987 sub unprotect_html {
1988 local($what) = @_;
1989 $what =~ s/\&\#38;/\&/g;
1990 $what =~ s/\&\#60;/\</g;
1991 $what =~ s/\&\#62;/\>/g;
1992 return($what);
1995 sub byalpha {
1996 $key2alpha{$a} cmp $key2alpha{$b};
1999 ##############################################################################
2001 # These next few lines are legal in both Perl and nroff.
2003 .00 ; # finish .ig
2005 'di \" finish diversion--previous line must be blank
2006 .nr nl 0-1 \" fake up transition to first page again
2007 .nr % 0 \" start at page 1
2008 '; __END__ ############# From here on it's a standard manual page ############
2009 .TH TEXI2HTML 1 "08/12/97"
2010 .AT 3
2011 .SH NAME
2012 texi2html \- a Texinfo to HTML converter
2013 .SH SYNOPSIS
2014 .B texi2html [OPTION]... FILE
2016 .B texi2html -check [-verbose] FILE...
2017 .SH DESCRIPTION
2018 .I Texi2html
2019 converts the given Texinfo file to a set of HTML files. It tries to handle
2020 most of the Texinfo commands. It creates hypertext links for cross-references,
2021 footnotes...
2023 It also tries to add links from a reference to its corresponding entry in the
2024 bibliography (if any). It may also handle a glossary (see the
2025 .B \-glossary
2026 option).
2028 .I Texi2html
2029 creates several files depending on the contents of the Texinfo file and on
2030 the chosen options (see FILES).
2032 The HTML files created by
2033 .I texi2html
2034 are closer to TeX than to Info, that's why
2035 .I texi2html
2036 converts @iftex sections and not @ifinfo ones by default. You can reverse
2037 this with the \-expandinfo option.
2038 .SH OPTIONS
2039 .TP 12
2040 .B \-check
2041 Check the given file and give the list of all things that may be Texinfo commands.
2042 This may be used to check the output of
2043 .I texi2html
2044 to find the Texinfo commands that have been left in the HTML file.
2046 .B \-expandinfo
2047 Expand @ifinfo sections, not @iftex ones.
2049 .B \-glossary
2050 Use the section named 'Glossary' to build a list of terms and put links in the HTML
2051 document from each term toward its definition.
2053 .B \-invisible \fIname\fP
2054 Use \fIname\fP to create invisible destination anchors for index links. This is a workaround
2055 for a known bug of many WWW browsers, including xmosaic.
2057 .B \-I \fIdir\fP
2058 Look also in \fIdir\fP to find included files.
2060 .B \-menu
2061 Show the Texinfo menus; by default they are ignored.
2063 .B \-monolithic
2064 Output only one file, including the table of contents and footnotes.
2066 .B \-number
2067 Number the sections.
2069 .B \-split_chapter
2070 Split the output into several HTML files (one per main section:
2071 chapter, appendix...).
2073 .B \-split_node
2074 Split the output into several HTML files (one per node).
2076 .B \-usage
2077 Print usage instructions, listing the current available command-line options.
2079 .B \-verbose
2080 Give a verbose output. Can be used with the
2081 .B \-check
2082 option.
2084 .SH FILES
2085 By default
2086 .I texi2html
2087 creates the following files (foo being the name of the Texinfo file):
2088 .TP 16
2089 .B foo_toc.html
2090 The table of contents.
2092 .B foo.html
2093 The document's contents.
2095 .B foo_foot.html
2096 The footnotes (if any).
2098 When used with the
2099 .B \-split
2100 option, it creates several files (one per chapter or node), named
2101 .B foo_n.html
2102 (n being the indice of the chapter or node), instead of the single
2103 .B foo.html
2104 file.
2106 When used with the
2107 .B \-monolithic
2108 option, it creates only one file:
2109 .B foo.html
2110 .SH VARIABLES
2111 .I texi2html
2112 predefines the following variables: \fBhtml\fP, \fBtexi2html\fP.
2113 .SH ADDITIONAL COMMANDS
2114 .I texi2html
2115 implements the following non-Texinfo commands:
2116 .TP 16
2117 .B @ifhtml
2118 This indicates the start of an HTML section, this section will passed through
2119 without any modofication.
2121 .B @end ifhtml
2122 This indcates the end of an HTML section.
2123 .SH VERSION
2124 This is \fItexi2html\fP version 1.51a, 1997-07-29.
2126 The latest version of \fItexi2html\fP can be found
2127 ftp://ftp.cs.umb.edu/pub/tex/texi2html
2128 .SH AUTHOR
2129 The main author is Lionel Cons, CERN CN/DCI/UWS.
2130 This version is maintained at ftp://ftp.cs.umb.edu/pub/tex/texi2html
2131 by kb@cs.umb.edu.
2132 Many other people around the net contributed to this program.
2133 .SH COPYRIGHT
2134 This program is the intellectual property of the European
2135 Laboratory for Particle Physics (known as CERN). No guarantee whatsoever is
2136 provided by CERN. No liability whatsoever is accepted for any loss or damage
2137 of any kind resulting from any defect or inaccuracy in this information or
2138 code.
2140 CERN, 1211 Geneva 23, Switzerland
2141 .SH "SEE ALSO"
2142 GNU Texinfo Documentation Format,
2143 HyperText Markup Language (HTML),
2144 World Wide Web (WWW).
2145 .SH BUGS
2146 This program does not understand all Texinfo commands (yet).
2148 TeX specific commands (normally enclosed in @iftex) will be
2149 passed unmodified.