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