#!/usr/local/bin/perl
'di ';
'ig 00 ';
#+##############################################################################
#                                                                              #
# File: texi2html                                                              #
#                                                                              #
# Description: Program to transform most Texinfo documents to HTML             #
#                                                                              #
#-##############################################################################

# From @(#)texi2html	1.52 01/05/98	
# $Id: texi2html,v 1.8 1999-07-30 10:37:05 obachman Exp $
# Homepage:
$T2H_HOMEPAGE = <<EOT;
http://www.mathematik.uni-kl.de/~obachman/Texi2html
EOT
# Authors:  
$T2H_AUTHORS = <<EOT;
Written (mainly) by: Lionel Cons, Lionel.Cons\@cern.ch
Currently maintained by : Olaf Bachmann, obachman\@mathematik.uni-kl.de
EOT
# Version:
$THISVERSION = "1.58";
$THISPROG = "texi2html $THISVERSION";	# program name and version
  
# The man page for this program is included at the end of this file and can be
# viewed using the command 'nroff -man texi2html'.
# Please read the copyright at the end of the man page.

$T2H_TODAY = &pretty_date;		# like "20 September 1993"
($T2H_USER = (getpwuid ($<))[6]) =~ s/,.*//; # Who am i 

#+++############################################################################
#                                                                              #
# Initialization                                                               #
# Pasted content of File $T2H_HOME/texi2html.init                              #
#                                                                              #
#---############################################################################

require "$ENV{T2H_HOME}/texi2html.init"; # Makefile:include

#+++############################################################################
#                                                                              #
# Constants                                                                    #
#                                                                              #
#---############################################################################

$DEBUG_TOC   =  1;
$DEBUG_INDEX =  2;
$DEBUG_BIB   =  4;
$DEBUG_GLOSS =  8;
$DEBUG_DEF   = 16;
$DEBUG_HTML  = 32;
$DEBUG_USER  = 64;
$DEBUG_L2H   = 128;


$BIBRE = '\[[\w\/-]+\]';		# RE for a bibliography reference
$FILERE = '[\/\w.+-]+';			# RE for a file name
$VARRE = '[^\s\{\}]+';			# RE for a variable name
$NODERE = '[^@{}:\'`",]+';		# RE for a node name
$NODESRE = '[^@{}:\'`"]+';		# RE for a list of node names
$XREFRE = '[^@{}]+';			# RE for a xref (should use NODERE)

$ERROR = "***";			        # prefix for errors and warnings
                                        # program home page
$PROTECTTAG = "_ThisIsProtected_";	# tag to recognize protected sections

$CHAPTEREND = "<!-- End chapter -->\n"; # to know where a chpater ends
$SECTIONEND = "<!-- End section -->\n"; # to know where section ends
$TOPEND     = "<!-- End top     -->\n"; # to know where top ends

  
#
# language dependent constants
#
#$LDC_SEE = 'see';
#$LDC_SECTION = 'section';
#$LDC_IN = 'in';
#$LDC_TOC = 'Table of Contents';
#$LDC_GOTO = 'Go to the';
#$LDC_FOOT = 'Footnotes';
#TODO: @def* shortcuts

#
# pre-defined indices
#
%predefined_index = (
		    'cp', 'c',
		    'fn', 'f',
		    'vr', 'v',
		    'ky', 'k',
		    'pg', 'p',
		    'tp', 't',
	            );

#
# valid indices
#
%valid_index = (
		    'c', 1,
		    'f', 1,
		    'v', 1,
		    'k', 1,
		    'p', 1,
		    't', 1,
		);

#
# texinfo section names to level
#
%sec2level = (
	      'top', 0,
	      'chapter', 1,
	      'unnumbered', 1,
	      'majorheading', 1,
	      'chapheading', 1,
	      'appendix', 1,
	      'section', 2,
	      'unnumberedsec', 2,
	      'heading', 2,
	      'appendixsec', 2,
	      'appendixsection', 2,
	      'subsection', 3,
	      'unnumberedsubsec', 3,
	      'subheading', 3,
	      'appendixsubsec', 3,
	      'subsubsection', 4,
	      'unnumberedsubsubsec', 4,
	      'subsubheading', 4,
	      'appendixsubsubsec', 4,
	      );

#
# accent map, TeX command to ISO name
#
%accent_map = (
	       '"',  'uml',
	       '~',  'tilde',
	       '^',  'circ',
	       '`',  'grave',
	       '\'', 'acute',
	       );

#
# texinfo "simple things" (@foo) to HTML ones
#
%simple_map = (
	       # cf. makeinfo.c
	       "*", "<BR>",		# HTML+
	       " ", " ",
	       "\t", " ",
  	       "-", "&#173;",	# soft hyphen
	       "\n", "\n",
	       "|", "",
	       'tab', '<\/TD><TD>',
	       # spacing commands
	       ":", "",
	       "!", "!",
	       "?", "?",
	       ".", ".",
	       "-", "",
	       );

#
# texinfo "things" (@foo{}) to HTML ones
#
%things_map = (
	       'TeX', 'TeX',
	       'br', '<P>',		# paragraph break
	       'bullet', '*',
	       'copyright', '(C)',
	       'dots', '...',
	       'equiv', '==',
	       'error', 'error-->',
	       'expansion', '==>',
	       'minus', '-',
	       'point', '-!-',
	       'print', '-|',
	       'result', '=>',
	       'today', $T2H_TODAY,
	       'aa', '&aring;',
	       'AA', '&Aring;',
	       'ae', '&aelig;',
	       'AE', '&AElig;',
	       'o',  '&oslash;',
	       'O',  '&Oslash;',
	       'ss', '&szlig;',
	       );

#
# texinfo styles (@foo{bar}) to HTML ones
#
%style_map = (
	      'asis', '',
	      'b', 'B',
	      'cite', 'CITE',
	      'code', 'CODE',
	      'ctrl', '&do_ctrl',	# special case
	      'dfn', 'EM',		# DFN tag is illegal in the standard
	      'dmn', '',		# useless
	      'email', '&do_email',     # insert a clickable email address
	      'emph', 'EM',
	      'file', '"TT',		# will put quotes, cf. &apply_style
	      'i', 'I',
	      'kbd', 'KBD',
	      'key', 'KBD',
	      'math', '&do_math',
	      'r', '',			# unsupported
	      'samp', '"SAMP',		# will put quotes, cf. &apply_style
	      'sc', '&do_sc',		# special case
	      'strong', 'STRONG',
	      't', 'TT',
	      'titlefont', '',		# useless
	      'uref', '&do_uref',       # insert a clickable URL
	      'url', '&do_url',         # insert a clickable URL
	      'var', 'VAR',
	      'w', '',			# unsupported
	      );

#
# texinfo format (@foo/@end foo) to HTML ones
#
%format_map = (
	       'display', 'PRE',
	       'example', 'PRE',
	       'format', 'PRE',
	       'lisp', 'PRE',
	       'quotation', 'BLOCKQUOTE',
	       'smallexample', 'PRE',
	       'smalllisp', 'PRE',
	       # lists
	       'itemize', 'UL',
	       'enumerate', 'OL',
	       # poorly supported
	       'flushleft', 'PRE',
	       'flushright', 'PRE',
	       );

#
# texinfo definition shortcuts to real ones
#
%def_map = (
	    # basic commands
	    'deffn', 0,
	    'defvr', 0,
	    'deftypefn', 0,
	    'deftypevr', 0,
	    'defcv', 0,
	    'defop', 0,
	    'deftp', 0,
	    # basic x commands
	    'deffnx', 0,
	    'defvrx', 0,
	    'deftypefnx', 0,
	    'deftypevrx', 0,
	    'defcvx', 0,
	    'defopx', 0,
	    'deftpx', 0,
	    # shortcuts
	    'defun', 'deffn Function',
	    'defmac', 'deffn Macro',
	    'defspec', 'deffn {Special Form}',
	    'defvar', 'defvr Variable',
	    'defopt', 'defvr {User Option}',
	    'deftypefun', 'deftypefn Function',
	    'deftypevar', 'deftypevr Variable',
	    'defivar', 'defcv {Instance Variable}',
	    'defmethod', 'defop Method',
	    # x shortcuts
	    'defunx', 'deffnx Function',
	    'defmacx', 'deffnx Macro',
	    'defspecx', 'deffnx {Special Form}',
	    'defvarx', 'defvrx Variable',
	    'defoptx', 'defvrx {User Option}',
	    'deftypefunx', 'deftypefnx Function',
	    'deftypevarx', 'deftypevrx Variable',
	    'defivarx', 'defcvx {Instance Variable}',
	    'defmethodx', 'defopx Method',
	    );

#
# things to skip
#
%to_skip = (
	    # comments
	    'c', 1,
	    'comment', 1,
            'ifnotinfo', 1,
            'ifnottex', 1,
	    'ifhtml', 1,
	    'end ifhtml', 1,
            'end ifnotinfo', 1,
            'end ifnottex', 1,
	    # useless
	    'detailmenu', 1,
            'direntry', 1,
	    'contents', 1,
	    'shortcontents', 1,
	    'summarycontents', 1,
	    'footnotestyle', 1,
	    'end ifclear', 1,
	    'end ifset', 1,
	    'titlepage', 1,
	    'end titlepage', 1,
	    # unsupported commands (formatting)
	    'afourpaper', 1,
	    'cropmarks', 1,
	    'finalout', 1,
	    'headings', 1,
            'sp', 1,
	    'need', 1,
	    'page', 1,
	    'setchapternewpage', 1,
	    'everyheading', 1,
	    'everyfooting', 1,
	    'evenheading', 1,
	    'evenfooting', 1,
	    'oddheading', 1,
	    'oddfooting', 1,
	    'smallbook', 1,
	    'vskip', 1,
	    'filbreak', 1,
	    'paragraphindent', 1,
	    # unsupported formats
	    'cartouche', 1,
	    'end cartouche', 1,
	    'group', 1,
	    'end group', 1,
	    );

#+++############################################################################
#                                                                              #
# Argument parsing, initialisation                                             #
#                                                                              #
#---############################################################################

#
# flush stdout and stderr after every write
#
select(STDERR);
$| = 1;
select(STDOUT);
$| = 1;

%value = ();				# hold texinfo variables, see also -D

$use_bibliography = 1;
$use_acc = 0;
$usage = <<EOT;
This is $THISPROG
To convert a Texinfo file to HMTL: $0 [options] file
 where options can be:
  -expandinfo         : use \@ifinfo sections, not \@iftex
  -glossary           : handle a glossary
  -invisible name     : use 'name' as an invisible anchor
  -Dname              : define name like with \@set
  -I dir              : search also for files in 'dir'
  -index_file file    : use 'file' as index file
  -menu               : handle menus
  -number             : number sections
  -split node|chapter : split on node or chapter 
  -short_ref          : cross references without section numbers
  -l2h                : use latex2html for \@math, \@tex, and \@sc 
  -l2h_latex2html prog: use 'prog' as latex2html program 
                        (default: 'latex2html')
  -l2h_tmp dir        : use 'dir' as temp dir for latex2html
  -l2h_clean          : remove temporary files generated by l2h extension
  -l2h_skip           : skip latex2html run (needs temporary files)
  -init_file 'file'   : use 'file' for texi2html and latex2html initialization 
  -sidx               : index jump label to top of section
  -usage              : print usage instructions
  -verbose            : verbose output
To check converted files: $0 -check [-verbose] files
EOT

while (@ARGV && $ARGV[0] =~ /^-/) {
    $_ = shift(@ARGV);
    if (/^-acc$/)            { $use_acc = 1; next; }
    if (/^-D(.+)?$/)         { $value{$1 || shift(@ARGV)} = 1; next; }
    if (/^-d(ebug)?(\d+)?$/) { $T2H_DEBUG = $2 || shift(@ARGV); next; }
    if (/^-doctype$/)        { $T2H_DOCTYPE = shift(@ARGV); next; }
    if (/^-c(heck)?$/)       { $T2H_CHECK = 1; next; }
    if (/^-e(xpand)?$/)      { $T2H_EXPAND = shift(@ARGV); next; }
    if (/^-g(lossary)?$/)    { $T2H_USE_GLOSSARY = 1; next; }
    if (/^-i(nvisible)?$/)   { $T2H_INVISIBLE_MARK = shift(@ARGV); next; }
    if (/^-I(.+)?$/)         { push(@T2H_INCLUDE_DIRS, $1 || shift(@ARGV)); next; }
    if (/^-iso$/)            { $T2H_USE_ISO = 1; next; }
    if (/^-init_file$/)      
    { 
      $init_file = shift(@ARGV); 
      if (-f $init_file)
      {
	print "# reading initialization file from $init_file\n" 
	  if ($T2H_VERBOSE);
	require($init_file);
      }
      else
      {
	print "$ERROR Error: can't read init file $int_file\n";
	$init_file = '';
      }
      next; 
    }
    if (/^-l2h$/)            { $T2H_L2H     = 1;            next; }
    if (/^-l2h_l2h$/)        { $T2H_L2H_L2H = shift(@ARGV); next; }
    if (/^-l2h_skip$/)       { $T2H_L2H_SKIP= 1;            next; }
    if (/^-l2h_tmp$/)        { $T2H_L2H_TMP = shift(@ARGV); next; }
    if (/^-l2h_clean$/)      { $T2H_L2H_CLEAN= 1;            next; }
    if (/^-m(enu)?$/)        { $T2H_SHOW_MENU = 1; next; }
    if (/^-nu(mber)?$/)      { $T2H_NUMBER_SECTIONS = 1; next; }
    if (/^-o(ut_file)?$/)    { $T2H_OUT = shift (@ARGV); 
                               undef $T2H_SPLIT; next;}    
    if (/^-p(refix)?$/)      { $T2H_PREFIX = shift(@ARGV); next; }
    if (/^-su(bdir)?$/)      { $T2H_SUBDIR = shift(@ARGV); next; }
    if (/^-short_e(xtn)?$/)  { $T2H_SHORTEXTN = 1; next; }
    if (/^-short_r(ef)?$/)   { $T2H_SHORT_REF = 1; next; }
    if (/^-si(dx)?$/)        { $T2H_SECTION_IDX = 1; next; }
    if (/^-s(plit)?$/)       { $T2H_SPLIT = shift(@ARGV); next;}
    if (/^-t(op_file)?$/)    { $T2H_TOP_FILE = shift (@ARGV); next;}    
    if (/^-v(erbose)?$/)     { $T2H_VERBOSE = 1; next; }
    if (/^-no_v(erbose)?$/)  { $T2H_VERBOSE = 0; next; }
    if (/^-vers(ion)?$/)     { print "$THISPROGRAM\n"; exit;}
    die "Unknown option: $_\n$usage";
}
if ($T2H_CHECK) {
    die "Need file to check\n$usage" unless @ARGV > 0;
    &check;
    exit;
}

if ($T2H_EXPAND eq 'info') 
{
  $to_skip{'ifinfo'} = 1;
  $to_skip{'end ifinfo'} = 1;
} 
elsif ($T2H_EXPAND eq 'tex')
{
  $to_skip{'iftex'} = 1;
  $to_skip{'end iftex'} = 1;
  
}

$T2H_INVISIBLE_MARK = '<IMG SRC="invisible.xbm">' if $T2H_INVISIBLE_MARK eq 'xbm';

#
# file name buisness
#
die "Need exactly one file to translate\n$usage" unless @ARGV == 1;
$docu = shift(@ARGV);
if ($docu =~ /.*\//) {
    chop($docu_dir = $&);
    $docu_name = $';
} else {
    $docu_dir = '.';
    $docu_name = $docu;
}
unshift(@T2H_INCLUDE_DIRS, $docu_dir);
$docu_name =~ s/\.te?x(i|info)?$//;	# basename of the document
$docu_name = $T2H_PREFIX if ($T2H_PREFIX);

# subdir
if ($T2H_SUBDIR && ! $T2H_OUT)
{
  $T2H_SUBDIR =~ s|/*$||;
  unless (-d "$T2H_SUBDIR" && -w "$T2H_SUBDIR")
  {
    if ( mkdir($T2H_SUBDIR, oct(755)))
    {
      print "# created directory $T2H_SUBDIR\n" if ($T2H_VERBOSE);
    }
    else
    {
      warn "$ERROR can't create directory $T2H_SUBDIR. Put results into current directory\n";
      $T2H_SUBDIR = '';
    }
  }
}

if ($T2H_SUBDIR && ! $T2H_OUT)
{
  $docu_rdir = "$T2H_SUBDIR/";
  print "# putting result files into directory $docu_rdir\n" if ($T2H_VERBOSE);
}
else
{
  if ($T2H_OUT && $T2H_OUT =~ m|(.*)/|)
  {
    $docu_rdir = "$1/";
    print "# putting result files into directory $docu_rdir\n" if ($T2H_VERBOSE);
  }
  else
  {
    print "# putting result files into current directory \n" if ($T2H_VERBOSE);
    $docu_rdir = '';
  }
}

# extension
if ($T2H_SHORTEXTN)
{
  $docu_ext = "htm";
}
else
{
  $docu_ext = "html";
}
if ($T2H_TOP_FILE =~ /\..*$/)
{
  $T2H_TOP_FILE = $`.".$docu_ext";
}
else
{
  $T2H_TOP_FILE .= ".$docu_ext";
}

# result files
if (! $T2H_OUT && ($T2H_SPLIT =~ /section/i || $T2H_SPLIT =~ /node/i))
{
  $T2H_SPLIT = 'section';
}
elsif (! $T2H_OUT && $T2H_SPLIT =~ /chapter/i)
{
  $T2H_SPLIT = 'chapter'
}
else
{
  undef $T2H_SPLIT;
}

$docu_doc = "$docu_name.$docu_ext";		# document's contents
$docu_doc_file = "$docu_rdir$docu_doc";
if ($T2H_SPLIT) 
{
  $docu_toc  = "${docu_name}_toc.$docu_ext"; # document's table of contents
  $docu_stoc = "${docu_name}_ovr.$docu_ext"; # document's short toc
  $docu_foot = "${docu_name}_fot.$docu_ext"; # document's footnotes
  $docu_about = "${docu_name}_abt.$docu_ext"; # about this document
  $docu_top  = $T2H_TOP_FILE;
}
else
{
  if ($T2H_OUT)
  {
    $docu_doc = $T2H_OUT;
    $docu_doc =~ s|.*/||;
  }
  $docu_toc = $docu_foot = $docu_stoc = $docu_about = $docu_top = $docu_doc;
}

$docu_toc_file  = "$docu_rdir$docu_toc";
$docu_stoc_file = "$docu_rdir$docu_stoc";
$docu_foot_file = "$docu_rdir$docu_foot";
$docu_about_file = "$docu_rdir$docu_about";
$docu_top_file  = "$docu_rdir$docu_top";

#
# variables
#
$value{'html'} = 1;			# predefine html (the output format)
$value{'texi2html'} = $THISVERSION;	# predefine texi2html (the translator)
# _foo: internal to track @foo
foreach ('_author', '_title', '_subtitle',
	 '_settitle', '_setfilename') {
    $value{$_} = '';		        # prevent -w warnings
}
%node2sec = ();				# node to section name
%sec2node = ();				# section to node name
%node2href = ();			# node to HREF
%node2next = ();			# node to next
%node2prev = ();			# node to prev
%node2up   = ();			# node to up
%bib2href = ();				# bibliography reference to HREF
%gloss2href = ();			# glossary term to HREF
@sections = ();				# list of sections
%tag2pro = ();				# protected sections

#
# initial indexes
#
$bib_num = 0;
$foot_num = 0;
$gloss_num = 0;
$idx_num = 0;
$sec_num = 0;
$doc_num = 0;
$html_num = 0;

#
# can I use ISO8879 characters? (HTML+)
#
if ($T2H_USE_ISO) {
    $things_map{'bullet'} = "&bull;";
    $things_map{'copyright'} = "&copy;";
    $things_map{'dots'} = "&hellip;";
    $things_map{'equiv'} = "&equiv;";
    $things_map{'expansion'} = "&rarr;";
    $things_map{'point'} = "&lowast;";
    $things_map{'result'} = "&rArr;";
}

#
# read texi2html extensions (if any)
#
$extensions = 'texi2html.ext'; # extensions in working directory
if (-f $extensions) {
    print "# reading extensions from $extensions\n" if $T2H_VERBOSE;
    require($extensions);
}
($progdir = $0) =~ s/[^\/]+$//;
if ($progdir && ($progdir ne './')) {
    $extensions = "${progdir}texi2html.ext"; # extensions in texi2html directory
    if (-f $extensions) {
	print "# reading extensions from $extensions\n" if $T2H_VERBOSE;
	require($extensions);
    }
}


print "# reading from $docu\n" if $T2H_VERBOSE;

#########################################################################
#
# latex2html stuff
# 
# latex2html conversions consist of three stages:
# 1) ToLatex: Put "latex" code into a latex file
# 2) ToHtml: Use latex2html to generate corresponding html code and images
# 3) FromHtml: Extract generated code and images from latex2html run
#

##########################
# default settings
#

# defaults for files and names

sub l2h_Init 
{
  local($root) = @_;
  
  return 0 unless ($root);
  
  $l2h_name =  "${root}_l2h";
  
  $l2h_latex_file = "$docu_rdir${l2h_name}.tex";
  $l2h_cache_file = "${docu_rdir}l2h_cache.pm";
  $T2H_L2H_L2H = "latex2html" unless ($T2H_L2H_L2H);
  
  # destination dir -- generated images are put there, should be the same
  # as dir of enclosing html document -- 
  $l2h_html_file = "$docu_rdir${l2h_name}.html";
  $l2h_prefix = "${l2h_name}_";
  return 1;
}


##########################
# 
# First stage: Generation of Latex file
# Initialize with: l2h_InitToLatex
# Add content with: l2h_ToLatex($text) --> HTML placeholder comment
# Finish with: l2h_FinishToLatex
# 

$l2h_latex_preample = <<EOT;
% This document was automatically generated by the l2h extenstion of texi2html
% DO NOT EDIT !!!
\\documentclass{article}
\\usepackage{html}
\\begin{document}
EOT

$l2h_latex_closing = <<EOT;
\\end{document}
EOT

# return used latex 1, if l2h could be initalized properly, 0 otherwise
sub l2h_InitToLatex
{
  %l2h_to_latex = ();
  unless ($T2H_L2H_SKIP)
  {
    unless (open(L2H_LATEX, ">$l2h_latex_file"))
    {
      warn "$ERROR Error l2h: Can't open latex file '$latex_file' for writing\n";
      return 0;
    }  
    print "# l2h: use ${l2h_latex_file} as latex file\n" if ($T2H_VERBOSE);
    print L2H_LATEX $l2h_latex_preample;
  }
  # open database for caching
  l2h_InitCache();
  $l2h_latex_count = 0;
  $l2h_to_latex_count = 0;
  $l2h_cached_count = 0;
  return  1;
}

# print text (1st arg) into latex file (if not already there), return
# HTML commentary which can be later on replaced by the latex2html
# generated text
sub l2h_ToLatex
{
  my($text) = @_;
  my($count);
  
  $l2h_to_latex_count++;
  $text =~ s/(\s*)$//;
  
  # try whether we can cache it
  my $cached_text = l2h_FromCache($text);
  if ($cached_text)
  {
    $l2h_cached_count++;
    return $cached_text;
  }
  
  # try whether we have text already on things to do
  unless ($count = $l2h_to_latex{$text})
  {
    $count = $l2h_latex_count;
    $l2h_latex_count++;
    $l2h_to_latex{$text} = $count;
    $l2h_to_latex[$count] = $text;
    unless ($T2H_L2H_SKIP)
    {
      print L2H_LATEX "\\begin{rawhtml}\n";
      print L2H_LATEX "<!-- l2h_begin ${l2h_name} ${count} -->\n";
      print L2H_LATEX "\\end{rawhtml}\n";
      
      print L2H_LATEX "$text\n";
      
      print L2H_LATEX "\\begin{rawhtml}\n";
      print L2H_LATEX "<!-- l2h_end ${l2h_name} ${count} -->\n";
      print L2H_LATEX "\\end{rawhtml}\n";
    }
  }
  return "<!-- l2h_replace ${l2h_name} ${count} -->"; 
}

# print closing into latex file and close it
sub l2h_FinishToLatex
{
  local ($reused);
  
  $reused = $l2h_to_latex_count - $l2h_latex_count - $l2h_cached_count;
  unless ($T2H_L2H_SKIP)
  {
    print L2H_LATEX $l2h_latex_closing;
    close(L2H_LATEX);
  }
  print "# l2h: finished to latex ($l2h_cached_count cached, $reused reused, $l2h_latex_count contents)\n" if ($T2H_VERBOSE);
  unless ($l2h_latex_count)
  {
    l2h_Finish();
    return 0;
  }
  return 1;
}

###################################
# Second stage: Use latex2html to generate corresponding html code and images
#
# l2h_ToHtml([$l2h_latex_file, [$l2h_html_dir]]):
#   Call latex2html on $l2h_latex_file
#   Put images (prefixed with $l2h_name."_") and html file(s) in $l2h_html_dir
#   Return 1, on success
#          0, otherwise
#
sub l2h_ToHtml
{
  local($call, $ext, $root, $dotbug);
  
  if ($T2H_L2H_SKIP)
  {
    print "# l2h: skipping latex2html run\n" if ($T2H_VERBOSE);
    return 1;
  }
  
  # Check for dot in directory where dvips will work
  if ($T2H_L2H_TMP)
  {
    if ($T2H_L2H_TMP =~ /\./)
    {
      warn "$ERROR Warning l2h: l2h_tmp dir contains a dot. Use /tmp, instead\n";
      $dotbug = 1;
    }
  }
  else
  {
    if (&getcwd =~ /\./)
    {
     warn "$ERROR Warning l2h: current dir contains a dot. Use /tmp as l2h_tmp dir \n";
     $dotbug = 1;
   }
  }
  # fix it, if necessary and hope that it works 
  $T2H_L2H_TMP = "/tmp" if ($dotbug);
    
  $call = $T2H_L2H_L2H;
  # use init file, if specified
  $call = $call . " -init_file " . $init_file if ($init_file && -f $init_file);
  # set output dir
  $call .=  ($docu_rdir ? " -dir $docu_rdir" : " -no_subdir");
  # use l2h_tmp, if specified
  $call = $call . " -tmp $T2H_L2H_TMP" if ($T2H_L2H_TMP);
  # options we want to be sure of
  $call = $call ." -address 0 -info 0 -split 0 -no_navigation -no_auto_link";
  $call = $call ." -prefix ${l2h_prefix} $l2h_latex_file"; 

  print "# l2h: executing '$call'\n" if ($T2H_VERBOSE);
  if (system($call))
  {
    warn "l2h ***Error: '${call}' did not succeed\n";
    return 0;
  }
  else
  {
    print "# l2h: latex2html finished successfully\n" if ($T2H_VERBOSE);
    return 1;
  }
}

# this is directly pasted over from latex2html
sub getcwd {
    local($_) = `pwd`;

    die "'pwd' failed (out of memory?)\n"
	unless length;
    chop;
    $_;
}


##########################
# Third stage: Extract generated contents from latex2html run
# Initialize with: l2h_InitFromHtml
#   open $l2h_html_file for reading
#   reads in contents into array indexed by numbers
#   return 1,  on success -- 0, otherwise
# Extract Html code with: l2h_FromHtml($text)
#   replaces in $text all previosuly inserted comments by generated html code
#   returns (possibly changed) $text
# Finish with: l2h_FinishFromHtml
#   closes $l2h_html_dir/$l2h_name.".$docu_ext" 

sub l2h_InitFromHtml
{
  local($h_line, $h_content, $count, %l2h_img);

  if (! open(L2H_HTML, "<${l2h_html_file}"))
  {
    print "$ERROR Error l2h: Can't open ${l2h_html_file} for reading\n";
    return 0;
  }
  print "# l2h: use ${l2h_html_file} as html file\n" if ($T2H_VERBOSE);

  $l2h_html_count = 0;
  
  while ($h_line = <L2H_HTML>)
  {
    if ($h_line =~ /^<!-- l2h_begin $l2h_name ([0-9]+) -->/)
    {
      $count = $1;
      $h_content = "";
      while ($h_line = <L2H_HTML>)
      {
	if ($h_line =~ /^<!-- l2h_end $l2h_name $count -->/)
	{
	  chomp $h_content;
	  chomp $h_content;
	  $l2h_html_count++;
	  $h_content = l2h_ToCache($count, $h_content);
	  $l2h_from_html[$count] = $h_content;
	  $h_content = '';
	  last;
	}
	$h_content = $h_content.$h_line;
      }
      if ($hcontent)
      {
	print "$ERROR Warning l2h: l2h_end $l2h_name $count not found\n" 
	  if ($T2H_VERBOSE);
	close(L2H_HTML);
	return 0;
      }
    }
  }
  print "# l2h: Got $l2h_html_count of $l2h_latex_count html contents\n"
    if ($T2H_VERBOSE);

  close(L2H_HTML);
  return 1;
}

sub l2h_FromHtml
{
  local($text) = @_;
  local($done, $to_do, $count);
  
  $to_do = $text;
  
  while ($to_do =~ /([^\000]*)<!-- l2h_replace $l2h_name ([0-9]+) -->([^\000]*)/)
  {
    $to_do = $1;
    $count = $2;
    $done = $3.$done;
    
    $done = "<!-- l2h_end $l2h_name $count -->".$done
      if ($T2H_DEBUG & $DEBUG_L2H);

    $done = &l2h_ExtractFromHtml($count) . $done;

    $done = "<!-- l2h_begin $l2h_name $count -->".$done
      if ($T2H_DEBUG & $DEBUG_L2H);
  }
  return $to_do.$done;
}


sub l2h_ExtractFromHtml
{
  local($count) = @_;
  
  return $l2h_from_html[$count] if ($l2h_from_html[$count]);
  
  if ($count >= 0 && $count < $l2h_latex_count)
  {
    # now we are in trouble
    local($l_l2h, $_);

    $l2h_extract_error++;
    print "$ERROR l2h: can't extract content $count from html\n" 
      if ($T2H_VERBOSE);
    # try simple (ordinary) substition (without l2h)
    $l_l2h = $T2H_L2H;
    $T2H_L2H = 0;
    $_ = $l2h_to_latex{$count};
    $_ = &substitute_style($_); 
    &unprotect_texi;
    $_ = "<!-- l2h: ". __LINE__ . " use texi2html -->" . $_
      if ($T2H_DEBUG & $DEBUG_L2H);
    $T2H_L2H = $l_l2h;
    return $_;
  }
  else
  {
    # now we have been incorrectly called
    $l2h_range_error++;
    print "$ERROR l2h: Request of $count content which is out of valide range [0,$l2h_latex_count)\n";
    return "<!-- l2h: ". __LINE__ . " out of range count $count -->"
      if ($T2H_DEBUG & $DEBUG_L2H);
    return "<!-- l2h: out of range count $count -->";
  }
}
    
sub l2h_FinishFromHtml
{
  if ($T2H_VERBOSE)
  {
    if ($l2h_extract_error + $l2h_range_error)
    {
      print "# l2h: finished from html ($l2h_extract_error extract and $l2h_range_error errors)\n";
    }
    else
    {
      print "# l2h: finished from html (no errors)\n";
    }
  }
}

sub l2h_Finish
{
  l2h_StoreCache();
  if ($T2H_L2H_CLEAN)
  {
    print "# l2h: removing temporary files generated by l2h extension\n"
      if $T2H_VERBOSE;
    while (<"$docu_rdir$l2h_name"*>)
    {
      unlink $_;
    }
  }
  print "# l2h: Finished\n" if $T2H_VERBOSE;
  return 1;
}

##############################
# stuff for l2h caching
#

# I tried doing this with a dbm data base, but it did not store all
# keys/values. Hence, I did as latex2html does it
sub l2h_InitCache
{
  if (-r "$l2h_cache_file")
  {
    my $rdo = do "$l2h_cache_file";
    warn("$ERROR l2h Error: could not load $docu_rdir$l2h_cache_file: $@\n")
      unless ($rdo);
  }
}

sub l2h_StoreCache
{
  return unless $l2h_latex_count;
  
  my ($key, $value);
  open(FH, ">$l2h_cache_file") || return warn"$ERROR l2h Error: could not open $docu_rdir$l2h_cache_file for writing: $!\n";

  
  while (($key, $value) = each %l2h_cache)
  {
    # escape stuff
    $key =~ s|/|\\/|g;
    $key =~ s|\\\\/|\\/|g;
    # weird, a \ at the end of the key results in an error
    # maybe this also broke the dbm database stuff
    $key =~ s|\\$|\\\\|;
    $value =~ s/\|/\\\|/g; 
    $value =~ s/\\\\\|/\\\|/g; 
    $value =~ s|\\\\|\\\\\\\\|g;
    print FH "\n\$l2h_cache_key = q/$key/;\n";
    print FH "\$l2h_cache{\$l2h_cache_key} = q|$value|;\n";
  }
  print FH "1;";
  close(FH);
}

# return cached html, if it exists for text, and if all pictures
# are there, as well
sub l2h_FromCache
{
  my $text = shift;
  my $cached = $l2h_cache{$text};
  if ($cached)
  {
    while ($cached =~ m/SRC="(.*?)"/g)
    {
      unless (-e "$docu_rdir$1")
      {
	return undef;
      }
    }
    return $cached;
  }
  return undef;
}

# insert generated html into cache, move away images, 
# return transformed html
$maximage = 1;
sub l2h_ToCache
{
  my $count = shift;
  my $content = shift;
  my @images = ($content =~ /SRC="(.*?)"/g);
  my ($src, $dest);

  for $src (@images)
  {
    $dest = $l2h_img{$src};
    unless ($dest)
    {
      my $ext;
      if ($src =~ /.*\.(.*)$/ && $1 ne $docu_ext)
      {
	$ext = $1;
      }
      else
      {
	warn "$ERROR: L2h image $src has invalid extension\n";
	next;
      }
      while (-e "$docu_rdir${docu_name}_$maximage.$ext") { $maximage++;}
      $dest = "${docu_name}_$maximage.$ext";
      system("cp -f $docu_rdir$src $docu_rdir$dest");
      $l2h_img{$src} = $dest;
      unlink "$docu_rdir$src" unless ($DEBUG & DEBUG_L2H);
    }
    $content =~ s/$src/$dest/g;
  }
  $l2h_cache{$l2h_to_latex[$count]} = $content;
  return $content;
}


#+++############################################################################
#                                                                              #
# Pass 1: read source, handle command, variable, simple substitution           #
#                                                                              #
#---############################################################################

@lines = ();				# whole document
@toc_lines = ();			# table of contents
@stoc_lines = ();			# table of contents
$curlevel = 0;				# current level in TOC
$node = '';				# current node name
$node_next = '';                        # current node next name               
$node_prev = '';                        # current node prev name
$node_up = '';                          # current node up name
$in_table = 0;				# am I inside a table
$table_type = '';			# type of table ('', 'f', 'v', 'multi')
@tables = ();			        # nested table support
$in_bibliography = 0;			# am I inside a bibliography
$in_glossary = 0;			# am I inside a glossary
$in_top = 0;				# am I inside the top node
$has_top = 0;				# did I see a top node?
$in_pre = 0;				# am I inside a preformatted section
$in_list = 0;				# am I inside a list
$in_html = 0;				# am I inside an HTML section
$first_line = 1;		        # is it the first line
$dont_html = 0;				# don't protect HTML on this line
$deferred_ref = '';			# deferred reference for indexes
@html_stack = ();			# HTML elements stack
$html_element = '';			# current HTML element
&html_reset;

# init l2h
$T2H_L2H = &l2h_Init($docu_name) if ($T2H_L2H);
$T2H_L2H = &l2h_InitToLatex      if ($T2H_L2H);    

# build code for simple substitutions
# the maps used (%simple_map and %things_map) MUST be aware of this
# watch out for regexps, / and escaped characters!
$subst_code = '';
foreach (keys(%simple_map)) {
    ($re = $_) =~ s/(\W)/\\$1/g; # protect regexp chars
    $subst_code .= "s/\\\@$re/$simple_map{$_}/g;\n";
}
foreach (keys(%things_map)) {
    $subst_code .= "s/\\\@$_\\{\\}/$things_map{$_}/g;\n";
}
if ($use_acc) {
    # accentuated characters
    foreach (keys(%accent_map)) {
	if ($_ eq "`") {
	    $subst_code .= "s/$;3";
	} elsif ($_ eq "'") {
	    $subst_code .= "s/$;4";
	} else {
	    $subst_code .= "s/\\\@\\$_";
	}
	$subst_code .= "([aeiou])/&\${1}$accent_map{$_};/gi;\n";
    }
}
eval("sub simple_substitutions { $subst_code }");

&init_input;
while ($_ = &next_line) {
    #
    # remove \input on the first lines only
    #
    if ($first_line) {
	next if /^\\input/;
	$first_line = 0;
    }
    #
    # parse texinfo tags
    #
    $tag = '';
    $end_tag = '';
    if (/^\s*\@end\s+(\w+)\b/) {
	$end_tag = $1;
    } elsif (/^\s*\@(\w+)\b/) {
	$tag = $1;
    }
    #
    # handle @html / @end html
    #
    if ($in_html) {
	if ($end_tag eq 'html') {
	    $in_html = 0;
	} else {
	    $tag2pro{$in_html} .= $_;
	}
	next;
    } elsif ($tag eq 'html') {
	$in_html = $PROTECTTAG . ++$html_num;
	push(@lines, $in_html);
	next;
    }
    #
    # try to skip the line
    #
    if ($end_tag) {
	next if $to_skip{"end $end_tag"};
    } elsif ($tag) {
	next if $to_skip{$tag};
	last if $tag eq 'bye';
    }
    if ($in_top) {
	# parsing the top node
	if ($tag eq 'node' || $tag eq 'include' || $sec2level{$tag}) {
	    # no more in top
	    $in_top = 0;
	    push(@lines, $TOPEND);
	}
    }
    #
    # try to remove inlined comments
    # syntax from tex-mode.el comment-start-skip
    #
    s/((^|[^\@])(\@\@)*)\@c(omment | |\{).*/$1/;
#     s/((^|[^\@])(\@\@)*)\@c(omment)? .*/$1/;
#     s/(.*)\@c{.*?}(.*)/$1$2/;
#     s/(.*)\@comment{.*?}(.*)/$1$2/;
#     s/^(.*)\@c /$1/;
#     s/^(.*)\@comment /$1/;
    # non-@ substitutions cf. texinfmt.el
    unless ($in_pre) {
	s/``/\"/g;
	s/''/\"/g;
	s/([\w ])---([\w ])/$1--$2/g;
    }
    #
    # analyze the tag
    #
    if ($tag) {
	# skip lines
	&skip_until($tag), next if $tag eq 'ignore';
	&skip_until($tag), next if $tag eq 'ifnothtml';
	if ($tag eq 'ifinfo')
	{
	  &skip_until($tag), next unless $T2H_EXPAND eq 'info';
	}
	if ($tag eq 'iftex')
	{
	  &skip_until($tag), next unless $T2H_EXPAND eq 'tex';
	} 
	if ($tag eq 'tex')
	{
	  # add to latex2html file
	  if ($T2H_EXPAND eq 'tex' && $T2H_L2H && ! $in_pre)
	  {
	    # add space to the end -- tex(i2dvi) does this, as well 
	    push(@lines, &l2h_ToLatex(&string_until($tag) . " "));
	  }
	  else
	  {
	    &skip_until($tag);
	  }
	  next;
	}
	# handle special tables
	if ($tag =~ /^(|f|v|multi)table$/) {
	    $table_type = $1;
	    $tag = 'table';
	}
	# special cases
	if ($tag eq 'top' || ($tag eq 'node' && /^\@node\s+top\s*,/i)) {
	    $in_top = 1;
	    $has_top = 1;
	    @lines = (); # ignore all lines before top (title page garbage)
	    next;
	} elsif ($tag eq 'node') {
	  if ($in_top)
	  {
	    $in_top = 0;
	    push(@lines, $TOPEND);
	  }
	  warn "$ERROR Bad node line: $_" unless $_ =~ /^\@node\s$NODESRE$/o;
	  $_ = &protect_html($_); # if node contains '&' for instance
	  s/^\@node\s+//;
	  ($node, $node_next, $node_prev, $node_up) = split(/,/);
	  &normalise_node($node);
	  &normalise_node($node_next);
	  &normalise_node($node_prev);
	  &normalise_node($node_up);
	  next;
	} elsif ($tag eq 'include') {
	    if (/^\@include\s+($FILERE)\s*$/o) {
		$file = $1;
		unless (-e $file) {
		    foreach $dir (@T2H_INCLUDE_DIRS) {
			$file = "$dir/$1";
			last if -e $file;
		    }
		}
		if (-e $file) {
		    &open($file);
		    print "# including $file\n" if $T2H_VERBOSE;
		} else {
		    warn "$ERROR Can't find $file, skipping";
		}
	    } else {
		warn "$ERROR Bad include line: $_";
	    }
	    next;
	} elsif ($tag eq 'ifclear') {
	    if (/^\@ifclear\s+($VARRE)\s*$/o) {
		next unless defined($value{$1});
		&skip_until($tag);
	    } else {
		warn "$ERROR Bad ifclear line: $_";
	    }
	    next;
	} elsif ($tag eq 'ifset') {
	    if (/^\@ifset\s+($VARRE)\s*$/o) {
		next if defined($value{$1});
		&skip_until($tag);
	    } else {
		warn "$ERROR Bad ifset line: $_";
	    }
	    next;
	} elsif ($tag eq 'menu') {
	    unless ($T2H_SHOW_MENU) {
		&skip_until($tag);
		next;
	    }
	    &html_push_if($tag);
	    push(@lines, &html_debug("\n", __LINE__));
	} elsif ($format_map{$tag}) {
	    $in_pre = 1 if $format_map{$tag} eq 'PRE';
	    &html_push_if($format_map{$tag});
	    push(@lines, &html_debug("\n", __LINE__));
	    $in_list++ if $format_map{$tag} eq 'UL' || $format_map{$tag} eq 'OL' ;
	    push(@lines, &debug('<FONT size="-1">'."\n", __LINE__))
	       if $tag =~ /smallexample/i;
	    push(@lines, &debug("<BLOCKQUOTE>\n", __LINE__))
	      if $tag =~ /example/i;
	    push(@lines, &debug("<$format_map{$tag}>\n", __LINE__));
	    next;
	} elsif ($tag eq 'table') {
	    if (/^\s*\@(|f|v|multi)table\s+\@(\w+)/) {
		$in_table = $2;
		unshift(@tables, join($;, $table_type, $in_table));
		if ($table_type eq "multi") {
		    # don't use borders -- gets confused by empty cells
		    push(@lines, &debug("<TABLE>\n", __LINE__));
		    &html_push_if('TABLE');
		} else {
		    push(@lines, &debug("<DL COMPACT>\n", __LINE__));
		    &html_push_if('DL');
		}
		push(@lines, &html_debug("\n", __LINE__));
	    } else {
		warn "$ERROR Bad table line: $_";
	    }
	    next;
	} elsif ($tag eq 'synindex' || $tag eq 'syncodeindex') {
	    if (/^\@$tag\s+(\w)\w\s+(\w)\w\s*$/) {
		eval("*${1}index = *${2}index");
	    } else {
		warn "$ERROR Bad syn*index line: $_";
	    }
	    next;
	} elsif ($tag eq 'sp') {
	    push(@lines, &debug("<P>\n", __LINE__));
	    next;
	} elsif ($tag eq 'center') {
	    push(@lines, &debug("<center>\n", __LINE__));
	    s/\@center//;
	} elsif ($tag eq 'setref') {
	    &protect_html; # if setref contains '&' for instance
	    if (/^\@$tag\s*{($NODERE)}\s*$/) {
		$setref = $1;
		$setref =~ s/\s+/ /g; # normalize
		$setref =~ s/ $//;
		$node2sec{$setref} = $name;
		$sec2node{$name} = $setref;
		$node2href{$setref} = "$docu_doc#$docid";
	    } else {
		warn "$ERROR Bad setref line: $_";
	    }
	    next;
	} elsif ($tag eq 'defindex' || $tag eq 'defcodeindex') {
	    if (/^\@$tag\s+(\w\w)\s*$/) {
		$valid_index{$1} = 1;
	    } else {
		warn "$ERROR Bad defindex line: $_";
	    }
	    next;
	} elsif ($tag eq 'lowersections') {
	    local ($sec, $level);
	    while (($sec, $level) = each %sec2level) {
		$sec2level{$sec} = $level + 1;
	    }
	    next;
	} elsif ($tag eq 'raisesections') {
	    local ($sec, $level);
	    while (($sec, $level) = each %sec2level) {
		$sec2level{$sec} = $level - 1;
	    }
	    next;
	} elsif (defined($def_map{$tag})) {
	    if ($def_map{$tag}) {
		s/^\@$tag\s+//;
		$tag = $def_map{$tag};
		$_ = "\@$tag $_";
		$tag =~ s/\s.*//;
	    }
	} elsif (defined($user_sub{$tag})) {
	    s/^\@$tag\s+//;
	    $sub = $user_sub{$tag};
	    print "# user $tag = $sub, arg: $_" if $T2H_DEBUG & $DEBUG_USER;
	    if (defined(&$sub)) {
		chop($_);
		&$sub($_);
	    } else {
		warn "$ERROR Bad user sub for $tag: $sub\n";
	    }
	    next;
	}
	if (defined($def_map{$tag})) {
	    s/^\@$tag\s+//;
	    if ($tag =~ /x$/) {
		# extra definition line
		$tag = $`;
		$is_extra = 1;
	    } else {
		$is_extra = 0;
	    }
	    while (/\{([^\{\}]*)\}/) {
		# this is a {} construct
		($before, $contents, $after) = ($`, $1, $');
		# protect spaces
		$contents =~ s/\s+/$;9/g;
		# restore $_ protecting {}
		$_ = "$before$;7$contents$;8$after";
	    }
	    @args = split(/\s+/, &protect_html($_));
	    foreach (@args) {
		s/$;9/ /g;	# unprotect spaces
		s/$;7/\{/g;	# ... {
		s/$;8/\}/g;	# ... }
	    }
	    $type = shift(@args);
	    $type =~ s/^\{(.*)\}$/$1/;
	    print "# def ($tag): {$type} ", join(', ', @args), "\n"
		if $T2H_DEBUG & $DEBUG_DEF;
	    $type .= ':'; # it's nicer like this
	    $name = shift(@args);
	    $name =~ s/^\{(.*)\}$/$1/;
	    if ($is_extra) {
		$_ = &debug("<DT>", __LINE__);
	    } else {
		$_ = &debug("<DL>\n<DT>", __LINE__);
	    }
	    if ($tag eq 'deffn' || $tag eq 'defvr' || $tag eq 'deftp') {
		$_ .= "<U>$type</U> <B>$name</B>";
		$_ .= " <I>@args</I>" if @args;
	    } elsif ($tag eq 'deftypefn' || $tag eq 'deftypevr'
		     || $tag eq 'defcv' || $tag eq 'defop') {
		$ftype = $name;
		$name = shift(@args);
		$name =~ s/^\{(.*)\}$/$1/;
		$_ .= "<U>$type</U> $ftype <B>$name</B>";
		$_ .= " <I>@args</I>" if @args;
	    } else {
		warn "$ERROR Unknown definition type: $tag\n";
		$_ .= "<U>$type</U> <B>$name</B>";
		$_ .= " <I>@args</I>" if @args;
	    }
 	    $_ .= &debug("\n<DD>", __LINE__);
	    $name = &unprotect_html($name);
	    if ($tag eq 'deffn' || $tag eq 'deftypefn') {
		unshift(@input_spool, "\@findex $name\n");
	    } elsif ($tag eq 'defop') {
		unshift(@input_spool, "\@findex $name on $ftype\n");
	    } elsif ($tag eq 'defvr' || $tag eq 'deftypevr' || $tag eq 'defcv') {
		unshift(@input_spool, "\@vindex $name\n");
	    } else {
		unshift(@input_spool, "\@tindex $name\n");
	    }
	    $dont_html = 1;
	}
    } elsif ($end_tag) {
	if ($format_map{$end_tag}) {
	    $in_pre = 0 if $format_map{$end_tag} eq 'PRE';
	    $in_list-- if $format_map{$end_tag} eq 'UL' || $format_map{$end_tag} eq 'OL' ;
	    &html_pop_if('LI', 'P');
	    &html_pop_if();
	    push(@lines, &debug("</$format_map{$end_tag}>\n", __LINE__));
	    push(@lines, &debug("</BLOCKQUOTE>\n", __LINE__))
	      if $end_tag =~ /example/i;
	    push(@lines, &debug("</FONT>\n", __LINE__))
	       if $end_tag =~ /smallexample/i;
	    push(@lines, &html_debug("\n", __LINE__));
	} elsif ($end_tag =~ /^(|f|v|multi)table$/) {
	    unless (@tables) {
		warn "$ERROR \@end $end_tag without \@*table\n";
		next;
	    }
	    ($table_type, $in_table) = split($;, shift(@tables));
	    unless ($1 eq $table_type) {
		warn "$ERROR \@end $end_tag without matching \@$end_tag\n";
		next;
	    }
	    if ($table_type eq "multi") {
		push(@lines, "</TR></TABLE>\n");
		&html_pop_if('TR');
	    } else {
		push(@lines, "</DL>\n");
		&html_pop_if('DD');
	    }
	    &html_pop_if();
	    if (@tables) {
		($table_type, $in_table) = split($;, $tables[0]);
	    } else {
		$in_table = 0;
	    }
	} elsif (defined($def_map{$end_tag})) {
 	    push(@lines, &debug("</DL>\n", __LINE__));
	} elsif ($end_tag eq 'menu') {
	    &html_pop_if();
	    push(@lines, $_); # must keep it for pass 2
	} 
	next;
    }
    #
    # misc things
    #
    # protect texi and HTML things
    &protect_texi;
    $_ = &protect_html($_) unless $dont_html;
    $dont_html = 0;
    # substitution (unsupported things)
    s/^\@exdent\s+//g;
    s/\@noindent\s+//g;
    s/\@refill\s+//g;
    # other substitutions
    &simple_substitutions;
    s/\@value{($VARRE)}/$value{$1}/eg;
    s/\@footnote\{/\@footnote$docu_doc\{/g; # mark footnotes, cf. pass 4
    #
    # analyze the tag again
    #
    if ($tag) {
      if (defined($sec2level{$tag}) && $sec2level{$tag} > 0) {
	    if (/^\@$tag\s+(.+)$/) {
		$name = $1;
		$name =~ s/\s+$//;
		$level = $sec2level{$tag};
		if ($tag =~ /heading$/) {
		    push(@lines, &html_debug("\n", __LINE__));
		    if ($html_element ne 'body') {
			# We are in a nice pickle here. We are trying to get a H? heading
			# even though we are not in the body level. So, we convert it to a
			# nice, bold, line by itself.
			$_ = &debug("\n\n<P><STRONG>$name</STRONG>\n\n", __LINE__);
		    } else {
			$_ = &debug("<H$level>$name</H$level>\n", __LINE__);
			&html_push_if('body');
		    }
		    print "# heading, section $name, level $level\n"
			if $T2H_DEBUG & $DEBUG_TOC;
		} else {
		$node = $name unless $node;  
		$name = &update_sec_num($tag, $level) . " $name"
		    if $T2H_NUMBER_SECTIONS && $tag !~ /^unnumbered/;
		  if (defined($toplevel))
		  {
		    push @lines, ($level==$toplevel ? $CHAPTEREND : $SECTIONEND);
		  }
		  else
		  {
		    # first time we see a "section"
		    unless ($level == 1) 
		    {
		      warn "$ERROR The first section found is not of level 1: $_";
		    }
		    $toplevel = $level;
		  }
		  push(@sections, $name);
		  next_doc() if ($T2H_SPLIT eq 'section' || 
				 ($T2H_SPLIT && $level == $toplevel));
		  $sec_num++;
		  $docid = "SEC$sec_num";
		  $tocid = "TOC$sec_num";
		    # check biblio and glossary
		  $in_bibliography = ($name =~ /^([A-Z]|\d+)?(\.\d+)*\s*bibliography$/i);
		  $in_glossary = ($name =~ /^([A-Z]|\d+)?(\.\d+)*\s*glossary$/i);
		    # check node
		    if ($node2sec{$node}) {
		      warn "$ERROR Duplicate node found: $node\n";
		    } else {
			    $node2sec{$node} = $name;
			    warn "$ERROR Duplicate section found: $name\n"
			      if ($sec2node{$name});
			    $sec2node{$name} = $node;
			    $node2href{$node} = "$docu_doc#$docid";
			    $node2next{$node} = $node_next;
			    $node2prev{$node} = $node_prev;
			    $node2up{$node} = $node_up;
			    print "# node $node, section $name, level $level\n"
				if $T2H_DEBUG & $DEBUG_TOC;
			}
			$node = '';
			$node_next = '';
			$node_prev = '';
			$node_next = '';
		    # update TOC
		    while ($level > $curlevel) {
			$curlevel++;
			push(@toc_lines, "<UL>\n");
		    }
		    while ($level < $curlevel) {
			$curlevel--;
			push(@toc_lines, "</UL>\n");
		    }
		    $_ = &t2h_anchor($tocid, "$docu_doc#$docid", $name, 1);
		    $_ = &substitute_style($_);
		    push(@stoc_lines, "$_<BR>\n") if ($level == 1);
		    push(@toc_lines, "<LI>" . $_ ."</LI>");
		    # update DOC
		    push(@lines, &html_debug("\n", __LINE__));
		    &html_reset;
#		    $_ =  "<H$level>".&t2h_anchor($docid, '', $name)."</H$level>\n";
		    $_ =  "<H$level> $name </H$level>\n";		    
		    $_ = &debug($_, __LINE__);
		    push(@lines, &html_debug("\n", __LINE__));
		}
		# update DOC
		foreach $line (split(/\n+/, $_)) {
		    push(@lines, "$line\n");
		}
		next;
	    } else {
		warn "$ERROR Bad section line: $_";
	    }
	} else {
	    # track variables
	    $value{$1} = $2, next if /^\@set\s+($VARRE)\s+(.*)$/o;
	    delete $value{$1}, next if /^\@clear\s+($VARRE)\s*$/o;
	    # store things
	    $value{'_setfilename'}   = $1, next if /^\@setfilename\s+(.*)$/;
	    $value{'_settitle'}      = $1, next if /^\@settitle\s+(.*)$/;
	    $value{'_author'}   .= "$1\n", next if /^\@author\s+(.*)$/;
	    $value{'_subtitle'} .= "$1\n", next if /^\@subtitle\s+(.*)$/;
	    $value{'_title'}    .= "$1\n", next if /^\@title\s+(.*)$/;
	    # index
	    if (/^\@(..?)index\s+/) {
		unless ($valid_index{$1}) {
		    warn "$ERROR Undefined index command: $_";
		    next;
		}
		$id = ($T2H_SECTION_IDX ? $docid : 'IDX' . ++$idx_num);
		$index = $1 . 'index';
		$what = &substitute_style($');
		$what =~ s/\s+$//;
		print "# found $index for '$what' id $id\n"
		    if $T2H_DEBUG & $DEBUG_INDEX;
		eval(<<EOC);
		if (defined(\$$index\{\$what\})) {
		    \$$index\{\$what\} .= "$;$docu_doc#$id";
		} else {
		    \$$index\{\$what\} = "$docu_doc#$id";
		}
EOC
		#
		# dirty hack to see if I can put an invisible anchor...
		#
		unless ($T2H_SECTION_IDX) {
		if (
		    $html_element eq 'P' ||
		    $html_element eq 'LI' ||
		    $html_element eq 'DT' ||
		    $html_element eq 'DD' ||
		    $html_element eq 'ADDRESS' ||
		    $html_element eq 'B' ||
		    $html_element eq 'BLOCKQUOTE' ||
		    $html_element eq 'PRE' ||
		    $html_element eq 'SAMP') {
                    push(@lines, &t2h_anchor($id, '', $T2H_INVISIBLE_MARK, !$in_pre));
                } elsif ($html_element eq 'body') {
		    push(@lines, &debug("<P>\n", __LINE__));
                    push(@lines, &t2h_anchor($id, '', $T2H_INVISIBLE_MARK, !$in_pre));
		    &html_push('P');
		} elsif ($html_element eq 'DL' ||
			 $html_element eq 'UL' ||
			 $html_element eq 'OL' ) {
		    $deferred_ref .= &t2h_anchor($id, '', $T2H_INVISIBLE_MARK, !$in_pre) . " ";
		}
	      }
		next;
	    }
	    # list item
	    if (/^\s*\@itemx?\s+/) {
		$what = $';
		$what =~ s/\s+$//;
		if ($in_bibliography && $use_bibliography) {
		    if ($what =~ /^$BIBRE$/o) {
			$id = 'BIB' . ++$bib_num;
			$bib2href{$what} = "$docu_doc#$id";
			print "# found bibliography for '$what' id $id\n"
			    if $T2H_DEBUG & $DEBUG_BIB;
			$what = &t2h_anchor($id, '', $what);
		    }
		} elsif ($in_glossary && $T2H_USE_GLOSSARY) {
		    $id = 'GLOSS' . ++$gloss_num;
		    $entry = $what;
		    $entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/;
		    $gloss2href{$entry} = "$docu_doc#$id";
		    print "# found glossary for '$entry' id $id\n"
			if $T2H_DEBUG & $DEBUG_GLOSS;
		    $what = &t2h_anchor($id, '', $what);
		}
		&html_pop_if('P');
		if ($html_element eq 'DL' || $html_element eq 'DD') {
		    if ($things_map{$in_table} && !$what) {
			# special case to allow @table @bullet for instance
			push(@lines, &debug("<DT>$things_map{$in_table}\n", __LINE__));
		    } else {
			push(@lines, &debug("<DT>\@$in_table\{$what\}\n", __LINE__));
		    }
		    push(@lines, "<DD>");
		    &html_push('DD') unless $html_element eq 'DD';
		    if ($table_type) { # add also an index
			unshift(@input_spool, "\@${table_type}index $what\n");
		    }
		} elsif ($html_element eq 'TABLE') {
		    push(@lines, &debug("<TR><TD>$what</TD>\n", __LINE__));
		    &html_push('TR');
		} elsif ($html_element eq 'TR') {
		    push(@lines, &debug("</TR>\n", __LINE__));
		    push(@lines, &debug("<TR><TD>$what</TD>\n", __LINE__));
		} else {
		    push(@lines, &debug("<LI>$what\n", __LINE__));
		    &html_push('LI') unless $html_element eq 'LI';
		}
		push(@lines, &html_debug("\n", __LINE__));
		if ($deferred_ref) {
		    push(@lines, &debug("$deferred_ref\n", __LINE__));
		    $deferred_ref = '';
		}
		next;
	    } elsif (/^\@tab\s+(.*)$/) {
		push(@lines, "<TD>$1</TD>\n");
		next;
	    }
	}
    }
    # paragraph separator
    if ($_ eq "\n") {
	next if $#lines >= 0 && $lines[$#lines] eq "\n";
	if ($html_element eq 'P') {
	    push (@lines, &debug("</P><P>\n", __LINE__));
	}
# 	else
# 	{
# 	  push(@lines, "<P></P>\n");
# 	  $_ = &debug("<P></P>\n", __LINE__);
# 	}
        elsif ($html_element eq 'body' || $html_element eq 'BLOCKQUOTE' || $html_element eq 'DD') 
	{
	  &html_push('P');
	  push(@lines, &debug("<P>\n", __LINE__));
	}
      }
    # otherwise
    push(@lines, $_);

    push(@lines, &debug("</center>\n", __LINE__))  if ($tag eq 'center');
}

# finish TOC
$level = 0;
while ($level < $curlevel) {
    $curlevel--;
    push(@toc_lines, "</UL>\n");
}

print "# end of pass 1\n" if $T2H_VERBOSE;

#+++############################################################################
#                                                                              #
# Pass 2/3: handle style, menu, index, cross-reference                         #
#                                                                              #
#---############################################################################

@lines2 = ();				# whole document (2nd pass)
@lines3 = ();				# whole document (3rd pass)
$in_menu = 0;				# am I inside a menu

while (@lines) {
    $_ = shift(@lines);
    #
    # special case (protected sections)
    #
    if (/^$PROTECTTAG/o) {
	push(@lines2, $_);
	next;
    }
    #
    # menu
    #
    if (/^\@menu\b/)
    {
      $in_menu = 1;
      $T2H_NUMBER_SECTIONS ?
	push(@lines2, &debug("<BLOCKQUOTE><TABLE BORDER=0 CELLSPACING=0> \n", __LINE__)) :
	  push(@lines2, &debug("<UL>\n", __LINE__));
      next;
    }
    if (/^\@end\s+menu\b/)
    {
      $in_menu = 0;
      $T2H_NUMBER_SECTIONS ?
	push(@lines2, &debug("</TABLE></BLOCKQUOTE>\n", __LINE__)) :
	  push(@lines2, &debug("</UL>\n", __LINE__));
      next;
    }
    if ($in_menu) {
	if (/^\*\s+($NODERE)::/o) {
	    $descr = $';
	    chop($descr);
	    &menu_entry($1, $1, $descr);
	} elsif (/^\*\s+(.+):\s+([^\t,\.\n]+)[\t,\.\n]/) {
	    $descr = $';
	    chop($descr);
	    &menu_entry($1, $2, $descr);
	} elsif (/^\*/) {
	    warn "$ERROR Bad menu line: $_";
	} else { # description continued?
	    push(@lines2, $_);
	}
	next;
    }
    #
    # printindex
    #
    # obachman: replace ^\@printindex by \@printindex, otherwise 
    # generation in debug mode fails
    if (/\@printindex\s+(\w\w)\b/) {
	local($index, *ary, @keys, $key, $letter, $last_letter, @refs, $fhidx);
	if ($predefined_index{$1}) {
	    $index = $predefined_index{$1} . 'index';
	} else {
	    $index = $1 . 'index';
	}
	# check for index summary
	$letter = $1;
	if ($letter =~ /$T2H_IDX_SUMMARY/)
	{
	  open(FHIDX, "> $docu_rdir$docu_name" . "_$letter.idx")
	    || die "Can't open > $docu_rdir$docu_name" . "_$letter.idx for writing: $!\n";
	  $fhidx = \*FHIDX;
	  print "# writing index summary in $docu_rdir$docu_name" . "_$letter.idx..." if $T2H_VERBOSE;
	}
	eval("*ary = *$index");
	@keys = keys(%ary);
	foreach $key (@keys) {
	    $_ = $key;
	    1 while s/<(\w+)>\`(.*)\'<\/\1>/$2/; # remove HTML tags with quotes
	    1 while s/<(\w+)>(.*)<\/\1>/$2/;     # remove HTML tags
	    $_ = &unprotect_html($_);
	    &unprotect_texi;
	    tr/A-Z/a-z/; # lowercase
	    $key2alpha{$key} = $_;
	    print "# index $key sorted as $_\n"
		if $key ne $_ && $T2H_DEBUG & $DEBUG_INDEX;
	}
	push(@lines2, "Jump to:\n");
	$last_letter = undef;
	foreach $key (sort byalpha @keys) {
	    $letter = substr($key2alpha{$key}, 0, 1);
	    $letter = substr($key2alpha{$key}, 0, 2) if $letter eq $;;
	    if (!defined($last_letter) || $letter ne $last_letter) {
		push(@lines2, "-\n") if defined($last_letter);
		push(@lines2, "<A HREF=\"#$index\_$letter\">" . &protect_html($letter) . "</A>\n");
		$last_letter = $letter;
	    }
	}
	push(@lines2, "<P>\n");
	$last_letter = undef;
	foreach $key (sort byalpha @keys) {
	    $letter = substr($key2alpha{$key}, 0, 1);
	    $letter = substr($key2alpha{$key}, 0, 2) if $letter eq $;;
	    if (!defined($last_letter) || $letter ne $last_letter) {
		push(@lines2, "</DIR>\n") if defined($last_letter);
		push(@lines2, "<H2><A NAME=\"$index\_$letter\">" . &protect_html($letter) . "</A></H2>\n");
		push(@lines2, "<DIR>\n");
		$last_letter = $letter;
	    }
	    @refs = ();
	    foreach (split(/$;/, $ary{$key})) {
		push(@refs, &t2h_anchor('', $_, $key, 0));
	    }
	    push(@lines2, "<LI>" . join(", ", @refs) . "\n");
	    if ($fhidx)
	    {
	      ($letter) = split(/$;/, $ary{$key});
	      $key = unprotect_html($key);
	      print $fhidx "$key\t$letter\n";
	    }
	}
	push(@lines2, "</DIR>\n") if defined($last_letter);
	if ($fhidx)
	{
	  print "\n" if $T2H_VERBOSE;
	  close($fhidx);
	}
	next;
    }
    #
    # simple style substitutions
    #
    $_ = &substitute_style($_);
    #
    # xref
    #
    while (/\@(x|px|info|)ref{($XREFRE)(}?)/o) {
	# note: Texinfo may accept other characters
	($type, $nodes, $full) = ($1, $2, $3);
	($before, $after) = ($`, $');
	if (! $full && $after) {
	    warn "$ERROR Bad xref (no ending } on line): $_";
	    $_ = "$before$;0${type}ref\{$nodes$after";
	    next; # while xref
	}
	if ($type eq 'x') {
	    $type = 'See ';
	} elsif ($type eq 'px') {
	    $type = 'see ';
	} elsif ($type eq 'info') {
	    $type = 'See Info';
	} else {
	    $type = '';
	}
	unless ($full) {
	    $next = shift(@lines);
	    $next = &substitute_style($next);
	    chop($nodes); # remove final newline
	    if ($next =~ /\}/) { # split on 2 lines
		$nodes .= " $`";
		$after = $';
	    } else {
		$nodes .= " $next";
		$next = shift(@lines);
		$next = &substitute_style($next);
		chop($nodes);
		if ($next =~ /\}/) { # split on 3 lines
		    $nodes .= " $`";
		    $after = $';
		} else {
		    warn "$ERROR Bad xref (no ending }): $_";
		    $_ = "$before$;0xref\{$nodes$after";
		    unshift(@lines, $next);
		    next; # while xref
		}
	    }
	}
	$nodes =~ s/\s+/ /g; # remove useless spaces
	@args = split(/\s*,\s*/, $nodes);
	$node = $args[0]; # the node is always the first arg
	&normalise_node($node);
	$sec = $node2sec{$node};
	$href = $node2href{$node};
	if (@args == 5) { # reference to another manual
	    $sec = $args[2] || $node;
	    $man = $args[4] || $args[3];
	    $_ = "${before}${type}section `$sec' in \@cite{$man}$after";
	} elsif ($type =~ /Info/) { # inforef
	    warn "$ERROR Wrong number of arguments: $_" unless @args == 3;
	    ($nn, $_, $in) = @args;
	    $_ = "${before}${type} file `$in', node `$nn'$after";
	} elsif ($sec && $href && ! $T2H_SHORT_REF) {
	    $_ = "${before}${type}section " . 
	      &t2h_anchor('', $href, $sec) . $after;
	} 
	elsif ($href && $T2H_SHORT_REF)
	{
	  $_ = "${before}${type} " . &t2h_anchor('', $href, $node) . $after;
	}
	else {
	    warn "$ERROR Undefined node ($node): $_";
	    $_ = "$before$;0xref{$nodes}$after";
	}
    }
    
    if (/^\@image\s*{/) {
      s/\@image\s*{//;
      my (@args) = split (/,/);
      my $base = $args[0];
      my $image;
      if (-r "$base.jpg") {
        $image = "$base.jpg";
      } elsif (-r "$base.png") {
        $image = "$base.png";
      } elsif (-r "$base.gif") {
        $image = "$base.gif";
      } else {
        warn "$ERROR no image file for $base: $_";
      }
      $_ = "<IMG SRC=\"$image\" ALT=\"$base\">";
    }

    #
    # try to guess bibliography references or glossary terms
    #
    unless (/^<H\d><A NAME=\"SEC\d/) {
	if ($use_bibliography) {
	    $done = '';
	    while (/$BIBRE/o) {
		($pre, $what, $post) = ($`, $&, $');
		$href = $bib2href{$what};
		if (defined($href) && $post !~ /^[^<]*<\/A>/) {
		    $done .= $pre . &t2h_anchor('', $href, $what);
		} else {
		    $done .= "$pre$what";
		}
		$_ = $post;
	    }
	    $_ = $done . $_;
	}
	if ($T2H_USE_GLOSSARY) {
	    $done = '';
	    while (/\b\w+\b/) {
		($pre, $what, $post) = ($`, $&, $');
		$entry = $what;
		$entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/;
		$href = $gloss2href{$entry};
		if (defined($href) && $post !~ /^[^<]*<\/A>/) {
		    $done .= $pre . &t2h_anchor('', $href, $what);
		} else {
		    $done .= "$pre$what";
		}
		$_ = $post;
	    }
	    $_ = $done . $_;
	}
    }
    # otherwise
    push(@lines2, $_);
}
print "# end of pass 2\n" if $T2H_VERBOSE;

#
# split style substitutions
#
while (@lines2) {
    $_ = shift(@lines2);
    #
    # special case (protected sections)
    #
    if (/^$PROTECTTAG/o) {
	push(@lines3, $_);
	next;
    }
    #
    # split style substitutions
    #
    $old = '';
    while ($old ne $_) {
        $old = $_;
	if (/\@(\w+)\{/) {
	    ($before, $style, $after) = ($`, $1, $');
	    if (defined($style_map{$style})) {
		$_ = $after;
		$text = '';
		$after = '';
		$failed = 1;
		while (@lines2) {
		    if (/\}/) {
			$text .= $`;
			$after = $';
			$failed = 0;
			last;
		    } else {
			$text .= $_;
			$_ = shift(@lines2);
		    }
		}
		if ($failed) {
		    die "* Bad syntax (\@$style) after: $before\n";
		} else {
		    $text = &apply_style($style, $text);
		    $_ = "$before$text$after";
		}
	    }
	}
    }
    # otherwise
    push(@lines3, $_);
}
print "# end of pass 3\n" if $T2H_VERBOSE;
	
#+++############################################################################
#                                                                              #
# Pass 4: foot notes, final cleanup                                            #
#                                                                              #
#---############################################################################

@foot_lines = ();			# footnotes
@doc_lines = ();			# final document
$end_of_para = 0;			# true if last line is <P>
	
while (@lines3) {
    $_ = shift(@lines3);
    #
    # special case (protected sections)
    #
    if (/^$PROTECTTAG/o) {
	push(@doc_lines, $_);
	$end_of_para = 0;
	next;
    }
    #
    # footnotes
    #
    while (/\@footnote([^\{\s]+)\{/) {
	($before, $d, $after) = ($`, $1, $');
	$_ = $after;
	$text = '';
	$after = '';
	$failed = 1;
	while (@lines3) {
	    if (/\}/) {
		$text .= $`;
		$after = $';
		$failed = 0;
		last;
	    } else {
		$text .= $_;
		$_ = shift(@lines3);
	    }
	}
	if ($failed) {
	    die "* Bad syntax (\@footnote) after: $before\n";
	} else {
	    $foot_num++;
	    $docid  = "DOCF$foot_num";
	    $footid = "FOOT$foot_num";
	    $foot = "($foot_num)";
	    push(@foot_lines, "<H3>" . &t2h_anchor($footid, "$d#$docid", $foot) . "</H3>\n");
	    $text = "<P>$text" unless $text =~ /^\s*<P>/;
	    push(@foot_lines, "$text\n");
	    $_ = $before . &t2h_anchor($docid, "$docu_foot#$footid", $foot) . $after;
	}
    }
    #
    # remove unnecessary <P>
    #
    if (/^\s*<P>\s*$/) {
	next if $end_of_para++;
    } else {
	$end_of_para = 0;
    }
    # otherwise
    push(@doc_lines, $_);
}
	
print "# end of pass 4\n" if $T2H_VERBOSE;

#+++############################################################################
#                                                                              #
# Pass 5: print things                                                         #
#                                                                              #
#---############################################################################

$T2H_L2H = &l2h_FinishToLatex if ($T2H_L2H);
$T2H_L2H = &l2h_ToHtml        if ($T2H_L2H);
$T2H_L2H = &l2h_InitFromHtml  if ($T2H_L2H);

# prepare %T2H_THISDOC
$T2H_THISDOC{fulltitle} = $value{'_title'} || $value{'_settitle'} || "Untitled Document";
$T2H_THISDOC{title} = $value{'_settitle'} || $T2H_THISDOC{fulltitle};
$T2H_THISDOC{author} = $value{'_author'};
$T2H_THISDOC{subtitle} = $value{'_subtitle'};
for $key (keys %T2H_THISDOC)
{
  $_ = &substitute_style($T2H_THISDOC{$key});
  &unprotect_texi;
  s/\s*$//;
  $T2H_THISDOC{$key} = $_;
}

# if no sections, then simply print docuemnt as is
unless (@sections)
{
  print "# Writing content into $docu_top_file \n" if $T2H_VERBOSE;
  open(FILE, "> $docu_doc_file") 
    || die "$ERROR: Can't open $docu_doc_file for writing: $!\n";

  t2h_print_page_head(\*FILE);
  $T2H_THIS_SECTION = \@doc_lines;
  t2h_print_lines(\*FILE);
  t2h_print_page_foot(\*FILE);
  close(FILE);
  goto Finish;
}

# initialize $T2H_HREF, $T2H_NAME
%T2H_HREF = 
  (
   'First' ,   sec_href($sections[0]),
   'Last',     sec_href($sections[$#sections]),
   'About',     $docu_about. '#SEC_About',
  );

# prepare TOC, OVERVIEW, TOP
$T2H_TOC = \@toc_lines;
$T2H_OVERVIEW = \@stoc_lines;
if ($has_top)
{
  while (1)
  {
    $_ = shift @doc_lines;
    last if /$TOPEND/;
    push @$T2H_TOP, $_;
  }
  $T2H_HREF{'Top'} = $docu_top . '#SEC_Top';
}
else
{
  $T2H_HREF{'Top'} = $T2H_HREF{First};
}

$node2href{Top} = $T2H_HREF{Top};
$T2H_HREF{Contents} = $docu_toc.'#SEC_Contents' if @toc_lines;
$T2H_HREF{Overview} = $docu_stoc.'#SEC_OVERVIEW' if @stoc_lines;
$T2H_HREF{Index} = $node2href{'Index'};

%T2H_NAME =
  (
   'First',   clean_name($sec2node{$sections[0]}),
   'Last',    clean_name($sec2node{$sections[$#sections]}),
   'About',    'About this document',
   'Contents', 'Table of Contents',
   'Overview', 'Overview (Short Table of Contents)',
   'Index' ,   '',
   'Top',      '' 
  );

#############################################################################
# print Top
#
open(FILE, "> $docu_top_file") 
  || die "$ERROR: Can't open $docu_top_file for writing: $!\n";
if ($T2H_TOP)
{
  print "# Creating Top in $docu_top_file ...\n" if $T2H_VERBOSE;
  t2h_print_page_head(\*FILE) unless ($T2H_SPLIT);
  $T2H_THIS_SECTION = $T2H_TOP;
  $T2H_HREF{This} = $T2H_HREF{Top};
  $T2H_NAME{This} = $T2H_NAME{Top};
  t2h_print_Top(\*FILE);
  
}
close(FILE) if $T2H_SPLIT;

#############################################################################
# Print sections
#
$T2H_NODE{Forward} = $sec2node{$sections[0]};
$T2H_NAME{Forward} = &clean_name($sec2node{$sections[0]});
$T2H_HREF{Forward} = sec_href($sections[0]);
$T2H_NODE{This} = 'Top';
$T2H_NAME{This} = $T2H_NAME{Top};
$T2H_HREF{This} = $T2H_HREF{Top};
if ($T2H_SPLIT)
{
  print "# writing " . scalar(@sections) . 
    " sections in $docu_rdir$docu_name"."_[1.." . 
      ($T2H_SPLIT eq 'section' ? scalar(@sections) : scalar(@$T2H_OVERVIEW) ) . 
	"]"  
	  if $T2H_VERBOSE;
  $previous = ($T2H_SPLIT eq 'chapter' ? $CHAPTEREND : $SECTIONEND);
  undef $FH;
  $doc_num = 0;
}
else
{
  print "# writing " . scalar(@sections) . " sections in $docu_top_file ..." 
    if $T2H_VERBOSE;
  $FH = \*FILE;
  $previous = '';
}

$counter = 0;
# loop through sections
while ($section = shift(@sections)) 
{
  if ($T2H_SPLIT && ($T2H_SPLIT eq 'section' || $previous eq $CHAPTEREND))
  { # open new page
    if ($FH)
    { #close previous page
      t2h_print_page_foot($FH);
      close($FH);
    }
    &next_doc;
    open(FILE, "> $docu_rdir$docu_doc") || 
      die "$ERROR: Can't open $docu_rdir$docu_doc for writing: $!\n";
    $FH = \*FILE;
    t2h_print_page_head($FH);
  }
  $T2H_NAME{Back} = $T2H_NAME{This};
  $T2H_HREF{Back} = $T2H_HREF{This};
  $T2H_NODE{Back} = $T2H_NODE{This};
  $T2H_NAME{This} = $T2H_NAME{Forward};
  $T2H_HREF{This} = $T2H_HREF{Forward};
  $T2H_NODE{This} = $T2H_NODE{Forward};
  if ($sections[0])
  {
    $T2H_NODE{Forward} = $sec2node{$sections[0]};
    $T2H_NAME{Forward} = &clean_name($T2H_NODE{Forward});
    $T2H_HREF{Forward} = sec_href($sections[0]);
  }
  else
  {
    undef $T2H_HREF{Forward}, $T2H_NODE{Forward}, $T2H_NAME{Forward};
  }

  $node = $node2up{$T2H_NODE{This}};
  $T2H_HREF{Up} = $node2href{$node};
  if ($T2H_HREF{Up} eq $T2H_HREF{This} || ! $T2H_HREF{Up})
  {
    $T2H_NAME{Up} = $T2H_NAME{Top};
    $T2H_HREF{Up} = $T2H_HREF{Top};
    $T2H_NODE{Up} = 'Up';
  }
  else
  {
    $T2H_NAME{Up} = &clean_name($node);
    $T2H_NODE{Up} = $node;
  }

  $node = $T2H_NODE{This};
  $node = $node2prev{$node};
  $T2H_NAME{Prev} = &clean_name($node);
  $T2H_HREF{Prev} = $node2href{$node};
  $T2H_NODE{Prev} = $node;

  $node = $T2H_NODE{This};
  if ($node2up{$node} && $node2up{$node} ne 'Top'&&
      ($node2prev{$node} eq $T2H_NODE{Back} || ! $node2prev{$node}))
  {
    $node = $node2up{$node};
    while ($node && $node ne $node2up{$node} && ! $node2prev{$node})
    {
      $node = $node2up{$node};
    }
    $node = $node2prev{$node} 
      unless $node2up{$node} eq 'Top' || ! $node2up{$node};
  }
  else
  {
    $node = $node2prev{$node};
  }
  $T2H_NAME{FastBack} = &clean_name($node);
  $T2H_HREF{FastBack} = $node2href{$node};
  $T2H_NODE{FastBack} = $node;
  
  $node = $T2H_NODE{This};
  $node = $node2next{$node};
  $T2H_NAME{Next} = &clean_name($node);
  $T2H_HREF{Next} = $node2href{$node};
  $T2H_NODE{Next} = $node;

  $node = $T2H_NODE{This};
  if ($node2up{$node} && $node2up{$node} ne 'Top'&& 
      ($node2next{$node} eq $T2H_NODE{Forward} || ! $node2next{$node}))
  {
    $node = $node2up{$node};
    while ($node && $node ne $node2up{$node} && ! $node2next{$node})
    {
      $node = $node2up{$node};
    }
  }
  $node = $node2next{$node};
  $T2H_NAME{FastForward} = &clean_name($node);
  $T2H_HREF{FastForward} = $node2href{$node};
  $T2H_NODE{FastForward} = $node;

  $T2H_THIS_SECTION = [];
  while (@doc_lines) {
    $_ = shift(@doc_lines);
    last if ($_ eq $SECTIONEND || $_ eq $CHAPTEREND);
    push(@$T2H_THIS_SECTION, $_);
  }
  $previous = $_;
  t2h_print_label($FH);
  t2h_print_section($FH);

  if ($T2H_VERBOSE)
  {
    $counter++;
    print "." if $counter =~ /00$/;
  }
}
if ($T2H_SPLIT)
{
  t2h_print_page_foot($FH);
  close($FH);
}
print "\n" if $T2H_VERBOSE;

#############################################################################
# Print ToC, Overview, Footnotes
#
undef $T2H_HREF{Prev};
undef $T2H_HREF{Next};
undef $T2H_HREF{Back};
undef $T2H_HREF{Forward};
undef $T2H_HREF{Up};

if (@foot_lines)
{
  print "# writing Footnotes in $docu_foot_file...\n" if $T2H_VERBOSE;
  open (FILE, "> $docu_foot_file") || die "$ERROR: Can't open $docu_foot_file for writing: $!\n"
      if $T2H_SPLIT;
  $T2H_HREF{This} = $docu_foot;
  $T2H_NAME{This} = 'Footnotes';
  $T2H_THIS_SECTION = \@foot_lines;
  t2h_print_footnotes(\*FILE);
  close(FILE) if $T2H_SPLIT;
}

if (@toc_lines)
{
  print "# writing Toc in $docu_toc_file...\n" if $T2H_VERBOSE;
  open (FILE, "> $docu_toc_file") || die "$ERROR: Can't open $docu_toc_file for writing: $!\n"
      if $T2H_SPLIT;
  $T2H_HREF{This} = $T2H_HREF{Contents};
  $T2H_NAME{This} = $T2H_NAME{Contents};
  $T2H_THIS_SECTION = \@toc_lines;
  t2h_print_Toc(\*FILE);
  close(FILE) if $T2H_SPLIT;
}

if (@stoc_lines)
{
  print "# writing Overview in $docu_stoc_file...\n" if $T2H_VERBOSE;
  open (FILE, "> $docu_stoc_file") || die "$ERROR: Can't open $docu_stoc_file for writing: $!\n"
      if $T2H_SPLIT;
  
  $T2H_HREF{This} = $T2H_HREF{Overview};
  $T2H_NAME{This} = $T2H_NAME{Overview};
  $T2H_THIS_SECTION = \@stoc_lines;
  t2h_print_Overview(\*FILE);
  close(FILE) if $T2H_SPLIT;
}

if ($about_body = t2h_about_body())
{
  print "# writing About in $docu_about_file...\n" if $T2H_VERBOSE;
  open (FILE, "> $docu_about_file") || die "$ERROR: Can't open $docu_about_file for writing: $!\n"
      if $T2H_SPLIT;
  
  $T2H_HREF{This} = $T2H_HREF{About};
  $T2H_NAME{This} = $T2H_NAME{About};
  $T2H_THIS_SECTION = [$about_body];
  t2h_print_About(\*FILE);
  close(FILE) if $T2H_SPLIT;
}

unless ($T2H_SPLIT)
{
  t2h_print_page_foot(\*FILE);
  close (FILE);
}
  
Finish:
&l2h_FinishFromHtml if ($T2H_L2H);
&l2h_Finish if($T2H_L2H);
print "# that's all folks\n" if $T2H_VERBOSE;

exit(0);

#+++############################################################################
#                                                                              #
# Low level functions                                                          #
#                                                                              #
#---############################################################################

sub clean_name 
{
  local ($_);
  $_ = &remove_style($_[0]);
  &unprotect_texi;
  return $_;
}

sub update_sec_num {
    local($name, $level) = @_;
    my $ret;

    $level--; # here we start at 0
    if ($name =~ /^appendix/ || defined(@appendix_sec_num)) {
	# appendix style
	if (defined(@appendix_sec_num)) {
	    &incr_sec_num($level, @appendix_sec_num);
	} else {
	    @appendix_sec_num = ('A', 0, 0, 0);
	}
	$ret = join('.', @appendix_sec_num[0..$level]);
    } else {
	# normal style
	if (defined(@normal_sec_num)) 
	{
	  &incr_sec_num($level, @normal_sec_num);
	} 
	else 
	{
	  @normal_sec_num = (1, 0, 0, 0);
	}
	$ret = join('.', @normal_sec_num[0..$level]);
    }
    
    $ret .= "." if $level == 0;
    return $ret;
}

sub incr_sec_num {
    local($level, $l);
    $level = shift(@_);
    $_[$level]++;
    foreach $l ($level+1 .. 3) {
	$_[$l] = 0;
    }
}

sub check {
    local($_, %seen, %context, $before, $match, $after);

    while (<>) {
	if (/\@(\*|\.|\:|\@|\{|\})/) {
	    $seen{$&}++;
	    $context{$&} .= "> $_" if $T2H_VERBOSE;
	    $_ = "$`XX$'";
	    redo;
	}
	if (/\@(\w+)/) {
	    ($before, $match, $after) = ($`, $&, $');
	    if ($before =~ /\b[\w-]+$/ && $after =~ /^[\w-.]*\b/) { # e-mail address
		$seen{'e-mail address'}++;
		$context{'e-mail address'} .= "> $_" if $T2H_VERBOSE;
	    } else {
		$seen{$match}++;
		$context{$match} .= "> $_" if $T2H_VERBOSE;
	    }
	    $match =~ s/^\@/X/;
	    $_ = "$before$match$after";
	    redo;
	}
    }
    
    foreach (sort(keys(%seen))) {
	if ($T2H_VERBOSE) {
	    print "$_\n";
	    print $context{$_};
	} else {
	    print "$_ ($seen{$_})\n";
	}
    }
}

sub open {
    local($name) = @_;

    ++$fh_name;
    if (open($fh_name, $name)) {
	unshift(@fhs, $fh_name);
    } else {
	warn "$ERROR Can't read file $name: $!\n";
    }
}

sub init_input {
    @fhs = ();			# hold the file handles to read
    @input_spool = ();		# spooled lines to read
    $fh_name = 'FH000';
    &open($docu);
}

sub next_line {
    local($fh, $line);

    if (@input_spool) {
	$line = shift(@input_spool);
	return($line);
    }
    while (@fhs) {
	$fh = $fhs[0];
	$line = <$fh>;
	return($line) if $line;
	close($fh);
	shift(@fhs);
    }
    return(undef);
}

# used in pass 1, use &next_line
sub skip_until {
    local($tag) = @_;
    local($_);

    while ($_ = &next_line) {
	return if /^\@end\s+$tag\s*$/;
    }
    die "* Failed to find '$tag' after: " . $lines[$#lines];
}

# used in pass 1 for l2h use &next_line
sub string_until {
    local($tag) = @_;
    local($_, $string);

    while ($_ = &next_line) {
	return $string if /^\@end\s+$tag\s*$/;
#	$_ =~ s/hbox/mbox/g;
	$string = $string.$_;
    }
    die "* Failed to find '$tag' after: " . $lines[$#lines];
}

#
# HTML stacking to have a better HTML output
#

sub html_reset {
    @html_stack = ('html');
    $html_element = 'body';
}

sub html_push {
    local($what) = @_;
    push(@html_stack, $html_element);
    $html_element = $what;
}

sub html_push_if {
    local($what) = @_;
    push(@html_stack, $html_element)
	if ($html_element && $html_element ne 'P');
    $html_element = $what;
}

sub html_pop {
    $html_element = pop(@html_stack);
}

sub html_pop_if {
    local($elt);

    if (@_) {
	foreach $elt (@_) {
	    if ($elt eq $html_element) {
		$html_element = pop(@html_stack) if @html_stack;
		last;
	    }
	}
    } else {
	$html_element = pop(@html_stack) if @html_stack;
    }
}

sub html_debug {
    local($what, $line) = @_;
    return("<!-- $line @html_stack, $html_element -->$what")
	if $T2H_DEBUG & $DEBUG_HTML;
    return($what);
}

# to debug the output...
sub debug {
    local($what, $line) = @_;
    return("<!-- $line -->$what")
	if $T2H_DEBUG & $DEBUG_HTML;
    return($what);
}

sub normalise_node {
    $_[0] =~ s/\s+/ /g;
    $_[0] =~ s/ $//;
    $_[0] =~ s/^ //;
}

sub menu_entry {
    local($entry, $node, $descr) = @_;
    local($href);

    &normalise_node($node);
    $href = $node2href{$node};
    if ($href) {
	$descr =~ s/^\s+//;
	if ($T2H_NUMBER_SECTIONS)
	{
	  $entry = $node2sec{$entry} if ! $descr && $node2sec{$entry};
	  push(@lines2, 
	       '<TR><TD ALIGN="left">' . 
	       &t2h_anchor('', $href, $entry) . 
	       '</TD><TD ALIGN="left">' . $descr . "</TD><TR>\n");
	}
	else
	{
	  push(@lines2, "<LI>" . &t2h_anchor('', $href, $entry) . ": $descr\n");
	}
    } else {
	warn "$ERROR Undefined node ($node): $_";
    }
}

sub do_ctrl { "^$_[0]" }

sub do_email {
    local($addr, $text) = split(/,\s*/, $_[0]);

    $text = $addr unless $text;
    &t2h_anchor('', "mailto:$addr", $text);
}

sub do_sc 
{ 
  # l2h does this much better
  return &l2h_ToLatex("{\\sc ".&unprotect_html($_[0])."}") if ($T2H_L2H);
  return "\U$_[0]\E";
}

sub do_math
{
  return &l2h_ToLatex("\$".&unprotect_html($_[0])."\$") if ($T2H_L2H);
  return "<EM>".$text."</EM>";
}

sub do_uref {
    local($url, $text, $only_text) = split(/,\s*/, $_[0]);

    $text = $only_text if $only_text;
    $text = $url unless $text;
    &t2h_anchor('', $url, $text);
}

sub do_url { &t2h_anchor('', $_[0], $_[0]) }

sub apply_style {
    local($texi_style, $text) = @_;
    local($style);

    $style = $style_map{$texi_style};
    if (defined($style)) { # known style
	if ($style =~ /^\"/) { # add quotes
	    $style = $';
	    $text = "\`$text\'";
	}
	if ($style =~ /^\&/) { # custom
	    $style = $';
	    $text = &$style($text);
	} elsif ($style) { # good style
	    $text = "<$style>$text</$style>";
	} else { # no style
	}
    } else { # unknown style
	$text = undef;
    }
    return($text);
}

# remove Texinfo styles
sub remove_style {
    local($_) = @_;
    s/\@\w+{([^\{\}]+)}/$1/g;
    return($_);
}

sub substitute_style {
    local($_) = @_;
    local($changed, $done, $style, $text);

    $changed = 1;
    while ($changed) {
	$changed = 0;
	$done = '';
	while (/\@(\w+){([^\{\}]+)}/) {
	    $text = &apply_style($1, $2);
	    if ($text) {
		$_ = "$`$text$'";
		$changed = 1;
	    } else {
		$done .= "$`\@$1";
		$_ = "{$2}$'";
	    }
	}
        $_ = $done . $_;
    }
    return($_);
}

sub t2h_anchor {
    local($name, $href, $text, $newline) = @_;
    local($result);

    $result = "<A";
    $result .= " NAME=\"$name\"" if $name;
    $result .= " HREF=\"$href\"" if $href;
    $result .= ">$text</A>";
    $result .= "\n" if $newline;
    return($result);
}

sub pretty_date {
    local(@MoY, $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);

    @MoY = ('January', 'February', 'March', 'April', 'May', 'June',
	    'July', 'August', 'September', 'October', 'November', 'December');
    ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
    $year += ($year < 70) ? 2000 : 1900;
    # obachman: Let's do it as the Americans do
    return("$MoY[$mon], $mday  $year");
}

sub doc_href {
    local($num) = @_;

    return("${docu_name}_$num.$docu_ext");
}

sub sec_href
{
  return $node2href{$sec2node{$_[0]}};
}

sub next_doc {
    $docu_doc = &doc_href(++$doc_num);
}

sub t2h_print_lines {
    my ($fh, $lines) = @_;
    local($_);
    $lines = $T2H_THIS_SECTION unless $lines;
    my $cnt = 0;
    for (@$lines) 
    {
	$_ = l2h_FromHtml($_) if ($T2H_L2H);
	if (/^$PROTECTTAG/o) {
	    $_ = $tag2pro{$_};
	} else {
	    &unprotect_texi;
	}
	print $fh $_;
	$cnt += split(/\W*\s+\W*/);
    }
    return $cnt;
}

sub protect_texi {
    # protect @ { } ` '
    s/\@\@/$;0/go;
    s/\@\{/$;1/go;
    s/\@\}/$;2/go;
    s/\@\`/$;3/go;
    s/\@\'/$;4/go;
}

sub protect_html {
    local($what) = @_;
    # protect & < >
    $what =~ s/\&/\&\#38;/g;
    $what =~ s/\</\&\#60;/g;
    $what =~ s/\>/\&\#62;/g;
    # but recognize some HTML things
    $what =~ s/\&\#60;\/A\&\#62;/<\/A>/g;	      # </A>
    $what =~ s/\&\#60;A ([^\&]+)\&\#62;/<A $1>/g;     # <A [^&]+>
    $what =~ s/\&\#60;IMG ([^\&]+)\&\#62;/<IMG $1>/g; # <IMG [^&]+>
    return($what);
}

sub unprotect_texi {
    s/$;0/\@/go;
    s/$;1/\{/go;
    s/$;2/\}/go;
    s/$;3/\`/go;
    s/$;4/\'/go;
}

sub unprotect_html {
    local($what) = @_;
    $what =~ s/\&\#38;/\&/g;
    $what =~ s/\&\#60;/\</g;
    $what =~ s/\&\#62;/\>/g;
    return($what);
}

sub byalpha {
    $key2alpha{$a} cmp $key2alpha{$b};
}

sub t2h_print_label
{
    my $fh = shift;
    my $href = shift || $T2H_HREF{This};
    $href =~ s/.*#(.*)$/$1/;
    print $fh qq{<A NAME="$href"></A>\n};
}

##############################################################################

	# These next few lines are legal in both Perl and nroff.

.00 ;			# finish .ig
 
'di			\" finish diversion--previous line must be blank
.nr nl 0-1		\" fake up transition to first page again
.nr % 0			\" start at page 1
'; __END__ ############# From here on it's a standard manual page ############
.TH TEXI2HTML 1 "01/05/98"
.AT 3
.SH NAME
texi2html \- a Texinfo to HTML converter
.SH SYNOPSIS
.B texi2html [options] file
.PP
.B texi2html -check [-verbose] files
.SH DESCRIPTION
.I Texi2html
converts the given Texinfo file to a set of HTML files. It tries to handle
most of the Texinfo commands. It creates hypertext links for cross-references,
footnotes...
.PP
It also tries to add links from a reference to its corresponding entry in the
bibliography (if any). It may also handle a glossary (see the
.B \-glossary
option).
.PP
.I Texi2html
may furthermore use latex2html to generate HTML (code and/or images) for @math
and @iftex tags (see the 
.B \-l2h
option).
.PP
.I Texi2html
creates several files depending on the contents of the Texinfo file and on
the chosen options (see FILES).
.PP
The HTML files created by
.I texi2html
are closer to TeX than to Info, that's why
.SH OPTIONS
.TP 12
.B \-check
Check the given file and give the list of all things that may be Texinfo commands.
This may be used to check the output of
.I texi2html
to find the Texinfo commands that have been left in the HTML file.
.TP
.B \-expand info|tex|none
Expand @ifinfo, or @iftex, or sections (default: info)
.TP
.B \-glossary
Use the section named 'Glossary' to build a list of terms and put links in the HTML
document from each term toward its definition.
.TP
.B \-invisible \fIname\fP
Use \fIname\fP to create invisible destination anchors for index links
(you can for instance use the invisible.xbm file shipped with this program).
This is a workaround for a known bug of many WWW browsers, including netscape.
.TP
.B \-I \fIdir\fP
Look also in \fIdir\fP to find included files.
.TP
.B \-menu
Show the Texinfo menus; by default they are ignored.
.TP
.B \-monolithic
Output only one file, including the table of contents and footnotes.
.TP
.B \-number
Number the sections.
.TP
.B \-split_chapter
Split the output into several HTML files (one per main section:
chapter, appendix...).
.TP
.B \-split_node
Split the output into several HTML files (one per node).
.TP
.B \-l2h
Use latex2html for content of @math and @tex tags. Content must be such that 
both, latex and tex, can translate it correctly. I.e., no tex-only constructs 
must be used.
.TP
.B \-l2h_latex2html \fIprog\fP  
Use \fIprog\fP as latex2html program (default \fIlatex2html\fP). 
Program must be executable. 
.TP
.B \-l2h_init \fIfile\fP  
Use \fIfile\fP as latex2html init file. \fIfile\fP should be used to specify in which way latex2html handles mathematical expressions and formulas. 

Note that latex2html locates  
(and uses) init-files in the following order (provided they exist): 
(1) global init file (usually in latex2html source dir) 
(2) $HOME/.latex2html_init 
(3) ./.latex2html_init 
(4) init file given on command line.  
.TP
.B \-l2h_dir \fIdir\fP
Use \fIdir\fP as tmp dir for latex2html. This directory (resp. its path) 
must not contain a dot  (i.e., a ".").
.TP 
.B \-l2h_clean
remove all intermediate files generated by latex2html (prevents caching!)  
.TP 
.B \-l2h_skip
Do not really run latex2html. Use (kept) files of previous runs, instead.
.TP
.B \-usage
Print usage instructions, listing the current available command-line options.
.TP
.B \-verbose
Give a verbose output. Can be used with the
.B \-check
option.
.PP
.SH FILES
By default
.I texi2html
creates the following files (foo being the name of the Texinfo file):
.TP 16
.B foo_toc.html
The table of contents.
.TP
.B foo.html
The document's contents.
.TP
.B foo_foot.html
The footnotes (if any).
.TP
.B foo_l2h_img*
Images generated by latex2html (if any).
.PP
When used with the
.B \-split
option, it creates several files (one per chapter or node), named
.B foo_n.html
(n being the index of the chapter or node), instead of the single
.B foo.html
file.
.PP
When used with the
.B \-monolithic
option, it creates only one file:
.B foo.html
.SH VARIABLES
.I texi2html
predefines the following variables: \fBhtml\fP, \fBtexi2html\fP.
.SH ADDITIONAL COMMANDS
.I texi2html
implements the following non-Texinfo commands (maybe they are in Texinfo now...):
.TP 16
.B @html
This indicates the start of an HTML section, this section will passed through
without any modification.
.TP
.B @end html
This indicates the end of an HTML section.
.SH VERSION
This is \fItexi2html\fP version 1.56k, 1999-02-20.
.PP
The latest version of \fItexi2html\fP and \fIlatex22html\fPcan be found in WWW, cf. URLs
http://wwwinfo.cern.ch/dis/texi2html/
.br
http://texinfo.org/texi2html/
.br
http://www-dsed.llnl.gov/files/programs/unix/latex2html
.br
.SH AUTHOR
The main author is Lionel Cons, CERN IT/DIS/OSE, Lionel.Cons@cern.ch.
Many other people around the net contributed to this program.
.SH COPYRIGHT
This program is the intellectual property of the European
Laboratory for Particle Physics (known as CERN). No guarantee whatsoever is
provided by CERN. No liability whatsoever is accepted for any loss or damage
of any kind resulting from any defect or inaccuracy in this information or
code.
.PP
CERN, 1211 Geneva 23, Switzerland
.SH "SEE ALSO"
GNU Texinfo Documentation Format,
HyperText Markup Language (HTML),
World Wide Web (WWW).
.SH BUGS
This program does not understand all Texinfo commands (yet). A row of
a  mutlicolumn table has to be in one line.
.PP
TeX specific commands (normally enclosed in @iftex) will be
passed over unmodified, unless latex2html is enabled.
.ex
