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