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