1#!/usr/local/bin/perl 2'di '; 3'ig 00 '; 4#+############################################################################## 5# # 6# File: texi2html # 7# # 8# Description: Program to transform most Texinfo documents to HTML # 9# # 10#-############################################################################## 11 12# @(#)texi2html 1.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. 15 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. 19 20#+++############################################################################ 21# # 22# Constants # 23# # 24#---############################################################################ 25 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; 33 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) 40 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">'; 48 49# 50# language dependent constants 51# 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 59 60# 61# pre-defined indices 62# 63%predefined_index = ( 64 'cp', 'c', 65 'fn', 'f', 66 'vr', 'v', 67 'ky', 'k', 68 'pg', 'p', 69 'tp', 't', 70 ); 71 72# 73# valid indices 74# 75%valid_index = ( 76 'c', 1, 77 'f', 1, 78 'v', 1, 79 'k', 1, 80 'p', 1, 81 't', 1, 82 ); 83 84# 85# texinfo section names to level 86# 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, 107 ); 108 109# 110# accent map, TeX command to ISO name 111# 112%accent_map = ( 113 '"', 'uml', 114 '~', 'tilde', 115 '^', 'circ', 116 '`', 'grave', 117 '\'', 'acute', 118 ); 119 120# 121# texinfo "simple things" (@foo) to HTML ones 122# 123%simple_map = ( 124 # cf. makeinfo.c 125 "*", "<BR>", # HTML+ 126 " ", " ", 127 "\n", "\n", 128 "|", "", 129 # spacing commands 130 ":", "", 131 "!", "!", 132 "?", "?", 133 ".", ".", 134 "-", "", 135 ); 136 137# 138# texinfo "things" (@foo{}) to HTML ones 139# 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', 'å', 155 'AA', 'Å', 156 'ae', 'æ', 157 'AE', 'Æ', 158 'o', 'ø', 159 'O', 'Ø', 160 'ss', 'ß', 161 'exclamdown', '¡', 162 'questiondown', '¿', 163 'pounds', '£' 164 ); 165 166# 167# texinfo styles (@foo{bar}) to HTML ones 168# 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', 200 ); 201 202# 203# texinfo format (@foo/@end foo) to HTML ones 204# 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', 219 ); 220 221# 222# texinfo definition shortcuts to real ones 223# 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', 261 ); 262 263# 264# things to skip 265# 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, 302 ); 303 304#+++############################################################################ 305# # 306# Argument parsing, initialisation # 307# # 308#---############################################################################ 309 310%value = (); # hold texinfo variables, see also -D 311 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; 329This is $THISPROG 330To 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 344To check converted files: $0 -check [-verbose] files 345EOT 346 347while (@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; 367 } 368 next; 369 } 370 if (/^-v(erbose)?$/) { $verbose = 1; next; } 371 die $usage; 372} 373if ($check) { 374 die $usage unless @ARGV > 0; 375 ✓ 376 exit; 377} 378 379if (($split_node || $split_chapter) && $monolithic) { 380 warn "Can't use -monolithic with -split, -monolithic ignored.\n"; 381 $monolithic = 0; 382} 383if ($expandinfo) { 384 $to_skip{'ifinfo'}++; 385 $to_skip{'end ifinfo'}++; 386} else { 387 $to_skip{'iftex'}++; 388 $to_skip{'end iftex'}++; 389} 390$invisible_mark = '<IMG SRC="invisible.xbm">' if $invisible_mark eq 'xbm'; 391die $usage unless @ARGV == 1; 392$docu = shift(@ARGV); 393if ($docu =~ /.*\//) { 394 chop($docu_dir = $&); 395 $docu_name = $'; 396} else { 397 $docu_dir = '.'; 398 $docu_name = $docu; 399} 400unshift(@include_dirs, $docu_dir); 401$docu_name =~ s/\.te?x(i|info)?$//; # basename of the document 402 403$docu_doc = "$docu_name.html"; # document's contents 404if ($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 409} 410 411# 412# variables 413# 414$value{'html'} = 1; # predefine html (the output format) 415$value{'texi2html'} = '1.52a'; # predefine texi2html (the translator) 416# _foo: internal to track @foo 417foreach ('_author', '_title', '_subtitle', 418 '_settitle', '_setfilename') { 419 $value{$_} = ''; # prevent -w warnings 420} 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 427 428# 429# initial indexes 430# 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; 438 439# 440# can I use ISO8879 characters? (HTML+) 441# 442if ($use_iso) { 443 $things_map{'bullet'} = "•"; 444 $things_map{'copyright'} = "©"; 445 $things_map{'dots'} = "…"; 446 $things_map{'equiv'} = "≡"; 447 $things_map{'expansion'} = "→"; 448 $things_map{'point'} = "∗"; 449 $things_map{'result'} = "⇒"; 450} 451 452# 453# read texi2html extensions (if any) 454# 455$extensions = 'texi2html.ext'; # extensions in working directory 456if (-f $extensions) { 457 print "# reading extensions from $extensions\n" if $verbose; 458 require($extensions); 459} 460($progdir = $0) =~ s/[^\/]+$//; 461if ($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); 466 } 467} 468 469print "# reading from $docu\n" if $verbose; 470 471#+++############################################################################ 472# # 473# Pass 1: read source, handle command, variable, simple substitution # 474# # 475#---############################################################################ 476 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; 498 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 = ''; 503foreach (keys(%simple_map)) { 504 ($re = $_) =~ s/(\W)/\\$1/g; # protect regexp chars 505 $subst_code .= "s/\\\@$re/$simple_map{$_}/g;\n"; 506} 507foreach (keys(%things_map)) { 508 $subst_code .= "s/\\\@$_\\{\\}/$things_map{$_}/g;\n"; 509} 510if ($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/\\\@\\$_"; 519 } 520 $subst_code .= "([aeiou])/&\${1}$accent_map{$_};/gi;\n"; 521 } 522} 523eval("sub simple_substitutions { $subst_code }"); 524 525&init_input; 526while ($_ = &next_line) { 527 # 528 # remove \input on the first lines only 529 # 530 if ($first_line) { 531 next if /^\\input/; 532 $first_line = 0; 533 } 534 # 535 # parse texinfo tags 536 # 537 $tag = ''; 538 $end_tag = ''; 539 if (/^\@end\s+(\w+)\b/) { 540 $end_tag = $1; 541 } elsif (/^\@(\w+)\b/) { 542 $tag = $1; 543 } 544 # 545 # handle @ifhtml / @end ifhtml 546 # 547 if ($in_html) { 548 if ($end_tag eq 'ifhtml') { 549 $in_html = 0; 550 } else { 551 $tag2pro{$in_html} .= $_; 552 } 553 next; 554 } elsif ($tag eq 'ifhtml') { 555 $in_html = $PROTECTTAG . ++$html_num; 556 push(@lines, $in_html); 557 next; 558 } 559 # 560 # try to skip the line 561 # 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'; 567 } 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; 576 } 577 } 578 # 579 # try to remove inlined comments 580 # syntax from tex-mode.el comment-start-skip 581 # 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; 588 } 589 # 590 # analyze the tag 591 # 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'; 599 } 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'; 605 } 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); 622 } 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; 631 } 632 } 633 if (-e $file) { 634 &open($file); 635 print "# including $file\n" if $verbose; 636 } else { 637 warn "$ERROR Can't find $file, skipping"; 638 } 639 } else { 640 warn "$ERROR Bad include line: $_"; 641 } 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: $_"; 649 } 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: $_"; 657 } 658 next; 659 } elsif ($tag eq 'menu') { 660 unless ($show_menu) { 661 &skip_until($tag); 662 next; 663 } 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'); 683 } 684 push(@lines, &html_debug("\n", __LINE__)); 685 } else { 686 warn "$ERROR Bad table line: $_"; 687 } 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: $_"; 694 } 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: $_"; 709 } 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: $_"; 716 } 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.*//; 724 } 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"; 734 } 735 next; 736 } 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; 745 } 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"; 753 } 754 @args = split(/\s+/, &protect_html($_)); 755 foreach (@args) { 756 s/$;9/ /g; # unprotect spaces 757 s/$;7/\{/g; # ... { 758 s/$;8/\}/g; # ... } 759 } 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__); 771 } 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; 786 } 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"); 797 } 798 $dont_html = 1; 799 } 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; 812 } 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; 817 } 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'); 824 } 825 &html_pop_if(); 826 if (@tables) { 827 ($table_type, $in_table) = split($;, $tables[0]); 828 } else { 829 $in_table = 0; 830 } 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 836 } 837 next; 838 } 839 # 840 # misc things 841 # 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 855 # 856 # analyze the tag again 857 # 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'); 876 } 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"; 886 } 887 $toplevel = $level; 888 } 889 if ($level == $toplevel) { 890 &next_doc; 891 push(@lines, $SPLITTAG) if $split_num++; 892 push(@sections, $name); 893 } 894 } 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; 910 } 911 $node = ''; 912 } else { 913 print "# no node, section $name, level $level\n" 914 if $debug & $DEBUG_TOC; 915 } 916 # update TOC 917 while ($level > $curlevel) { 918 $curlevel++; 919 push(@toc_lines, "<UL>\n"); 920 } 921 while ($level < $curlevel) { 922 $curlevel--; 923 push(@toc_lines, "</UL>\n"); 924 } 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__)); 933 } 934 # update DOC 935 foreach $line (split(/\n+/, $_)) { 936 push(@lines, "$line\n"); 937 } 938 next; 939 } else { 940 warn "$ERROR Bad section line: $_"; 941 } 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; 957 } 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"; 969 } 970EOC 971 # 972 # dirty hack to see if I can put an invisible anchor... 973 # 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) . " "; 992 } 993 next; 994 } 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); 1006 } 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); 1015 } 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__)); 1023 } 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"); 1028 } 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'; 1038 } 1039 push(@lines, &html_debug("\n", __LINE__)); 1040 if ($deferred_ref) { 1041 push(@lines, &debug("$deferred_ref\n", __LINE__)); 1042 $deferred_ref = ''; 1043 } 1044 next; 1045 } elsif (/^\@tab\s+(.*)$/) { 1046 push(@lines, "<TD>$1</TD>\n"); 1047 next; 1048 } 1049 } 1050 } 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; 1058 } 1059 } elsif ($html_element eq 'body' || $html_element eq 'BLOCKQUOTE') { 1060 push(@lines, "<P>\n"); 1061 &html_push('P'); 1062 $_ = &debug($_, __LINE__); 1063 } 1064 # otherwise 1065 push(@lines, $_); 1066} 1067 1068# finish TOC 1069$level = 0; 1070while ($level < $curlevel) { 1071 $curlevel--; 1072 push(@toc_lines, "</UL>\n"); 1073} 1074 1075print "# end of pass 1\n" if $verbose; 1076 1077#+++############################################################################ 1078# # 1079# Pass 2/3: handle style, menu, index, cross-reference # 1080# # 1081#---############################################################################ 1082 1083@lines2 = (); # whole document (2nd pass) 1084@lines3 = (); # whole document (3rd pass) 1085$in_menu = 0; # am I inside a menu 1086 1087while (@lines) { 1088 $_ = shift(@lines); 1089 # 1090 # special case (protected sections) 1091 # 1092 if (/^$PROTECTTAG/o) { 1093 push(@lines2, $_); 1094 next; 1095 } 1096 # 1097 # menu 1098 # 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, $_); 1114 } 1115 next; 1116 } 1117 # 1118 # printindex 1119 # 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'; 1126 } 1127 eval("*ary = *$index"); 1128 @keys = keys(%ary); 1129 foreach $key (@keys) { 1130 $_ = $key; 1131 1 while s/<(\w+)>\`(.*)\´<\/\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; 1139 } 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; 1149 } 1150 } 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; 1161 } 1162 @refs = (); 1163 foreach (split(/$;/, $ary{$key})) { 1164 push(@refs, &anchor('', $_, $key, 0)); 1165 } 1166 push(@lines2, "<LI>" . join(", ", @refs) . "\n"); 1167 } 1168 push(@lines2, "</DIR>\n") if defined($last_letter); 1169 next; 1170 } 1171 # 1172 # simple style substitutions 1173 # 1174 $_ = &substitute_style($_); 1175 # 1176 # xref 1177 # 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 1186 } 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 = ''; 1195 } 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 1216 } 1217 } 1218 } 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"; 1238 } 1239 } 1240 # 1241 # try to guess bibliography references or glossary terms 1242 # 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"; 1253 } 1254 $_ = $post; 1255 } 1256 $_ = $done . $_; 1257 } 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"; 1269 } 1270 $_ = $post; 1271 } 1272 $_ = $done . $_; 1273 } 1274 } 1275 # otherwise 1276 push(@lines2, $_); 1277} 1278print "# end of pass 2\n" if $verbose; 1279 1280# 1281# split style substitutions 1282# 1283while (@lines2) { 1284 $_ = shift(@lines2); 1285 # 1286 # special case (protected sections) 1287 # 1288 if (/^$PROTECTTAG/o) { 1289 push(@lines3, $_); 1290 next; 1291 } 1292 # 1293 # split style substitutions 1294 # 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); 1314 } 1315 } 1316 if ($failed) { 1317 die "* Bad syntax (\@$style) after: $before\n"; 1318 } else { 1319 $text = &apply_style($style, $text); 1320 $_ = "$before$text$after"; 1321 } 1322 } 1323 } 1324 } 1325 # otherwise 1326 push(@lines3, $_); 1327} 1328print "# end of pass 3\n" if $verbose; 1329 1330#+++############################################################################ 1331# # 1332# Pass 4: foot notes, final cleanup # 1333# # 1334#---############################################################################ 1335 1336@foot_lines = (); # footnotes 1337@doc_lines = (); # final document 1338$end_of_para = 0; # true if last line is <P> 1339 1340while (@lines3) { 1341 $_ = shift(@lines3); 1342 # 1343 # special case (protected sections) 1344 # 1345 if (/^$PROTECTTAG/o) { 1346 push(@doc_lines, $_); 1347 $end_of_para = 0; 1348 next; 1349 } 1350 # 1351 # footnotes 1352 # 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); 1368 } 1369 } 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; 1381 } 1382 } 1383 # 1384 # remove unnecessary <P> 1385 # 1386 if (/^\s*<P>\s*$/) { 1387 next if $end_of_para++; 1388 } else { 1389 $end_of_para = 0; 1390 } 1391 # otherwise 1392 push(@doc_lines, $_); 1393} 1394print "# end of pass 4\n" if $verbose; 1395 1396#+++############################################################################ 1397# # 1398# Pass 5: print things # 1399# # 1400#---############################################################################ 1401 1402$header = <<EOT; 1403<!-- This HTML file has been created by $THISPROG 1404 from $docu on $TODAY --> 1405EOT 1406 1407$full_title = $value{'_title'} || $value{'_settitle'} || "Untitled Document"; 1408$title = $value{'_settitle'} || $full_title; 1409$_ = &substitute_style($full_title); 1410&unprotect_texi; 1411s/\n$//; # rmv last \n (if any) 1412$full_title = "<H1>" . join("</H1>\n<H1>", split(/\n/, $_)) . "</H1>\n"; 1413 1414# 1415# print ToC 1416# 1417if (!$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"; 1427 } 1428} 1429 1430# 1431# print footnotes 1432# 1433if (!$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"; 1443 } 1444} 1445 1446# 1447# print document 1448# 1449if ($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, $_); 1479 } 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"; 1487 } 1488 } 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; 1497 } 1498 if ($monolithic && @toc_lines) { 1499 &print_ruler; 1500 print FILE "<H1>Table of Contents</H1>\n"; 1501 &print(*toc_lines, FILE); 1502 } 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); 1509 } 1510 if ($monolithic || !@toc_lines) { 1511 &print_toplevel_footer; 1512 } else { 1513 &print_footer; 1514 } 1515 close(FILE); 1516 } else { 1517 warn "$ERROR Can't write to $docu_doc: $!\n"; 1518 } 1519} 1520 1521print "# that's all folks\n" if $verbose; 1522 1523#+++############################################################################ 1524# # 1525# Low level functions # 1526# # 1527#---############################################################################ 1528 1529sub update_sec_num { 1530 local($name, $level) = @_; 1531 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); 1539 } 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); 1547 } 1548 return(join('.', @normal_sec_num[0..$level])); 1549 } 1550} 1551 1552sub incr_sec_num { 1553 local($level, $l); 1554 $level = shift(@_); 1555 $_[$level]++; 1556 foreach $l ($level+1 .. 3) { 1557 $_[$l] = 0; 1558 } 1559} 1560 1561sub check { 1562 local($_, %seen, %context, $before, $match, $after); 1563 1564 while (<>) { 1565 if (/\@(\*|\.|\:|\@|\{|\})/) { 1566 $seen{$&}++; 1567 $context{$&} .= "> $_" if $verbose; 1568 $_ = "$`XX$'"; 1569 redo; 1570 } 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; 1579 } 1580 $match =~ s/^\@/X/; 1581 $_ = "$before$match$after"; 1582 redo; 1583 } 1584 } 1585 1586 foreach (sort(keys(%seen))) { 1587 if ($verbose) { 1588 print "$_\n"; 1589 print $context{$_}; 1590 } else { 1591 print "$_ ($seen{$_})\n"; 1592 } 1593 } 1594} 1595 1596sub open { 1597 local($name) = @_; 1598 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"; 1604 } 1605} 1606 1607sub init_input { 1608 @fhs = (); # hold the file handles to read 1609 @input_spool = (); # spooled lines to read 1610 $fh_name = 'FH000'; 1611 &open($docu); 1612} 1613 1614sub next_line { 1615 local($fh, $line); 1616 1617 if (@input_spool) { 1618 $line = shift(@input_spool); 1619 return($line); 1620 } 1621 while (@fhs) { 1622 $fh = $fhs[0]; 1623 $line = <$fh>; 1624 return($line) if $line; 1625 close($fh); 1626 shift(@fhs); 1627 } 1628 return(undef); 1629} 1630 1631# used in pass 1, use &next_line 1632sub skip_until { 1633 local($tag) = @_; 1634 local($_); 1635 1636 while ($_ = &next_line) { 1637 return if /^\@end\s+$tag\s*$/; 1638 } 1639 die "* Failed to find '$tag' after: " . $lines[$#lines]; 1640} 1641 1642# 1643# HTML stacking to have a better HTML output 1644# 1645 1646sub html_reset { 1647 @html_stack = ('html'); 1648 $html_element = 'body'; 1649} 1650 1651sub html_push { 1652 local($what) = @_; 1653 push(@html_stack, $html_element); 1654 $html_element = $what; 1655} 1656 1657sub html_push_if { 1658 local($what) = @_; 1659 push(@html_stack, $html_element) 1660 if ($html_element && $html_element ne 'P'); 1661 $html_element = $what; 1662} 1663 1664sub html_pop { 1665 $html_element = pop(@html_stack); 1666} 1667 1668sub html_pop_if { 1669 local($elt); 1670 1671 if (@_) { 1672 foreach $elt (@_) { 1673 if ($elt eq $html_element) { 1674 $html_element = pop(@html_stack) if @html_stack; 1675 last; 1676 } 1677 } 1678 } else { 1679 $html_element = pop(@html_stack) if @html_stack; 1680 } 1681} 1682 1683sub html_debug { 1684 local($what, $line) = @_; 1685 return("<!-- $line @html_stack, $html_element -->$what") 1686 if $debug & $DEBUG_HTML; 1687 return($what); 1688} 1689 1690# to debug the output... 1691sub debug { 1692 local($what, $line) = @_; 1693 return("<!-- $line -->$what") 1694 if $debug & $DEBUG_HTML; 1695 return($what); 1696} 1697 1698sub normalise_node { 1699 $_[0] =~ s/\s+/ /g; 1700 $_[0] =~ s/ $//; 1701 $_[0] =~ s/^ //; 1702} 1703 1704sub menu_entry { 1705 local($entry, $node, $descr) = @_; 1706 local($href); 1707 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): $_"; 1716 } 1717} 1718 1719sub do_ctrl { "^$_[0]" } 1720 1721sub do_email { 1722 local($addr, $text) = split(/,\s*/, $_[0]); 1723 1724 $text = $addr unless $text; 1725 &anchor('', "mailto:$addr", $text); 1726} 1727 1728sub do_sc { "\U$_[0]\E" } 1729 1730sub do_uref { 1731 local($url, $text) = split(/,\s*/, $_[0]); 1732 1733 $text = $url unless $text; 1734 &anchor('', $url, $text); 1735} 1736 1737sub do_url { &anchor('', $_[0], $_[0]) } 1738 1739sub do_diaeresis { return "&$_[0]uml;"; } 1740sub do_acuteaccent { return "&$_[0]acute;"; } 1741sub do_graveaccent { return "&$_[0]grave;"; } 1742sub do_tildeaccent { return "&$_[0]tilde;"; } 1743sub do_cedilla { return "&$_[0]cedil;"; } 1744sub do_circumflex { return "&$_[0]circ;"; } 1745 1746sub apply_style { 1747 local($texi_style, $text) = @_; 1748 local($style); 1749 1750 $style = $style_map{$texi_style}; 1751 if (defined($style)) { # known style 1752 if ($style =~ /^\"/) { # add quotes 1753 $style = $'; 1754 $text = "\`$text\´"; 1755 } 1756 if ($style =~ /^\&/) { # custom 1757 $style = $'; 1758 $text = &$style($text); 1759 } elsif ($style) { # good style 1760 $text = "<$style>$text</$style>"; 1761 } else { # no style 1762 } 1763 } else { # unknown style 1764 $text = undef; 1765 } 1766 return($text); 1767} 1768 1769# remove Texinfo styles 1770sub remove_style { 1771 local($_) = @_; 1772 s/\@\w+{([^\{\}]+)}/$1/g; 1773 return($_); 1774} 1775 1776sub substitute_style { 1777 local($_) = @_; 1778 local($changed, $done, $style, $text); 1779 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}$'"; 1792 } 1793 } 1794 $_ = $done . $_; 1795 } 1796 return($_); 1797} 1798 1799sub anchor { 1800 local($name, $href, $text, $newline) = @_; 1801 local($result); 1802 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); 1809} 1810 1811sub pretty_date { 1812 local(@MoY, $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst); 1813 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"); 1819} 1820 1821sub doc_name { 1822 local($num) = @_; 1823 1824 return("${docu_name}_$num.html"); 1825} 1826 1827sub next_doc { 1828 $docu_doc = &doc_name(++$doc_num); 1829} 1830 1831sub print { 1832 local(*lines, $fh) = @_; 1833 local($_); 1834 1835 while (@lines) { 1836 $_ = shift(@lines); 1837 if (/^$PROTECTTAG/o) { 1838 $_ = $tag2pro{$_}; 1839 } else { 1840 &unprotect_texi; 1841 } 1842 print $fh $_; 1843 } 1844} 1845 1846sub print_ruler { 1847 print FILE "<P><HR><P>\n"; 1848} 1849 1850sub print_header { 1851 local($_); 1852 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; 1861 } 1862 print FILE <<EOT; 1863<HTML> 1864<HEAD> 1865$header 1866<TITLE>$_</TITLE> 1867</HEAD> 1868<BODY> 1869EOT 1870} 1871 1872sub print_toplevel_header { 1873 local($_); 1874 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"; 1883 } 1884 } 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"; 1892 } 1893 } 1894 print FILE "<P>\n"; 1895} 1896 1897sub print_footer { 1898 print FILE <<EOT; 1899</BODY> 1900</HTML> 1901EOT 1902} 1903 1904sub print_toplevel_footer { 1905 &print_ruler; 1906 print FILE <<EOT; 1907This document was generated on $TODAY using the 1908<A HREF=\"$HOMEPAGE\">texi2html</A> 1909translator version 1.52a.</P> 1910EOT 1911 &print_footer; 1912} 1913 1914sub protect_texi { 1915 # protect @ { } ` ' 1916 s/\@\@/$;0/go; 1917 s/\@\{/$;1/go; 1918 s/\@\}/$;2/go; 1919 s/\@\`/$;3/go; 1920 s/\@\'/$;4/go; 1921} 1922 1923sub 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); 1934} 1935 1936sub unprotect_texi { 1937 s/$;0/\@/go; 1938 s/$;1/\{/go; 1939 s/$;2/\}/go; 1940 s/$;3/\`/go; 1941 s/$;4/\'/go; 1942} 1943 1944sub unprotect_html { 1945 local($what) = @_; 1946 $what =~ s/\&\#38;/\&/g; 1947 $what =~ s/\&\#60;/\</g; 1948 $what =~ s/\&\#62;/\>/g; 1949 return($what); 1950} 1951 1952sub byalpha { 1953 $key2alpha{$a} cmp $key2alpha{$b}; 1954} 1955 1956############################################################################## 1957 1958 # These next few lines are legal in both Perl and nroff. 1959 1960.00 ; # finish .ig 1961 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 1969texi2html \- a Texinfo to HTML converter 1970.SH SYNOPSIS 1971.B texi2html [options] file 1972.PP 1973.B texi2html -check [-verbose] files 1974.SH DESCRIPTION 1975.I Texi2html 1976converts the given Texinfo file to a set of HTML files. It tries to handle 1977most of the Texinfo commands. It creates hypertext links for cross-references, 1978footnotes... 1979.PP 1980It also tries to add links from a reference to its corresponding entry in the 1981bibliography (if any). It may also handle a glossary (see the 1982.B \-glossary 1983option). 1984.PP 1985.I Texi2html 1986creates several files depending on the contents of the Texinfo file and on 1987the chosen options (see FILES). 1988.PP 1989The HTML files created by 1990.I texi2html 1991are closer to TeX than to Info, that's why 1992.I texi2html 1993converts @iftex sections and not @ifinfo ones by default. You can reverse 1994this with the \-expandinfo option. 1995.SH OPTIONS 1996.TP 12 1997.B \-check 1998Check the given file and give the list of all things that may be Texinfo commands. 1999This may be used to check the output of 2000.I texi2html 2001to find the Texinfo commands that have been left in the HTML file. 2002.TP 2003.B \-expandinfo 2004Expand @ifinfo sections, not @iftex ones. 2005.TP 2006.B \-glossary 2007Use the section named 'Glossary' to build a list of terms and put links in the HTML 2008document from each term toward its definition. 2009.TP 2010.B \-invisible \fIname\fP 2011Use \fIname\fP to create invisible destination anchors for index links 2012(you can for instance use the invisible.xbm file shipped with this program). 2013This is a workaround for a known bug of many WWW browsers, including netscape. 2014.TP 2015.B \-I \fIdir\fP 2016Look also in \fIdir\fP to find included files. 2017.TP 2018.B \-menu 2019Show the Texinfo menus; by default they are ignored. 2020.TP 2021.B \-monolithic 2022Output only one file, including the table of contents and footnotes. 2023.TP 2024.B \-number 2025Number the sections. 2026.TP 2027.B \-split_chapter 2028Split the output into several HTML files (one per main section: 2029chapter, appendix...). 2030.TP 2031.B \-split_node 2032Split the output into several HTML files (one per node). 2033.TP 2034.B \-usage 2035Print usage instructions, listing the current available command-line options. 2036.TP 2037.B \-verbose 2038Give a verbose output. Can be used with the 2039.B \-check 2040option. 2041.PP 2042.SH FILES 2043By default 2044.I texi2html 2045creates the following files (foo being the name of the Texinfo file): 2046.TP 16 2047.B foo_toc.html 2048The table of contents. 2049.TP 2050.B foo.html 2051The document's contents. 2052.TP 2053.B foo_foot.html 2054The footnotes (if any). 2055.PP 2056When used with the 2057.B \-split 2058option, 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 2062file. 2063.PP 2064When used with the 2065.B \-monolithic 2066option, it creates only one file: 2067.B foo.html 2068.SH VARIABLES 2069.I texi2html 2070predefines the following variables: \fBhtml\fP, \fBtexi2html\fP. 2071.SH ADDITIONAL COMMANDS 2072.I texi2html 2073implements the following non-Texinfo commands (maybe they are in Texinfo now...): 2074.TP 16 2075.B @ifhtml 2076This indicates the start of an HTML section, this section will passed through 2077without any modification. 2078.TP 2079.B @end ifhtml 2080This indicates the end of an HTML section. 2081.SH VERSION 2082This is \fItexi2html\fP version 1.52a, 01/05/98. 2083.PP 2084The latest version of \fItexi2html\fP can be found in WWW, cf. URL 2085http://wwwinfo.cern.ch/dis/texi2html/ 2086.SH AUTHOR 2087The main author is Lionel Cons, CERN IT/DIS/OSE, Lionel.Cons@cern.ch. 2088Many other people around the net contributed to this program. 2089.SH COPYRIGHT 2090This program is the intellectual property of the European 2091Laboratory for Particle Physics (known as CERN). No guarantee whatsoever is 2092provided by CERN. No liability whatsoever is accepted for any loss or damage 2093of any kind resulting from any defect or inaccuracy in this information or 2094code. 2095.PP 2096CERN, 1211 Geneva 23, Switzerland 2097.SH "SEE ALSO" 2098GNU Texinfo Documentation Format, 2099HyperText Markup Language (HTML), 2100World Wide Web (WWW). 2101.SH BUGS 2102This program does not understand all Texinfo commands (yet). 2103.PP 2104TeX specific commands (normally enclosed in @iftex) will be 2105passed unmodified. 2106.ex 2107