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