4 #+##############################################################################
8 # Description: Program to transform most Texinfo documents to HTML #
10 #-##############################################################################
12 # @(#)texi2html 1.51 09/10/96 Written (mainly) by Lionel Cons, Lionel.Cons@cern.ch
14 # The man page for this program is included at the end of this file and can be
15 # viewed using the command 'nroff -man texi2html'.
16 # Please read the copyright at the end of the man page.
18 #+++############################################################################
22 #---############################################################################
32 $BIBRE = '\[[\w\/]+\]'; # RE for a bibliography reference
33 $FILERE = '[\/\w.+-]+'; # RE for a file name
34 $VARRE = '[^\s\{\}]+'; # RE for a variable name
35 $NODERE = '[^@{}:\'`",]+'; # RE for a node name
36 $NODESRE = '[^@{}:\'`"]+'; # RE for a list of node names
37 $XREFRE = '[^@{}]+'; # RE for a xref (should use NODERE)
39 $ERROR = "***"; # prefix for errors and warnings
40 $THISPROG = "texi2html 1.51"; # program name and version
41 $HOMEPAGE = "http://wwwcn.cern.ch/dci/texi2html/"; # program home page
42 $TODAY = &pretty_date
; # like "20 September 1993"
43 $SPLITTAG = "<!-- SPLIT HERE -->\n"; # tag to know where to split
44 $PROTECTTAG = "_ThisIsProtected_"; # tag to recognize protected sections
45 $html2_doctype = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0 Strict Level 2//EN">';
48 # language dependent constants
51 #$LDC_SECTION = 'section';
53 #$LDC_TOC = 'Table of Contents';
54 #$LDC_GOTO = 'Go to the';
55 #$LDC_FOOT = 'Footnotes';
56 # TODO: @def* shortcuts
83 # texinfo section names to level
98 'unnumberedsubsec', 3,
102 'unnumberedsubsubsec', 4,
104 'appendixsubsubsec', 4,
108 # accent map, TeX command to ISO name
119 # texinfo "simple things" (@foo) to HTML ones
135 # texinfo "things" (@foo{}) to HTML ones
139 'br', '<P>', # paragraph break
154 # texinfo styles (@foo{bar}) to HTML ones
161 'ctrl', '&do_ctrl', # special case
162 'dfn', 'STRONG', # DFN tag is illegal in the standard
165 'file', '"TT', # will put quotes, cf. &apply_style
169 'r', '', # unsupported
170 'samp', '"SAMP', # will put quotes, cf. &apply_style
171 'sc', '&do_sc', # special case
174 'titlefont', '', # useless
176 'w', '', # unsupported
180 # texinfo format (@foo/@end foo) to HTML ones
187 'quotation', 'BLOCKQUOTE',
188 'smallexample', 'PRE',
199 # texinfo definition shortcuts to real ones
219 'defun', 'deffn Function',
220 'defmac', 'deffn Macro',
221 'defspec', 'deffn {Special Form}',
222 'defvar', 'defvr Variable',
223 'defopt', 'defvr {User Option}',
224 'deftypefun', 'deftypefn Function',
225 'deftypevar', 'deftypevr Variable',
226 'defivar', 'defcv {Instance Variable}',
227 'defmethod', 'defop Method',
229 'defunx', 'deffnx Function',
230 'defmacx', 'deffnx Macro',
231 'defspecx', 'deffnx {Special Form}',
232 'defvarx', 'defvrx Variable',
233 'defoptx', 'defvrx {User Option}',
234 'deftypefunx', 'deftypefnx Function',
235 'deftypevarx', 'deftypevrx Variable',
236 'defivarx', 'defcvx {Instance Variable}',
237 'defmethodx', 'defopx Method',
250 'summarycontents', 1,
256 # unsupported commands (formatting)
263 'setchapternewpage', 1,
273 # unsupported formats
280 #+++############################################################################
282 # Argument parsing, initialisation #
284 #---############################################################################
286 $use_bibliography = 1;
293 $invisible_mark = '';
297 $number_sections = 0;
304 To convert a Texinfo file to HMTL: $0 [options] file
305 where options can be:
306 -expandinfo : use \@ifinfo sections, not \@iftex
307 -glossary : handle a glossary
308 -invisible name: use 'name' as an invisible anchor
309 -I dir : search also for files in 'dir'
311 -monolithic : output only one file including ToC
312 -number : number sections
313 -split_chapter : split on main sections
314 -split_node : split on nodes
315 -usage : print usage instructions
316 -verbose : verbose output
317 To check converted files: $0 -check [-verbose] files
320 while ($#ARGV >= 0 && $ARGV[0] =~ /^-/) {
322 if (/^-acc$/) { $use_acc = 1; next; }
323 if (/^-d(ebug)?(\d+)?$/) { $debug = $2 || shift(@ARGV); next; }
324 if (/^-doctype$/) { $doctype = shift(@ARGV); next; }
325 if (/^-c(heck)?$/) { $check = 1; next; }
326 if (/^-e(xpandinfo)?$/) { $expandinfo = 1; next; }
327 if (/^-g(lossary)?$/) { $use_glossary = 1; next; }
328 if (/^-i(nvisible)?$/) { $invisible_mark = shift(@ARGV); next; }
329 if (/^-iso$/) { $use_iso = 1; next; }
330 if (/^-I(.+)?$/) { push(@include_dirs, $1 || shift(@ARGV)); next; }
331 if (/^-m(enu)?$/) { $show_menu = 1; next; }
332 if (/^-mono(lithic)?$/) { $monolithic = 1; next; }
333 if (/^-n(umber)?$/) { $number_sections = 1; next; }
334 if (/^-s(plit)?_?(n(ode)?|c(hapter)?)?$/) {
342 if (/^-v(erbose)?$/) { $verbose = 1; next; }
346 die $usage unless @ARGV > 0;
351 if (($split_node || $split_chapter) && $monolithic) {
352 warn "Can't use -monolithic with -split, -monolithic ignored.\n";
356 $to_skip{'ifinfo'}++;
357 $to_skip{'end ifinfo'}++;
360 $to_skip{'end iftex'}++;
362 $invisible_mark = '<IMG SRC="invisible.xbm">' if $invisible_mark eq 'xbm';
363 die $usage unless @ARGV == 1;
364 $docu = shift(@ARGV);
365 if ($docu =~ /.*\//) {
366 chop($docu_dir = $&);
372 unshift(@include_dirs, $docu_dir);
373 $docu_name =~ s/\.te?x(i|info)?$//; # basename of the document
375 $docu_doc = "$docu_name.html"; # document's contents
377 $docu_toc = $docu_foot = $docu_doc;
379 $docu_toc = "${docu_name}_toc.html"; # document's table of contents
380 $docu_foot = "${docu_name}_foot.html"; # document's footnotes
386 %value = (); # hold texinfo variables
387 $value{'html'} = 1; # predefine html (the output format)
388 $value{'texi2html'} = '1.51'; # predefine texi2html (the translator)
389 # _foo: internal to track @foo
390 foreach ('_author', '_title', '_subtitle',
391 '_settitle', '_setfilename') {
392 $value{$_} = ''; # prevent -w warnings
394 %node2sec = (); # node to section name
395 %node2href = (); # node to HREF
396 %bib2href = (); # bibliography reference to HREF
397 %gloss2href = (); # glossary term to HREF
398 @sections = (); # list of sections
399 %tag2pro = (); # protected sections
413 # can I use ISO8879 characters? (HTML+)
416 $things_map{'bullet'} = "•";
417 $things_map{'copyright'} = "©";
418 $things_map{'dots'} = "…";
419 $things_map{'equiv'} = "≡";
420 $things_map{'expansion'} = "→";
421 $things_map{'point'} = "∗";
422 $things_map{'result'} = "⇒";
426 # read texi2html extensions (if any)
428 $extensions = 'texi2html.ext'; # extensions in working directory
429 if (-f
$extensions) {
430 print "# reading extensions from $extensions\n" if $verbose;
431 require($extensions);
433 ($progdir = $0) =~ s/[^\/]+$//;
434 if ($progdir && ($progdir ne './')) {
435 $extensions = "${progdir}texi2html.ext"; # extensions in texi2html directory
436 if (-f
$extensions) {
437 print "# reading extensions from $extensions\n" if $verbose;
438 require($extensions);
442 print "# reading from $docu\n" if $verbose;
444 #+++############################################################################
446 # Pass 1: read source, handle command, variable, simple substitution #
448 #---############################################################################
450 @lines = (); # whole document
451 @toc_lines = (); # table of contents
452 $toplevel = 0; # top level seen in hierarchy
453 $curlevel = 0; # current level in TOC
454 $node = ''; # current node name
455 $in_table = 0; # am I inside a table
456 $table_type = ''; # type of table ('', 'f', 'v')
457 @tables = (); # nested table support
458 $in_bibliography = 0; # am I inside a bibliography
459 $in_glossary = 0; # am I inside a glossary
460 $in_top = 0; # am I inside the top node
461 $in_pre = 0; # am I inside a preformatted section
462 $in_list = 0; # am I inside a list
463 $in_html = 0; # am I inside an HTML section
464 $first_line = 1; # is it the first line
465 $dont_html = 0; # don't protect HTML on this line
466 $split_num = 0; # split index
467 $deferred_ref = ''; # deferred reference for indexes
468 @html_stack = (); # HTML elements stack
469 $html_element = ''; # current HTML element
472 # build code for simple substitutions
473 # the maps used (%simple_map and %things_map) MUST be aware of this
474 # watch out for regexps, / and escaped characters!
476 foreach (keys(%simple_map)) {
477 ($re = $_) =~ s/(\W)/\\$1/g; # protect regexp chars
478 $subst_code .= "s/\\\@$re/$simple_map{$_}/g;\n";
480 foreach (keys(%things_map)) {
481 $subst_code .= "s/\\\@$_\\{\\}/$things_map{$_}/g;\n";
484 # accentuated characters
485 foreach (keys(%accent_map)) {
487 $subst_code .= "s/$;3";
488 } elsif ($_ eq "'") {
489 $subst_code .= "s/$;4";
491 $subst_code .= "s/\\\@\\$_";
493 $subst_code .= "([aeiou])/&\${1}$accent_map{$_};/gi;\n";
496 eval("sub simple_substitutions { $subst_code }");
499 while ($_ = &next_line
) {
501 # remove \input on the first lines only
512 if (/^\@end\s+(\w+)\b/) {
514 } elsif (/^\@(\w+)\b/) {
518 # handle @ifhtml / @end ifhtml
521 if ($end_tag eq 'ifhtml') {
524 $tag2pro{$in_html} .= $_;
527 } elsif ($tag eq 'ifhtml') {
528 $in_html = $PROTECTTAG . ++$html_num;
529 push(@lines, $in_html);
533 # try to skip the line
536 next if $to_skip{"end $end_tag"};
538 next if $to_skip{$tag};
539 last if $tag eq 'bye';
542 # parsing the top node
543 if ($tag eq 'node' || $tag eq 'include' || $sec2level{$tag}) {
552 # try to remove inlined comments
553 # syntax from tex-mode.el comment-start-skip
555 s/((^|[^\@])(\@\@)*)\@c(omment)? .*/$1/;
556 # non-@ substitutions cf. texinfmt.el
559 s/([\w ])---([\w ])/$1--$2/g;
565 &skip_until
($tag), next if $tag eq 'ignore';
567 &skip_until
($tag), next if $tag eq 'iftex';
569 &skip_until
($tag), next if $tag eq 'ifinfo';
571 &skip_until
($tag), next if $tag eq 'tex';
572 # handle special tables
573 if ($tag eq 'table') {
575 } elsif ($tag eq 'ftable') {
578 } elsif ($tag eq 'vtable') {
583 if ($tag eq 'top' || ($tag eq 'node' && /^\@node\s+top\s*,/i)) {
585 @lines = (); # ignore all lines before top (title page garbage)
587 } elsif ($tag eq 'node') {
589 warn "$ERROR Bad node line: $_" unless $_ =~ /^\@node\s$NODESRE$/o;
590 $_ = &protect_html
($_); # if node contains '&' for instance
592 ($node) = split(/,/);
593 &normalise_node
($node);
596 push(@lines, $SPLITTAG) if $split_num++;
597 push(@sections, $node);
600 } elsif ($tag eq 'include') {
601 if (/^\@include\s+($FILERE)\s*$/o) {
604 foreach $dir (@include_dirs) {
611 print "# including $file\n" if $verbose;
613 warn "$ERROR Can't find $file, skipping";
616 warn "$ERROR Bad include line: $_";
619 } elsif ($tag eq 'ifclear') {
620 if (/^\@ifclear\s+($VARRE)\s*$/o) {
621 next unless defined($value{$1});
624 warn "$ERROR Bad ifclear line: $_";
627 } elsif ($tag eq 'ifset') {
628 if (/^\@ifset\s+($VARRE)\s*$/o) {
629 next if defined($value{$1});
632 warn "$ERROR Bad ifset line: $_";
635 } elsif ($tag eq 'menu') {
636 unless ($show_menu) {
641 push(@lines, &html_debug
("\n", __LINE__
));
642 } elsif ($format_map{$tag}) {
643 $in_pre = 1 if $format_map{$tag} eq 'PRE';
644 &html_push_if
($format_map{$tag});
645 push(@lines, &html_debug
("\n", __LINE__
));
646 $in_list++ if $format_map{$tag} eq 'UL' || $format_map{$tag} eq 'OL' ;
647 push(@lines, &debug
("<$format_map{$tag}>\n", __LINE__
));
649 } elsif ($tag eq 'table') {
650 if (/^\@[fv]?table\s+\@(\w+)\s*$/) {
652 unshift(@tables, join($;, $table_type, $in_table));
653 push(@lines, &debug
("<DL COMPACT>\n", __LINE__
));
655 push(@lines, &html_debug
("\n", __LINE__
));
657 warn "$ERROR Bad table line: $_";
660 } elsif ($tag eq 'synindex' || $tag eq 'syncodeindex') {
661 if (/^\@$tag\s+(\w)\w\s+(\w)\w\s*$/) {
662 eval("*${1}index = *${2}index");
664 warn "$ERROR Bad syn*index line: $_";
667 } elsif ($tag eq 'sp') {
668 push(@lines, &debug
("<P>\n", __LINE__
));
670 } elsif ($tag eq 'setref') {
671 &protect_html
; # if setref contains '&' for instance
672 if (/^\@$tag\s*{($NODERE)}\s*$/) {
674 $setref =~ s/\s+/ /g; # normalize
676 $node2sec{$setref} = $name;
677 $node2href{$setref} = "$docu_doc#$docid";
679 warn "$ERROR Bad setref line: $_";
682 } elsif ($tag eq 'defindex' || $tag eq 'defcodeindex') {
683 if (/^\@$tag\s+(\w\w)\s*$/) {
684 $valid_index{$1} = 1;
686 warn "$ERROR Bad defindex line: $_";
689 } elsif (defined($def_map{$tag})) {
690 if ($def_map{$tag}) {
692 $tag = $def_map{$tag};
696 } elsif (defined($user_sub{$tag})) {
698 $sub = $user_sub{$tag};
699 print "# user $tag = $sub, arg: $_" if $debug & $DEBUG_USER;
700 if (defined(&$sub)) {
704 warn "$ERROR Bad user sub for $tag: $sub\n";
708 if (defined($def_map{$tag})) {
711 # extra definition line
717 while (/\{([^\{\}]*)\}/) {
718 # this is a {} construct
719 ($before, $contents, $after) = ($`, $1, $');
721 $contents =~ s/\s+/$;9/g;
722 # restore $_ protecting {}
723 $_ = "$before$;7$contents$;8$after";
725 @args = split(/\s+/, &protect_html($_));
727 s/$;9/ /g; # unprotect spaces
731 $type = shift(@args);
732 $type =~ s/^\{(.*)\}$/$1/;
733 print "# def ($tag): {$type} ", join(', ', @args), "\n"
734 if $debug & $DEBUG_DEF;
735 $type .= ':'; # it's nicer like this
736 $name = shift(@args);
737 $name =~ s/^\{(.*)\}$/$1/;
739 $_ = &debug
("<DT>", __LINE__
);
741 $_ = &debug
("<DL>\n<DT>", __LINE__
);
743 if ($tag eq 'deffn' || $tag eq 'defvr' || $tag eq 'deftp') {
744 $_ .= "<U>$type</U> <B>$name</B>";
745 $_ .= " <I>@args</I>" if @args;
746 } elsif ($tag eq 'deftypefn' || $tag eq 'deftypevr'
747 || $tag eq 'defcv' || $tag eq 'defop') {
749 $name = shift(@args);
750 $name =~ s/^\{(.*)\}$/$1/;
751 $_ .= "<U>$type</U> $ftype <B>$name</B>";
752 $_ .= " <I>@args</I>" if @args;
754 warn "$ERROR Unknown definition type: $tag\n";
755 $_ .= "<U>$type</U> <B>$name</B>";
756 $_ .= " <I>@args</I>" if @args;
758 $_ .= &debug
("\n<DD>", __LINE__
);
759 $name = &unprotect_html
($name);
760 if ($tag eq 'deffn' || $tag eq 'deftypefn') {
761 unshift(@input_spool, "\@findex $name\n");
762 } elsif ($tag eq 'defop') {
763 unshift(@input_spool, "\@findex $name on $ftype\n");
764 } elsif ($tag eq 'defvr' || $tag eq 'deftypevr' || $tag eq 'defcv') {
765 unshift(@input_spool, "\@vindex $name\n");
767 unshift(@input_spool, "\@tindex $name\n");
772 if ($format_map{$end_tag}) {
773 $in_pre = 0 if $format_map{$end_tag} eq 'PRE';
774 $in_list-- if $format_map{$end_tag} eq 'UL' || $format_map{$end_tag} eq 'OL' ;
775 &html_pop_if
('LI', 'P');
777 push(@lines, &debug
("</$format_map{$end_tag}>\n", __LINE__
));
778 push(@lines, &html_debug
("\n", __LINE__
));
779 } elsif ($end_tag eq 'table' ||
780 $end_tag eq 'ftable' ||
781 $end_tag eq 'vtable') {
784 ($table_type, $in_table) = split($;, $tables[0]);
788 push(@lines, "</DL>\n");
791 } elsif (defined($def_map{$end_tag})) {
792 push(@lines, &debug
("</DL>\n", __LINE__
));
793 } elsif ($end_tag eq 'menu') {
795 push(@lines, $_); # must keep it for pass 2
802 # protect texi and HTML things
804 $_ = &protect_html
($_) unless $dont_html;
806 # substitution (unsupported things)
811 # other substitutions
812 &simple_substitutions
;
813 s/\@value{($VARRE)}/$value{$1}/eg;
814 s/\@footnote\{/\@footnote$docu_doc\{/g; # mark footnotes, cf. pass 4
816 # analyze the tag again
819 if (defined($sec2level{$tag}) && $sec2level{$tag} > 0) {
820 if (/^\@$tag\s+(.+)$/) {
823 $level = $sec2level{$tag};
824 $name = &update_sec_num
($tag, $level) . " $name"
825 if $number_sections && $tag !~ /^unnumbered/;
826 if ($tag =~ /heading$/) {
827 push(@lines, &html_debug
("\n", __LINE__
));
828 if ($html_element ne 'body') {
829 # We are in a nice pickle here. We are trying to get a H? heading
830 # even though we are not in the body level. So, we convert it to a
831 # nice, bold, line by itself.
832 $_ = &debug
("\n\n<P><STRONG>$name</STRONG></P>\n\n", __LINE__
);
834 $_ = &debug
("<H$level>$name</H$level>\n", __LINE__
);
835 &html_push_if
('body');
837 print "# heading, section $name, level $level\n"
838 if $debug & $DEBUG_TOC;
840 if ($split_chapter) {
842 # first time we see a "section"
843 unless ($level == 1) {
844 warn "$ERROR The first section found is not of level 1: $_";
845 warn "$ERROR I'll split on sections of level $level...\n";
849 if ($level == $toplevel) {
851 push(@lines, $SPLITTAG) if $split_num++;
852 push(@sections, $name);
856 $docid = "SEC$sec_num";
857 $tocid = "TOC$sec_num";
858 # check biblio and glossary
859 $in_bibliography = ($name =~ /^([A-Z]|\d+)?(\.\d+)*\s*bibliography$/i);
860 $in_glossary = ($name =~ /^([A-Z]|\d+)?(\.\d+)*\s*glossary$/i);
863 if ($node2sec{$node}) {
864 warn "$ERROR Duplicate node found: $node\n";
866 $node2sec{$node} = $name;
867 $node2href{$node} = "$docu_doc#$docid";
868 print "# node $node, section $name, level $level\n"
869 if $debug & $DEBUG_TOC;
873 print "# no node, section $name, level $level\n"
874 if $debug & $DEBUG_TOC;
877 while ($level > $curlevel) {
879 push(@toc_lines, "<UL>\n");
881 while ($level < $curlevel) {
883 push(@toc_lines, "</UL>\n");
885 $_ = "<LI>" . &anchor
($tocid, "$docu_doc#$docid", $name, 1);
886 push(@toc_lines, &substitute_style
($_));
888 push(@lines, &html_debug
("\n", __LINE__
));
890 $_ = "<H$level>".&anchor
($docid, "$docu_toc#$tocid", $name)."</H$level>\n";
891 $_ = &debug
($_, __LINE__
);
892 push(@lines, &html_debug
("\n", __LINE__
));
895 foreach $line (split(/\n+/, $_)) {
896 push(@lines, "$line\n");
900 warn "$ERROR Bad section line: $_";
904 $value{$1} = $2, next if /^\@set\s+($VARRE)\s+(.*)$/o;
905 delete $value{$1}, next if /^\@clear\s+($VARRE)\s*$/o;
907 $value{'_setfilename'} = $1, next if /^\@setfilename\s+(.*)$/;
908 $value{'_settitle'} = $1, next if /^\@settitle\s+(.*)$/;
909 $value{'_author'} .= "$1\n", next if /^\@author\s+(.*)$/;
910 $value{'_subtitle'} .= "$1\n", next if /^\@subtitle\s+(.*)$/;
911 $value{'_title'} .= "$1\n", next if /^\@title\s+(.*)$/;
913 if (/^\@(..?)index\s+/) {
914 unless ($valid_index{$1}) {
915 warn "$ERROR Undefined index command: $_";
918 $id = 'IDX' . ++$idx_num;
919 $index = $1 . 'index';
920 $what = &substitute_style
($');
922 print "# found $index for '$what' id $id\n"
923 if $debug & $DEBUG_INDEX;
925 if (defined(\$$index\{\$what\})) {
926 \$$index\{\$what\} .= "$;$docu_doc#$id";
928 \$$index\{\$what\} = "$docu_doc#$id";
932 # dirty hack to see if I can put an invisible anchor...
934 if ($html_element eq 'P' ||
935 $html_element eq 'LI' ||
936 $html_element eq 'DT' ||
937 $html_element eq 'DD' ||
938 $html_element eq 'ADDRESS' ||
939 $html_element eq 'B' ||
940 $html_element eq 'BLOCKQUOTE' ||
941 $html_element eq 'PRE' ||
942 $html_element eq 'SAMP') {
943 push(@lines, &anchor
($id, '', $invisible_mark, !$in_pre));
944 } elsif ($html_element eq 'body') {
945 push(@lines, &debug
("<P>\n", __LINE__
));
946 push(@lines, &anchor
($id, '', $invisible_mark, !$in_pre));
948 } elsif ($html_element eq 'DL' ||
949 $html_element eq 'UL' ||
950 $html_element eq 'OL' ) {
951 $deferred_ref .= &anchor
($id, '', $invisible_mark, !$in_pre) . " ";
956 if (/^\@itemx?\s+/) {
959 if ($in_bibliography && $use_bibliography) {
960 if ($what =~ /^$BIBRE$/o) {
961 $id = 'BIB
' . ++$bib_num;
962 $bib2href{$what} = "$docu_doc#$id";
963 print "# found bibliography for '$what' id $id\n"
964 if $debug & $DEBUG_BIB;
965 $what = &anchor($id, '', $what);
967 } elsif ($in_glossary && $use_glossary) {
968 $id = 'GLOSS
' . ++$gloss_num;
970 $entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/;
971 $gloss2href{$entry} = "$docu_doc#$id";
972 print "# found glossary for '$entry' id $id\n"
973 if $debug & $DEBUG_GLOSS;
974 $what = &anchor($id, '', $what);
977 if ($html_element eq 'DL
' || $html_element eq 'DD
') {
978 if ($things_map{$in_table} && !$what) {
979 # special case to allow @table @bullet for instance
980 push(@lines, &debug("<DT>$things_map{$in_table}\n", __LINE__));
982 push(@lines, &debug("<DT>\@$in_table\{$what\}\n", __LINE__));
984 push(@lines, "<DD>");
985 &html_push('DD
') unless $html_element eq 'DD
';
986 if ($table_type) { # add also an index
987 unshift(@input_spool, "\@${table_type}index $what\n");
990 push(@lines, &debug("<LI>$what\n", __LINE__));
991 &html_push('LI
') unless $html_element eq 'LI
';
993 push(@lines, &html_debug("\n", __LINE__));
995 push(@lines, &debug("$deferred_ref\n", __LINE__));
1002 # paragraph separator
1004 next if $#lines >= 0 && $lines[$#lines] eq "\n";
1005 if ($html_element eq 'P
') {
1007 $_ = &debug("</P>\n", __LINE__);
1010 } elsif ($html_element eq 'body
' || $html_element eq 'BLOCKQUOTE
') {
1011 push(@lines, "<P>\n");
1013 $_ = &debug($_, __LINE__);
1021 while ($level < $curlevel) {
1023 push(@toc_lines, "</UL>\n");
1026 print "# end of pass 1\n" if $verbose;
1028 #+++############################################################################
1030 # Pass 2/3: handle style, menu, index, cross-reference #
1032 #---############################################################################
1034 @lines2 = (); # whole document (2nd pass)
1035 @lines3 = (); # whole document (3rd pass)
1036 $in_menu = 0; # am I inside a menu
1041 # special case (protected sections)
1043 if (/^$PROTECTTAG/o) {
1050 $in_menu = 1, push(@lines2, &debug("<UL>\n", __LINE__)), next if /^\@menu\b/;
1051 $in_menu = 0, push(@lines2, &debug("</UL>\n", __LINE__)), next if /^\@end\s+menu\b/;
1053 if (/^\*\s+($NODERE)::/o) {
1056 &menu_entry
($1, $1, $descr);
1057 } elsif (/^\*\s+(.+):\s+([^\t,\.\n]+)[\t,\.\n]/) {
1060 &menu_entry($1, $2, $descr);
1062 warn "$ERROR Bad menu line: $_";
1063 } else { # description continued?
1071 if (/^\@printindex\s+(\w\w)\b/) {
1072 local($index, *ary, @keys, $key, $letter, $last_letter, @refs);
1073 if ($predefined_index{$1}) {
1074 $index = $predefined_index{$1} . 'index';
1076 $index = $1 . 'index';
1078 eval("*ary = *$index");
1080 foreach $key (@keys) {
1082 1 while s/<(\w+)>\`(.*)\'<\/\1>/$2/; # remove HTML tags with quotes
1083 1 while s/<(\w+)>(.*)<\/\1>/$2/; # remove HTML tags
1084 $_ = &unprotect_html($_);
1086 tr/A-Z/a-z/; # lowercase
1087 $key2alpha{$key} = $_;
1088 print "# index $key sorted as $_\n"
1089 if $key ne $_ && $debug & $DEBUG_INDEX;
1091 $last_letter = undef;
1092 foreach $key (sort byalpha @keys) {
1093 $letter = substr($key2alpha{$key}, 0, 1);
1094 $letter = substr($key2alpha{$key}, 0, 2) if $letter eq $;;
1095 if (!defined($last_letter) || $letter ne $last_letter) {
1096 push(@lines2, "</DIR>\n") if defined($last_letter);
1097 push(@lines2, "<H2>" . &protect_html($letter) . "</H2>\n");
1098 push(@lines2, "<DIR>\n");
1099 $last_letter = $letter;
1102 foreach (split(/$;/, $ary{$key})) {
1103 push(@refs, &anchor('', $_, $key, 0));
1105 push(@lines2, "<LI>" . join(", ", @refs) . "\n");
1107 push(@lines2, "</DIR>\n") if defined($last_letter);
1111 # simple style substitutions
1113 $_ = &substitute_style($_);
1117 while (/\@(x|px|info|)ref{($XREFRE)(}?)/o) {
1118 # note: Texinfo may accept other characters
1119 ($type, $nodes, $full) = ($1, $2, $3);
1120 ($before, $after) = ($`, $');
1121 if (! $full && $after) {
1122 warn "$ERROR Bad xref (no ending } on line): $_";
1123 $_ = "$before$;0${type}ref\{$nodes$after";
1128 } elsif ($type eq 'px') {
1130 } elsif ($type eq 'info') {
1136 $next = shift(@lines);
1137 $next = &substitute_style
($next);
1138 chop($nodes); # remove final newline
1139 if ($next =~ /\}/) { # split on 2 lines
1144 $next = shift(@lines);
1145 $next = &substitute_style($next);
1147 if ($next =~ /\}/) { # split on 3 lines
1151 warn "$ERROR Bad xref (no ending }): $_";
1152 $_ = "$before$;0xref\{$nodes$after";
1153 unshift(@lines, $next);
1158 $nodes =~ s/\s+/ /g; # remove useless spaces
1159 @args = split(/\s*,\s*/, $nodes);
1160 $node = $args[0]; # the node is always the first arg
1161 &normalise_node
($node);
1162 $sec = $node2sec{$node};
1163 if (@args == 5) { # reference to another manual
1164 $sec = $args[2] || $node;
1165 $man = $args[4] || $args[3];
1166 $_ = "${before}${type}section `$sec' in \@cite{$man}$after";
1167 } elsif ($type =~ /Info/) { # inforef
1168 warn "$ERROR Wrong number of arguments: $_" unless @args == 3;
1169 ($nn, $_, $in) = @args;
1170 $_ = "${before}${type} file `$in', node `$nn'$after";
1172 $href = $node2href{$node};
1173 $_ = "${before}${type}section " . &anchor
('', $href, $sec) . $after;
1175 warn "$ERROR Undefined node ($node): $_";
1176 $_ = "$before$;0xref{$nodes}$after";
1180 # try to guess bibliography references or glossary terms
1182 unless (/^<H\d><A NAME=\"SEC\d/) {
1183 if ($use_bibliography) {
1186 ($pre, $what, $post) = ($`, $&, $');
1187 $href = $bib2href{$what};
1188 if (defined($href) && $post !~ /^[^<]*<\/A>/) {
1189 $done .= $pre . &anchor('', $href, $what);
1191 $done .= "$pre$what";
1197 if ($use_glossary) {
1200 ($pre, $what, $post) = ($`, $&, $');
1202 $entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/;
1203 $href = $gloss2href{$entry};
1204 if (defined($href) && $post !~ /^[^<]*<\/A
>/) {
1205 $done .= $pre . &anchor
('', $href, $what);
1207 $done .= "$pre$what";
1217 print "# end of pass 2\n" if $verbose;
1220 # split style substitutions
1223 $_ = shift(@lines2);
1225 # special case (protected sections)
1227 if (/^$PROTECTTAG/o) {
1232 # split style substitutions
1235 while ($old ne $_) {
1238 ($before, $style, $after) = ($`, $1, $');
1239 if (defined($style_map{$style})) {
1252 $_ = shift(@lines2);
1256 die "* Bad syntax (\@$style) after: $before\n";
1258 $text = &apply_style
($style, $text);
1259 $_ = "$before$text$after";
1267 print "# end of pass 3\n" if $verbose;
1269 #+++############################################################################
1271 # Pass 4: foot notes, final cleanup #
1273 #---############################################################################
1275 @foot_lines = (); # footnotes
1276 @doc_lines = (); # final document
1277 $end_of_para = 0; # true if last line is <P>
1280 $_ = shift(@lines3);
1282 # special case (protected sections)
1284 if (/^$PROTECTTAG/o) {
1285 push(@doc_lines, $_);
1292 while (/\@footnote([^\{\s]+)\{/) {
1293 ($before, $d, $after) = ($`, $1, $');
1306 $_ = shift(@lines3);
1310 die "* Bad syntax (\@footnote) after: $before\n";
1313 $docid = "DOCF$foot_num";
1314 $footid = "FOOT$foot_num";
1315 $foot = "($foot_num)";
1316 push(@foot_lines, "<H3>" . &anchor
($footid, "$d#$docid", $foot) . "</H3>\n");
1317 $text = "<P>$text" unless $text =~ /^\s*<P>/;
1318 push(@foot_lines, "$text\n");
1319 $_ = $before . &anchor
($docid, "$docu_foot#$footid", $foot) . $after;
1323 # remove unnecessary <P>
1325 if (/^\s*<P>\s*$/) {
1326 next if $end_of_para++;
1331 push(@doc_lines, $_);
1333 print "# end of pass 4\n" if $verbose;
1335 #+++############################################################################
1337 # Pass 5: print things #
1339 #---############################################################################
1342 <!-- This HTML file has been created by $THISPROG
1343 from $docu on $TODAY -->
1346 $full_title = $value{'_title'} || $value{'_settitle'} || "Untitled Document";
1347 $title = $value{'_settitle'} || $full_title;
1348 $_ = &substitute_style
($full_title);
1350 s/\n$//; # rmv last \n (if any)
1351 $full_title = "<H1>" . join("</H1>\n<H1>", split(/\n/, $_)) . "</H1
>\n";
1356 if (!$monolithic && @toc_lines) {
1357 if (open(FILE, "> $docu_toc")) {
1358 print "# creating $docu_toc...\n" if $verbose;
1359 &print_toplevel_header
("$title - Table of Contents");
1361 &print(*toc_lines
, FILE
);
1362 &print_toplevel_footer
;
1365 warn "$ERROR Can't write to $docu_toc: $!\n";
1372 if (!$monolithic && @foot_lines) {
1373 if (open(FILE
, "> $docu_foot")) {
1374 print "# creating $docu_foot...\n" if $verbose;
1375 &print_toplevel_header
("$title - Footnotes");
1377 &print(*foot_lines
, FILE
);
1378 &print_toplevel_footer
;
1381 warn "$ERROR Can't write to $docu_foot: $!\n";
1388 if ($split_chapter || $split_node) { # split
1390 $last_num = scalar(@sections);
1391 $first_doc = &doc_name
(1);
1392 $last_doc = &doc_name
($last_num);
1394 $section = shift(@sections);
1396 if (open(FILE
, "> $docu_doc")) {
1397 print "# creating $docu_doc...\n" if $verbose;
1398 &print_header
("$title - $section");
1399 $prev_doc = ($doc_num == 1 ? undef : &doc_name
($doc_num - 1));
1400 $next_doc = ($doc_num == $last_num ? undef : &doc_name
($doc_num + 1));
1401 $navigation = "Go to the ";
1402 $navigation .= ($prev_doc ? &anchor
('', $first_doc, "first") : "first");
1403 $navigation .= ", ";
1404 $navigation .= ($prev_doc ? &anchor
('', $prev_doc, "previous") : "previous");
1405 $navigation .= ", ";
1406 $navigation .= ($next_doc ? &anchor
('', $next_doc, "next") : "next");
1407 $navigation .= ", ";
1408 $navigation .= ($next_doc ? &anchor
('', $last_doc, "last") : "last");
1409 $navigation .= " section, " . &anchor
('', $docu_toc, "table of contents") . ".\n";
1410 print FILE
$navigation;
1412 # find corresponding lines
1414 while (@doc_lines) {
1415 $_ = shift(@doc_lines);
1416 last if ($_ eq $SPLITTAG);
1417 push(@tmp_lines, $_);
1419 &print(*tmp_lines
, FILE
);
1421 print FILE
$navigation;
1425 warn "$ERROR Can't write to $docu_doc: $!\n";
1428 } else { # not split
1429 if (open(FILE
, "> $docu_doc")) {
1430 print "# creating $docu_doc...\n" if $verbose;
1431 if ($monolithic || !@toc_lines) {
1432 &print_toplevel_header
($title);
1434 &print_header
($title);
1435 print FILE
$full_title;
1437 if ($monolithic && @toc_lines) {
1439 print FILE
"<H1>Table of Contents</H1>\n";
1440 &print(*toc_lines
, FILE
);
1443 &print(*doc_lines
, FILE
);
1444 if ($monolithic && @foot_lines) {
1446 print FILE
"<H1>Footnotes</H1>\n";
1447 &print(*foot_lines
, FILE
);
1449 if ($monolithic || !@toc_lines) {
1450 &print_toplevel_footer
;
1456 warn "$ERROR Can't write to $docu_doc: $!\n";
1460 print "# that's all folks\n" if $verbose;
1462 #+++############################################################################
1464 # Low level functions #
1466 #---############################################################################
1468 sub update_sec_num
{
1469 local($name, $level) = @_;
1471 $level--; # here we start at 0
1472 if ($name =~ /^appendix/) {
1474 if (defined(@appendix_sec_num)) {
1475 &incr_sec_num
($level, @appendix_sec_num);
1477 @appendix_sec_num = ('A', 0, 0, 0);
1479 return(join('.', @appendix_sec_num[0..$level]));
1482 if (defined(@normal_sec_num)) {
1483 &incr_sec_num
($level, @normal_sec_num);
1485 @normal_sec_num = (1, 0, 0, 0);
1487 return(join('.', @normal_sec_num[0..$level]));
1495 foreach $l ($level+1 .. 3) {
1501 local($_, %seen, %context, $before, $match, $after);
1504 if (/\@(\*|\.|\:|\@|\{|\})/) {
1506 $context{$&} .= "> $_" if $verbose;
1511 ($before, $match, $after) = ($`, $&, $');
1512 if ($before =~ /\b[\w-]+$/ && $after =~ /^[\w-.]*\b/) { # e-mail address
1513 $seen{'e-mail address
'}++;
1514 $context{'e-mail address
'} .= "> $_" if $verbose;
1517 $context{$match} .= "> $_" if $verbose;
1520 $_ = "$before$match$after";
1525 foreach (sort(keys(%seen))) {
1530 print "$_ ($seen{$_})\n";
1539 if (open($fh_name, $name)) {
1540 unshift(@fhs, $fh_name);
1542 warn "$ERROR Can't
read file
$name: $!\n";
1547 @fhs = (); # hold the file handles to read
1548 @input_spool = (); # spooled lines to read
1557 $line = shift(@input_spool);
1563 return($line) if $line;
1570 # used in pass 1, use &next_line
1575 while ($_ = &next_line) {
1576 return if /^\@end\s+$tag\s*$/;
1578 die "* Failed to find
'$tag' after
: " . $lines[$#lines];
1582 # HTML stacking to have a better HTML output
1586 @html_stack = ('html');
1587 $html_element = 'body';
1592 push(@html_stack, $html_element);
1593 $html_element = $what;
1598 push(@html_stack, $html_element)
1599 if ($html_element && $html_element ne 'P');
1600 $html_element = $what;
1604 $html_element = pop(@html_stack);
1612 if ($elt eq $html_element) {
1613 $html_element = pop(@html_stack) if @html_stack;
1618 $html_element = pop(@html_stack) if @html_stack;
1623 local($what, $line) = @_;
1624 return("<!-- $line @html_stack, $html_element -->$what")
1625 if $debug & $DEBUG_HTML;
1629 # to debug the output...
1631 local($what, $line) = @_;
1632 return("<!-- $line -->$what")
1633 if $debug & $DEBUG_HTML;
1637 sub normalise_node {
1644 local($entry, $node, $descr) = @_;
1647 &normalise_node($node);
1648 $href = $node2href{$node};
1651 $descr = ": $descr" if $descr;
1652 push(@lines2, "<LI
>" . &anchor('', $href, $entry) . "$descr\n");
1654 warn "$ERROR Undefined node
($node): $_";
1658 sub do_ctrl { "^$_[0]" }
1660 sub do_sc { "\U
$_[0]\E
" }
1663 local($texi_style, $text) = @_;
1666 $style = $style_map{$texi_style};
1667 if (defined($style)) { # known style
1668 if ($style =~ /^\"/) { # add quotes
1670 $text = "\
`$text\'";
1672 if ($style =~ /^\&/) { # custom
1674 $text = &$style($text);
1675 } elsif ($style) { # good style
1676 $text = "<$style>$text</$style>";
1679 } else { # unknown style
1685 # remove Texinfo styles
1688 s/\@\w+{([^\{\}]+)}/$1/g;
1692 sub substitute_style {
1694 local($changed, $done, $style, $text);
1700 while (/\@(\w+){([^\{\}]+)}/) {
1701 $text = &apply_style($1, $2);
1716 local($name, $href, $text, $newline) = @_;
1720 $result .= " NAME=\"$name\"" if $name;
1721 $result .= " HREF=\"$href\"" if $href;
1722 $result .= ">$text</A>";
1723 $result .= "\n" if $newline;
1728 local(@MoY, $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);
1730 @MoY = ('January', 'Febuary', 'March', 'April', 'May', 'June',
1731 'July', 'August', 'September', 'October', 'November', 'December');
1732 ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
1733 $year += ($year < 70) ? 2000 : 1900;
1734 return("$mday $MoY[$mon] $year");
1740 return("${docu_name}_$num.html");
1744 $docu_doc = &doc_name(++$doc_num);
1748 local(*lines, $fh) = @_;
1753 if (/^$PROTECTTAG/o) {
1763 print FILE "<P><HR><P>\n";
1770 $_ = &remove_style($_[0]);
1773 if ($doctype eq 'html2') {
1774 print FILE $html2_doctype;
1775 } elsif ($doctype) {
1776 print FILE $doctype;
1788 sub print_toplevel_header
{
1791 &print_header
; # pass given arg...
1792 print FILE
$full_title;
1793 if ($value{'_subtitle'}) {
1794 $value{'_subtitle'} =~ s/\n+$//;
1795 foreach (split(/\n/, $value{'_subtitle'})) {
1796 $_ = &substitute_style
($_);
1798 print FILE
"<H2>$_</H2>\n";
1801 if ($value{'_author'}) {
1802 $value{'_author'} =~ s/\n+$//;
1803 foreach (split(/\n/, $value{'_author'})) {
1804 $_ = &substitute_style
($_);
1806 s/[\w.-]+\@[\w.-]+/<A HREF="mailto:$&">$&<\/A
>/g
;
1807 print FILE
"<ADDRESS>$_</ADDRESS>\n";
1820 sub print_toplevel_footer
{
1823 This document was generated on $TODAY using the
1824 <A HREF=\"$HOMEPAGE\">texi2html</A>
1825 translator version 1.51.</P>
1842 $what =~ s/\&/\&\#38;/g;
1843 $what =~ s/\</\&\#60;/g;
1844 $what =~ s/\>/\&\#62;/g;
1845 # but recognize some HTML things
1846 $what =~ s/\&\#60;\/A\&\#62;/<\
/A>/g; # </A>
1847 $what =~ s/\&\#60;A ([^\&]+)\&\#62;/<A $1>/g; # <A [^&]+>
1848 $what =~ s/\&\#60;IMG ([^\&]+)\&\#62;/<IMG $1>/g; # <IMG [^&]+>
1852 sub unprotect_texi
{
1860 sub unprotect_html
{
1862 $what =~ s/\&\#38;/\&/g;
1863 $what =~ s/\&\#60;/\</g;
1864 $what =~ s/\&\#62;/\>/g;
1869 $key2alpha{$a} cmp $key2alpha{$b};
1872 ##############################################################################
1874 # These next few lines are legal in both Perl and nroff.
1878 'di \" finish diversion--previous line must be blank
1879 .nr nl 0-1 \" fake up transition to first page again
1880 .nr % 0 \" start at page 1
1881 '; __END__
############# From here on it's a standard manual page ############
1882 .TH TEXI2HTML
1 "09/10/96"
1885 texi2html \
- a Texinfo to HTML converter
1887 .B texi2html
[options
] file
1889 .B texi2html
-check
[-verbose
] files
1892 converts the
given Texinfo file to a set of HTML files
. It tries to handle
1893 most of the Texinfo commands
. It creates hypertext links
for cross-references
,
1896 It also tries to add links from a reference to its corresponding entry
in the
1897 bibliography
(if any
). It may also handle a glossary
(see the
1902 creates several files depending on the contents of the Texinfo file
and on
1903 the chosen options
(see FILES
).
1905 The HTML files created by
1907 are closer to TeX than to Info
, that
's why
1909 converts @iftex sections and not @ifinfo ones by default. You can reverse
1910 this with the \-expandinfo option.
1914 Check the given file and give the list of all things that may be Texinfo commands.
1915 This may be used to check the output of
1917 to find the Texinfo commands that have been left in the HTML file.
1920 Expand @ifinfo sections, not @iftex ones.
1923 Use the section named 'Glossary
' to build a list of terms and put links in the HTML
1924 document from each term toward its definition.
1926 .B \-invisible \fIname\fP
1927 Use \fIname\fP to create invisible destination anchors for index links. This is a workaround
1928 for a known bug of many WWW browsers, including xmosaic.
1931 Look also in \fIdir\fP to find included files.
1934 Show the Texinfo menus; by default they are ignored.
1937 Output only one file, including the table of contents and footnotes.
1940 Number the sections.
1943 Split the output into several HTML files (one per main section:
1944 chapter, appendix...).
1947 Split the output into several HTML files (one per node).
1950 Print usage instructions, listing the current available command-line options.
1953 Give a verbose output. Can be used with the
1960 creates the following files (foo being the name of the Texinfo file):
1963 The table of contents.
1966 The document's contents
.
1969 The footnotes
(if any
).
1973 option
, it creates several files
(one per chapter
or node
), named
1975 (n being the indice of the chapter
or node
), instead of the single
1981 option
, it creates only one file
:
1985 predefines the following variables
: \fBhtml
\fP
, \fBtexi
2html
\fP
.
1986 .SH ADDITIONAL COMMANDS
1988 implements the following non-Texinfo commands
:
1991 This indicates the start of an HTML section
, this section will passed through
1992 without any modofication
.
1995 This indcates the end of an HTML section
.
1997 This
is \fItexi
2html
\fP version
1.51, 09/10/96.
1999 The latest version of
\fItexi
2html
\fP can be found
in WWW
, cf
. URL
2000 http
://wwwcn
.cern
.ch
/dci/texi2html
/
2002 The main author
is Lionel Cons
, CERN CN
/DCI/UWS
, Lionel
.Cons
@cern.ch
.
2003 Many other people around the net contributed to this program
.
2005 This program
is the intellectual property of the European
2006 Laboratory
for Particle Physics
(known as CERN
). No guarantee whatsoever
is
2007 provided by CERN
. No liability whatsoever
is accepted
for any loss
or damage
2008 of any kind resulting from any defect
or inaccuracy
in this information
or
2011 CERN
, 1211 Geneva
23, Switzerland
2013 GNU Texinfo Documentation Format
,
2014 HyperText Markup Language
(HTML
),
2015 World Wide Web
(WWW
).
2017 This program
does not understand all Texinfo commands
(yet
).
2019 TeX specific commands
(normally enclosed
in @iftex) will be