[BACK]Return to texi2html CVS log [TXT][DIR] Up to [local] / OpenXM / src / asir-doc

File: [local] / OpenXM / src / asir-doc / Attic / texi2html (download)

Revision 1.3, Tue Mar 28 23:22:20 2017 UTC (7 years, 2 months ago) by takayama
Branch: MAIN
Changes since 1.2: +44493 -1953 lines

texi2html is replaced by the latest one.

#! /usr/local/bin/perl --
# perl
'di ';
'ig 00 ';
# texi2html: generated by addformats.sh from texi2html.temp and formats/html.init formats/info.init formats/docbook.init formats/xml.init formats/plaintext.init
# texi2html.temp: generated by buildt2h.sh from texi2html_configured.pl and MySimple.pm T2h_i18n.pm texi2html.init translations.pl examples/l2h.init T2h_l2h.pm documentlanguages.pl
#+##############################################################################
#
# texi2html: Program to transform Texinfo documents to HTML
#
#    Copyright (C) 1999-2010  Patrice Dumas <pertusus@free.fr>,
#                             Derek Price <derek@ximbiot.com>,
#                             Adrian Aichner <adrian@xemacs.org>,
#                           & others.
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
#    02110-1301  USA
#
# Some error messages come from texinfo (makeinfo), so copyright holder 
# is the FSF or the individual who wrote them. All come from before the 
# switch of texinfo to GPLv3+.
#
#-##############################################################################
# The man page for this program is included at the end of this file and can be
# viewed using the command 'nroff -man texi2html'.

# for POSIX::setlocale and File::Spec
require 5.00405;
# Perl pragma to restrict unsafe constructs
use strict;
# used in case of tests, to revert to "C" locale.
use POSIX qw(setlocale LC_ALL LC_CTYPE);
# used to obtain the name of the current working directory
use Cwd;
# Used to find the parent directory of this script.
use File::Basename;
# used to find a relative path back to the current working directory
use File::Spec;
# to determine the path separator and null file
use Config;

#use encoding::warnings;
# for translations
#use encoding 'utf8';
#use utf8;

#
# According to
# larry.jones@sdrc.com (Larry Jones)
# this pragma is not present in perl5.004_02:
#
# Perl pragma to control optional warnings
# use warnings;

# determine the path separators
my $path_separator = $Config{'path_sep'};
$path_separator = ':' if (!defined($path_separator));
my $quoted_path_separator = quotemeta($path_separator);

#++##########################################################################
#
# NOTE FOR DEBUGGING THIS SCRIPT:
# You can run 'perl -x texi2html.pl' directly, provided you have the script
# in the same directory with, or the environment variable T2H_HOME set to
# the directory containing, the texi2html.init, T2h_i18n.pm, translations.pl,
# l2h.init, & T2h_l2h.pm files.  Ditto makeinfo.pl, if you make it a
# symlink to texi2html.pl.
#
#--##########################################################################
my $T2H_HOME = defined $ENV{T2H_HOME} ? $ENV{T2H_HOME} : dirname $0;
if ($0 =~ /\.pl$/)
{
    # Issue a warning in debugging mode if $T2H_HOME is set but isn't
    # accessible.
    if (!-e $T2H_HOME)
    { warn "T2H_HOME ($T2H_HOME) does not exist."; }
    elsif (!-d $T2H_HOME)
    { warn "T2H_HOME ($T2H_HOME) is not a directory."; }
    elsif (!-x $T2H_HOME)
    { warn "T2H_HOME ($T2H_HOME) is not accessible."; }
}

# CVS version:
# $Id: texi2html.pl,v 1.393 2010/06/30 22:01:27 pertusus Exp $

# FIXME. Change for texinfo, and also simplify.

# Homepage:
my $T2H_HOMEPAGE = "http://www.nongnu.org/texi2html/";

# Authors (appears in comments):
my $T2H_AUTHORS = <<EOT;
texi2html was written by: 
            Lionel Cons <Lionel.Cons\@cern.ch> (original author)
            Karl Berry  <karl\@freefriends.org>
            Olaf Bachmann <obachman\@mathematik.uni-kl.de>
            and many others.
Maintained by: Many creative people.
Send bugs and suggestions to <texi2html-bug\@nongnu.org>
EOT

# Version: set in configure.in
my $THISVERSION = '5.0';
my $THISPROG = "texi2html $THISVERSION"; # program name and version

#+++########################################################################
#                                                                          #
# Paths and file names                                                     #
#                                                                          #
#---########################################################################

# set by configure, prefix for the sysconfdir and so on
my $prefix = '/usr/local';
my $datarootdir;# = '${prefix}/share';
my $sysconfdir;
my $pkgdatadir;
my $datadir;

# We need to eval as $prefix has to be expanded. However when we haven't
# run configure @sysconfdir will be expanded as an array, thus we verify
# whether configure was run or not
if ('${prefix}/etc' ne '@' . 'sysconfdir@')
{
    $sysconfdir = eval '"${prefix}/etc"';
}
else
{
    $sysconfdir = "/usr/local/etc";
}

if ('${prefix}/share' ne '@' . 'datarootdir@')
{
    $datarootdir = eval '"${prefix}/share"';
}
else
{
    $datarootdir = "/usr/local/share";
}

if ('${datarootdir}' ne '@' . 'datadir@')
{
    $pkgdatadir = eval '"${datarootdir}/texi2html"';
    $datadir = eval '"${datarootdir}"';
}
else
{
    $pkgdatadir = "/usr/local/share/texi2html";
    $datadir = "/usr/local/share";
}

my $target_prefix = "t_h";



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

my $DEBUG_MENU   =  1;
my $DEBUG_INDEX =  2;
my $DEBUG_TEXI  =  4;
my $DEBUG_MACROS =  8;
my $DEBUG_FORMATS   = 16;
my $DEBUG_ELEMENTS  = 32;
my $DEBUG_USER  = 64;
my $DEBUG_L2H   = 128;

my $VARRE = '[\w\-]+';          # RE for a variable name

my $MAX_LEVEL = 4;
my $MIN_LEVEL = 1;

#+++########################################################################
#                                                                          #
# Command name and default format                                          #
#                                                                          #
#---########################################################################

my $real_command_name = $0;
$real_command_name =~ s/.*\///;
$real_command_name =~ s/\.pl$//;

my %command_format = (
 'texi2html' => 'html',
 'makeinfo' => 'info',
 'texi2any' => 'raw-text',
);

# Config files

my $i18n_dir = 'i18n'; # name of the directory containing the per language files
my $conf_file_name = 'Config' ;
my $texinfo_htmlxref = 'htmlxref.cnf';

# directories for texinfo configuration files
my @texinfo_config_dirs = ('./.texinfo');
push @texinfo_config_dirs, "$ENV{'HOME'}/.texinfo" if (defined($ENV{'HOME'}));
push @texinfo_config_dirs, "$sysconfdir/texinfo" if (defined($sysconfdir));
push @texinfo_config_dirs, "$datadir/texinfo" if (defined($datadir));

my @program_config_dirs;
my @program_init_dirs;

# program name dependent initializations: config directories and default
# format.
sub set_config_init_dirs_output($)
{
  my $program_name = shift;
  if (!defined($command_format{$program_name}))
  {
    # user can make any link to set $0, or use --program with an unknown name. 
    # In that case the default is to use texi2any
    $program_name = 'texi2any';
  }
  my $default_output_format = $command_format{$program_name};


  # directories for config files
  @program_config_dirs = ('./');
  push @program_config_dirs, "$ENV{'HOME'}/.$program_name/" if (defined($ENV{'HOME'}));
  push @program_config_dirs, "$sysconfdir/$program_name/" if (defined($sysconfdir));
  push @program_config_dirs, "$datadir/$program_name" if (defined($datadir));

  # directories for init files
  @program_init_dirs = @program_config_dirs;
  # common directories for all command names
  foreach my $texinfo_config_dir (@texinfo_config_dirs)
  {
    push @program_init_dirs, "${texinfo_config_dir}/init/";
  }
  $Texi2HTML::Config::DEFAULT_OUTPUT_FORMAT = $default_output_format;
  $Texi2HTML::Config::COMMAND_NAME = $program_name;
  Texi2HTML::Config::t2h_default_load_format($default_output_format, 0);
}

#+++###########################################################################
#                                                                             #
# Initialization                                                              #
# Some declarations, some functions that are GPL and therefore cannot be in   #
# texi2html.init, some functions that are not to be customized.               #
# Pasted content of File $(srcdir)/texi2html.init: Default initializations    #
#                                                                             #
#---###########################################################################
{
package Texi2HTML::Config;

use Config;

# customization options variables

use vars qw(
$DEBUG
$PREFIX
$VERBOSE
$SUBDIR
$IDX_SUMMARY
$SPLIT
$SPLIT_SIZE
$SHORT_REF
@EXPAND
$TOP
$DOCTYPE 
$FRAMESET_DOCTYPE 
$ERROR_LIMIT
$CHECK 
$TEST 
$DUMP_TEXI
$MACRO_EXPAND
$CAPTION_STYLE
$USE_ISO 
$TOP_FILE 
$TOC_FILE
$FRAMES
$SHOW_MENU
$SHOW_TITLE
$NUMBER_SECTIONS
$NUMBER_FOOTNOTES
$USE_NODES
$USE_SECTIONS
$USE_NODE_TARGET
$USE_UNICODE
$USE_UNIDECODE
$TRANSLITERATE_FILE_NAMES
$NODE_FILES
$NODE_FILENAMES
$NODE_NAME_IN_MENU
$NODE_NAME_IN_INDEX
$AVOID_MENU_REDUNDANCY
$HEADERS
$NO_WARN
$FORCE
$MONOLITHIC
$SHORTEXTN 
$EXTENSION
$OUT 
$NOVALIDATE
$DEF_TABLE 
$DOCUMENTLANGUAGE 
$CONTENTS
$SHORTCONTENTS
$FOOTNOTESTYLE
$FILLCOLUMN
$SETCONTENTSAFTERTITLEPAGE
$SETSHORTCONTENTSAFTERTITLEPAGE
$KBDINPUTSTYLE
$FRENCHSPACING
$ALLOWCODEBREAKS
$SETFILENAME
$TOC_LINKS
$L2H 
$L2H_L2H 
$L2H_SKIP 
$L2H_TMP 
$L2H_CLEAN 
$L2H_FILE
$L2H_HTML_VERSION
$EXTERNAL_DIR
@INCLUDE_DIRS 
@PREPEND_DIRS 
@CONF_DIRS 
$IGNORE_PREAMBLE_TEXT
@CSS_FILES
@CSS_REFS
$INLINE_CONTENTS
$INLINE_INSERTCOPYING
$PARAGRAPHINDENT
$FIRSTPARAGRAPHINDENT
$ENABLE_ENCODING
$INTERNAL_LINKS
$DEFAULT_OUTPUT_FORMAT
$OUTPUT_FORMAT
$COMMAND_NAME
@COMMANDS
);

# customization variables
use vars qw(
$ENCODING_NAME
$DOCUMENT_ENCODING
$OUT_ENCODING
$IN_ENCODING
$DEFAULT_ENCODING
$MENU_PRE_STYLE
$MENU_PRE_COMPLEX_FORMAT
$EXAMPLE_INDENT_CELL
$SMALL_EXAMPLE_INDENT_CELL
$SMALL_FONT_SIZE
$SMALL_RULE
$DEFAULT_RULE
$MIDDLE_RULE
$BIG_RULE
$TOP_HEADING
$INDEX_CHAPTER
$SPLIT_INDEX
$USE_MENU_DIRECTIONS
$USE_UP_FOR_ADJACENT_NODES
$AFTER_BODY_OPEN
$PRE_BODY_CLOSE
$EXTRA_HEAD
$VERTICAL_HEAD_NAVIGATION
$WORDS_IN_PAGE
$ICONS
$UNNUMBERED_SYMBOL_IN_MENU
$SIMPLE_MENU
$MENU_SYMBOL
$MENU_ENTRY_COLON
$INDEX_ENTRY_COLON
$USE_ACCESSKEY
$USE_REL_REV
$USE_LINKS
$OPEN_QUOTE_SYMBOL
$CLOSE_QUOTE_SYMBOL
$NO_NUMBER_FOOTNOTE_SYMBOL
$NO_BULLET_LIST_STYLE
$NO_BULLET_LIST_ATTRIBUTE
$NO_BULLET_LIST_CLASS
$TOP_NODE_FILE
$TOP_NODE_FILE_TARGET
$TOP_NODE_UP
$NODE_FILE_EXTENSION
$STDIN_DOCU_NAME
$STDOUT_DOCU_NAME
$BEFORE_OVERVIEW
$AFTER_OVERVIEW
$BEFORE_TOC_LINES
$AFTER_TOC_LINES
$NEW_CROSSREF_STYLE
$TOP_HEADING_AT_BEGINNING
$USE_NUMERIC_ENTITY
$USE_SETFILENAME
$USE_SETFILENAME_EXTENSION
$SEPARATE_DESCRIPTION
$IGNORE_BEFORE_SETFILENAME
$OVERVIEW_LINK_TO_TOC
$COMPLETE_IMAGE_PATHS
$DATE
%ACTIVE_ICONS
%NAVIGATION_TEXT
%PASSIVE_ICONS
%BUTTONS_NAME
%BUTTONS_GOTO
%BUTTONS_EXAMPLE
%BUTTONS_ACCESSKEY
%BUTTONS_REL
%BUTTONS_TEXT
@T2H_FORMAT_EXPAND
@CHAPTER_BUTTONS
@MISC_BUTTONS
@SECTION_BUTTONS
@SECTION_FOOTER_BUTTONS
@NODE_FOOTER_BUTTONS
@TOP_BUTTONS
@LINKS_BUTTONS
@IMAGE_EXTENSIONS
@INPUT_FILE_SUFFIXES
$ENABLE_ENCODING_USE_ENTITY
$PROGRAM_NAME_IN_FOOTER
$HEADER_IN_TABLE
$DATE_IN_HEADER
$COMPLEX_FORMAT_IN_TABLE
$USE_TITLEPAGE_FOR_TITLE
$INLINE_CSS_STYLE
$NO_CSS
$I18N_PERL_HASH
$USE_NLS
);

# customization variables which may be guessed in the script
#our $ADDRESS;
use vars qw(
$BODYTEXT
$CSS_LINES
$DOCUMENT_DESCRIPTION
$EXTERNAL_CROSSREF_SPLIT
);

# I18n
use vars qw(
$I
$LANGUAGES
);

# customizable subroutines references
use vars qw(
$print_section
$one_section
$end_section
$print_Top_header
$print_Top_footer
$print_Top
$print_Toc
$print_Overview
$print_Footnotes
$print_About
$print_misc_header
$print_misc_footer
$print_misc
$print_section_header
$print_section_footer
$print_chapter_header
$print_chapter_footer
$print_element_header
$print_page_head
$print_page_foot
$print_head_navigation
$print_foot_navigation
$print_title
$button_icon_img
$button_formatting
$print_navigation
$about_body
$print_frame
$print_toc_frame
$toc_body
$contents
$internal_links
$shortcontents
$titlepage
$insertcopying
$css_lines
$print_redirection_page
$translate_names
$init_out
$finish_out
$node_file_name
$element_file_name
$node_target_name
$element_target_name
$placed_target_file_name
$inline_contents
$program_string

$preserve_misc_command
$misc_command_line
$misc_command_line_texi
$protect_text
$anchor
$anchor_label
$element_label
$misc_element_label
$def_item
$def
$menu
$menu_command
$menu_link
$menu_description
$menu_comment
$simple_menu_link
$ref_beginning
$info_ref
$book_ref
$external_href
$external_ref
$internal_ref
$table_item
$table_line
$row
$cell
$list_item
$comment
$def_line
$def_line_no_texi
$heading_no_texi
$raw
$raw_no_texi
$heading
$element_heading
$heading_text
$heading_text_preformatted
$paragraph
$preformatted
$empty_preformatted
$foot_line_and_ref
$foot_section
$image
$image_files
$index_entry_label
$index_entry
$index_entry_command
$index_letter
$print_index
$printindex
$index_summary
$summary_letter
$complex_format
$cartouche
$sp
$definition_category
$definition_index_entry
$table_list
$copying_comment
$documentdescription
$index_summary_file_entry
$index_summary_file_end
$index_summary_file_begin
$style
$line_command
$format
$normal_text
$empty_line
$unknown
$unknown_style
$float
$caption_shortcaption
$caption_shortcaption_command
$listoffloats
$listoffloats_entry
$listoffloats_caption
$listoffloats_float_style
$listoffloats_style
$acronym_like
$quotation
$quotation_prepend_text
$paragraph_style_command
$heading_texi
$index_element_heading_texi
$format_list_item_texi
$begin_format_texi
$begin_style_texi
$begin_paragraph_texi
$tab_item_texi
$footnote_texi
$colon_command
$simple_command
$thing_command
$begin_special_region
$end_special_region

$PRE_ABOUT
$AFTER_ABOUT
);

# hash which entries might be redefined by the user
use vars qw(
$complex_format_map
%complex_format_map
%accent_map
%def_map
%format_map
%simple_map
%simple_map_pre
%simple_map_texi
%simple_map_math
%style_map
%style_map_pre
%style_map_math
%style_map_texi
%simple_format_simple_map_texi
%simple_format_style_map_texi
%simple_format_texi_map
%line_command_map
%command_type
%paragraph_style
%stop_paragraph_command
%format_code_style
%region_formats_kept
%texi_formats_map
%things_map
%pre_map
%math_map
%texi_map
%sorting_things_map
%unicode_map
%unicode_diacritical
%transliterate_map 
%transliterate_accent_map
%no_transliterate_map
%ascii_character_map
%default_simple_map
%default_things_map
%default_texi_map
%default_style_map
%default_style_map_pre
%default_style_map_texi
%default_simple_format_style_map_texi
%numeric_entity_map
%perl_charset_to_html
%misc_pages_targets
%misc_command
%no_paragraph_commands
%css_map
%format_in_paragraph
%special_list_commands
%accent_letters
%unicode_accents
%special_accents
%inter_item_commands
$def_always_delimiters
$def_in_type_delimiters
$def_argument_separator_delimiters
%colon_command_punctuation_characters
$punctuation_characters
$after_punctuation_characters
@command_handler_setup
@command_handler_init
@command_handler_names
@command_handler_process
@command_handler_output
@command_handler_finish
%command_handler
%special_style
%null_device_file
%language_codes
%region_codes
%deprecated_commands
%output_format_names
%canonical_texinfo_encodings
@text_substitutions_normal
@text_substitutions_texi
@text_substitutions_simple_format
@text_substitutions_pre
%htmlxref_entries
);

# deprecated
use vars qw(
$address
%iso_symbols
%simple_map_pre_math
%simple_map_texi_math
$ENCODING
$CENTER_IMAGE
$HREF_DIR_INSTEAD_FILE
$EXPAND
$USE_GLOSSARY 
$INVISIBLE_MARK 
);

# subject to change
use vars qw(
%makeinfo_encoding_to_map
%makeinfo_unicode_to_eight_bit
%eight_bit_to_unicode
%t2h_encoding_aliases
);

# FIXME i18n ?
%output_format_names = (
  'info' => 'Info',
  'html' => 'HTML',
  'docbook' => 'Docbook XML',
  'xml' => 'Texinfo XML',
  'plaintext' => 'plain text',
  'raw-text' => 'raw text',
);

sub load($) 
{
    my $file = shift;
    # If required like other init files, the functions would be redefined
    # and the format dependent stuff wouldn't be loaded. Having the 
    # formats loaded could be worked around, for example there could be
    # a variable that, and if the variable is defined a function reference
    # should be called right after the require. There is no real 
    # workaround for having the function redefined, though.
    foreach my $output_format (keys(%output_format_names))
    {
      if ($file =~ /\/$output_format\.init$/)
      {
         t2h_default_load_format($output_format, 1);
         return 1;
      }
    }
    eval { require($file) ;};
    if ($@ ne '')
    {
        print STDERR "error loading $file: $@\n";
        return 0;
    }
    return 1;
}


sub set_conf($$;$)
{
    my $name = shift;
    my $value = shift;
    my $not_global = shift;

    unless ($not_global)
    {
       if (defined($value))
       {
          $Texi2HTML::GLOBAL{$name} = $value;
       }
       else
       {
          delete $Texi2HTML::GLOBAL{$name};
       }
       return 1;
    }
    return 0 if (defined($Texi2HTML::GLOBAL{$name}));
    if (defined($value))
    {
       $Texi2HTML::THISDOC{$name} = $value;
    }
    else
    {
       delete $Texi2HTML::THISDOC{$name};
    }
    return 1;
}

my %config_map = (
   'paragraphindent' => \$PARAGRAPHINDENT,
   'firstparagraphindent' => \$FIRSTPARAGRAPHINDENT,
   'footnotestyle' => \$FOOTNOTESTYLE,
   'fillcolumn' => \$FILLCOLUMN,
   'documentlanguage' => \$DOCUMENTLANGUAGE,
   'novalidate' => \$NOVALIDATE,
   'SPLIT' => \$SPLIT,
   'SPLIT_SIZE' => \$SPLIT_SIZE,
   'contents' => \$CONTENTS,
   'shortcontents' => \$SHORTCONTENTS,
   'doctype' => \$DOCTYPE,
   'headers' => \$HEADERS,
   'DOCUMENT_ENCODING' => \$DOCUMENT_ENCODING,
   'IN_ENCODING' => \$IN_ENCODING,
   'setcontentsaftertitlepage' => \$SETCONTENTSAFTERTITLEPAGE,
   'setshortcontentsaftertitlepage'  => \$SETSHORTCONTENTSAFTERTITLEPAGE,
   'kbdinputstyle' => \$KBDINPUTSTYLE,
   'frenchspacing' => \$FRENCHSPACING,
   'allowcodebreaks' => \$ALLOWCODEBREAKS,
   'setfilename' => \$SETFILENAME,
   'use_nls' => \$USE_NLS,
);

sub get_conf($)
{
    my $name = shift;
    return $Texi2HTML::THISDOC{$name} if (defined($Texi2HTML::THISDOC{$name}));
    return $Texi2HTML::GLOBAL{$name} if (defined($Texi2HTML::GLOBAL{$name}));
    return ${$config_map{$name}} if (defined($config_map{$name}));
    # there is no default value for many @-commmands, like headings....
    #print STDERR "Unknown conf string: $name\n";
}

# manage expanded sections
sub set_expansion($$)
{
    my $region = shift;
    my $set = shift;
    $set = 1 if (!defined($set));
    if ($set)
    {
         push (@EXPAND, $region) unless (grep {$_ eq $region} @EXPAND);
    }
    else
    {
         @EXPAND = grep {$_ ne $region} @EXPAND;
         @T2H_FORMAT_EXPAND = grep {$_ ne $region} @T2H_FORMAT_EXPAND;
    }
}

# needed in this namespace for translations
$I = \&Texi2HTML::I18n::get_string;
sub gdt($;$$)
{
    return &main::gdt(@_);
}

sub __($)
{
    return &main::__(@_);
}

sub __p($$)
{
    return &main::__p(@_);
}

sub N__($)
{
    return $_[0];
}

#
# Function refs covered by the GPL as part of the texi2html.pl original
# code. As such they cannot appear in texi2html.init which is public 
# domain (at least the things coded by me, and, if I'm not wrong also the 
# things coded by Olaf -- Pat).
#

sub HTML_DEFAULT_shortcontents($$)
{
    my $elements_list = shift;
    my $stoc_file = shift;
    return unless (Texi2HTML::Config::get_conf('shortcontents') or $FRAMES);
    my $ul_class = '';
    $ul_class = $NO_BULLET_LIST_CLASS if ($NUMBER_SECTIONS);
    my @result = ();
    foreach my $element (@$elements_list)
    {
        next if ($element->{'tag'} eq 'top' or $element->{'toc_level'} != 1);
        my $dest_for_stoc = $element->{'file'};
        my $dest_target_for_stoc = $element->{'target'};
        if ($Texi2HTML::Config::OVERVIEW_LINK_TO_TOC)
        {
            $dest_for_stoc = $Texi2HTML::THISDOC{'toc_file'};
            $dest_target_for_stoc = $element->{'tocid'};
        }
        $dest_for_stoc = '' if ($dest_for_stoc eq $stoc_file);
        my $text = $element->{'text'};
        my $stoc_entry = "<li>" . &$anchor ($element->{'stocid'}, "$dest_for_stoc#$dest_target_for_stoc",$text);
        push(@result, $stoc_entry. "</li>\n");
    }
    if (@result)
    {
        unshift @result, html_default_attribute_class('ul', $ul_class) .">\n";
        push @result, "</ul>\n";
        unshift @result, $BEFORE_OVERVIEW;
        push @result, $AFTER_OVERVIEW;
    }
    return \@result;
}


sub HTML_DEFAULT_contents($$)
{
    my $elements_list = shift;
    my $toc_file = shift;

    return unless (Texi2HTML::Config::get_conf('contents'));

    my $current_level = 0;
    my $ul_class = '';
    $ul_class = $NO_BULLET_LIST_CLASS if ($NUMBER_SECTIONS);
    my @result = ();
    foreach my $element (@$elements_list)
    {
        next if ($element->{'tag'} eq 'top');
        my $ind = '  ' x $current_level;
        my $level = $element->{'toc_level'};
        print STDERR "Bug no toc_level for ($element) $element->{'texi'}\n" if (!defined ($level));
        if ($level > $current_level)
        {
            while ($level > $current_level)
            {
                $current_level++;
                my $ln = "\n$ind".html_default_attribute_class('ul', $ul_class).">\n";
                $ind = '  ' x $current_level;
                push(@result, $ln);
            }
        }
        elsif ($level < $current_level)
        {
            while ($level < $current_level)
            {
                $current_level--;
                $ind = '  ' x $current_level;
                my $line = "</li>\n$ind</ul>";
                $line .=  "</li>" if ($level == $current_level);
                push(@result, "$line\n");
            }
        }
        else
        {
            push(@result, "</li>\n");
        }
        my $dest_for_toc = $element->{'file'};
        my $dest_for_stoc = $element->{'file'};
        my $dest_target_for_stoc = $element->{'target'};
        $dest_for_toc = '' if ($dest_for_toc eq $toc_file);
        my $text = $element->{'text'};
        my $toc_entry = "<li>" . &$anchor ($element->{'tocid'}, "$dest_for_toc#$element->{'target'}",$text);
        push (@result, $ind . $toc_entry);
    }
    while (0 < $current_level)
    {
        $current_level--;
        my $ind = '  ' x $current_level;
        push(@result, "</li>\n$ind</ul>\n");
    }
    if (@result)
    {
        unshift @result, $BEFORE_TOC_LINES;
        push @result, $AFTER_TOC_LINES;
    }
    return \@result;
}

#$toc_body                 = \&T2H_GPL_toc_body;
#$style                    = \&T2H_GPL_style;
#$format                   = \&T2H_GPL_format;
#$printindex               = \&t2h_GPL_default_printindex;
#$summary_letter           = \&t2h_default_summary_letter;


sub T2H_GPL_style($$$$$$$$$$)
{                           # known style
    my $style = shift;
    my $command = shift;
    my $text = shift;
    my $args = shift;
    my $no_close = shift;
    my $no_open = shift;
    my $line_nr = shift;
    my $state = shift;
    my $style_stack = shift;
    my $kept_line_nrs = shift;

    my $do_quotes = 0;
    my $use_attribute = 0;
    my $use_begin_end = 0;
    my $inline_attribute = 0;
    if (ref($style) eq 'HASH')
    {
        #print STDERR "GPL_STYLE $command ($style)\n";
        #print STDERR " @$args\n";
        if (ref($style->{'args'}) ne 'ARRAY')
        {
            print STDERR "BUG: args not an array for command `$command'\n";
        }
        $do_quotes = $style->{'quote'};
        if (defined($style->{'function'}))
        {
            $text = &{$style->{'function'}}($command, $args, $style_stack, $state, $line_nr, $kept_line_nrs);
        }
        elsif (@{$style->{'args'}} == 1) 
        {
            if (defined($style->{'inline_attribute'}))
            {
                $style = $style->{'inline_attribute'};
                $use_attribute = 1;
                $inline_attribute = 1;
            }
            elsif (defined($style->{'attribute'}))
            {
                $style = $style->{'attribute'};
                $use_attribute = 1;
            }
            #$text = $args->[0];
        }
    }
    else
    {
        if ($style =~ s/^\"//)
        {                       # add quotes
            $do_quotes = 1;
        }
        if ($style =~ s/^\&//)
        {                       # custom
            $style = 'Texi2HTML::Config::' . $style;
            eval "\$text = &$style(\$text, \$command, \$style_stack)";
        }
        elsif ($style ne '')
        {
            $use_attribute = 1;
        }
        else
        {                       # no style
        }
    }
    if ($use_attribute)
    {
        my ($attribute_text, $class);
        ($style, $class, $attribute_text) = html_default_parse_attribute ($style);
        $text = html_default_attribute_class($style, $class) . "$attribute_text>" . "$text" if (!$no_open or $inline_attribute);
        $text .= "</$style>" if (!$no_close or $inline_attribute);
        if ($do_quotes)
        {
             $text = $OPEN_QUOTE_SYMBOL . "$text" if (!$no_open);
             $text .= $CLOSE_QUOTE_SYMBOL if (!$no_close);
        }
    }
    if (ref($style) eq 'HASH')
    {
        if (defined($style->{'begin'}) and !$no_open)
        {
             $text = $style->{'begin'} . $text;
        }
        if (defined($style->{'end'}) and !$no_close)
        {
            $text = $text . $style->{'end'};
        }
        if (defined($style->{'inline_begin'}))
        {
             $text = $style->{'inline_begin'} . $text;
        }
        if (defined($style->{'inline_end'}))
        {
            $text = $text . $style->{'inline_end'};
        }
    }
    if ($do_quotes and !$use_attribute)
    {
        $text = $OPEN_QUOTE_SYMBOL . "$text" if (!$no_open);
        $text .= $CLOSE_QUOTE_SYMBOL if (!$no_close);
    }
    return $text;
}

sub T2H_GPL_format($$$)
{
    my $tag = shift;
    my $element = shift;
    my $text = shift;
    return '' if (!defined($element) or ($text !~ /\S/));
    return $text if ($element eq '');
    my $attribute_text = '';
    if ($element =~ /^(\w+)(\s+.*)/)
    {
        $element = $1;
        $attribute_text = $2;
    }
    return "<${element}$attribute_text>\n" . $text. "</$element>\n";
}

# for each index holds the letters split as determined by SPLIT_INDEX.
my %t2h_default_index_letters_array;
# equivalent of doc_nr, but with files (and hence numbers) added when 
# a split index leads to an additional element and a file is created.
my $t2h_default_file_number;
# this is an increasing number to construct the id for each newly
# created index element.
my $t2h_default_index_id_nr;
# this holds the file name associated with an element file, such
# as to follow the splitting coming from the main program, and also use
# the newly generated files.
my %t2h_default_seen_files;
# holds the elements and indices that are split to easily set the
# directions after they are done in the main program.
my $t2h_default_element_split_printindices;

# construct a hash of index names holding the letter grouped how they will
# be split.
sub t2h_default_init_split_indices()
{
    push @command_handler_process, \&t2h_default_index_rearrange_directions;
    %t2h_default_index_letters_array = ();
    %t2h_default_seen_files = ();
    $t2h_default_element_split_printindices = undef;
    $t2h_default_index_id_nr = 0;
    $t2h_default_file_number = 0;

    foreach my $index_name(keys %{$Texi2HTML::THISDOC{'index_letters_array'}})
    {
        my $entries_count = 0;
        my @letters = ();
        foreach my $letter_entry (@{$Texi2HTML::THISDOC{'index_letters_array'}->{$index_name}})
        {
          push @letters, $letter_entry;
          $entries_count += scalar(@{$letter_entry->{'entries'}});
          # Don't split if document is not split
          if (get_conf('SPLIT') and $SPLIT_INDEX and $entries_count >= $SPLIT_INDEX)
          {
            push @{$t2h_default_index_letters_array{$index_name}}, [ @letters ];
            @letters = ();
            $entries_count = 0;
          }
        }
        push @{$t2h_default_index_letters_array{$index_name}}, [ @letters ] if (scalar(@letters));
    }
}

sub t2h_default_associate_index_element($$$$)
{
  my $element = shift;
  my $is_top = shift;
  my $docu_name = shift;
  my $use_node_file = shift;

  my $default_element_file = $element->{'file'};

  # redo the file naming -- the doc_nr part -- in case new elements were 
  # inserted upon index split. But respect the default splitting to keep
  # the elements that are associated with the same file in the same file,
  # or the added file.
  if (!$use_node_file or $t2h_default_seen_files{$default_element_file})
  {
    my $file;
    if ($t2h_default_seen_files{$default_element_file})
    {
      $file = $t2h_default_seen_files{$default_element_file};
    }
    else
    {
      if ($is_top eq 'top')
      { # this is the element_top, so we keep docu_top as associated file.
        # this, in fact, is not necessary since the element_top is never
        # associated with another element, but who knows.
         $t2h_default_seen_files{$default_element_file} = $default_element_file;
      }
      else
      {
        $file = "${docu_name}_$t2h_default_file_number";
        $file .= '.' . $Texi2HTML::THISDOC{'extension'} if
           (defined($Texi2HTML::THISDOC{'extension'}));
        $t2h_default_seen_files{$default_element_file} = $file;
      }
      $t2h_default_file_number++;
    }
    $element->{'file'} = $file if (defined($file));
  }
  
  my $level = $element->{'level'};

  # Even if, without USE_SECTION, output can be split at chapter or 
  # section we don't split indices accordingly. We don't want to add
  # more cases where users want split indices, this was a very difficult
  # to maintain feature from the beginning.
  #$level = $element->{'with_section'}->{'level'} if (!defined($level) and
  #    defined($element->{'with_section'}));

  # if the element is not the level of splitting, then we don't split.
  # also if 'top' is set we don't split since the formatting is different
  # in that case and the result would be quite unpredictable.
  return if ($element->{'top'} or ((get_conf('SPLIT') ne 'node')
      and (!defined($level) or $level > $Texi2HTML::THISDOC{'split_level'})));

  #print STDERR "Doing printindices for $element $element->{'texi'}, file $element->{'file'} (@{$element->{'place'}})\n";


  # iterate over the @places of the element, which includes associated nodes,
  # associated elements, anchors, footnotes, floats, index entries, 
  # printindices (including the element command itself, be it a @node or 
  # a sectioning @-command). 
  # during the iteration, split printindices that needs it, and reassociate
  # other placed elements with files and elements.

  my $current_element = $element;
  my @places = @{$element->{'place'}};
  @{$element->{'place'}} = ();

  foreach my $place (@places)
  {
    my ($printindex, $printindex_to_split, $index_name);

    # determines if the placed thing is a printindex to be split
    if ($place->{'command'} and $place->{'command'} eq 'printindex')
    {
        $printindex = $place;
        $index_name = $printindex->{'name'};
        # ! empty index
        if (exists($t2h_default_index_letters_array{$index_name}) and 
        # split index
         scalar(@{$t2h_default_index_letters_array{$index_name}} > 1)
         # the condition defined($printindex->{'associated_element'} implies 
         # that we don't split printindex before first element, otherwise
         # there will be a need to begin document without a first element 
         # which would be annoying.
         and defined($printindex->{'associated_element'}))
        {
            $printindex_to_split = 1;
        }
    }
        
    # this is a non split printindex or any other placed thing.
    if (!$printindex_to_split)
    {
       push @{$current_element->{'place'}}, $place;
       # don't remodify the original element file, it was set right at the 
       # beginning of the function.
       $place->{'file'} = $current_element->{'file'} if ($place ne $element);
       # the 'element_ref' has to be reset. Otherwise, $place->{'element_ref'}
       # will appear as a new element and trigger closing the file and 
       # opening a new one.
       $place->{'element_ref'} = $current_element if ($place->{'element_ref'} and $current_element ne $element);
       # this resets the element associated with a printindex.
       if ($place->{'associated_element'} and $current_element ne $element)
       {
           $place->{'associated_element'} = $current_element;
       }
       next;
    }

    # now split the index

    my @letter_groups = ();
    my @letters_split = @{$t2h_default_index_letters_array{$index_name}};
    foreach my $letters_split (@letters_split)
    {
        push @letter_groups, {'letters' => [@$letters_split]};
    }

    $letter_groups[0]->{'element'} = $current_element;

    # besides preparing the new elements corresponding with split indices,
    # they are recorded for later directions rearrangements in 
    # t2h_default_index_rearrange_directions.

    # this weird construct is there because the element used as a key is 
    # converted to a string by perl, losing its meaning as a reference, 
    # the reference must be recorded explicitly
    $t2h_default_element_split_printindices->{$element}->{'element'} = $element;
    push @{$t2h_default_element_split_printindices->{$element}->{'printindices'}}, $printindex;
    #print STDERR "Setting $element, $element->{'texi'}, $printindex $printindex->{'name'} as a split element\n";
    foreach my $split_group (@letter_groups)
    {
        my $first_letter = $split_group->{'letters'}->[0]->{'letter'};
        my $last_letter = $split_group->{'letters'}->[-1]->{'letter'};
        if (!$split_group->{'element'})
        { # this is not the first letters group, which is already associated
          # with an element, a new element is done.

          # construct new element name
          my $letters_heading;
          if ($last_letter ne $first_letter)
          {
            $letters_heading = &$normal_text("$first_letter -- $last_letter");
          }
          else
          {
            $letters_heading = &$normal_text("$first_letter");
          }
          my ($name, $simple);
          my $texi = "ADDED ELEMENT $element->{'texi'}: $letters_heading";
          if (!defined($element->{'text'}))
          {
            my $element_heading_texi = &$heading_texi($element->{'tag'}, $element->{'texi'}, $element->{'number'});

            my $index_heading_texi = &$index_element_heading_texi(
                 $element_heading_texi,
                 $element->{'tag'},
                 $element->{'texi'},
                 $element->{'number'},
                 $first_letter, $last_letter);
            $name = main::substitute_line($index_heading_texi, sprintf(__p("\@sectionning_command index page","\@%s index page"), $element->{'tag'}));
            $simple = main::simple_format(undef,undef,"simple_format \@$element->{'tag'} index page", $index_heading_texi);
          }
          else
          { # should never happen, at this point 'text' is always undefined.
            $name = "$element->{'text'}: $letters_heading";
            $simple = "$element->{'simple_format'}: $letters_heading";
          }

          #file and id
          my $relative_file = $Texi2HTML::THISDOC{'file_base_name'} . '_' . $t2h_default_file_number;
          $t2h_default_file_number++;
          $relative_file .= '.' . $Texi2HTML::THISDOC{'extension'} if 
             (defined($Texi2HTML::THISDOC{'extension'}));
          my $id = "index_split-$t2h_default_index_id_nr";
          $t2h_default_index_id_nr++;

          my $new_element = { 'file' => $relative_file, 'id' => $id, 'target' => $id, 'text' => $name, 'texi' => $texi, 'seen' => 1, 'simple_format' => $simple };
          # to avoid crashing when there is a filename collision.
          main::add_file($new_element->{'file'});

          $split_group->{'element'} = $new_element;
          $current_element = $new_element;
          #print STDERR "Added file $new_element->{'file'} ($new_element, $new_element->{'id'}) for $new_element->{'texi'} ($first_letter:$last_letter)\n";
        }
        else
        { # this is the first index split, it is still associated with the element
          #print STDERR "No file added for ($first_letter:$last_letter)\n";
        }
    }
    $t2h_default_seen_files{$default_element_file} = $current_element->{'file'};
    $printindex->{'split_groups'} = \@letter_groups;
    #print STDERR "$index_name processed for $element, $element->{'texi'} (@{$printindex->{'split_groups'}})\n";
  }
}

# set directions for added elements now that they are done in the
# main program for all the other elements.
sub t2h_default_index_rearrange_directions()
{
  return if (!defined($t2h_default_element_split_printindices));
  foreach my $element_string (keys(%$t2h_default_element_split_printindices))
  {
    my $element = $t2h_default_element_split_printindices->{$element_string}->{'element'};
    my $current_element = $element;
    #print STDERR " E Processing $element_string,$current_element $current_element->{'texi'}\n";
    foreach my $printindex (@{$t2h_default_element_split_printindices->{$element_string}->{'printindices'}})
    {
      #print STDERR "  I Processing $printindex $printindex->{'name'} (@{$printindex->{'split_groups'}})\n";
      foreach my $split_group (@{$printindex->{'split_groups'}})
      {
        my $first_letter = $split_group->{'letters'}->[0]->{'letter'};
        my $last_letter = $split_group->{'letters'}->[-1]->{'letter'};

        my $new_element = $split_group->{'element'};
        next if ($current_element eq $new_element);
        #print STDERR "   G Processing ($first_letter:$last_letter) in $element->{'texi'}, index $printindex->{'name'}: $new_element->{'texi'}\n";
        $new_element->{'This'} = $new_element;
        if ($current_element->{'Forward'})
        {
          $current_element->{'Forward'}->{'Back'} = $new_element;
          $new_element->{'Forward'} = $current_element->{'Forward'};
        }
        $current_element->{'Forward'} = $new_element;
        $new_element->{'Back'} = $current_element;
        if ($current_element->{'Following'})
        {
#print STDERR "F: C($current_element): $current_element->{'texi'}, N($new_element): $new_element->{'texi'} -- C->F: $current_element->{'Following'}->{'texi'}\n";
          $new_element->{'Following'} = $current_element->{'Following'};
          $current_element->{'Following'} = $new_element;
        }
        foreach my $key ('FastForward', 'FastBack', 'Up', 'tag_level', 'tag',
            'level', 'node')
        {
          $new_element->{$key} = $element->{$key} if (defined($element->{$key}));
        }
        $new_element->{'this'} = $new_element;
        $new_element->{'element_ref'} = $new_element;
        $current_element = $new_element;
      }
    }
  }
}

# not needed to initialize it for a document, since it is reset 
# in index_summary
my $t2h_symbol_indices = 0;

# format a letter appearing in a summary for an index. The letter links to
# the place where the index elements beginning with this letter are (called
# a letter entry).
#
# arguments:
# letter
# file where the target letter entry is 
# identifier for the target letter entry

sub html_default_summary_letter($$$$$$$)
{
   my $letter = shift;
   my $file = shift;
   my $default_identifier = shift;
   my $index_element_id = shift;
   my $number = shift;
   my $index_element = shift;
   my $index_name = shift;

   return '' if ($letter =~ /^\s*$/);
   my $is_symbol = $letter !~ /^[A-Za-z]/;
   my $identifier = $default_identifier;

   if ($NEW_CROSSREF_STYLE)
   {
      if ($is_symbol)
      {
         $t2h_symbol_indices++;
         $identifier = $index_element_id . "_${index_name}_symbol-$t2h_symbol_indices";
      }
      else
      {
         $identifier = $index_element_id . "_${index_name}_letter-${letter}";
      }
   }
   my $result = &$anchor('', $file . '#' . $identifier, '<b>' . &$protect_text($letter) . '</b>', 'class="summary-letter"');
   return $result unless ($NEW_CROSSREF_STYLE);
   return ($result, $identifier, $is_symbol);
}

# this replaces do_index_page
# args should be:
# index_name
# printindex
sub t2h_GPL_default_printindex($$)
{
  my $index_name = shift;
  my $printindex = shift;
  # could be cross verified with argument

  my $identifier_index_nr = 0;
  my @split_letters;
  
  if (defined($printindex->{'split_groups'}) and scalar(@{$printindex->{'split_groups'}}))
  {
    @split_letters = @{$printindex->{'split_groups'}};
  }
  elsif (defined($Texi2HTML::THISDOC{'index_letters_array'}->{$index_name}) and scalar(@{$Texi2HTML::THISDOC{'index_letters_array'}->{$index_name}}))
  {
    my $element = $printindex->{'associated_element'};
    # this happens for printindex before the first element.
    if (!defined($element))
    {
       $element =  {'file' => '', 'id' => "$printindex->{'region'}_printindex"};
    }
    elsif (defined($element->{'element_ref'}))
    {
        $element = $element->{'element_ref'};
    }
    @split_letters = ({ 'letters' => $Texi2HTML::THISDOC{'index_letters_array'}->{$index_name}, 'element' => $element});
  }
  else
  {
    return '';
  }

  foreach my $split_group (@split_letters)
  {
    #do summmary
    my @non_alpha = ();
    my @alpha = ();
    #print STDERR "$index_name @{$split_group->{'letters'}}\n";
    # letter_id could be done once for all instead of for each split_group
    # and outside of t2h_default_summary_letter (or t2h_default_summary_letter
    # could be simplified and inlined
    my %letter_id;
    foreach my $summary_split_group (@split_letters)
    {
      foreach my $letter_entry (@{$summary_split_group->{'letters'}})
      {
        my $letter = $letter_entry->{'letter'};
        my $dest_file = '';
        
        ####################################### debug
        if (!defined($summary_split_group->{'element'}))
        {
            main::msg_debug ("index $index_name, letter $letter, element for summary_split_group $summary_split_group not defined");
        }
        elsif (!defined($summary_split_group->{'element'}->{'id'}))
        {
           main::msg_debug ("index $index_name, letter $letter, element $summary_split_group->{'element'} `$summary_split_group->{'element'}->{'texi'}', id undef");
        }
        ####################################### end debug
        $dest_file = $summary_split_group->{'element'}->{'file'}
           if ($summary_split_group ne $split_group);
        my $index_element_id = $summary_split_group->{'element'}->{'id'};
        my $default_identifier = $index_element_id . "_$identifier_index_nr";
        #print STDERR "$split_group $summary_split_group $summary_split_group->{'element'} $summary_split_group->{'element'}->{'id'}  $identifier_index_nr $index_element_id $default_identifier\n";
        $identifier_index_nr++;
        my ($result, $identifier, $is_symbol) =
          &$summary_letter($letter, $dest_file, $default_identifier, $index_element_id, '', '', $index_name);
        $identifier = $default_identifier if (!defined($identifier));
        $letter_id{$letter} = $identifier;
        $is_symbol = $letter !~ /^[A-Za-z]/ if (!defined($is_symbol));

        if ($result ne '')
        {
          if ($is_symbol)
          {
            push @non_alpha, $result;
          }
          else
          {
            push @alpha, $result;
          }
        }
      }
    }
    my $summary = &$index_summary(\@alpha, \@non_alpha);

    # reset symbols numbering
    $t2h_symbol_indices = 0;

    my $letters_text = '';
    foreach my $letter_entry (@{$split_group->{'letters'}})
    {
      my $letter = $letter_entry->{'letter'};
      my $entries_text = '';
      foreach my $index_entry_ref (@{$letter_entry->{'entries'}})
      {
        my ($text_href, $entry_file, $element_file, $entry_target,
          $entry_element_target, $formatted_entry, $element_href, 
          $entry_element_text, $in_region_not_in_output)
          =  main::get_index_entry_infos($index_entry_ref, $split_group->{'element'});
        $entries_text .= &$index_entry ($text_href, $formatted_entry, $element_href, $entry_element_text, $entry_file, $element_file, $entry_target, $entry_element_target, $in_region_not_in_output, $index_entry_ref);
      }
      $letters_text .= &$index_letter ($letter, $letter_id{$letter}, $entries_text)
    }
    my $index_text = &$print_index($letters_text, $index_name);
    $split_group->{'text'} = $summary . $index_text . $summary;
#    print STDERR "    ---> $index_name @{$split_group->{'letters'}}
#     * elt:   $split_group->{'element'}->{'id'}, $split_group->{'element'}->{'file'}, $split_group->{'element'}->{'name'}
#     * directions: B: $split_group->{'element'}->{'Back'}->{'name'}, F: $split_group->{'element'}->{'Forward'}->{'name'}, FB: $split_group->{'element'}->{'FastBack'}->{'name'}, FF: $split_group->{'element'}->{'FastForward'}->{'name'}
#     * text
#
#$split_group->{'text'}
#   
#";
  }
  my $current_page = shift @split_letters;
  if (!scalar(@split_letters))
  {
    return $current_page->{'text'};
  }

  while (1)
  {
    # print the index letters
    push @{$Texi2HTML::THIS_SECTION}, $current_page->{'text'};

    $current_page = shift @split_letters;
    last if (!defined($current_page));

    # there is no need to begin first element if not already done, since
    # the index is not split if not already in an element.
    # end the previous element
    main::finish_element ($Texi2HTML::THISDOC{'FH'}, $Texi2HTML::THIS_ELEMENT, $Texi2HTML::THIS_ELEMENT->{'Forward'}, 0);

    # do the new element beginning
    $Texi2HTML::THIS_ELEMENT = $current_page->{'element'};
    my $new_element = $Texi2HTML::THIS_ELEMENT;
    main::unref_file($new_element->{'file'});
    main::do_element_directions($new_element);
    my $do_page_head = main::open_out_file($new_element->{'file'});
    if ($do_page_head)
    {
      &$print_page_head($Texi2HTML::THISDOC{'FH'});
      &$print_chapter_header($Texi2HTML::THISDOC{'FH'}, $new_element) if Texi2HTML::Config::get_conf('SPLIT') eq 'chapter';
      &$print_section_header($Texi2HTML::THISDOC{'FH'}, $new_element) if Texi2HTML::Config::get_conf('SPLIT') eq 'section';
    }
    # almost nothing of this is used in the default html output
    @{$Texi2HTML::THIS_SECTION} = &$element_heading($new_element, $new_element->{'tag'}, $new_element->{'texi'},
       $new_element->{'text'}, 0, 0, $new_element->{'this'}, 1, 0, 0, "\@$new_element->{'tag'} $new_element->{'texi'}", 
       $new_element->{'id'}, $new_element);

  }
  return '';
}

# leave this within comments, and keep the require statement
# This way, you can directly run texi2html.pl, 
# if $T2H_HOME/documentlanguages.pl exists.
#
# @T2H_DOCUMENT_LANGUAGES@
%language_codes = (
'aa' => 1,
'ab' => 1,
'ae' => 1,
'af' => 1,
'ak' => 1,
'am' => 1,
'an' => 1,
'ar' => 1,
'as' => 1,
'av' => 1,
'ay' => 1,
'az' => 1,
'ba' => 1,
'be' => 1,
'bg' => 1,
'bh' => 1,
'bi' => 1,
'bm' => 1,
'bn' => 1,
'bo' => 1,
'br' => 1,
'ca' => 1,
'ce' => 1,
'ch' => 1,
'co' => 1,
'cr' => 1,
'cs' => 1,
'cu' => 1,
'cv' => 1,
'cy' => 1,
'da' => 1,
'de' => 1,
'dv' => 1,
'dz' => 1,
'ee' => 1,
'el' => 1,
'en' => 1,
'eo' => 1,
'es' => 1,
'et' => 1,
'eu' => 1,
'fa' => 1,
'ff' => 1,
'fi' => 1,
'fj' => 1,
'fo' => 1,
'fr' => 1,
'fy' => 1,
'ga' => 1,
'gd' => 1,
'gl' => 1,
'gn' => 1,
'gu' => 1,
'gv' => 1,
'ha' => 1,
'he' => 1,
'hi' => 1,
'ho' => 1,
'ht' => 1,
'hu' => 1,
'hy' => 1,
'hz' => 1,
'ia' => 1,
'ie' => 1,
'ig' => 1,
'ii' => 1,
'ik' => 1,
'io' => 1,
'is' => 1,
'it' => 1,
'iu' => 1,
'iw' => 1,
'ja' => 1,
'ji' => 1,
'jv' => 1,
'jw' => 1,
'ka' => 1,
'kg' => 1,
'ki' => 1,
'kj' => 1,
'kk' => 1,
'kl' => 1,
'km' => 1,
'kn' => 1,
'ko' => 1,
'kr' => 1,
'ks' => 1,
'ku' => 1,
'kv' => 1,
'kw' => 1,
'ky' => 1,
'la' => 1,
'lb' => 1,
'lg' => 1,
'li' => 1,
'ln' => 1,
'lo' => 1,
'lt' => 1,
'lu' => 1,
'lv' => 1,
'mg' => 1,
'mh' => 1,
'mi' => 1,
'mk' => 1,
'ml' => 1,
'mn' => 1,
'mo' => 1,
'mr' => 1,
'ms' => 1,
'mt' => 1,
'my' => 1,
'na' => 1,
'nd' => 1,
'ne' => 1,
'ng' => 1,
'nl' => 1,
'no' => 1,
'nr' => 1,
'nv' => 1,
'ny' => 1,
'oc' => 1,
'oj' => 1,
'om' => 1,
'or' => 1,
'os' => 1,
'pa' => 1,
'pi' => 1,
'pl' => 1,
'ps' => 1,
'pt' => 1,
'qu' => 1,
'rm' => 1,
'rn' => 1,
'ro' => 1,
'ru' => 1,
'rw' => 1,
'sa' => 1,
'sc' => 1,
'sd' => 1,
'se' => 1,
'sg' => 1,
'sh' => 1,
'si' => 1,
'sk' => 1,
'sl' => 1,
'sm' => 1,
'sn' => 1,
'so' => 1,
'sq' => 1,
'ss' => 1,
'st' => 1,
'su' => 1,
'sv' => 1,
'sw' => 1,
'ta' => 1,
'te' => 1,
'tg' => 1,
'th' => 1,
'ti' => 1,
'tk' => 1,
'tl' => 1,
'tn' => 1,
'to' => 1,
'tr' => 1,
'ts' => 1,
'tt' => 1,
'ty' => 1,
'ug' => 1,
'uk' => 1,
'ur' => 1,
'uz' => 1,
've' => 1,
'vi' => 1,
'vo' => 1,
'wa' => 1,
'wo' => 1,
'xh' => 1,
'yi' => 1,
'yo' => 1,
'za' => 1,
'zh' => 1,
'zu' => 1,
'aaa' => 1,
'aab' => 1,
'aac' => 1,
'aad' => 1,
'aaf' => 1,
'aag' => 1,
'aah' => 1,
'aai' => 1,
'aak' => 1,
'aal' => 1,
'aam' => 1,
'aan' => 1,
'aap' => 1,
'aaq' => 1,
'aas' => 1,
'aau' => 1,
'aav' => 1,
'aaw' => 1,
'aax' => 1,
'aaz' => 1,
'aba' => 1,
'abb' => 1,
'abc' => 1,
'abd' => 1,
'abe' => 1,
'abf' => 1,
'abg' => 1,
'abi' => 1,
'abj' => 1,
'abl' => 1,
'abm' => 1,
'abn' => 1,
'abo' => 1,
'abp' => 1,
'abq' => 1,
'abr' => 1,
'abs' => 1,
'abt' => 1,
'abu' => 1,
'abw' => 1,
'abx' => 1,
'aby' => 1,
'abz' => 1,
'aca' => 1,
'acb' => 1,
'acd' => 1,
'ace' => 1,
'acf' => 1,
'ach' => 1,
'aci' => 1,
'ack' => 1,
'acl' => 1,
'acn' => 1,
'acp' => 1,
'acr' => 1,
'acs' => 1,
'act' => 1,
'acu' => 1,
'acv' => 1,
'acz' => 1,
'ada' => 1,
'adb' => 1,
'add' => 1,
'ade' => 1,
'adg' => 1,
'adh' => 1,
'adi' => 1,
'adj' => 1,
'adl' => 1,
'adn' => 1,
'ado' => 1,
'adp' => 1,
'adq' => 1,
'adr' => 1,
'ads' => 1,
'adt' => 1,
'adu' => 1,
'adw' => 1,
'adx' => 1,
'ady' => 1,
'adz' => 1,
'aea' => 1,
'aed' => 1,
'aee' => 1,
'aek' => 1,
'ael' => 1,
'aem' => 1,
'aen' => 1,
'aeq' => 1,
'aer' => 1,
'aes' => 1,
'aeu' => 1,
'aew' => 1,
'aey' => 1,
'aez' => 1,
'afa' => 1,
'afd' => 1,
'afe' => 1,
'afg' => 1,
'afh' => 1,
'afi' => 1,
'afk' => 1,
'afn' => 1,
'afo' => 1,
'afp' => 1,
'afs' => 1,
'aft' => 1,
'afu' => 1,
'afz' => 1,
'aga' => 1,
'agb' => 1,
'agc' => 1,
'agd' => 1,
'age' => 1,
'agf' => 1,
'agg' => 1,
'agh' => 1,
'agi' => 1,
'agj' => 1,
'agk' => 1,
'agl' => 1,
'agm' => 1,
'agn' => 1,
'ago' => 1,
'agp' => 1,
'agq' => 1,
'agr' => 1,
'ags' => 1,
'agt' => 1,
'agu' => 1,
'agv' => 1,
'agw' => 1,
'agx' => 1,
'agy' => 1,
'agz' => 1,
'aha' => 1,
'ahb' => 1,
'ahg' => 1,
'ahh' => 1,
'ahi' => 1,
'ahk' => 1,
'ahl' => 1,
'ahm' => 1,
'ahn' => 1,
'aho' => 1,
'ahp' => 1,
'ahr' => 1,
'ahs' => 1,
'aht' => 1,
'aia' => 1,
'aib' => 1,
'aic' => 1,
'aid' => 1,
'aie' => 1,
'aif' => 1,
'aig' => 1,
'aih' => 1,
'aij' => 1,
'aik' => 1,
'ail' => 1,
'aim' => 1,
'ain' => 1,
'aio' => 1,
'aip' => 1,
'aiq' => 1,
'air' => 1,
'ais' => 1,
'ait' => 1,
'aiw' => 1,
'aix' => 1,
'aiy' => 1,
'aja' => 1,
'ajg' => 1,
'aji' => 1,
'ajw' => 1,
'ajz' => 1,
'akb' => 1,
'akc' => 1,
'akd' => 1,
'ake' => 1,
'akf' => 1,
'akg' => 1,
'akh' => 1,
'aki' => 1,
'akj' => 1,
'akk' => 1,
'akl' => 1,
'akm' => 1,
'ako' => 1,
'akp' => 1,
'akq' => 1,
'akr' => 1,
'aks' => 1,
'akt' => 1,
'aku' => 1,
'akv' => 1,
'akw' => 1,
'akx' => 1,
'aky' => 1,
'akz' => 1,
'ala' => 1,
'alc' => 1,
'ald' => 1,
'ale' => 1,
'alf' => 1,
'alg' => 1,
'alh' => 1,
'ali' => 1,
'alj' => 1,
'alk' => 1,
'all' => 1,
'alm' => 1,
'alo' => 1,
'alp' => 1,
'alq' => 1,
'alr' => 1,
'alt' => 1,
'alu' => 1,
'alv' => 1,
'alw' => 1,
'alx' => 1,
'aly' => 1,
'alz' => 1,
'ama' => 1,
'amb' => 1,
'amc' => 1,
'ame' => 1,
'amf' => 1,
'amg' => 1,
'ami' => 1,
'amj' => 1,
'amk' => 1,
'aml' => 1,
'amm' => 1,
'amn' => 1,
'amo' => 1,
'amp' => 1,
'amq' => 1,
'amr' => 1,
'ams' => 1,
'amt' => 1,
'amu' => 1,
'amv' => 1,
'amw' => 1,
'amx' => 1,
'amy' => 1,
'amz' => 1,
'ana' => 1,
'anb' => 1,
'anc' => 1,
'and' => 1,
'ane' => 1,
'anf' => 1,
'ang' => 1,
'anh' => 1,
'ani' => 1,
'anj' => 1,
'ank' => 1,
'anl' => 1,
'anm' => 1,
'ann' => 1,
'ano' => 1,
'anp' => 1,
'anq' => 1,
'anr' => 1,
'ans' => 1,
'ant' => 1,
'anu' => 1,
'anv' => 1,
'anw' => 1,
'anx' => 1,
'any' => 1,
'anz' => 1,
'aoa' => 1,
'aob' => 1,
'aoc' => 1,
'aod' => 1,
'aoe' => 1,
'aof' => 1,
'aog' => 1,
'aoh' => 1,
'aoi' => 1,
'aoj' => 1,
'aok' => 1,
'aol' => 1,
'aom' => 1,
'aon' => 1,
'aor' => 1,
'aos' => 1,
'aot' => 1,
'aox' => 1,
'aoz' => 1,
'apa' => 1,
'apb' => 1,
'ape' => 1,
'apg' => 1,
'aph' => 1,
'api' => 1,
'apj' => 1,
'apk' => 1,
'apl' => 1,
'apm' => 1,
'apn' => 1,
'apo' => 1,
'app' => 1,
'apq' => 1,
'apr' => 1,
'aps' => 1,
'apt' => 1,
'apu' => 1,
'apv' => 1,
'apw' => 1,
'apx' => 1,
'apy' => 1,
'apz' => 1,
'aqa' => 1,
'aqc' => 1,
'aqg' => 1,
'aql' => 1,
'aqm' => 1,
'aqn' => 1,
'aqp' => 1,
'aqr' => 1,
'arc' => 1,
'ard' => 1,
'are' => 1,
'arh' => 1,
'ari' => 1,
'arj' => 1,
'ark' => 1,
'arl' => 1,
'arn' => 1,
'aro' => 1,
'arp' => 1,
'arr' => 1,
'art' => 1,
'aru' => 1,
'arv' => 1,
'arw' => 1,
'arx' => 1,
'asa' => 1,
'asb' => 1,
'asc' => 1,
'asd' => 1,
'ase' => 1,
'asf' => 1,
'asg' => 1,
'ash' => 1,
'asi' => 1,
'asj' => 1,
'ask' => 1,
'asl' => 1,
'asn' => 1,
'aso' => 1,
'asp' => 1,
'asq' => 1,
'asr' => 1,
'ass' => 1,
'ast' => 1,
'asu' => 1,
'asv' => 1,
'asw' => 1,
'asx' => 1,
'asy' => 1,
'asz' => 1,
'ata' => 1,
'atb' => 1,
'atc' => 1,
'atd' => 1,
'ate' => 1,
'atg' => 1,
'ath' => 1,
'ati' => 1,
'atj' => 1,
'atk' => 1,
'atl' => 1,
'atm' => 1,
'atn' => 1,
'ato' => 1,
'atp' => 1,
'atq' => 1,
'atr' => 1,
'ats' => 1,
'att' => 1,
'atu' => 1,
'atv' => 1,
'atw' => 1,
'atx' => 1,
'aty' => 1,
'atz' => 1,
'aua' => 1,
'aub' => 1,
'auc' => 1,
'aud' => 1,
'aue' => 1,
'auf' => 1,
'aug' => 1,
'auh' => 1,
'aui' => 1,
'auj' => 1,
'auk' => 1,
'aul' => 1,
'aum' => 1,
'aun' => 1,
'auo' => 1,
'aup' => 1,
'auq' => 1,
'aur' => 1,
'aus' => 1,
'aut' => 1,
'auu' => 1,
'auw' => 1,
'aux' => 1,
'auy' => 1,
'avb' => 1,
'avd' => 1,
'avi' => 1,
'avk' => 1,
'avn' => 1,
'avo' => 1,
'avs' => 1,
'avt' => 1,
'avu' => 1,
'avv' => 1,
'awa' => 1,
'awb' => 1,
'awc' => 1,
'awd' => 1,
'awe' => 1,
'awh' => 1,
'awi' => 1,
'awk' => 1,
'awm' => 1,
'awn' => 1,
'awo' => 1,
'awr' => 1,
'aws' => 1,
'awt' => 1,
'awu' => 1,
'awv' => 1,
'aww' => 1,
'awx' => 1,
'awy' => 1,
'axb' => 1,
'axg' => 1,
'axk' => 1,
'axm' => 1,
'axx' => 1,
'aya' => 1,
'ayb' => 1,
'ayd' => 1,
'aye' => 1,
'ayg' => 1,
'ayi' => 1,
'ayk' => 1,
'ayo' => 1,
'ayq' => 1,
'ays' => 1,
'ayt' => 1,
'ayu' => 1,
'ayx' => 1,
'ayy' => 1,
'ayz' => 1,
'aza' => 1,
'azc' => 1,
'azg' => 1,
'azm' => 1,
'azo' => 1,
'azt' => 1,
'azz' => 1,
'baa' => 1,
'bab' => 1,
'bac' => 1,
'bad' => 1,
'bae' => 1,
'baf' => 1,
'bag' => 1,
'bah' => 1,
'bai' => 1,
'baj' => 1,
'bal' => 1,
'ban' => 1,
'bao' => 1,
'bap' => 1,
'bar' => 1,
'bas' => 1,
'bat' => 1,
'bau' => 1,
'bav' => 1,
'baw' => 1,
'bax' => 1,
'bay' => 1,
'baz' => 1,
'bba' => 1,
'bbb' => 1,
'bbc' => 1,
'bbd' => 1,
'bbe' => 1,
'bbf' => 1,
'bbg' => 1,
'bbh' => 1,
'bbi' => 1,
'bbj' => 1,
'bbk' => 1,
'bbl' => 1,
'bbm' => 1,
'bbn' => 1,
'bbo' => 1,
'bbp' => 1,
'bbq' => 1,
'bbr' => 1,
'bbs' => 1,
'bbt' => 1,
'bbu' => 1,
'bbv' => 1,
'bbw' => 1,
'bbx' => 1,
'bby' => 1,
'bca' => 1,
'bcb' => 1,
'bcd' => 1,
'bce' => 1,
'bcf' => 1,
'bcg' => 1,
'bch' => 1,
'bci' => 1,
'bcj' => 1,
'bck' => 1,
'bcm' => 1,
'bcn' => 1,
'bco' => 1,
'bcp' => 1,
'bcq' => 1,
'bcr' => 1,
'bcs' => 1,
'bct' => 1,
'bcu' => 1,
'bcv' => 1,
'bcw' => 1,
'bcy' => 1,
'bcz' => 1,
'bda' => 1,
'bdb' => 1,
'bdc' => 1,
'bdd' => 1,
'bde' => 1,
'bdg' => 1,
'bdh' => 1,
'bdi' => 1,
'bdj' => 1,
'bdk' => 1,
'bdl' => 1,
'bdm' => 1,
'bdn' => 1,
'bdo' => 1,
'bdp' => 1,
'bdq' => 1,
'bdr' => 1,
'bds' => 1,
'bdu' => 1,
'bdv' => 1,
'bdw' => 1,
'bdx' => 1,
'bdy' => 1,
'bdz' => 1,
'bea' => 1,
'beb' => 1,
'bec' => 1,
'bed' => 1,
'bee' => 1,
'bef' => 1,
'beg' => 1,
'beh' => 1,
'bei' => 1,
'bej' => 1,
'bek' => 1,
'bem' => 1,
'beo' => 1,
'bep' => 1,
'beq' => 1,
'ber' => 1,
'bes' => 1,
'bet' => 1,
'beu' => 1,
'bev' => 1,
'bew' => 1,
'bex' => 1,
'bey' => 1,
'bez' => 1,
'bfa' => 1,
'bfb' => 1,
'bfc' => 1,
'bfd' => 1,
'bfe' => 1,
'bff' => 1,
'bfg' => 1,
'bfh' => 1,
'bfi' => 1,
'bfj' => 1,
'bfk' => 1,
'bfl' => 1,
'bfm' => 1,
'bfn' => 1,
'bfo' => 1,
'bfp' => 1,
'bfq' => 1,
'bfr' => 1,
'bfs' => 1,
'bft' => 1,
'bfu' => 1,
'bfw' => 1,
'bfy' => 1,
'bfz' => 1,
'bga' => 1,
'bgb' => 1,
'bgc' => 1,
'bgd' => 1,
'bge' => 1,
'bgf' => 1,
'bgg' => 1,
'bgi' => 1,
'bgj' => 1,
'bgk' => 1,
'bgl' => 1,
'bgm' => 1,
'bgo' => 1,
'bgr' => 1,
'bgs' => 1,
'bgt' => 1,
'bgu' => 1,
'bgv' => 1,
'bgw' => 1,
'bgx' => 1,
'bgy' => 1,
'bgz' => 1,
'bha' => 1,
'bhb' => 1,
'bhc' => 1,
'bhd' => 1,
'bhe' => 1,
'bhf' => 1,
'bhg' => 1,
'bhh' => 1,
'bhi' => 1,
'bhj' => 1,
'bhl' => 1,
'bhm' => 1,
'bhn' => 1,
'bho' => 1,
'bhp' => 1,
'bhq' => 1,
'bhs' => 1,
'bht' => 1,
'bhu' => 1,
'bhv' => 1,
'bhw' => 1,
'bhx' => 1,
'bhy' => 1,
'bhz' => 1,
'bia' => 1,
'bib' => 1,
'bic' => 1,
'bid' => 1,
'bie' => 1,
'bif' => 1,
'big' => 1,
'bij' => 1,
'bik' => 1,
'bil' => 1,
'bim' => 1,
'bin' => 1,
'bio' => 1,
'bip' => 1,
'biq' => 1,
'bir' => 1,
'bit' => 1,
'biu' => 1,
'biv' => 1,
'biw' => 1,
'bix' => 1,
'biy' => 1,
'biz' => 1,
'bja' => 1,
'bjb' => 1,
'bjc' => 1,
'bjd' => 1,
'bje' => 1,
'bjf' => 1,
'bjg' => 1,
'bjh' => 1,
'bji' => 1,
'bjj' => 1,
'bjk' => 1,
'bjl' => 1,
'bjm' => 1,
'bjo' => 1,
'bjr' => 1,
'bjs' => 1,
'bjt' => 1,
'bju' => 1,
'bjv' => 1,
'bjw' => 1,
'bjx' => 1,
'bjy' => 1,
'bjz' => 1,
'bka' => 1,
'bkb' => 1,
'bkc' => 1,
'bkd' => 1,
'bkf' => 1,
'bkg' => 1,
'bkh' => 1,
'bki' => 1,
'bkj' => 1,
'bkk' => 1,
'bkl' => 1,
'bkm' => 1,
'bkn' => 1,
'bko' => 1,
'bkp' => 1,
'bkq' => 1,
'bkr' => 1,
'bks' => 1,
'bkt' => 1,
'bku' => 1,
'bkv' => 1,
'bkw' => 1,
'bkx' => 1,
'bky' => 1,
'bkz' => 1,
'bla' => 1,
'blb' => 1,
'blc' => 1,
'bld' => 1,
'ble' => 1,
'blf' => 1,
'blg' => 1,
'blh' => 1,
'bli' => 1,
'blj' => 1,
'blk' => 1,
'bll' => 1,
'blm' => 1,
'blo' => 1,
'blp' => 1,
'blq' => 1,
'blr' => 1,
'bls' => 1,
'blt' => 1,
'blv' => 1,
'blw' => 1,
'blx' => 1,
'bly' => 1,
'blz' => 1,
'bma' => 1,
'bmb' => 1,
'bmc' => 1,
'bmd' => 1,
'bme' => 1,
'bmf' => 1,
'bmg' => 1,
'bmh' => 1,
'bmi' => 1,
'bmj' => 1,
'bmk' => 1,
'bml' => 1,
'bmn' => 1,
'bmo' => 1,
'bmp' => 1,
'bmq' => 1,
'bmr' => 1,
'bms' => 1,
'bmt' => 1,
'bmu' => 1,
'bmv' => 1,
'bmw' => 1,
'bmx' => 1,
'bmy' => 1,
'bmz' => 1,
'bna' => 1,
'bnb' => 1,
'bnc' => 1,
'bnd' => 1,
'bne' => 1,
'bnf' => 1,
'bng' => 1,
'bni' => 1,
'bnj' => 1,
'bnk' => 1,
'bnl' => 1,
'bnm' => 1,
'bnn' => 1,
'bno' => 1,
'bnp' => 1,
'bnq' => 1,
'bnr' => 1,
'bns' => 1,
'bnt' => 1,
'bnu' => 1,
'bnv' => 1,
'bnw' => 1,
'bnx' => 1,
'bny' => 1,
'bnz' => 1,
'boa' => 1,
'bob' => 1,
'boe' => 1,
'bof' => 1,
'bog' => 1,
'boh' => 1,
'boi' => 1,
'boj' => 1,
'bok' => 1,
'bol' => 1,
'bom' => 1,
'bon' => 1,
'boo' => 1,
'bop' => 1,
'boq' => 1,
'bor' => 1,
'bot' => 1,
'bou' => 1,
'bov' => 1,
'bow' => 1,
'box' => 1,
'boy' => 1,
'boz' => 1,
'bpa' => 1,
'bpb' => 1,
'bpd' => 1,
'bpg' => 1,
'bph' => 1,
'bpi' => 1,
'bpj' => 1,
'bpk' => 1,
'bpl' => 1,
'bpm' => 1,
'bpn' => 1,
'bpo' => 1,
'bpp' => 1,
'bpq' => 1,
'bpr' => 1,
'bps' => 1,
'bpt' => 1,
'bpu' => 1,
'bpv' => 1,
'bpw' => 1,
'bpx' => 1,
'bpy' => 1,
'bpz' => 1,
'bqa' => 1,
'bqb' => 1,
'bqc' => 1,
'bqd' => 1,
'bqf' => 1,
'bqg' => 1,
'bqh' => 1,
'bqi' => 1,
'bqj' => 1,
'bqk' => 1,
'bql' => 1,
'bqm' => 1,
'bqn' => 1,
'bqo' => 1,
'bqp' => 1,
'bqq' => 1,
'bqr' => 1,
'bqs' => 1,
'bqt' => 1,
'bqu' => 1,
'bqv' => 1,
'bqw' => 1,
'bqx' => 1,
'bqy' => 1,
'bqz' => 1,
'bra' => 1,
'brb' => 1,
'brc' => 1,
'brd' => 1,
'brf' => 1,
'brg' => 1,
'brh' => 1,
'bri' => 1,
'brj' => 1,
'brk' => 1,
'brl' => 1,
'brm' => 1,
'brn' => 1,
'bro' => 1,
'brp' => 1,
'brq' => 1,
'brr' => 1,
'brs' => 1,
'brt' => 1,
'bru' => 1,
'brv' => 1,
'brw' => 1,
'brx' => 1,
'bry' => 1,
'brz' => 1,
'bsa' => 1,
'bsb' => 1,
'bsc' => 1,
'bse' => 1,
'bsf' => 1,
'bsg' => 1,
'bsh' => 1,
'bsi' => 1,
'bsj' => 1,
'bsk' => 1,
'bsl' => 1,
'bsm' => 1,
'bsn' => 1,
'bso' => 1,
'bsp' => 1,
'bsq' => 1,
'bsr' => 1,
'bss' => 1,
'bst' => 1,
'bsu' => 1,
'bsv' => 1,
'bsw' => 1,
'bsx' => 1,
'bsy' => 1,
'bta' => 1,
'btb' => 1,
'btc' => 1,
'btd' => 1,
'bte' => 1,
'btf' => 1,
'btg' => 1,
'bth' => 1,
'bti' => 1,
'btk' => 1,
'btl' => 1,
'btm' => 1,
'btn' => 1,
'btp' => 1,
'btq' => 1,
'btr' => 1,
'bts' => 1,
'btt' => 1,
'btu' => 1,
'btv' => 1,
'btw' => 1,
'btx' => 1,
'bty' => 1,
'btz' => 1,
'bua' => 1,
'bub' => 1,
'buc' => 1,
'bud' => 1,
'bue' => 1,
'buf' => 1,
'bug' => 1,
'buh' => 1,
'bui' => 1,
'buj' => 1,
'buk' => 1,
'bum' => 1,
'bun' => 1,
'buo' => 1,
'bup' => 1,
'buq' => 1,
'bus' => 1,
'but' => 1,
'buu' => 1,
'buv' => 1,
'buw' => 1,
'bux' => 1,
'buy' => 1,
'buz' => 1,
'bva' => 1,
'bvb' => 1,
'bvc' => 1,
'bvd' => 1,
'bvf' => 1,
'bvg' => 1,
'bvh' => 1,
'bvi' => 1,
'bvj' => 1,
'bvk' => 1,
'bvl' => 1,
'bvm' => 1,
'bvn' => 1,
'bvo' => 1,
'bvq' => 1,
'bvr' => 1,
'bvt' => 1,
'bvv' => 1,
'bvw' => 1,
'bvx' => 1,
'bvz' => 1,
'bwa' => 1,
'bwb' => 1,
'bwc' => 1,
'bwd' => 1,
'bwe' => 1,
'bwf' => 1,
'bwg' => 1,
'bwh' => 1,
'bwi' => 1,
'bwj' => 1,
'bwk' => 1,
'bwl' => 1,
'bwm' => 1,
'bwn' => 1,
'bwo' => 1,
'bwp' => 1,
'bwq' => 1,
'bwr' => 1,
'bws' => 1,
'bwt' => 1,
'bwu' => 1,
'bww' => 1,
'bwx' => 1,
'bwy' => 1,
'bwz' => 1,
'bxa' => 1,
'bxb' => 1,
'bxc' => 1,
'bxd' => 1,
'bxe' => 1,
'bxf' => 1,
'bxg' => 1,
'bxh' => 1,
'bxi' => 1,
'bxj' => 1,
'bxl' => 1,
'bxn' => 1,
'bxo' => 1,
'bxp' => 1,
'bxq' => 1,
'bxs' => 1,
'bxv' => 1,
'bxw' => 1,
'bxx' => 1,
'bxz' => 1,
'bya' => 1,
'byb' => 1,
'byc' => 1,
'byd' => 1,
'bye' => 1,
'byf' => 1,
'byg' => 1,
'byh' => 1,
'byi' => 1,
'byj' => 1,
'byk' => 1,
'byl' => 1,
'bym' => 1,
'byn' => 1,
'byo' => 1,
'byp' => 1,
'byq' => 1,
'byr' => 1,
'bys' => 1,
'byt' => 1,
'byv' => 1,
'byw' => 1,
'byx' => 1,
'byy' => 1,
'byz' => 1,
'bza' => 1,
'bzb' => 1,
'bzd' => 1,
'bze' => 1,
'bzf' => 1,
'bzg' => 1,
'bzh' => 1,
'bzi' => 1,
'bzj' => 1,
'bzk' => 1,
'bzl' => 1,
'bzm' => 1,
'bzn' => 1,
'bzo' => 1,
'bzp' => 1,
'bzq' => 1,
'bzr' => 1,
'bzs' => 1,
'bzt' => 1,
'bzu' => 1,
'bzv' => 1,
'bzw' => 1,
'bzx' => 1,
'bzy' => 1,
'bzz' => 1,
'caa' => 1,
'cab' => 1,
'cac' => 1,
'cad' => 1,
'cae' => 1,
'caf' => 1,
'cag' => 1,
'cah' => 1,
'cai' => 1,
'caj' => 1,
'cak' => 1,
'cal' => 1,
'cam' => 1,
'can' => 1,
'cao' => 1,
'cap' => 1,
'caq' => 1,
'car' => 1,
'cas' => 1,
'cau' => 1,
'cav' => 1,
'caw' => 1,
'cax' => 1,
'cay' => 1,
'caz' => 1,
'cba' => 1,
'cbb' => 1,
'cbc' => 1,
'cbd' => 1,
'cbe' => 1,
'cbg' => 1,
'cbh' => 1,
'cbi' => 1,
'cbj' => 1,
'cbk' => 1,
'cbl' => 1,
'cbn' => 1,
'cbo' => 1,
'cbr' => 1,
'cbs' => 1,
'cbt' => 1,
'cbu' => 1,
'cbv' => 1,
'cby' => 1,
'cca' => 1,
'ccc' => 1,
'ccd' => 1,
'cce' => 1,
'ccg' => 1,
'cch' => 1,
'ccj' => 1,
'ccl' => 1,
'ccm' => 1,
'ccn' => 1,
'cco' => 1,
'ccp' => 1,
'ccq' => 1,
'ccr' => 1,
'ccs' => 1,
'cda' => 1,
'cdc' => 1,
'cdd' => 1,
'cde' => 1,
'cdf' => 1,
'cdg' => 1,
'cdh' => 1,
'cdi' => 1,
'cdj' => 1,
'cdm' => 1,
'cdn' => 1,
'cdr' => 1,
'cds' => 1,
'cdy' => 1,
'cdz' => 1,
'cea' => 1,
'ceb' => 1,
'ceg' => 1,
'cel' => 1,
'cen' => 1,
'cet' => 1,
'cfa' => 1,
'cfd' => 1,
'cfg' => 1,
'cfm' => 1,
'cga' => 1,
'cgc' => 1,
'cgg' => 1,
'cgk' => 1,
'chb' => 1,
'chc' => 1,
'chd' => 1,
'chf' => 1,
'chg' => 1,
'chh' => 1,
'chj' => 1,
'chk' => 1,
'chl' => 1,
'chm' => 1,
'chn' => 1,
'cho' => 1,
'chp' => 1,
'chq' => 1,
'chr' => 1,
'cht' => 1,
'chw' => 1,
'chx' => 1,
'chy' => 1,
'chz' => 1,
'cia' => 1,
'cib' => 1,
'cic' => 1,
'cid' => 1,
'cie' => 1,
'cih' => 1,
'cik' => 1,
'cim' => 1,
'cin' => 1,
'cip' => 1,
'cir' => 1,
'ciy' => 1,
'cja' => 1,
'cje' => 1,
'cjh' => 1,
'cji' => 1,
'cjk' => 1,
'cjm' => 1,
'cjn' => 1,
'cjo' => 1,
'cjp' => 1,
'cjr' => 1,
'cjs' => 1,
'cjv' => 1,
'cka' => 1,
'ckh' => 1,
'ckl' => 1,
'cko' => 1,
'ckq' => 1,
'ckr' => 1,
'cks' => 1,
'ckt' => 1,
'cku' => 1,
'ckv' => 1,
'ckx' => 1,
'cky' => 1,
'ckz' => 1,
'cla' => 1,
'clc' => 1,
'cle' => 1,
'clh' => 1,
'cli' => 1,
'clk' => 1,
'cll' => 1,
'clm' => 1,
'clo' => 1,
'clu' => 1,
'clw' => 1,
'cly' => 1,
'cma' => 1,
'cmc' => 1,
'cme' => 1,
'cmg' => 1,
'cmi' => 1,
'cmk' => 1,
'cml' => 1,
'cmm' => 1,
'cmo' => 1,
'cmr' => 1,
'cms' => 1,
'cmt' => 1,
'cna' => 1,
'cnb' => 1,
'cnc' => 1,
'cng' => 1,
'cnh' => 1,
'cni' => 1,
'cnk' => 1,
'cnl' => 1,
'cno' => 1,
'cns' => 1,
'cnt' => 1,
'cnu' => 1,
'cnw' => 1,
'cnx' => 1,
'cob' => 1,
'coc' => 1,
'cod' => 1,
'coe' => 1,
'cof' => 1,
'cog' => 1,
'coh' => 1,
'coj' => 1,
'cok' => 1,
'col' => 1,
'com' => 1,
'con' => 1,
'coo' => 1,
'cop' => 1,
'coq' => 1,
'cot' => 1,
'cou' => 1,
'cov' => 1,
'cow' => 1,
'cox' => 1,
'coy' => 1,
'coz' => 1,
'cpa' => 1,
'cpb' => 1,
'cpc' => 1,
'cpe' => 1,
'cpf' => 1,
'cpg' => 1,
'cpi' => 1,
'cpn' => 1,
'cpp' => 1,
'cps' => 1,
'cpu' => 1,
'cpy' => 1,
'cra' => 1,
'crb' => 1,
'crc' => 1,
'crd' => 1,
'crf' => 1,
'crg' => 1,
'crh' => 1,
'cri' => 1,
'crn' => 1,
'cro' => 1,
'crp' => 1,
'crq' => 1,
'crr' => 1,
'crs' => 1,
'crt' => 1,
'crv' => 1,
'crw' => 1,
'crx' => 1,
'cry' => 1,
'crz' => 1,
'csa' => 1,
'csb' => 1,
'csc' => 1,
'csd' => 1,
'cse' => 1,
'csf' => 1,
'csg' => 1,
'csh' => 1,
'csi' => 1,
'csk' => 1,
'csl' => 1,
'csm' => 1,
'csn' => 1,
'cso' => 1,
'csq' => 1,
'csr' => 1,
'css' => 1,
'cst' => 1,
'csu' => 1,
'csy' => 1,
'csz' => 1,
'cta' => 1,
'ctc' => 1,
'ctd' => 1,
'cte' => 1,
'ctg' => 1,
'ctl' => 1,
'ctm' => 1,
'ctn' => 1,
'cto' => 1,
'ctp' => 1,
'ctt' => 1,
'ctu' => 1,
'ctz' => 1,
'cua' => 1,
'cub' => 1,
'cuc' => 1,
'cug' => 1,
'cuh' => 1,
'cui' => 1,
'cuj' => 1,
'cuk' => 1,
'cul' => 1,
'cum' => 1,
'cuo' => 1,
'cup' => 1,
'cuq' => 1,
'cur' => 1,
'cus' => 1,
'cut' => 1,
'cuu' => 1,
'cuv' => 1,
'cuw' => 1,
'cux' => 1,
'cvg' => 1,
'cvn' => 1,
'cwa' => 1,
'cwb' => 1,
'cwe' => 1,
'cwg' => 1,
'cwt' => 1,
'cya' => 1,
'cyb' => 1,
'cyo' => 1,
'czk' => 1,
'czn' => 1,
'czt' => 1,
'daa' => 1,
'dac' => 1,
'dad' => 1,
'dae' => 1,
'daf' => 1,
'dag' => 1,
'dah' => 1,
'dai' => 1,
'daj' => 1,
'dak' => 1,
'dal' => 1,
'dam' => 1,
'dao' => 1,
'dap' => 1,
'daq' => 1,
'dar' => 1,
'das' => 1,
'dau' => 1,
'dav' => 1,
'daw' => 1,
'dax' => 1,
'day' => 1,
'daz' => 1,
'dba' => 1,
'dbb' => 1,
'dbd' => 1,
'dbe' => 1,
'dbf' => 1,
'dbg' => 1,
'dbi' => 1,
'dbj' => 1,
'dbl' => 1,
'dbm' => 1,
'dbn' => 1,
'dbo' => 1,
'dbp' => 1,
'dbq' => 1,
'dbr' => 1,
'dbu' => 1,
'dbv' => 1,
'dby' => 1,
'dcc' => 1,
'dcr' => 1,
'ddd' => 1,
'dde' => 1,
'ddg' => 1,
'ddi' => 1,
'ddj' => 1,
'ddn' => 1,
'ddo' => 1,
'dds' => 1,
'ddw' => 1,
'dec' => 1,
'ded' => 1,
'dee' => 1,
'def' => 1,
'deg' => 1,
'deh' => 1,
'dei' => 1,
'dek' => 1,
'del' => 1,
'dem' => 1,
'den' => 1,
'dep' => 1,
'deq' => 1,
'der' => 1,
'des' => 1,
'dev' => 1,
'dez' => 1,
'dga' => 1,
'dgb' => 1,
'dgc' => 1,
'dgd' => 1,
'dge' => 1,
'dgg' => 1,
'dgh' => 1,
'dgi' => 1,
'dgk' => 1,
'dgn' => 1,
'dgr' => 1,
'dgs' => 1,
'dgu' => 1,
'dgx' => 1,
'dgz' => 1,
'dha' => 1,
'dhg' => 1,
'dhi' => 1,
'dhl' => 1,
'dhm' => 1,
'dhn' => 1,
'dho' => 1,
'dhr' => 1,
'dhs' => 1,
'dhu' => 1,
'dhv' => 1,
'dhw' => 1,
'dia' => 1,
'dic' => 1,
'did' => 1,
'dif' => 1,
'dig' => 1,
'dih' => 1,
'dii' => 1,
'dij' => 1,
'dil' => 1,
'dim' => 1,
'din' => 1,
'dio' => 1,
'dir' => 1,
'dis' => 1,
'dit' => 1,
'diu' => 1,
'dix' => 1,
'diy' => 1,
'diz' => 1,
'djb' => 1,
'djc' => 1,
'djd' => 1,
'dje' => 1,
'djf' => 1,
'dji' => 1,
'djj' => 1,
'djk' => 1,
'djl' => 1,
'djm' => 1,
'djn' => 1,
'djo' => 1,
'djr' => 1,
'dju' => 1,
'djw' => 1,
'dka' => 1,
'dkk' => 1,
'dkl' => 1,
'dkr' => 1,
'dkx' => 1,
'dlg' => 1,
'dlm' => 1,
'dln' => 1,
'dma' => 1,
'dmc' => 1,
'dme' => 1,
'dmg' => 1,
'dmk' => 1,
'dml' => 1,
'dmm' => 1,
'dmn' => 1,
'dmo' => 1,
'dmr' => 1,
'dms' => 1,
'dmu' => 1,
'dmv' => 1,
'dmx' => 1,
'dmy' => 1,
'dna' => 1,
'dnd' => 1,
'dne' => 1,
'dng' => 1,
'dni' => 1,
'dnk' => 1,
'dnn' => 1,
'dnr' => 1,
'dnt' => 1,
'dnu' => 1,
'dnw' => 1,
'dny' => 1,
'doa' => 1,
'dob' => 1,
'doc' => 1,
'doe' => 1,
'dof' => 1,
'doh' => 1,
'doi' => 1,
'dok' => 1,
'dol' => 1,
'don' => 1,
'doo' => 1,
'dop' => 1,
'doq' => 1,
'dor' => 1,
'dos' => 1,
'dot' => 1,
'dov' => 1,
'dow' => 1,
'dox' => 1,
'doy' => 1,
'doz' => 1,
'dpp' => 1,
'dra' => 1,
'drb' => 1,
'drd' => 1,
'dre' => 1,
'drg' => 1,
'drh' => 1,
'dri' => 1,
'drl' => 1,
'drn' => 1,
'dro' => 1,
'drq' => 1,
'drr' => 1,
'drs' => 1,
'drt' => 1,
'dru' => 1,
'drw' => 1,
'dry' => 1,
'dsb' => 1,
'dse' => 1,
'dsh' => 1,
'dsi' => 1,
'dsl' => 1,
'dsn' => 1,
'dso' => 1,
'dsq' => 1,
'dta' => 1,
'dtb' => 1,
'dti' => 1,
'dtk' => 1,
'dtm' => 1,
'dtp' => 1,
'dtr' => 1,
'dts' => 1,
'dtt' => 1,
'dtu' => 1,
'dua' => 1,
'dub' => 1,
'duc' => 1,
'dud' => 1,
'due' => 1,
'duf' => 1,
'dug' => 1,
'duh' => 1,
'dui' => 1,
'duj' => 1,
'duk' => 1,
'dul' => 1,
'dum' => 1,
'dun' => 1,
'duo' => 1,
'duq' => 1,
'dur' => 1,
'dus' => 1,
'duu' => 1,
'duv' => 1,
'duw' => 1,
'dux' => 1,
'duy' => 1,
'duz' => 1,
'dva' => 1,
'dwa' => 1,
'dwl' => 1,
'dwr' => 1,
'dws' => 1,
'dww' => 1,
'dya' => 1,
'dyb' => 1,
'dyd' => 1,
'dyg' => 1,
'dyi' => 1,
'dym' => 1,
'dyn' => 1,
'dyo' => 1,
'dyu' => 1,
'dyy' => 1,
'dza' => 1,
'dzd' => 1,
'dzg' => 1,
'dzl' => 1,
'dzn' => 1,
'ebg' => 1,
'ebo' => 1,
'ebr' => 1,
'ebu' => 1,
'ecr' => 1,
'ecs' => 1,
'ecy' => 1,
'eee' => 1,
'efa' => 1,
'efe' => 1,
'efi' => 1,
'ega' => 1,
'egl' => 1,
'ego' => 1,
'egx' => 1,
'egy' => 1,
'ehu' => 1,
'eip' => 1,
'eit' => 1,
'eiv' => 1,
'eja' => 1,
'eka' => 1,
'eke' => 1,
'ekg' => 1,
'eki' => 1,
'ekl' => 1,
'ekm' => 1,
'eko' => 1,
'ekp' => 1,
'ekr' => 1,
'eky' => 1,
'ele' => 1,
'elh' => 1,
'eli' => 1,
'elk' => 1,
'elm' => 1,
'elo' => 1,
'elp' => 1,
'elu' => 1,
'elx' => 1,
'ema' => 1,
'emb' => 1,
'eme' => 1,
'emg' => 1,
'emi' => 1,
'emm' => 1,
'emn' => 1,
'emo' => 1,
'emp' => 1,
'ems' => 1,
'emu' => 1,
'emw' => 1,
'emy' => 1,
'ena' => 1,
'enc' => 1,
'end' => 1,
'enf' => 1,
'enh' => 1,
'enm' => 1,
'enn' => 1,
'eno' => 1,
'enq' => 1,
'enr' => 1,
'enu' => 1,
'env' => 1,
'enw' => 1,
'eot' => 1,
'epi' => 1,
'era' => 1,
'erg' => 1,
'erh' => 1,
'eri' => 1,
'erk' => 1,
'ero' => 1,
'err' => 1,
'ers' => 1,
'ert' => 1,
'erw' => 1,
'ese' => 1,
'esh' => 1,
'esl' => 1,
'esm' => 1,
'esn' => 1,
'eso' => 1,
'esq' => 1,
'ess' => 1,
'esu' => 1,
'esx' => 1,
'etb' => 1,
'etc' => 1,
'eth' => 1,
'etn' => 1,
'eto' => 1,
'etr' => 1,
'ets' => 1,
'ett' => 1,
'etu' => 1,
'etx' => 1,
'etz' => 1,
'euq' => 1,
'eve' => 1,
'evh' => 1,
'evn' => 1,
'ewo' => 1,
'ext' => 1,
'eya' => 1,
'eze' => 1,
'faa' => 1,
'fab' => 1,
'fad' => 1,
'faf' => 1,
'fag' => 1,
'fah' => 1,
'fai' => 1,
'faj' => 1,
'fak' => 1,
'fal' => 1,
'fam' => 1,
'fan' => 1,
'fap' => 1,
'far' => 1,
'fau' => 1,
'fax' => 1,
'fay' => 1,
'faz' => 1,
'fcs' => 1,
'fer' => 1,
'ffi' => 1,
'fgr' => 1,
'fia' => 1,
'fie' => 1,
'fil' => 1,
'fip' => 1,
'fir' => 1,
'fit' => 1,
'fiu' => 1,
'fiw' => 1,
'fkv' => 1,
'fla' => 1,
'flh' => 1,
'fli' => 1,
'fll' => 1,
'fln' => 1,
'flr' => 1,
'fly' => 1,
'fmp' => 1,
'fmu' => 1,
'fng' => 1,
'fni' => 1,
'fod' => 1,
'foi' => 1,
'fom' => 1,
'fon' => 1,
'for' => 1,
'fos' => 1,
'fox' => 1,
'fpe' => 1,
'fqs' => 1,
'frc' => 1,
'frd' => 1,
'frk' => 1,
'frm' => 1,
'fro' => 1,
'frp' => 1,
'frq' => 1,
'frr' => 1,
'frs' => 1,
'frt' => 1,
'fse' => 1,
'fsl' => 1,
'fss' => 1,
'fud' => 1,
'fuj' => 1,
'fum' => 1,
'fun' => 1,
'fur' => 1,
'fut' => 1,
'fuu' => 1,
'fuy' => 1,
'fvr' => 1,
'fwa' => 1,
'fwe' => 1,
'gaa' => 1,
'gab' => 1,
'gad' => 1,
'gae' => 1,
'gaf' => 1,
'gag' => 1,
'gah' => 1,
'gai' => 1,
'gaj' => 1,
'gak' => 1,
'gal' => 1,
'gam' => 1,
'gao' => 1,
'gap' => 1,
'gaq' => 1,
'gar' => 1,
'gas' => 1,
'gat' => 1,
'gau' => 1,
'gav' => 1,
'gaw' => 1,
'gay' => 1,
'gba' => 1,
'gbb' => 1,
'gbc' => 1,
'gbd' => 1,
'gbe' => 1,
'gbf' => 1,
'gbg' => 1,
'gbh' => 1,
'gbi' => 1,
'gbj' => 1,
'gbk' => 1,
'gbl' => 1,
'gbm' => 1,
'gbn' => 1,
'gbr' => 1,
'gbs' => 1,
'gbu' => 1,
'gbv' => 1,
'gbx' => 1,
'gby' => 1,
'gbz' => 1,
'gcc' => 1,
'gcd' => 1,
'gce' => 1,
'gcf' => 1,
'gcl' => 1,
'gcn' => 1,
'gcr' => 1,
'gct' => 1,
'gdb' => 1,
'gdc' => 1,
'gdd' => 1,
'gde' => 1,
'gdf' => 1,
'gdg' => 1,
'gdh' => 1,
'gdi' => 1,
'gdj' => 1,
'gdk' => 1,
'gdl' => 1,
'gdm' => 1,
'gdn' => 1,
'gdo' => 1,
'gdq' => 1,
'gdr' => 1,
'gdu' => 1,
'gdx' => 1,
'gea' => 1,
'geb' => 1,
'ged' => 1,
'geg' => 1,
'geh' => 1,
'gei' => 1,
'gej' => 1,
'gek' => 1,
'gel' => 1,
'gem' => 1,
'geq' => 1,
'ges' => 1,
'gew' => 1,
'gex' => 1,
'gey' => 1,
'gez' => 1,
'gfk' => 1,
'gft' => 1,
'gga' => 1,
'ggb' => 1,
'ggd' => 1,
'gge' => 1,
'ggg' => 1,
'ggk' => 1,
'ggl' => 1,
'ggn' => 1,
'ggr' => 1,
'ggt' => 1,
'ggu' => 1,
'ggw' => 1,
'gha' => 1,
'ghc' => 1,
'ghe' => 1,
'ghh' => 1,
'ghk' => 1,
'ghl' => 1,
'ghn' => 1,
'gho' => 1,
'ghr' => 1,
'ghs' => 1,
'ght' => 1,
'gia' => 1,
'gib' => 1,
'gic' => 1,
'gid' => 1,
'gig' => 1,
'gil' => 1,
'gim' => 1,
'gin' => 1,
'gio' => 1,
'gip' => 1,
'giq' => 1,
'gir' => 1,
'gis' => 1,
'git' => 1,
'giw' => 1,
'gix' => 1,
'giy' => 1,
'giz' => 1,
'gji' => 1,
'gjk' => 1,
'gjn' => 1,
'gka' => 1,
'gke' => 1,
'gkn' => 1,
'glc' => 1,
'gld' => 1,
'glh' => 1,
'gli' => 1,
'glj' => 1,
'glk' => 1,
'glo' => 1,
'glr' => 1,
'glu' => 1,
'glw' => 1,
'gly' => 1,
'gma' => 1,
'gmb' => 1,
'gmd' => 1,
'gme' => 1,
'gmh' => 1,
'gml' => 1,
'gmn' => 1,
'gmq' => 1,
'gmu' => 1,
'gmv' => 1,
'gmw' => 1,
'gmx' => 1,
'gmy' => 1,
'gna' => 1,
'gnb' => 1,
'gnc' => 1,
'gnd' => 1,
'gne' => 1,
'gng' => 1,
'gnh' => 1,
'gni' => 1,
'gnk' => 1,
'gnl' => 1,
'gnm' => 1,
'gnn' => 1,
'gnq' => 1,
'gnr' => 1,
'gnt' => 1,
'gnu' => 1,
'gnz' => 1,
'goa' => 1,
'gob' => 1,
'goc' => 1,
'god' => 1,
'goe' => 1,
'gof' => 1,
'gog' => 1,
'goh' => 1,
'goi' => 1,
'goj' => 1,
'gok' => 1,
'gol' => 1,
'gon' => 1,
'goo' => 1,
'gop' => 1,
'goq' => 1,
'gor' => 1,
'gos' => 1,
'got' => 1,
'gou' => 1,
'gow' => 1,
'gox' => 1,
'goy' => 1,
'goz' => 1,
'gpa' => 1,
'gpn' => 1,
'gqa' => 1,
'gqi' => 1,
'gqn' => 1,
'gqr' => 1,
'gra' => 1,
'grb' => 1,
'grc' => 1,
'grd' => 1,
'grg' => 1,
'grh' => 1,
'gri' => 1,
'grk' => 1,
'grm' => 1,
'gro' => 1,
'grq' => 1,
'grr' => 1,
'grs' => 1,
'grt' => 1,
'gru' => 1,
'grw' => 1,
'grx' => 1,
'grz' => 1,
'gse' => 1,
'gsg' => 1,
'gsl' => 1,
'gsm' => 1,
'gsn' => 1,
'gsp' => 1,
'gss' => 1,
'gsw' => 1,
'gta' => 1,
'gti' => 1,
'gua' => 1,
'gub' => 1,
'guc' => 1,
'gud' => 1,
'gue' => 1,
'guf' => 1,
'guh' => 1,
'guk' => 1,
'gul' => 1,
'gum' => 1,
'guo' => 1,
'gup' => 1,
'guq' => 1,
'gur' => 1,
'gus' => 1,
'gut' => 1,
'guu' => 1,
'guv' => 1,
'guw' => 1,
'gux' => 1,
'guz' => 1,
'gva' => 1,
'gvc' => 1,
'gve' => 1,
'gvf' => 1,
'gvj' => 1,
'gvl' => 1,
'gvm' => 1,
'gvn' => 1,
'gvo' => 1,
'gvp' => 1,
'gvr' => 1,
'gvs' => 1,
'gvy' => 1,
'gwa' => 1,
'gwb' => 1,
'gwc' => 1,
'gwd' => 1,
'gwe' => 1,
'gwf' => 1,
'gwg' => 1,
'gwi' => 1,
'gwj' => 1,
'gwn' => 1,
'gwr' => 1,
'gwt' => 1,
'gwu' => 1,
'gww' => 1,
'gwx' => 1,
'gxx' => 1,
'gyb' => 1,
'gyd' => 1,
'gye' => 1,
'gyf' => 1,
'gyg' => 1,
'gyi' => 1,
'gyl' => 1,
'gym' => 1,
'gyn' => 1,
'gyr' => 1,
'gyy' => 1,
'gza' => 1,
'gzi' => 1,
'gzn' => 1,
'haa' => 1,
'hab' => 1,
'hac' => 1,
'had' => 1,
'haf' => 1,
'hag' => 1,
'hah' => 1,
'hai' => 1,
'haj' => 1,
'hal' => 1,
'ham' => 1,
'han' => 1,
'hao' => 1,
'hap' => 1,
'haq' => 1,
'har' => 1,
'has' => 1,
'hav' => 1,
'haw' => 1,
'hay' => 1,
'haz' => 1,
'hba' => 1,
'hbb' => 1,
'hbn' => 1,
'hbo' => 1,
'hbu' => 1,
'hca' => 1,
'hch' => 1,
'hds' => 1,
'hdy' => 1,
'hed' => 1,
'heg' => 1,
'heh' => 1,
'hei' => 1,
'hem' => 1,
'hgm' => 1,
'hgw' => 1,
'hhi' => 1,
'hhr' => 1,
'hhy' => 1,
'hia' => 1,
'hib' => 1,
'hid' => 1,
'hif' => 1,
'hig' => 1,
'hih' => 1,
'hii' => 1,
'hij' => 1,
'hik' => 1,
'hil' => 1,
'him' => 1,
'hio' => 1,
'hir' => 1,
'hit' => 1,
'hiw' => 1,
'hix' => 1,
'hka' => 1,
'hke' => 1,
'hkk' => 1,
'hks' => 1,
'hla' => 1,
'hlb' => 1,
'hld' => 1,
'hle' => 1,
'hlt' => 1,
'hlu' => 1,
'hmb' => 1,
'hmf' => 1,
'hmk' => 1,
'hmn' => 1,
'hmr' => 1,
'hmt' => 1,
'hmu' => 1,
'hmv' => 1,
'hmx' => 1,
'hmz' => 1,
'hna' => 1,
'hne' => 1,
'hnh' => 1,
'hni' => 1,
'hnn' => 1,
'hns' => 1,
'hnu' => 1,
'hoa' => 1,
'hob' => 1,
'hoc' => 1,
'hod' => 1,
'hoe' => 1,
'hoh' => 1,
'hoi' => 1,
'hok' => 1,
'hol' => 1,
'hom' => 1,
'hoo' => 1,
'hop' => 1,
'hor' => 1,
'hos' => 1,
'hot' => 1,
'hov' => 1,
'how' => 1,
'hoy' => 1,
'hoz' => 1,
'hpo' => 1,
'hps' => 1,
'hra' => 1,
'hre' => 1,
'hrk' => 1,
'hro' => 1,
'hrr' => 1,
'hrt' => 1,
'hru' => 1,
'hrx' => 1,
'hrz' => 1,
'hsb' => 1,
'hsh' => 1,
'hsl' => 1,
'hss' => 1,
'hti' => 1,
'hto' => 1,
'hts' => 1,
'htu' => 1,
'htx' => 1,
'hub' => 1,
'huc' => 1,
'hud' => 1,
'hue' => 1,
'huf' => 1,
'hug' => 1,
'huh' => 1,
'hui' => 1,
'huk' => 1,
'hul' => 1,
'hum' => 1,
'huo' => 1,
'hup' => 1,
'huq' => 1,
'hur' => 1,
'hus' => 1,
'hut' => 1,
'huu' => 1,
'huv' => 1,
'huw' => 1,
'hux' => 1,
'huy' => 1,
'huz' => 1,
'hvc' => 1,
'hve' => 1,
'hvk' => 1,
'hvn' => 1,
'hvv' => 1,
'hwa' => 1,
'hwc' => 1,
'hwo' => 1,
'hya' => 1,
'hyx' => 1,
'iai' => 1,
'ian' => 1,
'iap' => 1,
'iar' => 1,
'iba' => 1,
'ibb' => 1,
'ibd' => 1,
'ibe' => 1,
'ibg' => 1,
'ibi' => 1,
'ibl' => 1,
'ibm' => 1,
'ibn' => 1,
'ibr' => 1,
'ibu' => 1,
'iby' => 1,
'ica' => 1,
'ich' => 1,
'icl' => 1,
'icr' => 1,
'idb' => 1,
'idc' => 1,
'idd' => 1,
'ide' => 1,
'idi' => 1,
'idr' => 1,
'ids' => 1,
'idt' => 1,
'idu' => 1,
'ifa' => 1,
'ifb' => 1,
'ife' => 1,
'iff' => 1,
'ifk' => 1,
'ifm' => 1,
'ifu' => 1,
'ify' => 1,
'igb' => 1,
'ige' => 1,
'igg' => 1,
'igl' => 1,
'igm' => 1,
'ign' => 1,
'igo' => 1,
'igs' => 1,
'igw' => 1,
'ihb' => 1,
'ihi' => 1,
'ihp' => 1,
'iir' => 1,
'ijc' => 1,
'ije' => 1,
'ijj' => 1,
'ijn' => 1,
'ijo' => 1,
'ijs' => 1,
'iki' => 1,
'ikk' => 1,
'ikl' => 1,
'iko' => 1,
'ikp' => 1,
'ikv' => 1,
'ikw' => 1,
'ikx' => 1,
'ikz' => 1,
'ila' => 1,
'ilb' => 1,
'ilg' => 1,
'ili' => 1,
'ilk' => 1,
'ill' => 1,
'ilo' => 1,
'ils' => 1,
'ilu' => 1,
'ilv' => 1,
'ilw' => 1,
'ima' => 1,
'ime' => 1,
'imi' => 1,
'iml' => 1,
'imn' => 1,
'imo' => 1,
'imr' => 1,
'ims' => 1,
'imy' => 1,
'inb' => 1,
'inc' => 1,
'ine' => 1,
'ing' => 1,
'inh' => 1,
'inj' => 1,
'inl' => 1,
'inm' => 1,
'inn' => 1,
'ino' => 1,
'inp' => 1,
'ins' => 1,
'int' => 1,
'inz' => 1,
'ior' => 1,
'iou' => 1,
'iow' => 1,
'ipi' => 1,
'ipo' => 1,
'iqu' => 1,
'ira' => 1,
'ire' => 1,
'irh' => 1,
'iri' => 1,
'irk' => 1,
'irn' => 1,
'iro' => 1,
'irr' => 1,
'iru' => 1,
'irx' => 1,
'iry' => 1,
'isa' => 1,
'isc' => 1,
'isd' => 1,
'ise' => 1,
'isg' => 1,
'ish' => 1,
'isi' => 1,
'ism' => 1,
'isn' => 1,
'iso' => 1,
'isr' => 1,
'ist' => 1,
'isu' => 1,
'itb' => 1,
'itc' => 1,
'ite' => 1,
'iti' => 1,
'itk' => 1,
'itl' => 1,
'itm' => 1,
'ito' => 1,
'itr' => 1,
'its' => 1,
'itt' => 1,
'itv' => 1,
'itw' => 1,
'itx' => 1,
'ity' => 1,
'itz' => 1,
'ium' => 1,
'ivb' => 1,
'ivv' => 1,
'iwk' => 1,
'iwm' => 1,
'iwo' => 1,
'iws' => 1,
'ixc' => 1,
'ixl' => 1,
'iya' => 1,
'iyo' => 1,
'iyx' => 1,
'izh' => 1,
'izi' => 1,
'izr' => 1,
'jaa' => 1,
'jab' => 1,
'jac' => 1,
'jad' => 1,
'jae' => 1,
'jaf' => 1,
'jah' => 1,
'jaj' => 1,
'jal' => 1,
'jam' => 1,
'jao' => 1,
'jaq' => 1,
'jar' => 1,
'jas' => 1,
'jau' => 1,
'jay' => 1,
'jaz' => 1,
'jbe' => 1,
'jbj' => 1,
'jbn' => 1,
'jbo' => 1,
'jbr' => 1,
'jbt' => 1,
'jbu' => 1,
'jcs' => 1,
'jct' => 1,
'jda' => 1,
'jdg' => 1,
'jdt' => 1,
'jeb' => 1,
'jee' => 1,
'jeg' => 1,
'jeh' => 1,
'jei' => 1,
'jek' => 1,
'jel' => 1,
'jen' => 1,
'jer' => 1,
'jet' => 1,
'jeu' => 1,
'jgb' => 1,
'jge' => 1,
'jgo' => 1,
'jhi' => 1,
'jhs' => 1,
'jia' => 1,
'jib' => 1,
'jic' => 1,
'jid' => 1,
'jie' => 1,
'jig' => 1,
'jih' => 1,
'jii' => 1,
'jil' => 1,
'jim' => 1,
'jio' => 1,
'jiq' => 1,
'jit' => 1,
'jiu' => 1,
'jiv' => 1,
'jiy' => 1,
'jko' => 1,
'jku' => 1,
'jle' => 1,
'jma' => 1,
'jmb' => 1,
'jmc' => 1,
'jmd' => 1,
'jmi' => 1,
'jml' => 1,
'jmn' => 1,
'jmr' => 1,
'jms' => 1,
'jmx' => 1,
'jna' => 1,
'jnd' => 1,
'jng' => 1,
'jni' => 1,
'jnj' => 1,
'jnl' => 1,
'jns' => 1,
'job' => 1,
'jod' => 1,
'jor' => 1,
'jos' => 1,
'jow' => 1,
'jpa' => 1,
'jpr' => 1,
'jpx' => 1,
'jqr' => 1,
'jra' => 1,
'jrb' => 1,
'jrr' => 1,
'jrt' => 1,
'jru' => 1,
'jsl' => 1,
'jua' => 1,
'jub' => 1,
'juc' => 1,
'jud' => 1,
'juh' => 1,
'juk' => 1,
'jul' => 1,
'jum' => 1,
'jun' => 1,
'juo' => 1,
'jup' => 1,
'jur' => 1,
'jus' => 1,
'jut' => 1,
'juu' => 1,
'juw' => 1,
'juy' => 1,
'jvd' => 1,
'jvn' => 1,
'jwi' => 1,
'jya' => 1,
'jyy' => 1,
'kaa' => 1,
'kab' => 1,
'kac' => 1,
'kad' => 1,
'kae' => 1,
'kaf' => 1,
'kag' => 1,
'kah' => 1,
'kai' => 1,
'kaj' => 1,
'kak' => 1,
'kam' => 1,
'kao' => 1,
'kap' => 1,
'kaq' => 1,
'kar' => 1,
'kav' => 1,
'kaw' => 1,
'kax' => 1,
'kay' => 1,
'kba' => 1,
'kbb' => 1,
'kbc' => 1,
'kbd' => 1,
'kbe' => 1,
'kbf' => 1,
'kbg' => 1,
'kbh' => 1,
'kbi' => 1,
'kbj' => 1,
'kbk' => 1,
'kbl' => 1,
'kbm' => 1,
'kbn' => 1,
'kbo' => 1,
'kbp' => 1,
'kbq' => 1,
'kbr' => 1,
'kbs' => 1,
'kbt' => 1,
'kbu' => 1,
'kbv' => 1,
'kbw' => 1,
'kbx' => 1,
'kbz' => 1,
'kca' => 1,
'kcb' => 1,
'kcc' => 1,
'kcd' => 1,
'kce' => 1,
'kcf' => 1,
'kcg' => 1,
'kch' => 1,
'kci' => 1,
'kcj' => 1,
'kck' => 1,
'kcl' => 1,
'kcm' => 1,
'kcn' => 1,
'kco' => 1,
'kcp' => 1,
'kcq' => 1,
'kcr' => 1,
'kcs' => 1,
'kct' => 1,
'kcu' => 1,
'kcv' => 1,
'kcw' => 1,
'kcx' => 1,
'kcy' => 1,
'kcz' => 1,
'kda' => 1,
'kdc' => 1,
'kdd' => 1,
'kde' => 1,
'kdf' => 1,
'kdg' => 1,
'kdh' => 1,
'kdi' => 1,
'kdj' => 1,
'kdk' => 1,
'kdl' => 1,
'kdm' => 1,
'kdn' => 1,
'kdo' => 1,
'kdp' => 1,
'kdq' => 1,
'kdr' => 1,
'kdt' => 1,
'kdu' => 1,
'kdv' => 1,
'kdw' => 1,
'kdx' => 1,
'kdy' => 1,
'kdz' => 1,
'kea' => 1,
'keb' => 1,
'kec' => 1,
'ked' => 1,
'kee' => 1,
'kef' => 1,
'keg' => 1,
'keh' => 1,
'kei' => 1,
'kej' => 1,
'kek' => 1,
'kel' => 1,
'kem' => 1,
'ken' => 1,
'keo' => 1,
'kep' => 1,
'keq' => 1,
'ker' => 1,
'kes' => 1,
'ket' => 1,
'keu' => 1,
'kev' => 1,
'kew' => 1,
'kex' => 1,
'key' => 1,
'kez' => 1,
'kfa' => 1,
'kfb' => 1,
'kfc' => 1,
'kfd' => 1,
'kfe' => 1,
'kff' => 1,
'kfg' => 1,
'kfh' => 1,
'kfi' => 1,
'kfj' => 1,
'kfk' => 1,
'kfl' => 1,
'kfm' => 1,
'kfn' => 1,
'kfo' => 1,
'kfp' => 1,
'kfq' => 1,
'kfr' => 1,
'kfs' => 1,
'kft' => 1,
'kfu' => 1,
'kfv' => 1,
'kfw' => 1,
'kfx' => 1,
'kfy' => 1,
'kfz' => 1,
'kga' => 1,
'kgb' => 1,
'kgc' => 1,
'kgd' => 1,
'kge' => 1,
'kgf' => 1,
'kgg' => 1,
'kgh' => 1,
'kgi' => 1,
'kgj' => 1,
'kgk' => 1,
'kgl' => 1,
'kgm' => 1,
'kgn' => 1,
'kgo' => 1,
'kgp' => 1,
'kgq' => 1,
'kgr' => 1,
'kgs' => 1,
'kgt' => 1,
'kgu' => 1,
'kgv' => 1,
'kgw' => 1,
'kgx' => 1,
'kgy' => 1,
'kha' => 1,
'khb' => 1,
'khc' => 1,
'khd' => 1,
'khe' => 1,
'khf' => 1,
'khg' => 1,
'khh' => 1,
'khi' => 1,
'khj' => 1,
'khl' => 1,
'khn' => 1,
'kho' => 1,
'khp' => 1,
'khq' => 1,
'khr' => 1,
'khs' => 1,
'kht' => 1,
'khu' => 1,
'khv' => 1,
'khw' => 1,
'khx' => 1,
'khy' => 1,
'khz' => 1,
'kia' => 1,
'kib' => 1,
'kic' => 1,
'kid' => 1,
'kie' => 1,
'kif' => 1,
'kig' => 1,
'kih' => 1,
'kii' => 1,
'kij' => 1,
'kil' => 1,
'kim' => 1,
'kio' => 1,
'kip' => 1,
'kiq' => 1,
'kis' => 1,
'kit' => 1,
'kiv' => 1,
'kiw' => 1,
'kix' => 1,
'kiy' => 1,
'kiz' => 1,
'kja' => 1,
'kjb' => 1,
'kjc' => 1,
'kjd' => 1,
'kje' => 1,
'kjf' => 1,
'kjg' => 1,
'kjh' => 1,
'kji' => 1,
'kjj' => 1,
'kjk' => 1,
'kjl' => 1,
'kjm' => 1,
'kjn' => 1,
'kjo' => 1,
'kjp' => 1,
'kjq' => 1,
'kjr' => 1,
'kjs' => 1,
'kjt' => 1,
'kju' => 1,
'kjx' => 1,
'kjy' => 1,
'kjz' => 1,
'kka' => 1,
'kkb' => 1,
'kkc' => 1,
'kkd' => 1,
'kke' => 1,
'kkf' => 1,
'kkg' => 1,
'kkh' => 1,
'kki' => 1,
'kkj' => 1,
'kkk' => 1,
'kkl' => 1,
'kkm' => 1,
'kkn' => 1,
'kko' => 1,
'kkp' => 1,
'kkq' => 1,
'kkr' => 1,
'kks' => 1,
'kkt' => 1,
'kku' => 1,
'kkv' => 1,
'kkw' => 1,
'kkx' => 1,
'kky' => 1,
'kkz' => 1,
'kla' => 1,
'klb' => 1,
'klc' => 1,
'kld' => 1,
'kle' => 1,
'klf' => 1,
'klg' => 1,
'klh' => 1,
'kli' => 1,
'klj' => 1,
'klk' => 1,
'kll' => 1,
'klm' => 1,
'kln' => 1,
'klo' => 1,
'klp' => 1,
'klq' => 1,
'klr' => 1,
'kls' => 1,
'klt' => 1,
'klu' => 1,
'klv' => 1,
'klw' => 1,
'klx' => 1,
'kly' => 1,
'klz' => 1,
'kma' => 1,
'kmb' => 1,
'kmc' => 1,
'kmd' => 1,
'kme' => 1,
'kmf' => 1,
'kmg' => 1,
'kmh' => 1,
'kmi' => 1,
'kmj' => 1,
'kmk' => 1,
'kml' => 1,
'kmm' => 1,
'kmn' => 1,
'kmo' => 1,
'kmp' => 1,
'kmq' => 1,
'kms' => 1,
'kmt' => 1,
'kmu' => 1,
'kmv' => 1,
'kmw' => 1,
'kmx' => 1,
'kmy' => 1,
'kmz' => 1,
'kna' => 1,
'knb' => 1,
'knd' => 1,
'kne' => 1,
'knf' => 1,
'kni' => 1,
'knj' => 1,
'knk' => 1,
'knl' => 1,
'knm' => 1,
'kno' => 1,
'knp' => 1,
'knq' => 1,
'knr' => 1,
'kns' => 1,
'knt' => 1,
'knu' => 1,
'knv' => 1,
'knw' => 1,
'knx' => 1,
'kny' => 1,
'knz' => 1,
'koa' => 1,
'koc' => 1,
'kod' => 1,
'koe' => 1,
'kof' => 1,
'kog' => 1,
'koh' => 1,
'koj' => 1,
'kok' => 1,
'kol' => 1,
'koo' => 1,
'kop' => 1,
'koq' => 1,
'kos' => 1,
'kot' => 1,
'kou' => 1,
'kov' => 1,
'kow' => 1,
'kox' => 1,
'koy' => 1,
'koz' => 1,
'kpa' => 1,
'kpb' => 1,
'kpc' => 1,
'kpd' => 1,
'kpe' => 1,
'kpf' => 1,
'kpg' => 1,
'kph' => 1,
'kpi' => 1,
'kpj' => 1,
'kpk' => 1,
'kpl' => 1,
'kpm' => 1,
'kpn' => 1,
'kpo' => 1,
'kpp' => 1,
'kpq' => 1,
'kpr' => 1,
'kps' => 1,
'kpt' => 1,
'kpu' => 1,
'kpw' => 1,
'kpx' => 1,
'kpy' => 1,
'kpz' => 1,
'kqa' => 1,
'kqb' => 1,
'kqc' => 1,
'kqd' => 1,
'kqe' => 1,
'kqf' => 1,
'kqg' => 1,
'kqh' => 1,
'kqi' => 1,
'kqj' => 1,
'kqk' => 1,
'kql' => 1,
'kqm' => 1,
'kqn' => 1,
'kqo' => 1,
'kqp' => 1,
'kqq' => 1,
'kqr' => 1,
'kqs' => 1,
'kqt' => 1,
'kqu' => 1,
'kqv' => 1,
'kqw' => 1,
'kqx' => 1,
'kqy' => 1,
'kqz' => 1,
'kra' => 1,
'krb' => 1,
'krc' => 1,
'krd' => 1,
'kre' => 1,
'krf' => 1,
'krh' => 1,
'kri' => 1,
'krj' => 1,
'krk' => 1,
'krl' => 1,
'krm' => 1,
'krn' => 1,
'kro' => 1,
'krp' => 1,
'krr' => 1,
'krs' => 1,
'kru' => 1,
'krv' => 1,
'krw' => 1,
'krx' => 1,
'kry' => 1,
'krz' => 1,
'ksa' => 1,
'ksb' => 1,
'ksc' => 1,
'ksd' => 1,
'kse' => 1,
'ksf' => 1,
'ksg' => 1,
'ksh' => 1,
'ksi' => 1,
'ksj' => 1,
'ksk' => 1,
'ksl' => 1,
'ksm' => 1,
'ksn' => 1,
'kso' => 1,
'ksp' => 1,
'ksq' => 1,
'ksr' => 1,
'kss' => 1,
'kst' => 1,
'ksu' => 1,
'ksv' => 1,
'ksw' => 1,
'ksx' => 1,
'ksy' => 1,
'ksz' => 1,
'kta' => 1,
'ktb' => 1,
'ktc' => 1,
'ktd' => 1,
'kte' => 1,
'ktf' => 1,
'ktg' => 1,
'kth' => 1,
'kti' => 1,
'ktj' => 1,
'ktk' => 1,
'ktl' => 1,
'ktm' => 1,
'ktn' => 1,
'kto' => 1,
'ktp' => 1,
'ktq' => 1,
'ktr' => 1,
'kts' => 1,
'ktt' => 1,
'ktu' => 1,
'ktv' => 1,
'ktw' => 1,
'ktx' => 1,
'kty' => 1,
'ktz' => 1,
'kub' => 1,
'kuc' => 1,
'kud' => 1,
'kue' => 1,
'kuf' => 1,
'kug' => 1,
'kuh' => 1,
'kui' => 1,
'kuj' => 1,
'kuk' => 1,
'kul' => 1,
'kum' => 1,
'kun' => 1,
'kuo' => 1,
'kup' => 1,
'kuq' => 1,
'kus' => 1,
'kut' => 1,
'kuu' => 1,
'kuv' => 1,
'kuw' => 1,
'kux' => 1,
'kuy' => 1,
'kuz' => 1,
'kva' => 1,
'kvc' => 1,
'kvd' => 1,
'kve' => 1,
'kvf' => 1,
'kvg' => 1,
'kvh' => 1,
'kvi' => 1,
'kvj' => 1,
'kvk' => 1,
'kvl' => 1,
'kvm' => 1,
'kvn' => 1,
'kvo' => 1,
'kvp' => 1,
'kvq' => 1,
'kvs' => 1,
'kvt' => 1,
'kvu' => 1,
'kvv' => 1,
'kvw' => 1,
'kvx' => 1,
'kvy' => 1,
'kvz' => 1,
'kwa' => 1,
'kwb' => 1,
'kwc' => 1,
'kwd' => 1,
'kwe' => 1,
'kwf' => 1,
'kwg' => 1,
'kwh' => 1,
'kwi' => 1,
'kwj' => 1,
'kwk' => 1,
'kwl' => 1,
'kwm' => 1,
'kwn' => 1,
'kwo' => 1,
'kwp' => 1,
'kwq' => 1,
'kwr' => 1,
'kws' => 1,
'kwt' => 1,
'kwu' => 1,
'kwv' => 1,
'kww' => 1,
'kwx' => 1,
'kwz' => 1,
'kxa' => 1,
'kxb' => 1,
'kxc' => 1,
'kxe' => 1,
'kxf' => 1,
'kxh' => 1,
'kxi' => 1,
'kxj' => 1,
'kxk' => 1,
'kxl' => 1,
'kxm' => 1,
'kxn' => 1,
'kxo' => 1,
'kxp' => 1,
'kxq' => 1,
'kxr' => 1,
'kxs' => 1,
'kxt' => 1,
'kxu' => 1,
'kxv' => 1,
'kxw' => 1,
'kxx' => 1,
'kxy' => 1,
'kxz' => 1,
'kya' => 1,
'kyb' => 1,
'kyc' => 1,
'kyd' => 1,
'kye' => 1,
'kyf' => 1,
'kyg' => 1,
'kyh' => 1,
'kyi' => 1,
'kyj' => 1,
'kyk' => 1,
'kyl' => 1,
'kym' => 1,
'kyn' => 1,
'kyo' => 1,
'kyp' => 1,
'kyq' => 1,
'kyr' => 1,
'kys' => 1,
'kyt' => 1,
'kyu' => 1,
'kyv' => 1,
'kyw' => 1,
'kyx' => 1,
'kyy' => 1,
'kyz' => 1,
'kza' => 1,
'kzb' => 1,
'kzc' => 1,
'kzd' => 1,
'kze' => 1,
'kzf' => 1,
'kzg' => 1,
'kzh' => 1,
'kzi' => 1,
'kzj' => 1,
'kzk' => 1,
'kzl' => 1,
'kzm' => 1,
'kzn' => 1,
'kzo' => 1,
'kzp' => 1,
'kzq' => 1,
'kzr' => 1,
'kzs' => 1,
'kzt' => 1,
'kzu' => 1,
'kzv' => 1,
'kzw' => 1,
'kzx' => 1,
'kzy' => 1,
'kzz' => 1,
'laa' => 1,
'lab' => 1,
'lac' => 1,
'lad' => 1,
'lae' => 1,
'laf' => 1,
'lag' => 1,
'lah' => 1,
'lai' => 1,
'laj' => 1,
'lak' => 1,
'lal' => 1,
'lam' => 1,
'lan' => 1,
'lap' => 1,
'laq' => 1,
'lar' => 1,
'las' => 1,
'lau' => 1,
'law' => 1,
'lax' => 1,
'lay' => 1,
'laz' => 1,
'lba' => 1,
'lbb' => 1,
'lbc' => 1,
'lbe' => 1,
'lbf' => 1,
'lbg' => 1,
'lbi' => 1,
'lbj' => 1,
'lbm' => 1,
'lbn' => 1,
'lbo' => 1,
'lbq' => 1,
'lbr' => 1,
'lbs' => 1,
'lbt' => 1,
'lbu' => 1,
'lbv' => 1,
'lbw' => 1,
'lbx' => 1,
'lby' => 1,
'lbz' => 1,
'lcc' => 1,
'lcd' => 1,
'lch' => 1,
'lcl' => 1,
'lcm' => 1,
'lcp' => 1,
'lcq' => 1,
'lcs' => 1,
'ldb' => 1,
'ldd' => 1,
'ldg' => 1,
'ldh' => 1,
'ldj' => 1,
'ldk' => 1,
'ldl' => 1,
'ldm' => 1,
'ldn' => 1,
'ldo' => 1,
'ldp' => 1,
'ldq' => 1,
'lea' => 1,
'leb' => 1,
'lec' => 1,
'led' => 1,
'lee' => 1,
'lef' => 1,
'leg' => 1,
'leh' => 1,
'lei' => 1,
'lej' => 1,
'lek' => 1,
'lel' => 1,
'lem' => 1,
'len' => 1,
'leo' => 1,
'lep' => 1,
'leq' => 1,
'ler' => 1,
'les' => 1,
'let' => 1,
'leu' => 1,
'lev' => 1,
'lew' => 1,
'lex' => 1,
'ley' => 1,
'lez' => 1,
'lfa' => 1,
'lfn' => 1,
'lga' => 1,
'lgb' => 1,
'lgg' => 1,
'lgh' => 1,
'lgi' => 1,
'lgk' => 1,
'lgl' => 1,
'lgm' => 1,
'lgn' => 1,
'lgq' => 1,
'lgr' => 1,
'lgt' => 1,
'lgu' => 1,
'lgz' => 1,
'lha' => 1,
'lhh' => 1,
'lhi' => 1,
'lhl' => 1,
'lhm' => 1,
'lhn' => 1,
'lhp' => 1,
'lhs' => 1,
'lht' => 1,
'lhu' => 1,
'lia' => 1,
'lib' => 1,
'lic' => 1,
'lid' => 1,
'lie' => 1,
'lif' => 1,
'lig' => 1,
'lih' => 1,
'lii' => 1,
'lij' => 1,
'lik' => 1,
'lil' => 1,
'lio' => 1,
'lip' => 1,
'liq' => 1,
'lir' => 1,
'lis' => 1,
'liu' => 1,
'liv' => 1,
'lix' => 1,
'liy' => 1,
'liz' => 1,
'lje' => 1,
'lji' => 1,
'ljl' => 1,
'ljp' => 1,
'lka' => 1,
'lkc' => 1,
'lkd' => 1,
'lke' => 1,
'lkh' => 1,
'lki' => 1,
'lkj' => 1,
'lkl' => 1,
'lkn' => 1,
'lkr' => 1,
'lkt' => 1,
'lky' => 1,
'lla' => 1,
'llb' => 1,
'llc' => 1,
'lld' => 1,
'lle' => 1,
'llf' => 1,
'llg' => 1,
'llh' => 1,
'lli' => 1,
'llk' => 1,
'lll' => 1,
'llm' => 1,
'lln' => 1,
'llo' => 1,
'llp' => 1,
'llq' => 1,
'lls' => 1,
'llu' => 1,
'llx' => 1,
'lma' => 1,
'lmb' => 1,
'lmc' => 1,
'lmd' => 1,
'lme' => 1,
'lmf' => 1,
'lmg' => 1,
'lmh' => 1,
'lmi' => 1,
'lmj' => 1,
'lmk' => 1,
'lml' => 1,
'lmm' => 1,
'lmn' => 1,
'lmo' => 1,
'lmp' => 1,
'lmq' => 1,
'lmr' => 1,
'lmu' => 1,
'lmv' => 1,
'lmw' => 1,
'lmx' => 1,
'lmy' => 1,
'lmz' => 1,
'lna' => 1,
'lnb' => 1,
'lnd' => 1,
'lng' => 1,
'lnh' => 1,
'lni' => 1,
'lnj' => 1,
'lnl' => 1,
'lnm' => 1,
'lnn' => 1,
'lno' => 1,
'lns' => 1,
'lnu' => 1,
'lnz' => 1,
'loa' => 1,
'lob' => 1,
'loc' => 1,
'loe' => 1,
'lof' => 1,
'log' => 1,
'loh' => 1,
'loi' => 1,
'loj' => 1,
'lok' => 1,
'lol' => 1,
'lom' => 1,
'lon' => 1,
'loo' => 1,
'lop' => 1,
'loq' => 1,
'lor' => 1,
'los' => 1,
'lot' => 1,
'lou' => 1,
'lov' => 1,
'low' => 1,
'lox' => 1,
'loy' => 1,
'loz' => 1,
'lpa' => 1,
'lpe' => 1,
'lpn' => 1,
'lpo' => 1,
'lpx' => 1,
'lra' => 1,
'lrc' => 1,
'lre' => 1,
'lrg' => 1,
'lrk' => 1,
'lrl' => 1,
'lrn' => 1,
'lro' => 1,
'lrr' => 1,
'lrt' => 1,
'lrv' => 1,
'lrz' => 1,
'lsa' => 1,
'lsd' => 1,
'lse' => 1,
'lsg' => 1,
'lsh' => 1,
'lsi' => 1,
'lsl' => 1,
'lso' => 1,
'lsp' => 1,
'lsr' => 1,
'lss' => 1,
'lst' => 1,
'ltc' => 1,
'lti' => 1,
'ltn' => 1,
'ltu' => 1,
'lua' => 1,
'luc' => 1,
'lud' => 1,
'lue' => 1,
'luf' => 1,
'lui' => 1,
'luj' => 1,
'luk' => 1,
'lul' => 1,
'lum' => 1,
'lun' => 1,
'luo' => 1,
'lup' => 1,
'luq' => 1,
'lur' => 1,
'lus' => 1,
'lut' => 1,
'luu' => 1,
'luv' => 1,
'luw' => 1,
'luy' => 1,
'luz' => 1,
'lva' => 1,
'lvk' => 1,
'lvu' => 1,
'lwa' => 1,
'lwe' => 1,
'lwh' => 1,
'lwl' => 1,
'lwm' => 1,
'lwo' => 1,
'lwt' => 1,
'lww' => 1,
'lya' => 1,
'lyg' => 1,
'lyn' => 1,
'lzl' => 1,
'lzn' => 1,
'lzz' => 1,
'maa' => 1,
'mab' => 1,
'mad' => 1,
'mae' => 1,
'maf' => 1,
'mag' => 1,
'mai' => 1,
'maj' => 1,
'mak' => 1,
'mam' => 1,
'man' => 1,
'map' => 1,
'maq' => 1,
'mas' => 1,
'mat' => 1,
'mau' => 1,
'mav' => 1,
'maw' => 1,
'maz' => 1,
'mba' => 1,
'mbb' => 1,
'mbc' => 1,
'mbd' => 1,
'mbe' => 1,
'mbf' => 1,
'mbh' => 1,
'mbi' => 1,
'mbj' => 1,
'mbk' => 1,
'mbl' => 1,
'mbm' => 1,
'mbn' => 1,
'mbo' => 1,
'mbp' => 1,
'mbq' => 1,
'mbr' => 1,
'mbs' => 1,
'mbt' => 1,
'mbu' => 1,
'mbv' => 1,
'mbw' => 1,
'mbx' => 1,
'mby' => 1,
'mbz' => 1,
'mca' => 1,
'mcb' => 1,
'mcc' => 1,
'mcd' => 1,
'mce' => 1,
'mcf' => 1,
'mcg' => 1,
'mch' => 1,
'mci' => 1,
'mcj' => 1,
'mck' => 1,
'mcl' => 1,
'mcm' => 1,
'mcn' => 1,
'mco' => 1,
'mcp' => 1,
'mcq' => 1,
'mcr' => 1,
'mcs' => 1,
'mct' => 1,
'mcu' => 1,
'mcv' => 1,
'mcw' => 1,
'mcx' => 1,
'mcy' => 1,
'mcz' => 1,
'mda' => 1,
'mdb' => 1,
'mdc' => 1,
'mdd' => 1,
'mde' => 1,
'mdf' => 1,
'mdg' => 1,
'mdh' => 1,
'mdi' => 1,
'mdj' => 1,
'mdk' => 1,
'mdl' => 1,
'mdm' => 1,
'mdn' => 1,
'mdp' => 1,
'mdq' => 1,
'mdr' => 1,
'mds' => 1,
'mdt' => 1,
'mdu' => 1,
'mdv' => 1,
'mdw' => 1,
'mdx' => 1,
'mdy' => 1,
'mdz' => 1,
'mea' => 1,
'meb' => 1,
'mec' => 1,
'med' => 1,
'mee' => 1,
'mef' => 1,
'meg' => 1,
'meh' => 1,
'mei' => 1,
'mej' => 1,
'mek' => 1,
'mel' => 1,
'mem' => 1,
'men' => 1,
'mep' => 1,
'meq' => 1,
'mer' => 1,
'mes' => 1,
'met' => 1,
'meu' => 1,
'mev' => 1,
'mew' => 1,
'mey' => 1,
'mez' => 1,
'mfc' => 1,
'mfd' => 1,
'mfe' => 1,
'mff' => 1,
'mfg' => 1,
'mfh' => 1,
'mfi' => 1,
'mfj' => 1,
'mfk' => 1,
'mfl' => 1,
'mfm' => 1,
'mfn' => 1,
'mfo' => 1,
'mfp' => 1,
'mfq' => 1,
'mfr' => 1,
'mfs' => 1,
'mft' => 1,
'mfu' => 1,
'mfv' => 1,
'mfw' => 1,
'mfx' => 1,
'mfy' => 1,
'mfz' => 1,
'mga' => 1,
'mgb' => 1,
'mgc' => 1,
'mgd' => 1,
'mge' => 1,
'mgf' => 1,
'mgg' => 1,
'mgh' => 1,
'mgi' => 1,
'mgj' => 1,
'mgk' => 1,
'mgl' => 1,
'mgm' => 1,
'mgn' => 1,
'mgo' => 1,
'mgp' => 1,
'mgq' => 1,
'mgr' => 1,
'mgs' => 1,
'mgt' => 1,
'mgu' => 1,
'mgv' => 1,
'mgw' => 1,
'mgx' => 1,
'mgy' => 1,
'mgz' => 1,
'mha' => 1,
'mhb' => 1,
'mhc' => 1,
'mhd' => 1,
'mhe' => 1,
'mhf' => 1,
'mhg' => 1,
'mhh' => 1,
'mhi' => 1,
'mhj' => 1,
'mhk' => 1,
'mhl' => 1,
'mhm' => 1,
'mhn' => 1,
'mho' => 1,
'mhp' => 1,
'mhq' => 1,
'mhs' => 1,
'mht' => 1,
'mhu' => 1,
'mhw' => 1,
'mhx' => 1,
'mhy' => 1,
'mhz' => 1,
'mia' => 1,
'mib' => 1,
'mic' => 1,
'mid' => 1,
'mie' => 1,
'mif' => 1,
'mig' => 1,
'mih' => 1,
'mii' => 1,
'mij' => 1,
'mik' => 1,
'mil' => 1,
'mim' => 1,
'mio' => 1,
'mip' => 1,
'miq' => 1,
'mir' => 1,
'mit' => 1,
'miu' => 1,
'miw' => 1,
'mix' => 1,
'miy' => 1,
'miz' => 1,
'mja' => 1,
'mjc' => 1,
'mjd' => 1,
'mje' => 1,
'mjg' => 1,
'mjh' => 1,
'mji' => 1,
'mjj' => 1,
'mjk' => 1,
'mjl' => 1,
'mjm' => 1,
'mjn' => 1,
'mjo' => 1,
'mjp' => 1,
'mjq' => 1,
'mjr' => 1,
'mjs' => 1,
'mjt' => 1,
'mju' => 1,
'mjv' => 1,
'mjw' => 1,
'mjx' => 1,
'mjy' => 1,
'mjz' => 1,
'mka' => 1,
'mkb' => 1,
'mkc' => 1,
'mke' => 1,
'mkf' => 1,
'mkg' => 1,
'mkh' => 1,
'mki' => 1,
'mkj' => 1,
'mkk' => 1,
'mkl' => 1,
'mkm' => 1,
'mkn' => 1,
'mko' => 1,
'mkp' => 1,
'mkq' => 1,
'mkr' => 1,
'mks' => 1,
'mkt' => 1,
'mkv' => 1,
'mkw' => 1,
'mkx' => 1,
'mky' => 1,
'mkz' => 1,
'mla' => 1,
'mlb' => 1,
'mlc' => 1,
'mld' => 1,
'mle' => 1,
'mlf' => 1,
'mlh' => 1,
'mli' => 1,
'mlj' => 1,
'mlk' => 1,
'mll' => 1,
'mlm' => 1,
'mln' => 1,
'mlo' => 1,
'mlp' => 1,
'mlr' => 1,
'mls' => 1,
'mlu' => 1,
'mlv' => 1,
'mlw' => 1,
'mlx' => 1,
'mlz' => 1,
'mma' => 1,
'mmb' => 1,
'mmc' => 1,
'mmd' => 1,
'mme' => 1,
'mmf' => 1,
'mmg' => 1,
'mmh' => 1,
'mmi' => 1,
'mmj' => 1,
'mmk' => 1,
'mml' => 1,
'mmm' => 1,
'mmn' => 1,
'mmo' => 1,
'mmp' => 1,
'mmq' => 1,
'mmt' => 1,
'mmu' => 1,
'mmv' => 1,
'mmw' => 1,
'mmx' => 1,
'mmy' => 1,
'mmz' => 1,
'mna' => 1,
'mnb' => 1,
'mnc' => 1,
'mnd' => 1,
'mne' => 1,
'mnf' => 1,
'mng' => 1,
'mnh' => 1,
'mni' => 1,
'mnj' => 1,
'mnl' => 1,
'mnm' => 1,
'mnn' => 1,
'mno' => 1,
'mnq' => 1,
'mnr' => 1,
'mns' => 1,
'mnt' => 1,
'mnu' => 1,
'mnv' => 1,
'mnw' => 1,
'mnx' => 1,
'mny' => 1,
'mnz' => 1,
'moa' => 1,
'moc' => 1,
'mod' => 1,
'moe' => 1,
'mof' => 1,
'mog' => 1,
'moh' => 1,
'moi' => 1,
'moj' => 1,
'mok' => 1,
'mom' => 1,
'moo' => 1,
'mop' => 1,
'moq' => 1,
'mor' => 1,
'mos' => 1,
'mot' => 1,
'mou' => 1,
'mov' => 1,
'mow' => 1,
'mox' => 1,
'moy' => 1,
'moz' => 1,
'mpa' => 1,
'mpb' => 1,
'mpc' => 1,
'mpd' => 1,
'mpe' => 1,
'mpg' => 1,
'mph' => 1,
'mpi' => 1,
'mpj' => 1,
'mpk' => 1,
'mpl' => 1,
'mpm' => 1,
'mpn' => 1,
'mpo' => 1,
'mpp' => 1,
'mpq' => 1,
'mpr' => 1,
'mps' => 1,
'mpt' => 1,
'mpu' => 1,
'mpv' => 1,
'mpw' => 1,
'mpx' => 1,
'mpy' => 1,
'mpz' => 1,
'mqa' => 1,
'mqb' => 1,
'mqc' => 1,
'mqe' => 1,
'mqf' => 1,
'mqh' => 1,
'mqi' => 1,
'mqj' => 1,
'mqk' => 1,
'mql' => 1,
'mqm' => 1,
'mqn' => 1,
'mqo' => 1,
'mqp' => 1,
'mqq' => 1,
'mqr' => 1,
'mqs' => 1,
'mqt' => 1,
'mqu' => 1,
'mqv' => 1,
'mqw' => 1,
'mqx' => 1,
'mqy' => 1,
'mqz' => 1,
'mra' => 1,
'mrb' => 1,
'mrc' => 1,
'mrd' => 1,
'mre' => 1,
'mrf' => 1,
'mrg' => 1,
'mrh' => 1,
'mrk' => 1,
'mrl' => 1,
'mrm' => 1,
'mrn' => 1,
'mro' => 1,
'mrp' => 1,
'mrq' => 1,
'mrr' => 1,
'mrs' => 1,
'mrt' => 1,
'mru' => 1,
'mrv' => 1,
'mrw' => 1,
'mrx' => 1,
'mry' => 1,
'mrz' => 1,
'msb' => 1,
'msd' => 1,
'mse' => 1,
'msf' => 1,
'msg' => 1,
'msj' => 1,
'msk' => 1,
'msl' => 1,
'msm' => 1,
'msn' => 1,
'mso' => 1,
'msp' => 1,
'msq' => 1,
'msr' => 1,
'mss' => 1,
'mst' => 1,
'msu' => 1,
'msv' => 1,
'msw' => 1,
'msx' => 1,
'msy' => 1,
'msz' => 1,
'mta' => 1,
'mtb' => 1,
'mtc' => 1,
'mtd' => 1,
'mte' => 1,
'mtf' => 1,
'mtg' => 1,
'mth' => 1,
'mti' => 1,
'mtj' => 1,
'mtk' => 1,
'mtl' => 1,
'mtm' => 1,
'mtn' => 1,
'mto' => 1,
'mtp' => 1,
'mtq' => 1,
'mts' => 1,
'mtt' => 1,
'mtu' => 1,
'mtv' => 1,
'mtw' => 1,
'mtx' => 1,
'mty' => 1,
'mua' => 1,
'mub' => 1,
'muc' => 1,
'mud' => 1,
'mue' => 1,
'mug' => 1,
'muh' => 1,
'muj' => 1,
'muk' => 1,
'mum' => 1,
'mun' => 1,
'muo' => 1,
'mur' => 1,
'mus' => 1,
'mut' => 1,
'muu' => 1,
'muv' => 1,
'mux' => 1,
'muy' => 1,
'muz' => 1,
'mva' => 1,
'mvb' => 1,
'mvd' => 1,
'mvg' => 1,
'mvh' => 1,
'mvi' => 1,
'mvk' => 1,
'mvl' => 1,
'mvm' => 1,
'mvn' => 1,
'mvo' => 1,
'mvp' => 1,
'mvq' => 1,
'mvr' => 1,
'mvs' => 1,
'mvt' => 1,
'mvu' => 1,
'mvv' => 1,
'mvw' => 1,
'mvx' => 1,
'mvy' => 1,
'mvz' => 1,
'mwa' => 1,
'mwb' => 1,
'mwc' => 1,
'mwd' => 1,
'mwe' => 1,
'mwf' => 1,
'mwg' => 1,
'mwh' => 1,
'mwi' => 1,
'mwj' => 1,
'mwl' => 1,
'mwm' => 1,
'mwn' => 1,
'mwo' => 1,
'mwp' => 1,
'mwq' => 1,
'mwr' => 1,
'mws' => 1,
'mwt' => 1,
'mwu' => 1,
'mwv' => 1,
'mwx' => 1,
'mwy' => 1,
'mwz' => 1,
'mxa' => 1,
'mxb' => 1,
'mxc' => 1,
'mxd' => 1,
'mxe' => 1,
'mxf' => 1,
'mxg' => 1,
'mxh' => 1,
'mxi' => 1,
'mxj' => 1,
'mxk' => 1,
'mxl' => 1,
'mxm' => 1,
'mxn' => 1,
'mxo' => 1,
'mxp' => 1,
'mxq' => 1,
'mxr' => 1,
'mxs' => 1,
'mxt' => 1,
'mxu' => 1,
'mxv' => 1,
'mxw' => 1,
'mxx' => 1,
'mxy' => 1,
'mxz' => 1,
'myb' => 1,
'myc' => 1,
'myd' => 1,
'mye' => 1,
'myf' => 1,
'myg' => 1,
'myh' => 1,
'myi' => 1,
'myj' => 1,
'myk' => 1,
'myl' => 1,
'mym' => 1,
'myn' => 1,
'myo' => 1,
'myp' => 1,
'myr' => 1,
'mys' => 1,
'myt' => 1,
'myu' => 1,
'myv' => 1,
'myw' => 1,
'myx' => 1,
'myy' => 1,
'myz' => 1,
'mza' => 1,
'mzb' => 1,
'mzc' => 1,
'mzd' => 1,
'mze' => 1,
'mzg' => 1,
'mzh' => 1,
'mzi' => 1,
'mzj' => 1,
'mzk' => 1,
'mzl' => 1,
'mzm' => 1,
'mzn' => 1,
'mzo' => 1,
'mzp' => 1,
'mzq' => 1,
'mzr' => 1,
'mzs' => 1,
'mzt' => 1,
'mzu' => 1,
'mzv' => 1,
'mzw' => 1,
'mzx' => 1,
'mzy' => 1,
'mzz' => 1,
'naa' => 1,
'nab' => 1,
'nac' => 1,
'nad' => 1,
'nae' => 1,
'naf' => 1,
'nag' => 1,
'nah' => 1,
'nai' => 1,
'naj' => 1,
'nak' => 1,
'nal' => 1,
'nam' => 1,
'nao' => 1,
'nap' => 1,
'naq' => 1,
'nar' => 1,
'nas' => 1,
'nat' => 1,
'naw' => 1,
'nax' => 1,
'nay' => 1,
'naz' => 1,
'nba' => 1,
'nbb' => 1,
'nbc' => 1,
'nbd' => 1,
'nbe' => 1,
'nbf' => 1,
'nbg' => 1,
'nbh' => 1,
'nbi' => 1,
'nbj' => 1,
'nbk' => 1,
'nbm' => 1,
'nbn' => 1,
'nbo' => 1,
'nbp' => 1,
'nbq' => 1,
'nbr' => 1,
'nbs' => 1,
'nbt' => 1,
'nbu' => 1,
'nbv' => 1,
'nbw' => 1,
'nbx' => 1,
'nby' => 1,
'nca' => 1,
'ncb' => 1,
'ncc' => 1,
'ncd' => 1,
'nce' => 1,
'ncf' => 1,
'ncg' => 1,
'nch' => 1,
'nci' => 1,
'ncj' => 1,
'nck' => 1,
'ncl' => 1,
'ncm' => 1,
'ncn' => 1,
'nco' => 1,
'ncp' => 1,
'ncr' => 1,
'ncs' => 1,
'nct' => 1,
'ncu' => 1,
'ncx' => 1,
'ncz' => 1,
'nda' => 1,
'ndb' => 1,
'ndc' => 1,
'ndd' => 1,
'ndf' => 1,
'ndg' => 1,
'ndh' => 1,
'ndi' => 1,
'ndj' => 1,
'ndk' => 1,
'ndl' => 1,
'ndm' => 1,
'ndn' => 1,
'ndp' => 1,
'ndq' => 1,
'ndr' => 1,
'nds' => 1,
'ndt' => 1,
'ndu' => 1,
'ndv' => 1,
'ndw' => 1,
'ndx' => 1,
'ndy' => 1,
'ndz' => 1,
'nea' => 1,
'neb' => 1,
'nec' => 1,
'ned' => 1,
'nee' => 1,
'nef' => 1,
'neg' => 1,
'neh' => 1,
'nei' => 1,
'nej' => 1,
'nek' => 1,
'nem' => 1,
'nen' => 1,
'neo' => 1,
'neq' => 1,
'ner' => 1,
'nes' => 1,
'net' => 1,
'nev' => 1,
'new' => 1,
'nex' => 1,
'ney' => 1,
'nez' => 1,
'nfa' => 1,
'nfd' => 1,
'nfl' => 1,
'nfr' => 1,
'nfu' => 1,
'nga' => 1,
'ngb' => 1,
'ngc' => 1,
'ngd' => 1,
'nge' => 1,
'ngf' => 1,
'ngg' => 1,
'ngh' => 1,
'ngi' => 1,
'ngj' => 1,
'ngk' => 1,
'ngl' => 1,
'ngm' => 1,
'ngn' => 1,
'ngo' => 1,
'ngp' => 1,
'ngq' => 1,
'ngr' => 1,
'ngs' => 1,
'ngt' => 1,
'ngu' => 1,
'ngv' => 1,
'ngw' => 1,
'ngx' => 1,
'ngy' => 1,
'ngz' => 1,
'nha' => 1,
'nhb' => 1,
'nhc' => 1,
'nhe' => 1,
'nhf' => 1,
'nhg' => 1,
'nhh' => 1,
'nhi' => 1,
'nhk' => 1,
'nhm' => 1,
'nhn' => 1,
'nho' => 1,
'nhp' => 1,
'nhq' => 1,
'nhr' => 1,
'nht' => 1,
'nhu' => 1,
'nhv' => 1,
'nhw' => 1,
'nhx' => 1,
'nhy' => 1,
'nhz' => 1,
'nia' => 1,
'nib' => 1,
'nic' => 1,
'nid' => 1,
'nie' => 1,
'nif' => 1,
'nig' => 1,
'nih' => 1,
'nii' => 1,
'nij' => 1,
'nik' => 1,
'nil' => 1,
'nim' => 1,
'nin' => 1,
'nio' => 1,
'nir' => 1,
'nis' => 1,
'nit' => 1,
'niu' => 1,
'niv' => 1,
'niw' => 1,
'nix' => 1,
'niy' => 1,
'niz' => 1,
'nja' => 1,
'njb' => 1,
'njd' => 1,
'njh' => 1,
'nji' => 1,
'njj' => 1,
'njl' => 1,
'njm' => 1,
'njn' => 1,
'njo' => 1,
'njr' => 1,
'njs' => 1,
'njt' => 1,
'nju' => 1,
'njx' => 1,
'njy' => 1,
'nka' => 1,
'nkb' => 1,
'nkc' => 1,
'nkd' => 1,
'nke' => 1,
'nkf' => 1,
'nkg' => 1,
'nkh' => 1,
'nki' => 1,
'nkj' => 1,
'nkk' => 1,
'nkm' => 1,
'nkn' => 1,
'nko' => 1,
'nkp' => 1,
'nkr' => 1,
'nks' => 1,
'nkt' => 1,
'nku' => 1,
'nkv' => 1,
'nkw' => 1,
'nkx' => 1,
'nkz' => 1,
'nla' => 1,
'nlc' => 1,
'nlg' => 1,
'nli' => 1,
'nlj' => 1,
'nlk' => 1,
'nll' => 1,
'nln' => 1,
'nlo' => 1,
'nlr' => 1,
'nlu' => 1,
'nlv' => 1,
'nlx' => 1,
'nly' => 1,
'nlz' => 1,
'nma' => 1,
'nmb' => 1,
'nmc' => 1,
'nmd' => 1,
'nme' => 1,
'nmf' => 1,
'nmg' => 1,
'nmh' => 1,
'nmi' => 1,
'nmj' => 1,
'nmk' => 1,
'nml' => 1,
'nmm' => 1,
'nmn' => 1,
'nmo' => 1,
'nmp' => 1,
'nmq' => 1,
'nmr' => 1,
'nms' => 1,
'nmt' => 1,
'nmu' => 1,
'nmv' => 1,
'nmw' => 1,
'nmx' => 1,
'nmy' => 1,
'nmz' => 1,
'nna' => 1,
'nnb' => 1,
'nnc' => 1,
'nnd' => 1,
'nne' => 1,
'nnf' => 1,
'nng' => 1,
'nnh' => 1,
'nni' => 1,
'nnj' => 1,
'nnk' => 1,
'nnl' => 1,
'nnm' => 1,
'nnn' => 1,
'nnp' => 1,
'nnq' => 1,
'nnr' => 1,
'nns' => 1,
'nnt' => 1,
'nnu' => 1,
'nnv' => 1,
'nnw' => 1,
'nnx' => 1,
'nny' => 1,
'nnz' => 1,
'noa' => 1,
'noc' => 1,
'nod' => 1,
'noe' => 1,
'nof' => 1,
'nog' => 1,
'noh' => 1,
'noi' => 1,
'nok' => 1,
'nom' => 1,
'non' => 1,
'noo' => 1,
'nop' => 1,
'noq' => 1,
'nos' => 1,
'not' => 1,
'nou' => 1,
'nov' => 1,
'now' => 1,
'noy' => 1,
'noz' => 1,
'npa' => 1,
'npb' => 1,
'nph' => 1,
'npl' => 1,
'npn' => 1,
'npo' => 1,
'nps' => 1,
'npu' => 1,
'npy' => 1,
'nqg' => 1,
'nqk' => 1,
'nqm' => 1,
'nqn' => 1,
'nqo' => 1,
'nra' => 1,
'nrb' => 1,
'nrc' => 1,
'nre' => 1,
'nrg' => 1,
'nri' => 1,
'nrl' => 1,
'nrm' => 1,
'nrn' => 1,
'nrp' => 1,
'nrr' => 1,
'nrt' => 1,
'nrx' => 1,
'nrz' => 1,
'nsa' => 1,
'nsc' => 1,
'nsd' => 1,
'nse' => 1,
'nsg' => 1,
'nsh' => 1,
'nsi' => 1,
'nsk' => 1,
'nsl' => 1,
'nsm' => 1,
'nsn' => 1,
'nso' => 1,
'nsp' => 1,
'nsq' => 1,
'nsr' => 1,
'nss' => 1,
'nst' => 1,
'nsu' => 1,
'nsv' => 1,
'nsw' => 1,
'nsx' => 1,
'nsy' => 1,
'nsz' => 1,
'nte' => 1,
'nti' => 1,
'ntj' => 1,
'ntk' => 1,
'ntm' => 1,
'nto' => 1,
'ntp' => 1,
'ntr' => 1,
'nts' => 1,
'ntu' => 1,
'ntw' => 1,
'nty' => 1,
'ntz' => 1,
'nua' => 1,
'nub' => 1,
'nuc' => 1,
'nud' => 1,
'nue' => 1,
'nuf' => 1,
'nug' => 1,
'nuh' => 1,
'nui' => 1,
'nuj' => 1,
'nul' => 1,
'num' => 1,
'nun' => 1,
'nuo' => 1,
'nup' => 1,
'nuq' => 1,
'nur' => 1,
'nus' => 1,
'nut' => 1,
'nuu' => 1,
'nuv' => 1,
'nuw' => 1,
'nux' => 1,
'nuy' => 1,
'nuz' => 1,
'nvh' => 1,
'nvm' => 1,
'nwa' => 1,
'nwb' => 1,
'nwc' => 1,
'nwe' => 1,
'nwi' => 1,
'nwm' => 1,
'nwr' => 1,
'nwx' => 1,
'nwy' => 1,
'nxa' => 1,
'nxd' => 1,
'nxe' => 1,
'nxg' => 1,
'nxi' => 1,
'nxl' => 1,
'nxm' => 1,
'nxn' => 1,
'nxr' => 1,
'nxu' => 1,
'nxx' => 1,
'nyb' => 1,
'nyc' => 1,
'nye' => 1,
'nyf' => 1,
'nyg' => 1,
'nyh' => 1,
'nyi' => 1,
'nyj' => 1,
'nyk' => 1,
'nyl' => 1,
'nym' => 1,
'nyn' => 1,
'nyo' => 1,
'nyp' => 1,
'nyq' => 1,
'nyr' => 1,
'nys' => 1,
'nyt' => 1,
'nyu' => 1,
'nyv' => 1,
'nyw' => 1,
'nyx' => 1,
'nyy' => 1,
'nza' => 1,
'nzb' => 1,
'nzi' => 1,
'nzk' => 1,
'nzm' => 1,
'nzs' => 1,
'nzu' => 1,
'nzy' => 1,
'oaa' => 1,
'oac' => 1,
'oar' => 1,
'oav' => 1,
'obi' => 1,
'obl' => 1,
'obm' => 1,
'obo' => 1,
'obr' => 1,
'obt' => 1,
'obu' => 1,
'oca' => 1,
'och' => 1,
'oco' => 1,
'ocu' => 1,
'oda' => 1,
'odk' => 1,
'odt' => 1,
'odu' => 1,
'ofo' => 1,
'ofs' => 1,
'ofu' => 1,
'ogb' => 1,
'ogc' => 1,
'oge' => 1,
'ogg' => 1,
'ogo' => 1,
'ogu' => 1,
'oht' => 1,
'ohu' => 1,
'oia' => 1,
'oin' => 1,
'ojp' => 1,
'ojv' => 1,
'oka' => 1,
'okb' => 1,
'okd' => 1,
'oke' => 1,
'okh' => 1,
'okj' => 1,
'okk' => 1,
'okl' => 1,
'okm' => 1,
'okn' => 1,
'oko' => 1,
'okr' => 1,
'oks' => 1,
'oku' => 1,
'okv' => 1,
'okx' => 1,
'ola' => 1,
'old' => 1,
'ole' => 1,
'olm' => 1,
'olo' => 1,
'olr' => 1,
'oma' => 1,
'omb' => 1,
'omc' => 1,
'ome' => 1,
'omg' => 1,
'omi' => 1,
'omk' => 1,
'oml' => 1,
'omn' => 1,
'omo' => 1,
'omp' => 1,
'omq' => 1,
'omr' => 1,
'omt' => 1,
'omu' => 1,
'omv' => 1,
'omw' => 1,
'omx' => 1,
'ona' => 1,
'onb' => 1,
'one' => 1,
'ong' => 1,
'oni' => 1,
'onj' => 1,
'onk' => 1,
'onn' => 1,
'ono' => 1,
'onp' => 1,
'onr' => 1,
'ons' => 1,
'ont' => 1,
'onu' => 1,
'onw' => 1,
'onx' => 1,
'ood' => 1,
'oog' => 1,
'oon' => 1,
'oor' => 1,
'oos' => 1,
'opa' => 1,
'opk' => 1,
'opm' => 1,
'opo' => 1,
'opt' => 1,
'opy' => 1,
'ora' => 1,
'ore' => 1,
'org' => 1,
'orh' => 1,
'oro' => 1,
'orr' => 1,
'ort' => 1,
'oru' => 1,
'orv' => 1,
'orw' => 1,
'orx' => 1,
'orz' => 1,
'osa' => 1,
'osc' => 1,
'osi' => 1,
'oso' => 1,
'osp' => 1,
'ost' => 1,
'osu' => 1,
'osx' => 1,
'ota' => 1,
'otb' => 1,
'otd' => 1,
'ote' => 1,
'oti' => 1,
'otk' => 1,
'otl' => 1,
'otm' => 1,
'otn' => 1,
'oto' => 1,
'otq' => 1,
'otr' => 1,
'ots' => 1,
'ott' => 1,
'otu' => 1,
'otx' => 1,
'oty' => 1,
'otz' => 1,
'oua' => 1,
'oub' => 1,
'oue' => 1,
'oui' => 1,
'oum' => 1,
'oun' => 1,
'owi' => 1,
'owl' => 1,
'oyb' => 1,
'oyd' => 1,
'oym' => 1,
'oyy' => 1,
'ozm' => 1,
'paa' => 1,
'pab' => 1,
'pac' => 1,
'pad' => 1,
'pae' => 1,
'paf' => 1,
'pag' => 1,
'pah' => 1,
'pai' => 1,
'pak' => 1,
'pal' => 1,
'pam' => 1,
'pao' => 1,
'pap' => 1,
'paq' => 1,
'par' => 1,
'pas' => 1,
'pat' => 1,
'pau' => 1,
'pav' => 1,
'paw' => 1,
'pax' => 1,
'pay' => 1,
'paz' => 1,
'pbb' => 1,
'pbc' => 1,
'pbe' => 1,
'pbf' => 1,
'pbg' => 1,
'pbh' => 1,
'pbi' => 1,
'pbl' => 1,
'pbn' => 1,
'pbo' => 1,
'pbp' => 1,
'pbr' => 1,
'pbs' => 1,
'pbv' => 1,
'pby' => 1,
'pbz' => 1,
'pca' => 1,
'pcb' => 1,
'pcc' => 1,
'pcd' => 1,
'pce' => 1,
'pcf' => 1,
'pcg' => 1,
'pch' => 1,
'pci' => 1,
'pcj' => 1,
'pck' => 1,
'pcl' => 1,
'pcm' => 1,
'pcn' => 1,
'pcp' => 1,
'pcr' => 1,
'pcw' => 1,
'pda' => 1,
'pdc' => 1,
'pdi' => 1,
'pdn' => 1,
'pdo' => 1,
'pdt' => 1,
'pdu' => 1,
'pea' => 1,
'peb' => 1,
'ped' => 1,
'pee' => 1,
'pef' => 1,
'peg' => 1,
'peh' => 1,
'pei' => 1,
'pej' => 1,
'pek' => 1,
'pem' => 1,
'peo' => 1,
'pep' => 1,
'peq' => 1,
'pev' => 1,
'pex' => 1,
'pey' => 1,
'pez' => 1,
'pfa' => 1,
'pfe' => 1,
'pfl' => 1,
'pgg' => 1,
'pgi' => 1,
'pgk' => 1,
'pgn' => 1,
'pgs' => 1,
'pgu' => 1,
'pgy' => 1,
'pha' => 1,
'phd' => 1,
'phg' => 1,
'phh' => 1,
'phi' => 1,
'phk' => 1,
'phl' => 1,
'phm' => 1,
'phn' => 1,
'pho' => 1,
'phq' => 1,
'pht' => 1,
'phu' => 1,
'phv' => 1,
'phw' => 1,
'pia' => 1,
'pib' => 1,
'pic' => 1,
'pid' => 1,
'pie' => 1,
'pif' => 1,
'pig' => 1,
'pih' => 1,
'pii' => 1,
'pij' => 1,
'pil' => 1,
'pim' => 1,
'pin' => 1,
'pio' => 1,
'pip' => 1,
'pir' => 1,
'pis' => 1,
'pit' => 1,
'piu' => 1,
'piv' => 1,
'piw' => 1,
'pix' => 1,
'piy' => 1,
'piz' => 1,
'pjt' => 1,
'pka' => 1,
'pkb' => 1,
'pkc' => 1,
'pkg' => 1,
'pkh' => 1,
'pkn' => 1,
'pkp' => 1,
'pkr' => 1,
'pks' => 1,
'pkt' => 1,
'pku' => 1,
'pla' => 1,
'plb' => 1,
'plc' => 1,
'pld' => 1,
'ple' => 1,
'plf' => 1,
'plg' => 1,
'plh' => 1,
'plj' => 1,
'plk' => 1,
'pll' => 1,
'pln' => 1,
'plo' => 1,
'plp' => 1,
'plq' => 1,
'plr' => 1,
'pls' => 1,
'plu' => 1,
'plv' => 1,
'plw' => 1,
'ply' => 1,
'plz' => 1,
'pma' => 1,
'pmb' => 1,
'pmc' => 1,
'pme' => 1,
'pmf' => 1,
'pmh' => 1,
'pmi' => 1,
'pmj' => 1,
'pmk' => 1,
'pml' => 1,
'pmm' => 1,
'pmn' => 1,
'pmo' => 1,
'pmq' => 1,
'pmr' => 1,
'pms' => 1,
'pmt' => 1,
'pmw' => 1,
'pmx' => 1,
'pmy' => 1,
'pmz' => 1,
'pna' => 1,
'pnc' => 1,
'pne' => 1,
'png' => 1,
'pnh' => 1,
'pni' => 1,
'pnm' => 1,
'pnn' => 1,
'pno' => 1,
'pnp' => 1,
'pnq' => 1,
'pnr' => 1,
'pns' => 1,
'pnt' => 1,
'pnu' => 1,
'pnv' => 1,
'pnw' => 1,
'pnx' => 1,
'pny' => 1,
'pnz' => 1,
'poc' => 1,
'pod' => 1,
'poe' => 1,
'pof' => 1,
'pog' => 1,
'poh' => 1,
'poi' => 1,
'pok' => 1,
'pom' => 1,
'pon' => 1,
'poo' => 1,
'pop' => 1,
'poq' => 1,
'pos' => 1,
'pot' => 1,
'pov' => 1,
'pow' => 1,
'pox' => 1,
'poy' => 1,
'poz' => 1,
'ppa' => 1,
'ppe' => 1,
'ppi' => 1,
'ppk' => 1,
'ppl' => 1,
'ppm' => 1,
'ppn' => 1,
'ppo' => 1,
'ppp' => 1,
'ppq' => 1,
'ppr' => 1,
'pps' => 1,
'ppt' => 1,
'ppu' => 1,
'pqa' => 1,
'pqe' => 1,
'pqm' => 1,
'pqw' => 1,
'pra' => 1,
'prb' => 1,
'prc' => 1,
'prd' => 1,
'pre' => 1,
'prg' => 1,
'prh' => 1,
'pri' => 1,
'prk' => 1,
'prl' => 1,
'prm' => 1,
'prn' => 1,
'pro' => 1,
'prp' => 1,
'prq' => 1,
'prr' => 1,
'prt' => 1,
'pru' => 1,
'prw' => 1,
'prx' => 1,
'pry' => 1,
'prz' => 1,
'psa' => 1,
'psc' => 1,
'psd' => 1,
'psg' => 1,
'psh' => 1,
'psi' => 1,
'psl' => 1,
'psm' => 1,
'psn' => 1,
'pso' => 1,
'psp' => 1,
'psq' => 1,
'psr' => 1,
'pss' => 1,
'psu' => 1,
'psw' => 1,
'psy' => 1,
'pta' => 1,
'pth' => 1,
'pti' => 1,
'ptn' => 1,
'pto' => 1,
'ptp' => 1,
'ptr' => 1,
'ptt' => 1,
'ptu' => 1,
'ptv' => 1,
'ptw' => 1,
'pty' => 1,
'pua' => 1,
'pub' => 1,
'puc' => 1,
'pud' => 1,
'pue' => 1,
'puf' => 1,
'pug' => 1,
'pui' => 1,
'puj' => 1,
'puk' => 1,
'pum' => 1,
'puo' => 1,
'pup' => 1,
'puq' => 1,
'pur' => 1,
'put' => 1,
'puu' => 1,
'puw' => 1,
'pux' => 1,
'puy' => 1,
'puz' => 1,
'pwa' => 1,
'pwb' => 1,
'pwg' => 1,
'pwm' => 1,
'pwn' => 1,
'pwo' => 1,
'pwr' => 1,
'pww' => 1,
'pxm' => 1,
'pye' => 1,
'pym' => 1,
'pyn' => 1,
'pyu' => 1,
'pyx' => 1,
'pyy' => 1,
'pzn' => 1,
'qua' => 1,
'quc' => 1,
'qui' => 1,
'qum' => 1,
'qun' => 1,
'quq' => 1,
'quv' => 1,
'qvy' => 1,
'qwe' => 1,
'qwm' => 1,
'qwt' => 1,
'qxq' => 1,
'qxs' => 1,
'qya' => 1,
'qyp' => 1,
'raa' => 1,
'rab' => 1,
'rac' => 1,
'rad' => 1,
'raf' => 1,
'rah' => 1,
'rai' => 1,
'raj' => 1,
'rak' => 1,
'ral' => 1,
'ram' => 1,
'ran' => 1,
'rao' => 1,
'rap' => 1,
'raq' => 1,
'rar' => 1,
'ras' => 1,
'rat' => 1,
'rau' => 1,
'rav' => 1,
'raw' => 1,
'rax' => 1,
'ray' => 1,
'raz' => 1,
'rbb' => 1,
'rcf' => 1,
'rdb' => 1,
'rea' => 1,
'reb' => 1,
'ree' => 1,
'reg' => 1,
'rei' => 1,
'rej' => 1,
'rel' => 1,
'rem' => 1,
'ren' => 1,
'rer' => 1,
'res' => 1,
'ret' => 1,
'rey' => 1,
'rga' => 1,
'rge' => 1,
'rgk' => 1,
'rgn' => 1,
'rgr' => 1,
'rgs' => 1,
'rgu' => 1,
'rhg' => 1,
'rhp' => 1,
'ria' => 1,
'rie' => 1,
'rif' => 1,
'ril' => 1,
'rim' => 1,
'rin' => 1,
'rir' => 1,
'rit' => 1,
'riu' => 1,
'rjg' => 1,
'rji' => 1,
'rjs' => 1,
'rka' => 1,
'rkb' => 1,
'rkh' => 1,
'rki' => 1,
'rkm' => 1,
'rkt' => 1,
'rma' => 1,
'rmb' => 1,
'rmd' => 1,
'rme' => 1,
'rmg' => 1,
'rmh' => 1,
'rmi' => 1,
'rmk' => 1,
'rmm' => 1,
'rmp' => 1,
'rmr' => 1,
'rms' => 1,
'rmt' => 1,
'rmu' => 1,
'rmv' => 1,
'rmx' => 1,
'rmz' => 1,
'rna' => 1,
'rnd' => 1,
'rng' => 1,
'rnl' => 1,
'rnn' => 1,
'rnp' => 1,
'rnw' => 1,
'roa' => 1,
'rob' => 1,
'roc' => 1,
'rod' => 1,
'roe' => 1,
'rof' => 1,
'rog' => 1,
'rol' => 1,
'rom' => 1,
'roo' => 1,
'rop' => 1,
'ror' => 1,
'rou' => 1,
'row' => 1,
'rpn' => 1,
'rpt' => 1,
'rri' => 1,
'rro' => 1,
'rsb' => 1,
'rsi' => 1,
'rsl' => 1,
'rth' => 1,
'rtm' => 1,
'rtw' => 1,
'rub' => 1,
'ruc' => 1,
'rue' => 1,
'ruf' => 1,
'rug' => 1,
'ruh' => 1,
'rui' => 1,
'ruk' => 1,
'ruo' => 1,
'rup' => 1,
'ruq' => 1,
'rut' => 1,
'ruu' => 1,
'ruy' => 1,
'ruz' => 1,
'rwa' => 1,
'rwk' => 1,
'rwm' => 1,
'rwo' => 1,
'ryn' => 1,
'rys' => 1,
'ryu' => 1,
'saa' => 1,
'sab' => 1,
'sac' => 1,
'sad' => 1,
'sae' => 1,
'saf' => 1,
'sah' => 1,
'sai' => 1,
'saj' => 1,
'sak' => 1,
'sal' => 1,
'sam' => 1,
'sao' => 1,
'sap' => 1,
'saq' => 1,
'sar' => 1,
'sas' => 1,
'sat' => 1,
'sau' => 1,
'sav' => 1,
'saw' => 1,
'sax' => 1,
'say' => 1,
'saz' => 1,
'sba' => 1,
'sbb' => 1,
'sbc' => 1,
'sbd' => 1,
'sbe' => 1,
'sbf' => 1,
'sbg' => 1,
'sbh' => 1,
'sbi' => 1,
'sbj' => 1,
'sbk' => 1,
'sbl' => 1,
'sbm' => 1,
'sbn' => 1,
'sbo' => 1,
'sbp' => 1,
'sbq' => 1,
'sbr' => 1,
'sbs' => 1,
'sbt' => 1,
'sbu' => 1,
'sbv' => 1,
'sbw' => 1,
'sbx' => 1,
'sby' => 1,
'sbz' => 1,
'sca' => 1,
'scb' => 1,
'sce' => 1,
'scf' => 1,
'scg' => 1,
'sch' => 1,
'sci' => 1,
'sck' => 1,
'scl' => 1,
'scn' => 1,
'sco' => 1,
'scp' => 1,
'scq' => 1,
'scu' => 1,
'scv' => 1,
'scw' => 1,
'scx' => 1,
'sda' => 1,
'sdb' => 1,
'sde' => 1,
'sdf' => 1,
'sdg' => 1,
'sdj' => 1,
'sdk' => 1,
'sdl' => 1,
'sdm' => 1,
'sdo' => 1,
'sdp' => 1,
'sdr' => 1,
'sds' => 1,
'sdt' => 1,
'sdu' => 1,
'sdv' => 1,
'sdx' => 1,
'sdz' => 1,
'sea' => 1,
'seb' => 1,
'sec' => 1,
'sed' => 1,
'see' => 1,
'sef' => 1,
'seg' => 1,
'seh' => 1,
'sei' => 1,
'sej' => 1,
'sek' => 1,
'sel' => 1,
'sem' => 1,
'sen' => 1,
'seo' => 1,
'sep' => 1,
'seq' => 1,
'ser' => 1,
'ses' => 1,
'set' => 1,
'seu' => 1,
'sev' => 1,
'sew' => 1,
'sey' => 1,
'sez' => 1,
'sfb' => 1,
'sfs' => 1,
'sfw' => 1,
'sga' => 1,
'sgb' => 1,
'sge' => 1,
'sgg' => 1,
'sgh' => 1,
'sgi' => 1,
'sgk' => 1,
'sgl' => 1,
'sgm' => 1,
'sgn' => 1,
'sgo' => 1,
'sgp' => 1,
'sgr' => 1,
'sgt' => 1,
'sgu' => 1,
'sgw' => 1,
'sgx' => 1,
'sgz' => 1,
'sha' => 1,
'shb' => 1,
'shc' => 1,
'she' => 1,
'shg' => 1,
'shh' => 1,
'shi' => 1,
'shj' => 1,
'shk' => 1,
'shl' => 1,
'shm' => 1,
'shn' => 1,
'sho' => 1,
'shp' => 1,
'shq' => 1,
'shr' => 1,
'shs' => 1,
'sht' => 1,
'shv' => 1,
'shw' => 1,
'shx' => 1,
'shy' => 1,
'shz' => 1,
'sia' => 1,
'sib' => 1,
'sid' => 1,
'sie' => 1,
'sif' => 1,
'sig' => 1,
'sih' => 1,
'sii' => 1,
'sij' => 1,
'sik' => 1,
'sil' => 1,
'sim' => 1,
'sio' => 1,
'sip' => 1,
'siq' => 1,
'sir' => 1,
'sis' => 1,
'sit' => 1,
'siu' => 1,
'siv' => 1,
'siw' => 1,
'six' => 1,
'siy' => 1,
'siz' => 1,
'sja' => 1,
'sjb' => 1,
'sjd' => 1,
'sje' => 1,
'sjg' => 1,
'sjk' => 1,
'sjl' => 1,
'sjm' => 1,
'sjn' => 1,
'sjo' => 1,
'sjp' => 1,
'sjr' => 1,
'sjs' => 1,
'sjt' => 1,
'sju' => 1,
'sjw' => 1,
'ska' => 1,
'skb' => 1,
'skc' => 1,
'skd' => 1,
'ske' => 1,
'skf' => 1,
'skh' => 1,
'ski' => 1,
'skj' => 1,
'skk' => 1,
'skm' => 1,
'skn' => 1,
'sko' => 1,
'skp' => 1,
'skq' => 1,
'sks' => 1,
'skt' => 1,
'sku' => 1,
'skv' => 1,
'skw' => 1,
'skx' => 1,
'sky' => 1,
'skz' => 1,
'sla' => 1,
'slc' => 1,
'sld' => 1,
'sle' => 1,
'slf' => 1,
'slg' => 1,
'slh' => 1,
'sli' => 1,
'slj' => 1,
'sll' => 1,
'slm' => 1,
'sln' => 1,
'slp' => 1,
'slq' => 1,
'slr' => 1,
'sls' => 1,
'slt' => 1,
'slu' => 1,
'slw' => 1,
'slx' => 1,
'sly' => 1,
'slz' => 1,
'sma' => 1,
'smb' => 1,
'smc' => 1,
'smd' => 1,
'smf' => 1,
'smg' => 1,
'smh' => 1,
'smi' => 1,
'smj' => 1,
'smk' => 1,
'sml' => 1,
'smm' => 1,
'smn' => 1,
'smp' => 1,
'smq' => 1,
'smr' => 1,
'sms' => 1,
'smt' => 1,
'smu' => 1,
'smv' => 1,
'smw' => 1,
'smx' => 1,
'smy' => 1,
'smz' => 1,
'snb' => 1,
'snc' => 1,
'sne' => 1,
'snf' => 1,
'sng' => 1,
'snh' => 1,
'sni' => 1,
'snj' => 1,
'snk' => 1,
'snl' => 1,
'snm' => 1,
'snn' => 1,
'sno' => 1,
'snp' => 1,
'snq' => 1,
'snr' => 1,
'sns' => 1,
'snu' => 1,
'snv' => 1,
'snw' => 1,
'snx' => 1,
'sny' => 1,
'snz' => 1,
'soa' => 1,
'sob' => 1,
'soc' => 1,
'sod' => 1,
'soe' => 1,
'sog' => 1,
'soh' => 1,
'soi' => 1,
'soj' => 1,
'sok' => 1,
'sol' => 1,
'son' => 1,
'soo' => 1,
'sop' => 1,
'soq' => 1,
'sor' => 1,
'sos' => 1,
'sou' => 1,
'sov' => 1,
'sow' => 1,
'sox' => 1,
'soy' => 1,
'soz' => 1,
'spb' => 1,
'spc' => 1,
'spd' => 1,
'spe' => 1,
'spg' => 1,
'spi' => 1,
'spk' => 1,
'spl' => 1,
'spm' => 1,
'spo' => 1,
'spp' => 1,
'spq' => 1,
'spr' => 1,
'sps' => 1,
'spt' => 1,
'spu' => 1,
'spx' => 1,
'sqa' => 1,
'sqh' => 1,
'sqj' => 1,
'sqm' => 1,
'sqn' => 1,
'sqo' => 1,
'sqq' => 1,
'sqr' => 1,
'sqs' => 1,
'sqt' => 1,
'squ' => 1,
'sra' => 1,
'srb' => 1,
'sre' => 1,
'srf' => 1,
'srg' => 1,
'srh' => 1,
'sri' => 1,
'srk' => 1,
'srl' => 1,
'srm' => 1,
'srn' => 1,
'srq' => 1,
'srr' => 1,
'srs' => 1,
'srt' => 1,
'sru' => 1,
'srv' => 1,
'srw' => 1,
'srx' => 1,
'sry' => 1,
'srz' => 1,
'ssa' => 1,
'ssb' => 1,
'ssc' => 1,
'ssd' => 1,
'sse' => 1,
'ssf' => 1,
'ssg' => 1,
'ssi' => 1,
'ssj' => 1,
'ssk' => 1,
'ssl' => 1,
'ssm' => 1,
'ssn' => 1,
'sso' => 1,
'ssp' => 1,
'ssq' => 1,
'ssr' => 1,
'sss' => 1,
'sst' => 1,
'ssu' => 1,
'ssv' => 1,
'ssx' => 1,
'ssy' => 1,
'ssz' => 1,
'sta' => 1,
'stb' => 1,
'std' => 1,
'ste' => 1,
'stf' => 1,
'stg' => 1,
'sth' => 1,
'sti' => 1,
'stj' => 1,
'stk' => 1,
'stl' => 1,
'stm' => 1,
'stn' => 1,
'sto' => 1,
'stp' => 1,
'stq' => 1,
'str' => 1,
'sts' => 1,
'stt' => 1,
'stu' => 1,
'stv' => 1,
'stw' => 1,
'sua' => 1,
'sub' => 1,
'suc' => 1,
'sue' => 1,
'sug' => 1,
'sui' => 1,
'suj' => 1,
'suk' => 1,
'sul' => 1,
'sum' => 1,
'suq' => 1,
'sur' => 1,
'sus' => 1,
'sut' => 1,
'suv' => 1,
'suw' => 1,
'sux' => 1,
'suy' => 1,
'suz' => 1,
'sva' => 1,
'svb' => 1,
'svc' => 1,
'sve' => 1,
'svk' => 1,
'svr' => 1,
'svs' => 1,
'svx' => 1,
'swb' => 1,
'swf' => 1,
'swg' => 1,
'swi' => 1,
'swj' => 1,
'swk' => 1,
'swl' => 1,
'swm' => 1,
'swn' => 1,
'swo' => 1,
'swp' => 1,
'swq' => 1,
'swr' => 1,
'sws' => 1,
'swt' => 1,
'swu' => 1,
'sww' => 1,
'swx' => 1,
'swy' => 1,
'sxb' => 1,
'sxc' => 1,
'sxe' => 1,
'sxg' => 1,
'sxk' => 1,
'sxl' => 1,
'sxm' => 1,
'sxn' => 1,
'sxo' => 1,
'sxr' => 1,
'sxs' => 1,
'sxu' => 1,
'sxw' => 1,
'sya' => 1,
'syb' => 1,
'syc' => 1,
'syd' => 1,
'syi' => 1,
'syk' => 1,
'syl' => 1,
'sym' => 1,
'syn' => 1,
'syo' => 1,
'syr' => 1,
'sys' => 1,
'syw' => 1,
'syy' => 1,
'sza' => 1,
'szb' => 1,
'szc' => 1,
'szd' => 1,
'sze' => 1,
'szg' => 1,
'szl' => 1,
'szn' => 1,
'szp' => 1,
'szv' => 1,
'szw' => 1,
'taa' => 1,
'tab' => 1,
'tac' => 1,
'tad' => 1,
'tae' => 1,
'taf' => 1,
'tag' => 1,
'tai' => 1,
'taj' => 1,
'tak' => 1,
'tal' => 1,
'tan' => 1,
'tao' => 1,
'tap' => 1,
'tar' => 1,
'tas' => 1,
'tau' => 1,
'tav' => 1,
'taw' => 1,
'tax' => 1,
'tay' => 1,
'taz' => 1,
'tba' => 1,
'tbb' => 1,
'tbc' => 1,
'tbd' => 1,
'tbe' => 1,
'tbf' => 1,
'tbg' => 1,
'tbh' => 1,
'tbi' => 1,
'tbj' => 1,
'tbk' => 1,
'tbl' => 1,
'tbm' => 1,
'tbn' => 1,
'tbo' => 1,
'tbp' => 1,
'tbq' => 1,
'tbr' => 1,
'tbs' => 1,
'tbt' => 1,
'tbu' => 1,
'tbv' => 1,
'tbw' => 1,
'tbx' => 1,
'tby' => 1,
'tbz' => 1,
'tca' => 1,
'tcb' => 1,
'tcc' => 1,
'tcd' => 1,
'tce' => 1,
'tcf' => 1,
'tcg' => 1,
'tch' => 1,
'tci' => 1,
'tck' => 1,
'tcl' => 1,
'tcm' => 1,
'tcn' => 1,
'tco' => 1,
'tcp' => 1,
'tcq' => 1,
'tcs' => 1,
'tct' => 1,
'tcu' => 1,
'tcw' => 1,
'tcx' => 1,
'tcy' => 1,
'tcz' => 1,
'tda' => 1,
'tdb' => 1,
'tdc' => 1,
'tdd' => 1,
'tdf' => 1,
'tdg' => 1,
'tdh' => 1,
'tdi' => 1,
'tdj' => 1,
'tdk' => 1,
'tdl' => 1,
'tdn' => 1,
'tdo' => 1,
'tdq' => 1,
'tdr' => 1,
'tds' => 1,
'tdt' => 1,
'tdu' => 1,
'tdv' => 1,
'tdy' => 1,
'tea' => 1,
'teb' => 1,
'ted' => 1,
'tee' => 1,
'tef' => 1,
'teg' => 1,
'teh' => 1,
'tei' => 1,
'tek' => 1,
'tem' => 1,
'ten' => 1,
'teo' => 1,
'tep' => 1,
'teq' => 1,
'ter' => 1,
'tes' => 1,
'tet' => 1,
'teu' => 1,
'tev' => 1,
'tew' => 1,
'tex' => 1,
'tey' => 1,
'tfi' => 1,
'tfn' => 1,
'tfo' => 1,
'tfr' => 1,
'tft' => 1,
'tga' => 1,
'tgb' => 1,
'tgc' => 1,
'tgd' => 1,
'tge' => 1,
'tgf' => 1,
'tgg' => 1,
'tgh' => 1,
'tgi' => 1,
'tgo' => 1,
'tgp' => 1,
'tgq' => 1,
'tgr' => 1,
'tgs' => 1,
'tgt' => 1,
'tgu' => 1,
'tgv' => 1,
'tgw' => 1,
'tgx' => 1,
'tgy' => 1,
'thc' => 1,
'thd' => 1,
'the' => 1,
'thf' => 1,
'thh' => 1,
'thi' => 1,
'thk' => 1,
'thl' => 1,
'thm' => 1,
'thn' => 1,
'thp' => 1,
'thq' => 1,
'thr' => 1,
'ths' => 1,
'tht' => 1,
'thu' => 1,
'thw' => 1,
'thx' => 1,
'thy' => 1,
'tia' => 1,
'tic' => 1,
'tid' => 1,
'tie' => 1,
'tif' => 1,
'tig' => 1,
'tih' => 1,
'tii' => 1,
'tij' => 1,
'tik' => 1,
'til' => 1,
'tim' => 1,
'tin' => 1,
'tio' => 1,
'tip' => 1,
'tiq' => 1,
'tis' => 1,
'tit' => 1,
'tiu' => 1,
'tiv' => 1,
'tiw' => 1,
'tix' => 1,
'tiy' => 1,
'tiz' => 1,
'tja' => 1,
'tjg' => 1,
'tji' => 1,
'tjm' => 1,
'tjn' => 1,
'tjo' => 1,
'tjs' => 1,
'tju' => 1,
'tka' => 1,
'tkb' => 1,
'tkd' => 1,
'tke' => 1,
'tkf' => 1,
'tkk' => 1,
'tkl' => 1,
'tkm' => 1,
'tkn' => 1,
'tkp' => 1,
'tkq' => 1,
'tkr' => 1,
'tks' => 1,
'tkt' => 1,
'tku' => 1,
'tkw' => 1,
'tkx' => 1,
'tkz' => 1,
'tla' => 1,
'tlb' => 1,
'tlc' => 1,
'tld' => 1,
'tlf' => 1,
'tlg' => 1,
'tlh' => 1,
'tli' => 1,
'tlj' => 1,
'tlk' => 1,
'tll' => 1,
'tlm' => 1,
'tln' => 1,
'tlo' => 1,
'tlp' => 1,
'tlq' => 1,
'tlr' => 1,
'tls' => 1,
'tlt' => 1,
'tlu' => 1,
'tlv' => 1,
'tlw' => 1,
'tlx' => 1,
'tly' => 1,
'tma' => 1,
'tmb' => 1,
'tmc' => 1,
'tmd' => 1,
'tme' => 1,
'tmf' => 1,
'tmg' => 1,
'tmh' => 1,
'tmi' => 1,
'tmj' => 1,
'tmk' => 1,
'tml' => 1,
'tmm' => 1,
'tmn' => 1,
'tmo' => 1,
'tmp' => 1,
'tmq' => 1,
'tmr' => 1,
'tms' => 1,
'tmt' => 1,
'tmu' => 1,
'tmv' => 1,
'tmy' => 1,
'tmz' => 1,
'tna' => 1,
'tnb' => 1,
'tnc' => 1,
'tnd' => 1,
'tne' => 1,
'tnf' => 1,
'tng' => 1,
'tnh' => 1,
'tni' => 1,
'tnk' => 1,
'tnl' => 1,
'tnm' => 1,
'tnn' => 1,
'tno' => 1,
'tnp' => 1,
'tnq' => 1,
'tnr' => 1,
'tns' => 1,
'tnt' => 1,
'tnu' => 1,
'tnv' => 1,
'tnw' => 1,
'tnx' => 1,
'tny' => 1,
'tnz' => 1,
'tob' => 1,
'toc' => 1,
'tod' => 1,
'toe' => 1,
'tof' => 1,
'tog' => 1,
'toh' => 1,
'toi' => 1,
'toj' => 1,
'tol' => 1,
'tom' => 1,
'too' => 1,
'top' => 1,
'toq' => 1,
'tor' => 1,
'tos' => 1,
'tou' => 1,
'tov' => 1,
'tow' => 1,
'tox' => 1,
'toy' => 1,
'toz' => 1,
'tpa' => 1,
'tpc' => 1,
'tpe' => 1,
'tpf' => 1,
'tpg' => 1,
'tpi' => 1,
'tpj' => 1,
'tpk' => 1,
'tpl' => 1,
'tpm' => 1,
'tpn' => 1,
'tpo' => 1,
'tpp' => 1,
'tpq' => 1,
'tpr' => 1,
'tpt' => 1,
'tpu' => 1,
'tpv' => 1,
'tpw' => 1,
'tpx' => 1,
'tpy' => 1,
'tpz' => 1,
'tqb' => 1,
'tql' => 1,
'tqm' => 1,
'tqn' => 1,
'tqo' => 1,
'tqp' => 1,
'tqq' => 1,
'tqr' => 1,
'tqt' => 1,
'tqu' => 1,
'tqw' => 1,
'tra' => 1,
'trb' => 1,
'trc' => 1,
'trd' => 1,
'tre' => 1,
'trf' => 1,
'trg' => 1,
'trh' => 1,
'tri' => 1,
'trj' => 1,
'trk' => 1,
'trl' => 1,
'trm' => 1,
'trn' => 1,
'tro' => 1,
'trp' => 1,
'trq' => 1,
'trr' => 1,
'trs' => 1,
'trt' => 1,
'tru' => 1,
'trv' => 1,
'trw' => 1,
'trx' => 1,
'try' => 1,
'trz' => 1,
'tsa' => 1,
'tsb' => 1,
'tsc' => 1,
'tsd' => 1,
'tse' => 1,
'tsf' => 1,
'tsg' => 1,
'tsh' => 1,
'tsi' => 1,
'tsj' => 1,
'tsk' => 1,
'tsl' => 1,
'tsm' => 1,
'tsp' => 1,
'tsq' => 1,
'tsr' => 1,
'tss' => 1,
'tsu' => 1,
'tsv' => 1,
'tsw' => 1,
'tsx' => 1,
'tsy' => 1,
'tsz' => 1,
'tta' => 1,
'ttb' => 1,
'ttc' => 1,
'ttd' => 1,
'tte' => 1,
'ttf' => 1,
'ttg' => 1,
'tth' => 1,
'tti' => 1,
'ttj' => 1,
'ttk' => 1,
'ttl' => 1,
'ttm' => 1,
'ttn' => 1,
'tto' => 1,
'ttp' => 1,
'ttr' => 1,
'tts' => 1,
'ttt' => 1,
'ttu' => 1,
'ttv' => 1,
'ttw' => 1,
'tty' => 1,
'ttz' => 1,
'tua' => 1,
'tub' => 1,
'tuc' => 1,
'tud' => 1,
'tue' => 1,
'tuf' => 1,
'tug' => 1,
'tuh' => 1,
'tui' => 1,
'tuj' => 1,
'tul' => 1,
'tum' => 1,
'tun' => 1,
'tuo' => 1,
'tup' => 1,
'tuq' => 1,
'tus' => 1,
'tut' => 1,
'tuu' => 1,
'tuv' => 1,
'tuw' => 1,
'tux' => 1,
'tuz' => 1,
'tva' => 1,
'tvd' => 1,
'tve' => 1,
'tvk' => 1,
'tvl' => 1,
'tvm' => 1,
'tvn' => 1,
'tvo' => 1,
'tvs' => 1,
'tvt' => 1,
'tvw' => 1,
'tvy' => 1,
'twa' => 1,
'twb' => 1,
'twc' => 1,
'twd' => 1,
'twe' => 1,
'twf' => 1,
'twg' => 1,
'twh' => 1,
'twl' => 1,
'twm' => 1,
'twn' => 1,
'two' => 1,
'twp' => 1,
'twq' => 1,
'twr' => 1,
'twt' => 1,
'twu' => 1,
'tww' => 1,
'twx' => 1,
'twy' => 1,
'txa' => 1,
'txb' => 1,
'txc' => 1,
'txe' => 1,
'txg' => 1,
'txh' => 1,
'txi' => 1,
'txm' => 1,
'txn' => 1,
'txo' => 1,
'txq' => 1,
'txr' => 1,
'txs' => 1,
'txt' => 1,
'txu' => 1,
'txx' => 1,
'tya' => 1,
'tye' => 1,
'tyh' => 1,
'tyi' => 1,
'tyj' => 1,
'tyl' => 1,
'tyn' => 1,
'typ' => 1,
'tyr' => 1,
'tys' => 1,
'tyt' => 1,
'tyu' => 1,
'tyv' => 1,
'tyx' => 1,
'tyz' => 1,
'tza' => 1,
'tzh' => 1,
'tzj' => 1,
'tzm' => 1,
'tzn' => 1,
'tzo' => 1,
'tzx' => 1,
'uam' => 1,
'uan' => 1,
'uar' => 1,
'uba' => 1,
'ubi' => 1,
'ubr' => 1,
'ubu' => 1,
'uby' => 1,
'uda' => 1,
'ude' => 1,
'udg' => 1,
'udi' => 1,
'udj' => 1,
'udl' => 1,
'udm' => 1,
'udu' => 1,
'ues' => 1,
'ufi' => 1,
'uga' => 1,
'ugb' => 1,
'uge' => 1,
'ugn' => 1,
'ugo' => 1,
'ugy' => 1,
'uha' => 1,
'uhn' => 1,
'uis' => 1,
'uiv' => 1,
'uji' => 1,
'uka' => 1,
'ukg' => 1,
'ukh' => 1,
'ukl' => 1,
'ukp' => 1,
'ukq' => 1,
'uks' => 1,
'uku' => 1,
'ukw' => 1,
'ula' => 1,
'ulb' => 1,
'ulc' => 1,
'ulf' => 1,
'uli' => 1,
'ulk' => 1,
'ull' => 1,
'ulm' => 1,
'uln' => 1,
'ulu' => 1,
'uma' => 1,
'umb' => 1,
'umc' => 1,
'umd' => 1,
'umg' => 1,
'umi' => 1,
'umm' => 1,
'umn' => 1,
'umo' => 1,
'ump' => 1,
'umr' => 1,
'ums' => 1,
'una' => 1,
'une' => 1,
'ung' => 1,
'unk' => 1,
'unp' => 1,
'unr' => 1,
'unx' => 1,
'unz' => 1,
'uok' => 1,
'upi' => 1,
'upv' => 1,
'ura' => 1,
'urb' => 1,
'urc' => 1,
'ure' => 1,
'urf' => 1,
'urg' => 1,
'urh' => 1,
'uri' => 1,
'urj' => 1,
'url' => 1,
'urm' => 1,
'urn' => 1,
'uro' => 1,
'urp' => 1,
'urr' => 1,
'urt' => 1,
'uru' => 1,
'urv' => 1,
'urw' => 1,
'urx' => 1,
'ury' => 1,
'urz' => 1,
'usa' => 1,
'ush' => 1,
'usi' => 1,
'usk' => 1,
'usp' => 1,
'usu' => 1,
'uta' => 1,
'ute' => 1,
'utp' => 1,
'utr' => 1,
'utu' => 1,
'uum' => 1,
'uun' => 1,
'uur' => 1,
'uuu' => 1,
'uve' => 1,
'uvh' => 1,
'uvl' => 1,
'uwa' => 1,
'uya' => 1,
'vaa' => 1,
'vae' => 1,
'vaf' => 1,
'vag' => 1,
'vah' => 1,
'vai' => 1,
'vaj' => 1,
'val' => 1,
'vam' => 1,
'van' => 1,
'vao' => 1,
'vap' => 1,
'var' => 1,
'vas' => 1,
'vau' => 1,
'vav' => 1,
'vay' => 1,
'vbb' => 1,
'vec' => 1,
'ved' => 1,
'vel' => 1,
'vem' => 1,
'veo' => 1,
'vep' => 1,
'ver' => 1,
'vgr' => 1,
'vgt' => 1,
'vic' => 1,
'vid' => 1,
'vif' => 1,
'vig' => 1,
'vil' => 1,
'vin' => 1,
'vis' => 1,
'vit' => 1,
'viv' => 1,
'vka' => 1,
'vki' => 1,
'vkj' => 1,
'vkl' => 1,
'vkm' => 1,
'vko' => 1,
'vkp' => 1,
'vku' => 1,
'vlp' => 1,
'vls' => 1,
'vma' => 1,
'vmb' => 1,
'vmc' => 1,
'vmd' => 1,
'vme' => 1,
'vmf' => 1,
'vmg' => 1,
'vmh' => 1,
'vmi' => 1,
'vmj' => 1,
'vmk' => 1,
'vml' => 1,
'vmm' => 1,
'vmp' => 1,
'vmq' => 1,
'vmr' => 1,
'vms' => 1,
'vmu' => 1,
'vmv' => 1,
'vmw' => 1,
'vmx' => 1,
'vmy' => 1,
'vmz' => 1,
'vnk' => 1,
'vnm' => 1,
'vnp' => 1,
'vor' => 1,
'vot' => 1,
'vra' => 1,
'vrs' => 1,
'vrt' => 1,
'vsi' => 1,
'vsl' => 1,
'vsv' => 1,
'vto' => 1,
'vum' => 1,
'vun' => 1,
'vut' => 1,
'vwa' => 1,
'waa' => 1,
'wab' => 1,
'wac' => 1,
'wad' => 1,
'wae' => 1,
'waf' => 1,
'wag' => 1,
'wah' => 1,
'wai' => 1,
'waj' => 1,
'wak' => 1,
'wal' => 1,
'wam' => 1,
'wan' => 1,
'wao' => 1,
'wap' => 1,
'waq' => 1,
'war' => 1,
'was' => 1,
'wat' => 1,
'wau' => 1,
'wav' => 1,
'waw' => 1,
'wax' => 1,
'way' => 1,
'waz' => 1,
'wba' => 1,
'wbb' => 1,
'wbe' => 1,
'wbf' => 1,
'wbh' => 1,
'wbi' => 1,
'wbj' => 1,
'wbk' => 1,
'wbl' => 1,
'wbm' => 1,
'wbp' => 1,
'wbq' => 1,
'wbt' => 1,
'wbv' => 1,
'wbw' => 1,
'wca' => 1,
'wci' => 1,
'wdd' => 1,
'wdg' => 1,
'wdj' => 1,
'wdu' => 1,
'wea' => 1,
'wec' => 1,
'wed' => 1,
'weh' => 1,
'wei' => 1,
'wem' => 1,
'wen' => 1,
'weo' => 1,
'wep' => 1,
'wer' => 1,
'wes' => 1,
'wet' => 1,
'weu' => 1,
'wew' => 1,
'wfg' => 1,
'wga' => 1,
'wgg' => 1,
'wgi' => 1,
'wgo' => 1,
'wgw' => 1,
'wgy' => 1,
'wha' => 1,
'whg' => 1,
'whk' => 1,
'whu' => 1,
'wib' => 1,
'wic' => 1,
'wie' => 1,
'wif' => 1,
'wig' => 1,
'wih' => 1,
'wii' => 1,
'wij' => 1,
'wik' => 1,
'wil' => 1,
'wim' => 1,
'win' => 1,
'wir' => 1,
'wit' => 1,
'wiu' => 1,
'wiv' => 1,
'wiw' => 1,
'wiy' => 1,
'wja' => 1,
'wji' => 1,
'wka' => 1,
'wkb' => 1,
'wkd' => 1,
'wkl' => 1,
'wku' => 1,
'wkw' => 1,
'wla' => 1,
'wlc' => 1,
'wle' => 1,
'wlg' => 1,
'wli' => 1,
'wlk' => 1,
'wll' => 1,
'wlm' => 1,
'wlo' => 1,
'wlr' => 1,
'wls' => 1,
'wlu' => 1,
'wlv' => 1,
'wlw' => 1,
'wlx' => 1,
'wly' => 1,
'wma' => 1,
'wmb' => 1,
'wmc' => 1,
'wmd' => 1,
'wme' => 1,
'wmh' => 1,
'wmi' => 1,
'wmm' => 1,
'wmn' => 1,
'wmo' => 1,
'wms' => 1,
'wmt' => 1,
'wmw' => 1,
'wmx' => 1,
'wnb' => 1,
'wnc' => 1,
'wnd' => 1,
'wne' => 1,
'wng' => 1,
'wni' => 1,
'wnk' => 1,
'wnm' => 1,
'wno' => 1,
'wnp' => 1,
'wnu' => 1,
'woa' => 1,
'wob' => 1,
'woc' => 1,
'wod' => 1,
'woe' => 1,
'wof' => 1,
'wog' => 1,
'woi' => 1,
'wok' => 1,
'wom' => 1,
'won' => 1,
'woo' => 1,
'wor' => 1,
'wos' => 1,
'wow' => 1,
'woy' => 1,
'wpc' => 1,
'wra' => 1,
'wrb' => 1,
'wrd' => 1,
'wrg' => 1,
'wrh' => 1,
'wri' => 1,
'wrl' => 1,
'wrm' => 1,
'wrn' => 1,
'wrp' => 1,
'wrr' => 1,
'wrs' => 1,
'wru' => 1,
'wrv' => 1,
'wrw' => 1,
'wrx' => 1,
'wrz' => 1,
'wsa' => 1,
'wsi' => 1,
'wsk' => 1,
'wsr' => 1,
'wss' => 1,
'wsu' => 1,
'wsv' => 1,
'wtf' => 1,
'wti' => 1,
'wtk' => 1,
'wtm' => 1,
'wtw' => 1,
'wua' => 1,
'wub' => 1,
'wud' => 1,
'wuh' => 1,
'wul' => 1,
'wum' => 1,
'wun' => 1,
'wur' => 1,
'wut' => 1,
'wuv' => 1,
'wux' => 1,
'wuy' => 1,
'wwa' => 1,
'wwo' => 1,
'wwr' => 1,
'www' => 1,
'wxa' => 1,
'wya' => 1,
'wyb' => 1,
'wym' => 1,
'wyr' => 1,
'wyy' => 1,
'xaa' => 1,
'xab' => 1,
'xac' => 1,
'xad' => 1,
'xae' => 1,
'xag' => 1,
'xai' => 1,
'xal' => 1,
'xam' => 1,
'xan' => 1,
'xao' => 1,
'xap' => 1,
'xaq' => 1,
'xar' => 1,
'xas' => 1,
'xat' => 1,
'xau' => 1,
'xav' => 1,
'xaw' => 1,
'xay' => 1,
'xba' => 1,
'xbc' => 1,
'xbi' => 1,
'xbm' => 1,
'xbo' => 1,
'xbr' => 1,
'xbw' => 1,
'xbx' => 1,
'xcb' => 1,
'xcc' => 1,
'xce' => 1,
'xcg' => 1,
'xch' => 1,
'xcl' => 1,
'xcm' => 1,
'xcn' => 1,
'xco' => 1,
'xcr' => 1,
'xct' => 1,
'xcu' => 1,
'xcv' => 1,
'xcw' => 1,
'xcy' => 1,
'xdc' => 1,
'xdm' => 1,
'xdy' => 1,
'xeb' => 1,
'xed' => 1,
'xeg' => 1,
'xel' => 1,
'xem' => 1,
'xep' => 1,
'xer' => 1,
'xes' => 1,
'xet' => 1,
'xeu' => 1,
'xfa' => 1,
'xga' => 1,
'xgf' => 1,
'xgl' => 1,
'xgn' => 1,
'xgr' => 1,
'xha' => 1,
'xhc' => 1,
'xhd' => 1,
'xhr' => 1,
'xht' => 1,
'xhu' => 1,
'xhv' => 1,
'xia' => 1,
'xib' => 1,
'xii' => 1,
'xil' => 1,
'xin' => 1,
'xip' => 1,
'xir' => 1,
'xiv' => 1,
'xiy' => 1,
'xka' => 1,
'xkb' => 1,
'xkc' => 1,
'xkd' => 1,
'xke' => 1,
'xkf' => 1,
'xkg' => 1,
'xkh' => 1,
'xki' => 1,
'xkj' => 1,
'xkk' => 1,
'xkl' => 1,
'xkn' => 1,
'xko' => 1,
'xkp' => 1,
'xkq' => 1,
'xkr' => 1,
'xks' => 1,
'xkt' => 1,
'xku' => 1,
'xkv' => 1,
'xkw' => 1,
'xkx' => 1,
'xky' => 1,
'xkz' => 1,
'xla' => 1,
'xlb' => 1,
'xlc' => 1,
'xld' => 1,
'xle' => 1,
'xlg' => 1,
'xli' => 1,
'xln' => 1,
'xlo' => 1,
'xlp' => 1,
'xls' => 1,
'xlu' => 1,
'xly' => 1,
'xma' => 1,
'xmb' => 1,
'xmc' => 1,
'xmd' => 1,
'xme' => 1,
'xmf' => 1,
'xmg' => 1,
'xmh' => 1,
'xmj' => 1,
'xmk' => 1,
'xml' => 1,
'xmn' => 1,
'xmo' => 1,
'xmp' => 1,
'xmq' => 1,
'xmr' => 1,
'xms' => 1,
'xmt' => 1,
'xmu' => 1,
'xmx' => 1,
'xmy' => 1,
'xmz' => 1,
'xna' => 1,
'xnb' => 1,
'xnd' => 1,
'xng' => 1,
'xnh' => 1,
'xnn' => 1,
'xno' => 1,
'xns' => 1,
'xoc' => 1,
'xod' => 1,
'xog' => 1,
'xoi' => 1,
'xok' => 1,
'xom' => 1,
'xon' => 1,
'xoo' => 1,
'xop' => 1,
'xor' => 1,
'xow' => 1,
'xpc' => 1,
'xpg' => 1,
'xpi' => 1,
'xpk' => 1,
'xpm' => 1,
'xpn' => 1,
'xpo' => 1,
'xpp' => 1,
'xpr' => 1,
'xps' => 1,
'xpu' => 1,
'xpy' => 1,
'xqa' => 1,
'xqt' => 1,
'xra' => 1,
'xrb' => 1,
'xre' => 1,
'xri' => 1,
'xrm' => 1,
'xrn' => 1,
'xrr' => 1,
'xrt' => 1,
'xru' => 1,
'xrw' => 1,
'xsa' => 1,
'xsb' => 1,
'xsc' => 1,
'xsd' => 1,
'xse' => 1,
'xsh' => 1,
'xsi' => 1,
'xsj' => 1,
'xsm' => 1,
'xsn' => 1,
'xso' => 1,
'xsp' => 1,
'xsq' => 1,
'xsr' => 1,
'xss' => 1,
'xsu' => 1,
'xsv' => 1,
'xsy' => 1,
'xta' => 1,
'xtb' => 1,
'xtc' => 1,
'xtd' => 1,
'xte' => 1,
'xtg' => 1,
'xti' => 1,
'xtj' => 1,
'xtl' => 1,
'xtm' => 1,
'xtn' => 1,
'xto' => 1,
'xtp' => 1,
'xtq' => 1,
'xtr' => 1,
'xts' => 1,
'xtt' => 1,
'xtu' => 1,
'xtw' => 1,
'xty' => 1,
'xtz' => 1,
'xua' => 1,
'xub' => 1,
'xug' => 1,
'xuj' => 1,
'xum' => 1,
'xuo' => 1,
'xup' => 1,
'xur' => 1,
'xut' => 1,
'xuu' => 1,
'xve' => 1,
'xvi' => 1,
'xvn' => 1,
'xvo' => 1,
'xvs' => 1,
'xwa' => 1,
'xwc' => 1,
'xwe' => 1,
'xwg' => 1,
'xwl' => 1,
'xwo' => 1,
'xwr' => 1,
'xxb' => 1,
'xxk' => 1,
'xxr' => 1,
'xxt' => 1,
'xyl' => 1,
'xzh' => 1,
'xzm' => 1,
'xzp' => 1,
'yaa' => 1,
'yab' => 1,
'yac' => 1,
'yad' => 1,
'yae' => 1,
'yaf' => 1,
'yag' => 1,
'yah' => 1,
'yai' => 1,
'yaj' => 1,
'yak' => 1,
'yal' => 1,
'yam' => 1,
'yao' => 1,
'yap' => 1,
'yaq' => 1,
'yar' => 1,
'yas' => 1,
'yat' => 1,
'yau' => 1,
'yav' => 1,
'yaw' => 1,
'yax' => 1,
'yay' => 1,
'yaz' => 1,
'yba' => 1,
'ybb' => 1,
'ybd' => 1,
'ybe' => 1,
'ybh' => 1,
'ybi' => 1,
'ybj' => 1,
'ybk' => 1,
'ybl' => 1,
'ybm' => 1,
'ybn' => 1,
'ybo' => 1,
'ybx' => 1,
'yby' => 1,
'ych' => 1,
'ycl' => 1,
'ycn' => 1,
'ycp' => 1,
'yde' => 1,
'ydg' => 1,
'ydk' => 1,
'yds' => 1,
'yea' => 1,
'yec' => 1,
'yee' => 1,
'yei' => 1,
'yej' => 1,
'yel' => 1,
'yen' => 1,
'yer' => 1,
'yes' => 1,
'yet' => 1,
'yeu' => 1,
'yev' => 1,
'yey' => 1,
'ygl' => 1,
'ygm' => 1,
'ygp' => 1,
'ygr' => 1,
'ygw' => 1,
'yha' => 1,
'yhl' => 1,
'yia' => 1,
'yif' => 1,
'yig' => 1,
'yii' => 1,
'yij' => 1,
'yik' => 1,
'yil' => 1,
'yim' => 1,
'yin' => 1,
'yip' => 1,
'yiq' => 1,
'yir' => 1,
'yis' => 1,
'yit' => 1,
'yiu' => 1,
'yiv' => 1,
'yix' => 1,
'yiy' => 1,
'yiz' => 1,
'yka' => 1,
'ykg' => 1,
'yki' => 1,
'ykk' => 1,
'ykl' => 1,
'ykm' => 1,
'yko' => 1,
'ykr' => 1,
'ykt' => 1,
'yky' => 1,
'yla' => 1,
'yle' => 1,
'ylg' => 1,
'yli' => 1,
'yll' => 1,
'ylm' => 1,
'yln' => 1,
'ylo' => 1,
'ylr' => 1,
'ylu' => 1,
'yly' => 1,
'yma' => 1,
'ymb' => 1,
'ymc' => 1,
'ymd' => 1,
'yme' => 1,
'ymg' => 1,
'ymh' => 1,
'ymi' => 1,
'ymk' => 1,
'yml' => 1,
'ymm' => 1,
'ymn' => 1,
'ymo' => 1,
'ymp' => 1,
'ymq' => 1,
'ymr' => 1,
'yms' => 1,
'ymt' => 1,
'ymx' => 1,
'ymz' => 1,
'yna' => 1,
'ynd' => 1,
'yne' => 1,
'yng' => 1,
'ynh' => 1,
'ynk' => 1,
'ynl' => 1,
'ynn' => 1,
'yno' => 1,
'yns' => 1,
'ynu' => 1,
'yob' => 1,
'yog' => 1,
'yoi' => 1,
'yok' => 1,
'yol' => 1,
'yom' => 1,
'yon' => 1,
'yos' => 1,
'yox' => 1,
'yoy' => 1,
'ypa' => 1,
'ypb' => 1,
'ypg' => 1,
'yph' => 1,
'ypk' => 1,
'ypm' => 1,
'ypn' => 1,
'ypo' => 1,
'ypp' => 1,
'ypz' => 1,
'yra' => 1,
'yrb' => 1,
'yre' => 1,
'yri' => 1,
'yrk' => 1,
'yrl' => 1,
'yrn' => 1,
'yrs' => 1,
'yrw' => 1,
'ysc' => 1,
'ysd' => 1,
'ysl' => 1,
'ysn' => 1,
'yso' => 1,
'ysp' => 1,
'ysr' => 1,
'yss' => 1,
'ysy' => 1,
'yta' => 1,
'ytl' => 1,
'ytp' => 1,
'yua' => 1,
'yub' => 1,
'yuc' => 1,
'yuf' => 1,
'yug' => 1,
'yui' => 1,
'yuj' => 1,
'yuk' => 1,
'yul' => 1,
'yum' => 1,
'yun' => 1,
'yup' => 1,
'yuq' => 1,
'yur' => 1,
'yut' => 1,
'yuu' => 1,
'yuw' => 1,
'yux' => 1,
'yuy' => 1,
'yuz' => 1,
'yva' => 1,
'yvt' => 1,
'ywa' => 1,
'ywl' => 1,
'ywn' => 1,
'ywq' => 1,
'ywr' => 1,
'ywt' => 1,
'ywu' => 1,
'yww' => 1,
'yyu' => 1,
'yyz' => 1,
'yzg' => 1,
'yzk' => 1,
'zag' => 1,
'zah' => 1,
'zaj' => 1,
'zak' => 1,
'zal' => 1,
'zap' => 1,
'zau' => 1,
'zay' => 1,
'zaz' => 1,
'zbc' => 1,
'zbe' => 1,
'zbl' => 1,
'zbt' => 1,
'zbw' => 1,
'zdj' => 1,
'zea' => 1,
'zeg' => 1,
'zen' => 1,
'zga' => 1,
'zgr' => 1,
'zhb' => 1,
'zhi' => 1,
'zhw' => 1,
'zhx' => 1,
'zia' => 1,
'zib' => 1,
'zik' => 1,
'zim' => 1,
'zin' => 1,
'zir' => 1,
'ziw' => 1,
'ziz' => 1,
'zka' => 1,
'zkb' => 1,
'zkg' => 1,
'zkh' => 1,
'zkk' => 1,
'zko' => 1,
'zkp' => 1,
'zkr' => 1,
'zkt' => 1,
'zku' => 1,
'zkv' => 1,
'zkz' => 1,
'zle' => 1,
'zls' => 1,
'zlw' => 1,
'zma' => 1,
'zmb' => 1,
'zmc' => 1,
'zmd' => 1,
'zme' => 1,
'zmf' => 1,
'zmg' => 1,
'zmh' => 1,
'zmj' => 1,
'zmk' => 1,
'zml' => 1,
'zmm' => 1,
'zmn' => 1,
'zmo' => 1,
'zmp' => 1,
'zmq' => 1,
'zmr' => 1,
'zms' => 1,
'zmt' => 1,
'zmu' => 1,
'zmv' => 1,
'zmw' => 1,
'zmx' => 1,
'zmy' => 1,
'zmz' => 1,
'zna' => 1,
'znd' => 1,
'zne' => 1,
'zng' => 1,
'znk' => 1,
'zns' => 1,
'zoc' => 1,
'zoh' => 1,
'zom' => 1,
'zoq' => 1,
'zor' => 1,
'zos' => 1,
'zra' => 1,
'zrg' => 1,
'zrn' => 1,
'zro' => 1,
'zrp' => 1,
'zrs' => 1,
'zsa' => 1,
'zsk' => 1,
'zsl' => 1,
'zsu' => 1,
'zua' => 1,
'zuh' => 1,
'zum' => 1,
'zun' => 1,
'zuy' => 1,
'zwa' => 1,
'zyp' => 1,
'zza' => 1,
);

%region_codes = (
'AC' => 1,
'AD' => 1,
'AE' => 1,
'AF' => 1,
'AG' => 1,
'AI' => 1,
'AL' => 1,
'AM' => 1,
'AN' => 1,
'AO' => 1,
'AQ' => 1,
'AR' => 1,
'AS' => 1,
'AT' => 1,
'AU' => 1,
'AW' => 1,
'AX' => 1,
'AZ' => 1,
'BA' => 1,
'BB' => 1,
'BD' => 1,
'BE' => 1,
'BF' => 1,
'BG' => 1,
'BH' => 1,
'BI' => 1,
'BJ' => 1,
'BL' => 1,
'BM' => 1,
'BN' => 1,
'BO' => 1,
'BR' => 1,
'BS' => 1,
'BT' => 1,
'BU' => 1,
'BV' => 1,
'BW' => 1,
'BY' => 1,
'BZ' => 1,
'CA' => 1,
'CC' => 1,
'CD' => 1,
'CF' => 1,
'CG' => 1,
'CH' => 1,
'CI' => 1,
'CK' => 1,
'CL' => 1,
'CM' => 1,
'CN' => 1,
'CO' => 1,
'CP' => 1,
'CR' => 1,
'CS' => 1,
'CU' => 1,
'CV' => 1,
'CX' => 1,
'CY' => 1,
'CZ' => 1,
'DD' => 1,
'DE' => 1,
'DG' => 1,
'DJ' => 1,
'DK' => 1,
'DM' => 1,
'DO' => 1,
'DZ' => 1,
'EA' => 1,
'EC' => 1,
'EE' => 1,
'EG' => 1,
'EH' => 1,
'ER' => 1,
'ES' => 1,
'ET' => 1,
'EU' => 1,
'FI' => 1,
'FJ' => 1,
'FK' => 1,
'FM' => 1,
'FO' => 1,
'FR' => 1,
'FX' => 1,
'GA' => 1,
'GB' => 1,
'GD' => 1,
'GE' => 1,
'GF' => 1,
'GG' => 1,
'GH' => 1,
'GI' => 1,
'GL' => 1,
'GM' => 1,
'GN' => 1,
'GP' => 1,
'GQ' => 1,
'GR' => 1,
'GS' => 1,
'GT' => 1,
'GU' => 1,
'GW' => 1,
'GY' => 1,
'HK' => 1,
'HM' => 1,
'HN' => 1,
'HR' => 1,
'HT' => 1,
'HU' => 1,
'IC' => 1,
'ID' => 1,
'IE' => 1,
'IL' => 1,
'IM' => 1,
'IN' => 1,
'IO' => 1,
'IQ' => 1,
'IR' => 1,
'IS' => 1,
'IT' => 1,
'JE' => 1,
'JM' => 1,
'JO' => 1,
'JP' => 1,
'KE' => 1,
'KG' => 1,
'KH' => 1,
'KI' => 1,
'KM' => 1,
'KN' => 1,
'KP' => 1,
'KR' => 1,
'KW' => 1,
'KY' => 1,
'KZ' => 1,
'LA' => 1,
'LB' => 1,
'LC' => 1,
'LI' => 1,
'LK' => 1,
'LR' => 1,
'LS' => 1,
'LT' => 1,
'LU' => 1,
'LV' => 1,
'LY' => 1,
'MA' => 1,
'MC' => 1,
'MD' => 1,
'ME' => 1,
'MF' => 1,
'MG' => 1,
'MH' => 1,
'MK' => 1,
'ML' => 1,
'MM' => 1,
'MN' => 1,
'MO' => 1,
'MP' => 1,
'MQ' => 1,
'MR' => 1,
'MS' => 1,
'MT' => 1,
'MU' => 1,
'MV' => 1,
'MW' => 1,
'MX' => 1,
'MY' => 1,
'MZ' => 1,
'NA' => 1,
'NC' => 1,
'NE' => 1,
'NF' => 1,
'NG' => 1,
'NI' => 1,
'NL' => 1,
'NO' => 1,
'NP' => 1,
'NR' => 1,
'NT' => 1,
'NU' => 1,
'NZ' => 1,
'OM' => 1,
'PA' => 1,
'PE' => 1,
'PF' => 1,
'PG' => 1,
'PH' => 1,
'PK' => 1,
'PL' => 1,
'PM' => 1,
'PN' => 1,
'PR' => 1,
'PS' => 1,
'PT' => 1,
'PW' => 1,
'PY' => 1,
'QA' => 1,
'RE' => 1,
'RO' => 1,
'RS' => 1,
'RU' => 1,
'RW' => 1,
'SA' => 1,
'SB' => 1,
'SC' => 1,
'SD' => 1,
'SE' => 1,
'SG' => 1,
'SH' => 1,
'SI' => 1,
'SJ' => 1,
'SK' => 1,
'SL' => 1,
'SM' => 1,
'SN' => 1,
'SO' => 1,
'SR' => 1,
'ST' => 1,
'SU' => 1,
'SV' => 1,
'SY' => 1,
'SZ' => 1,
'TA' => 1,
'TC' => 1,
'TD' => 1,
'TF' => 1,
'TG' => 1,
'TH' => 1,
'TJ' => 1,
'TK' => 1,
'TL' => 1,
'TM' => 1,
'TN' => 1,
'TO' => 1,
'TP' => 1,
'TR' => 1,
'TT' => 1,
'TV' => 1,
'TW' => 1,
'TZ' => 1,
'UA' => 1,
'UG' => 1,
'UM' => 1,
'US' => 1,
'UY' => 1,
'UZ' => 1,
'VA' => 1,
'VC' => 1,
'VE' => 1,
'VG' => 1,
'VI' => 1,
'VN' => 1,
'VU' => 1,
'WF' => 1,
'WS' => 1,
'YD' => 1,
'YE' => 1,
'YT' => 1,
'YU' => 1,
'ZA' => 1,
'ZM' => 1,
'ZR' => 1,
'ZW' => 1,
);


require "$T2H_HOME/documentlanguages.pl"
    if ($0 =~ /\.pl$/ &&
        -e "$T2H_HOME/documentlanguages.pl" && -r "$T2H_HOME/documentlanguages.pl");

# leave this within comments, and keep the require statement
# This way, you can directly run texi2html.pl, if 
# $T2H_HOME/texi2html.init exists.

# @INIT@
# -*-perl-*-
# vim: set filetype=perl:
######################################################################
# File: texi2html.init
#
# Default values for command-line arguments and for various customizable
# procedures are set in this file.
#
# A copy of this file is pasted into the beginning of texi2html by
# running './configure'.
#
# Copy this file, rename it and make changes to it, if you like.
# Afterwards, load the file with command-line 
# option --init-file <your_init_file>
#
# $Id: texi2html.init,v 1.272 2010/06/26 09:54:22 pertusus Exp $

######################################################################
# The following variables can also be set by command-line options
#
#
# The default values are set in this file, texi2html.init and the content
# of this file is included at the beginning of the texi2html script file. 
# Those values may be overrided by values set in $sysconfdir/texi2html/Config 
# and then by values set in $HOME/texi2html/Config.
#
# command line switches may override these values, and values set in files
# specified by --init-file are also taken into account.
# values set in these files overwrite values set by the command-line
# options appearing before --init-file and might still be overwritten by
# command-line arguments following the --init-file option.

##################################################################
# options common with makeinfo
# -I
# add a directory to the list of directories where @include files are
# searched for (besides the directory of the file). additional '-I' 
# args are appended to this list.
# (APA: Don't implicitely search ., to conform with the docs!)
# my @INCLUDE_DIRS = (".");

#use strict;

@INCLUDE_DIRS = ();

# -P
# prepend a directory to the list of directories where @include files are
# searched for before the directory of the file. additional '-P' 
# args are prepended to this list.
@PREPEND_DIRS = ();

# --split section|chapter|node|none
# if $SPLIT is set to 'section' (resp. 'chapter') one html file per section 
# (resp. chapter) is generated. If $SPLIT is set to 'node' one html file per 
# node or sectioning element is generated. In all these cases separate pages 
# for Top, Table of content (Toc), Overview and About are generated.
# Otherwise a monolithic html file that contains the whole document is 
# created.
#$SPLIT = 'section';
$SPLIT = '';

# --separated-footnotes
# if this is set footnotes are on a separated page. Otherwise they are at
# the end of each file (if the document is split).
$FOOTNOTESTYLE = 'end';

# --fill-column
$FILLCOLUMN = 72;

# --number | --no-number
# if this is set the sections are numbered, and section names and numbers 
# are used in references and menus (instead of node names).
$NUMBER_SECTIONS = 1;

# --headers
# if this is set then navigation panels are printed at the beginning of each 
# section.
# If the document is split at nodes then navigation panels are 
# printed at the end if there were more than $WORDS_IN_PAGE words on page.
#
# Navigation panels are always printed at the beginning of output files.
#
# This is most useful if you do not want to have section navigation
# with --split chapter. There will be chapter navigation panel at the 
# beginning and at the end of chapters anyway.
# this is mostly not used in the default case, important for html.
$HEADERS = 0;

# -o filename
# If this is set a monolithic document is outputted into $filename.
$OUT = undef;

# --split-size
# if undef, the info output is not split
$SPLIT_SIZE = 300000;

# --internal-links
$INTERNAL_LINKS = undef;

# --no-validate
# suppress node cross-reference validation
$NOVALIDATE = 0;

# --documentlanguage
# use gdt('my string') if you want to have translations of 'my string'
# and provide the translations in $LANGUAGES->{$DOCUMENTLANGUAGE} with 
# 'my string' as key.
# To add a new language use ISO 639 language codes (see e.g. perl module 
# Locale-Codes-1.02 for  definitions). Supply translations in the 
# $LANGUAGES hash and put it in a file with $LANG as name in an i18n 
# directory. 
# This is used for the initial language, it is overriden during 
# document processing if there is a @documentlanguage.
# It is ignored if the language is passed on the command line.
$DOCUMENTLANGUAGE = 'en';

# --transliterate-file-names 
# transliterate node names for external refs (and internal if NODE_FILES)
$TRANSLITERATE_FILE_NAMES = 1;

# --error-limit
# quit after NUM errors (default 1000).
$ERROR_LIMIT = 1000;

# --css-include
# All the specified css files are used. More precisely the @import sections
# are added to the beginning of the CSS_LINES the remaining is added at
# the end of the CSS_LINES (after the css rules generated by the program).
# cf texinfo manual for more info.
# - means STDIN
@CSS_FILES = ();

# --css-ref
# the specified url are used as stylesheet links
@CSS_REFS = ();

# --paragraph-indent
$PARAGRAPHINDENT = 3;

# --enable-encoding
$ENABLE_ENCODING = 0;

# --force
$FORCE = 0;

# --no-warn
$NO_WARN = 0;

# --number-footnotes
$NUMBER_FOOTNOTES = 1;

# not in makeinfo but in texi2dvi
# --command
@COMMANDS = ();

##################################################################
# option specific of texi2html
# --debug
# The integer value specifies what kind of debugging output is generated.
$DEBUG = 0;

# --doctype
# The value is the 'SystemLiteral' which identifies the canonical DTD 
# for the document.
# Definition: The SystemLiteral is called the entity's system
# identifier. It is a URI, which may be used to retrieve the entity.
# See http://www.xml.com/axml/target.html#NT-ExternalID
$DOCTYPE = '';

# --frameset-doctype
# When frames are used, this SystemLiteral identifies the DTD used for
# the file containing the frame description.
$FRAMESET_DOCTYPE = '';

# --test
# If this value is true, some variables which should be dynamically generated 
# (the date, the user running texi2html, the version of texi2html) are set to 
# fix and given values. This is usefull in case the resulting manual is 
# compared with a reference. For example this is used in the tests.
$TEST = 0;

# --dump-texi
# This value is usefull for debugging purposes. The result of the first pass is
# put in <document name>.passtexi, the result of the second pass is put in 
# <document name>.passfirst.
$DUMP_TEXI = 0;

# --expand
# the @EXPAND array contains the expanded section names.
@EXPAND = ();

# --invisible
# This seems obsolete and is not used anywhere.
# This was a workaround for a known bug of many WWW browsers, including 
# netscape. This was used to create invisible destination in anchors.
$INVISIBLE_MARK = '';
# $INVISIBLE_MARK = '&#160;';

# --iso
# if this value is true, ISO8859 characters are used for quotes.
# --iso does more than what USE_ISO does.
$USE_ISO = 0;

# --conf-dir
# append to the files searched for init files.
@CONF_DIRS = ();

# --top-file
# This file name is used for the top-level file.
# The extension is set appropriately, if necessary.
# If empty, <basename of document>.html is used.
# Typically, you would set this to "index.html".
$TOP_FILE = '';

# --toc-file
# This file name is used for the table of contents.  The
# extension is set appropriately, if necessary.
# If empty, <basename of document>_toc.html is used.
$TOC_FILE = '';

# --frames
# if the value is true, HTML 4.0 "frames" are used. 
# A file describing the frame layout is generated, together with a file 
# with the short table of contents.
$FRAMES = 0;

# --menu | --no-menu
# if the value is true the Texinfo menus are shown.
# this is defined in all the formats
$SHOW_MENU = 1;

# --use-nodes
# if this is set the nodes are used as sectioning elements. 
# Otherwise the nodes are incorporated in sections.
$USE_NODES = 1;

# --node-files
# if this is set one file per node is generated, which can be a target for 
# cross manual references.
$NODE_FILES = 0;

# --toc-links
# if this is set, links from headings to toc entries are created.
$TOC_LINKS = 0;

# --subdir
# If this is set, then put result files into the specified directory.
# If not set, then result files are put into the current directory.
#$SUBDIR = 'html';
$SUBDIR = '';

# --short-extn
# If this is set, then all HTML files will have extension ".htm" instead of
# ".html". This is helpful when shipping the document to DOS-based systems.
$SHORTEXTN = 0;

# --prefix
# This set the output file prefix, prepended to all .html, .gif and .pl files.
# By default, this is the basename of the document.
$PREFIX = '';

# --short-ref
# if this is set cross-references are given without section.
$SHORT_REF = 1;

# --idx-sum
# if value is set, then for each @printindex <index name>
# <document name>_<index name>.idx is created which contains lines of the form
# key ref sorted alphabetically (case matters).
$IDX_SUMMARY = 0;

# --def-table
# If this is set a table construction for @def.... instead of definition 
# lists.
# (New Option: 27.07.2000 Karl Heinz Marbaise)
$DEF_TABLE = 0;

# --verbose
# if this is set chatter about what we are doing.
$VERBOSE = '';

# --ignore-preamble-text
# If this is set the text before @node and sectioning commands is ignored.
$IGNORE_PREAMBLE_TEXT = 0;

# --html-xref-prefix
# base directory for external manuals.
#$EXTERNAL_DIR = '../';
$EXTERNAL_DIR = undef;

# --l2h
# if this is set, latex2html is used for generation of math content.
$L2H = '';

# --monolithic
# output only one file including ToC. It only makes sense when not split
$MONOLITHIC = 1;

######################
# The following options are only relevant if $L2H is set
#
# --l2h-l2h
# name/location of latex2html program
$L2H_L2H = "latex2html";

# --l2h-skip
# If this is set the actual call to latex2html is skipped. The previously
# generated content is reused, instead.
# If set to 0, the cache is not used.
# If undef the cache is used for as many tex fragments as possible
# and for the remaining the command is run.
$L2H_SKIP = undef;

# --l2h-tmp
# If this is set l2h uses the specified directory for temporary files. The path
# leading to this directory may not contain a dot (i.e., a ".");
# otherwise, l2h will fail.
$L2H_TMP = '';
 
# --l2h-file
# If set, l2h uses the file as latex2html init file
$L2H_FILE = 'l2h.init';

# --l2h-clean
# if this is set the intermediate files generated by texi2html in relation with
# latex2html are cleaned (they all have the prefix <document name>_l2h_).
$L2H_CLEAN = 1;

##############################################################################
#
# The following can only be set in the init file
#
##############################################################################

@INPUT_FILE_SUFFIXES = ('.txi','.texinfo','.texi','.txinfo','');

$FIRSTPARAGRAPHINDENT = 'none';

@T2H_FORMAT_EXPAND = ('plaintext');

# simple headers formatting, not in a table and using node names.
$HEADER_IN_TABLE = 0;

# output the generation date in the header.
$DATE_IN_HEADER = 0;

# use table for indentation of complex formats
$COMPLEX_FORMAT_IN_TABLE = 0;

# if set, node names are used to construct file names
# if undef, it is set if split at node, or $NODE_FILES is set.
$NODE_FILENAMES = undef;

# If true do table of contents even if there is no @content
$CONTENTS = undef;

# If true do short table of contents even if there is no @shortcontent
$SHORTCONTENTS = undef;

# set by @setcontentsaftertitlepage/@setshortcontentsaftertitlepage
$SETCONTENTSAFTERTITLEPAGE = undef;
$SETSHORTCONTENTSAFTERTITLEPAGE = undef;

# corresponds with @kbdinputstyle
$KBDINPUTSTYLE = 'distinct';

# corresponds with @frenchspacing
$FRENCHSPACING = 'off';

# correspond with @allowcodebreaks
$ALLOWCODEBREAKS = 'true';

# corresponds with @setfilename. Set with caution.
$SETFILENAME = undef;

# if unset, don't show a title
$SHOW_TITLE = 1;

# if set style is added in attribute.
$INLINE_CSS_STYLE = 0;

# if set, no css is used.
$NO_CSS = 0;

# if set, the image files are completed to be relative from the
# document directory, to the source manual directory and then to
# the image
$COMPLETE_IMAGE_PATHS = 0;

# if true, begin outputting at @setfilename, if this command is present.
$IGNORE_BEFORE_SETFILENAME = 1;

# if true the link in Overview link to the corresponding Toc entry.
$OVERVIEW_LINK_TO_TOC = 1;

# if set, use node anchors for sections targets
$USE_NODE_TARGET = 1;

# new style for crossrefs
$NEW_CROSSREF_STYLE = 1;

# top heading is always at the beginning of the element.
$TOP_HEADING_AT_BEGINNING = 0;

# use titlepage for the title instead of a simplest title
$USE_TITLEPAGE_FOR_TITLE = 0;

# if set, center @image by default
# otherwise, do not center by default
# Deprecated and not used anymore
$CENTER_IMAGE = 1;

# used as identation for block enclosing command @example, etc
# If not empty, must be enclosed in <td></td>
$EXAMPLE_INDENT_CELL = '';

# same as above, only for @small
$SMALL_EXAMPLE_INDENT_CELL = '';

# unused
$SMALL_FONT_SIZE = '-1';

# horizontal rules
# not used
$SMALL_RULE = '';
$MIDDLE_RULE = '';
# used in html
$DEFAULT_RULE = '';
$BIG_RULE = '';

# output the program name in the footer
$PROGRAM_NAME_IN_FOOTER = 0;

# if non-empty, and no @..heading appeared in Top node, then
# use this as header for top node/section, otherwise use value of
# @settitle or @shorttitle (in that order)
$TOP_HEADING = '';

# if set, use this chapter for 'Index' button, else
# use first chapter with @printindex
$INDEX_CHAPTER = '';

$SIMPLE_MENU = 1;

$OPEN_QUOTE_SYMBOL = "\`";
$CLOSE_QUOTE_SYMBOL = "'";

$NO_NUMBER_FOOTNOTE_SYMBOL = '*';

# if true put a $MENU_SYMBOL before unnumbered in menus
$UNNUMBERED_SYMBOL_IN_MENU = 0;

# extension for nodes files when NODE_FILES is true
$NODE_FILE_EXTENSION = 'txt';	    

# extension
$EXTENSION = 'txt';

# file name used for Top node when NODE_FILES is true
#$TOP_NODE_FILE = 'index';
$TOP_NODE_FILE = undef;

# file name used for Top node in references
$TOP_NODE_FILE_TARGET = 'index';

# file used as document basename, when input file is -
$STDIN_DOCU_NAME = 'stdin';

# file used as document output basename, when output file is -
$STDOUT_DOCU_NAME = 'stdout';

# node name used for Top node when automatic node directions are used
$TOP_NODE_UP = '(dir)';

# this controls the pre style for menus
$MENU_PRE_STYLE = 'font-family: serif';

# on bug-texinfo is has been said the the style is not code_style
# for menus (except for the node name).
# this controls the menu preformatted format
# FIXME this is not dynamic, so change in MENU_PRE_STYLE is not taken 
# into account.
# This is used if the menu appears within a preformatted format (which
# is certainly an invalid construct), and SIMPLE_MENU is not set.
$MENU_PRE_COMPLEX_FORMAT = {
              'class' => 'menu-preformatted',
#              'style' => 'code'
   };

# This controls the ul style for toc
$NO_BULLET_LIST_STYLE = '';
$NO_BULLET_LIST_ATTRIBUTE = '';

# These lines are inserted before and after the shortcontents 
$BEFORE_OVERVIEW = "";
$AFTER_OVERVIEW = "";

# These lines are inserted before and after the contents 
$BEFORE_TOC_LINES = "";
$AFTER_TOC_LINES = "";

# if set (e.g., to index.html) replace hrefs to this file
# (i.e., to index.html) by ./
# Obsolete. Worked around a bug that is fixed now.
$HREF_DIR_INSTEAD_FILE = '';

# text inserted after <body ...>
$AFTER_BODY_OPEN = '';

# text inserted before </body>, this will be automatically inside <p></p>
$PRE_BODY_CLOSE = '';

# this is added inside <head></head> after <title> and some <meta name>
# stuff, it can be used for eg. <style>, <script>, <meta> etc. tags.
$EXTRA_HEAD = '';

# Specifies the minimum page length required before a navigation panel
# is placed at the bottom of a page 
# FIXME this is not true:
# THIS_WORDS_IN_PAGE holds number of words of current page
$WORDS_IN_PAGE = 300;

# if this is set a vertical navigation panel is used.
$VERTICAL_HEAD_NAVIGATION = 0;

# html version for latex2html
$L2H_HTML_VERSION = "4.0";

# use icons.
$ICONS = 0;

# use old framework for translations
$I18N_PERL_HASH = 0;


# this resets some defaults, those that are also set in formats and
# not set in every formats.
#
# this is called below after %default_style_map_texi is defined
sub t2h_default_set_variables_default()
{
  $CAPTION_STYLE = 'strong';

# if this variable is true, @setfilename is used if found to determine the
# out file name
  $USE_SETFILENAME = 1;

# if true, use the filename and extension from setfilename. For Info.
  $USE_SETFILENAME_EXTENSION = 0;

# FIXME is this right?
# default used in init_out for the setting of the ENCODING_NAME variable
  $DEFAULT_ENCODING = 'utf8';

# if set and menu entry equals menu description, then do not print 
# menu description.
# Likewise, if node name equals entry name, do not print entry name.
  $AVOID_MENU_REDUNDANCY = 0;

# if true, use the original command if the result is an entity
  $ENABLE_ENCODING_USE_ENTITY = 0;

# if set, output the contents where the command is located
# This is ignored if set*contentsaftertitlepage is set
  $INLINE_CONTENTS = 1;

# symbol put at the beginning of nodes entry in menu (and optionnaly of 
# unnumbered in menus, see UNNUMBERED_SYMBOL_IN_MENU variable)
  $MENU_SYMBOL = '*';

# symbol put at the end of nodes entry in menu
  $MENU_ENTRY_COLON = ':';

# symbol put at the end of index entries
  $INDEX_ENTRY_COLON = ':';

# if set, then use node names in menu entries, instead of section names
  $NODE_NAME_IN_MENU = 1;

# if set use the node names in index entry, instead of section names
# if not set, it is set to the same value than NODE_NAME_IN_MENU
  $NODE_NAME_IN_INDEX = undef;

# if set always separate description and menu link, even in 
# preformatted environment
  $SEPARATE_DESCRIPTION = 0;

# try up sections to complete the node directions
  $USE_UP_FOR_ADJACENT_NODES = 0;

# use accesskey in hrefs
  $USE_ACCESSKEY = 1;

# use rel= and rev= in hrefs. Currently only rel is used
  $USE_REL_REV = 1;

# generate <link> elements in head
  $USE_LINKS = 1;

# if this variable is true, numeric entities are used when there is no
# corresponding textual entity.
  $USE_NUMERIC_ENTITY = 0;

# if set and $SPLIT is set, then split index pages at the next letter
# after they have more than that many entries
  $SPLIT_INDEX = 0;

# file name used for Top node when NODE_FILES is true
  $TOP_NODE_FILE = undef;

# extensions used for images
  @IMAGE_EXTENSIONS = ('png','jpg', 'txt');

  $USE_NODES = 1;

  $USE_SECTIONS = 1;

# also set by command line options
  $FOOTNOTESTYLE = 'end';

  $DOCTYPE = '';

  $USE_ISO = 0;

  $NUMBER_SECTIONS = 1;
  
  $TOP_FILE = '';

  $ENABLE_ENCODING = 0;

#
# Formatting functions
#
# They will be reset here between formats switch
# if they are defined in this function.
#

# these are more or less the documented vanilla versions, so they
# are reset
$unknown           = \&t2h_default_unknown;
$unknown_style     = \&t2h_default_unknown_style;
$external_ref      = \&t2h_default_external_ref;
$internal_ref      = \&t2h_default_internal_ref;
$tab_item_texi     = \&t2h_default_tab_item_texi;
$complex_format    = \&t2h_default_complex_format;
$toc_body          = \&T2H_DEFAULT_toc_body;
$misc_command_line = \&t2h_default_misc_command_line;
$misc_command_line_texi = \&t2h_default_misc_command_line;
$print_title               = \&T2H_DEFAULT_print_title;
# reset in info and xml
$element_heading = \&t2h_default_element_heading;
# reset in html
$inline_contents    = \&T2H_DEFAULT_inline_contents;
# reset in docbook and info.
$style                    = \&T2H_GPL_style;
$format                   = \&T2H_GPL_format;
# reset in info
$simple_command             = \&t2h_default_simple_command;
# reset in info
$thing_command              = \&t2h_default_thing_command;
# reset in html and xml
$caption_shortcaption     = \&t2h_default_caption_shortcaption;
$caption_shortcaption_command  = \&t2h_default_caption_shortcaption_command;
# reset in docbook and xml. Not really vanilla, but documented.
$printindex        = \&t2h_GPL_default_printindex;
# reset by xml and html
$misc_element_label         = \&t2h_default_misc_element_label;
# set in html
$init_out    = \&t2h_default_init_out;
# set in info and xml
$paragraph_style_command  = \&t2h_default_paragraph_style_command;
# set in info
$colon_command            = \&t2h_default_colon_command;
# set in docbook
$quotation_prepend_text   = \&t2h_default_quotation_prepend_text;
# set in info
$copying_comment = \&t2h_default_copying_comment;

# set in html and info
$print_section            = \&T2H_DEFAULT_print_section;

# set in docbook and xml
%colon_command_punctuation_characters = (
   '.' => '.',
   ':' => ':',
   '?' => '?',
   '!' => '!'
);



# in info
$footnote_texi = undef;
$begin_paragraph_texi = undef;
$begin_style_texi = undef;
$begin_special_region = undef;
$end_special_region = undef;
$empty_preformatted = undef;

%line_command_map = (
       'title'    => '',
       'subtitle' => '',
       'author'   => '',
);

%format_in_paragraph = (
);
# map mapping css specification to style

%css_map = 
     (
     );

@text_substitutions_normal = ();
@text_substitutions_texi = ();
@text_substitutions_simple_format = ();
@text_substitutions_pre = ();

%region_formats_kept = ();

%style_map_texi = ();
t2h_default_copy_style_map (\%default_style_map_texi, \%style_map_texi);

# reset in info
%simple_map_texi = %default_simple_map;

# modified in docbook
%special_accents = (
      'ringaccent' => 'aA',
      "'"          => 'aeiouyAEIOUY',
      ','          => 'cC',
      '^'          => 'aeiouAEIOU',
      '`'          => 'aeiouAEIOU',
      '~'          => 'nNaoAO',
      '"'          => 'aeiouyAEIOU',
# according to http://www2.lib.virginia.edu/small/vhp/download/ISO.txt
# however this doesn't seems to work in firefox
#      'ogonek'     => 'aeiuAEIU',
);

# modified by info, xml, docbook
# %no_paragraph_commands should not be reset since it has been 
# filled with defaults for many other commands.

# FIXME this prevents the user from setting those entries.
$no_paragraph_commands{'cindex'} = 1;
$no_paragraph_commands{'float'} = 1;
delete $no_paragraph_commands{'anchor'};

# modified in docbook and xml
%stop_paragraph_command = (
 'titlefont' => 1,
 'insertcopying' => 1,
 'sp' => 1,
 'verbatiminclude' => 1,
 'page' => 1,
# FIXME they also stop preformatted, so cannot be here.
# 'printindex' => 1,
# 'listoffloats' => 1
);

}

sub t2h_default_raw_text_load()
{
  $SPLIT = '';
  # extension for nodes files when NODE_FILES is true
  $NODE_FILE_EXTENSION = 'txt';	    

  # extension
  $EXTENSION = 'txt';
  @T2H_FORMAT_EXPAND = ('plaintext');
  $USE_TITLEPAGE_FOR_TITLE = 0;
  $HEADERS = 0;
  $SIMPLE_MENU = 1;
  $INLINE_INSERTCOPYING = 0;
  $NODE_FILENAMES = undef;

  %simple_map = %default_simple_map;
  %simple_map_pre = %simple_map;

  %things_map = %default_things_map;
  %pre_map = %things_map;

  %style_map = ();
  %style_map_pre = ();
  t2h_default_copy_style_map (\%default_style_map, \%style_map);
  t2h_default_copy_style_map (\%default_style_map_pre, \%style_map_pre);

  # could also be t2h_default_set_iso_symbols()
  t2h_remove_text_substitutions("'", 1, 0, 0, 1);
  t2h_remove_text_substitutions('`', 1, 0, 0, 1);
  $OPEN_QUOTE_SYMBOL = '`';
  $CLOSE_QUOTE_SYMBOL = "'";

  $BEFORE_OVERVIEW = "";
  $AFTER_OVERVIEW = "";

  $BEFORE_TOC_LINES = "";
  $AFTER_TOC_LINES = "";


  foreach my $complex_format ('example', 'smallexample', 'display',
  'smalldisplay', 'lisp', 'smalllisp', 'format', 'smallformat',
  'menu', 'detailmenu', 'direntry', 'menu_comment')
  {
    $complex_format_map{$complex_format}->{'begin'} = '';
    $complex_format_map{$complex_format}->{'end'} = '';
  }

  %format_map = (
#       'quotation'   =>  'blockquote',
       # lists
#       'itemize'     =>  'ul',
       'enumerate'   =>  '',
#       'multitable'  =>  'table',
       'table'       =>  '',
       'vtable'      =>  '',
       'ftable'      =>  '',
       'group'       =>  '',
       'raggedright'       =>  '',
#       'detailmenu'  =>  '',
       );

  #
  # Controls the layout
  #

  $print_page_head              = \&T2H_DEFAULT_print_page_head;
  $contents                 = \&T2H_DEFAULT_contents;
  $shortcontents            = \&T2H_DEFAULT_shortcontents;
  $one_section              = \&T2H_DEFAULT_one_section;
  $print_Top                = \&T2H_DEFAULT_print_Top;
  $print_Top_footer             = \&T2H_DEFAULT_print_Top_footer;
  $print_misc_header            = \&T2H_DEFAULT_print_misc_header;
  $print_misc_footer            = \&T2H_DEFAULT_print_misc_footer;
  $print_section_footer     = \&T2H_DEFAULT_print_section_footer;
  $print_chapter_header     = \&T2H_DEFAULT_print_chapter_header;
  $print_section_header     = \&T2H_DEFAULT_print_section_header;
  $print_chapter_footer     = \&T2H_DEFAULT_print_chapter_footer;
  $print_page_foot              = \&T2H_DEFAULT_print_page_foot;
  $print_head_navigation    = \&T2H_DEFAULT_print_head_navigation;
  $print_foot_navigation    = \&T2H_DEFAULT_print_foot_navigation;
  $end_section              = \&T2H_DEFAULT_end_section;
  # changed in info
  $print_Footnotes              = \&T2H_DEFAULT_print_Footnotes;
  # used if split
  $about_body                 = \&T2H_DEFAULT_about_body;
  $print_navigation           = \&T2H_DEFAULT_print_navigation;

  #
  # Controls the formatting
  #

  $empty_line               = \&t2h_default_empty_line;
  $anchor            = \&t2h_default_anchor;
  $anchor_label               = \&t2h_default_anchor_label;
  $image             = \&t2h_default_image;
  $heading           = \&t2h_default_heading;
  $heading_text      = \&t2h_default_heading_text;
  $heading_text_preformatted      = \&t2h_default_heading_text_preformatted;
  $element_label              = \&t2h_default_element_label;
  $index_entry_label = \&t2h_default_index_entry_label;
  #$menu_command      = \&t2h_default_menu_command;
  $menu_link         = \&t2h_default_menu_link;
  #$menu_description  = \&t2h_default_menu_description;
  $paragraph         = \&t2h_default_paragraph;
  $preformatted      = \&t2h_default_preformatted;
  $protect_text      = \&t2h_default_protect_text;
  $normal_text       = \&t2h_default_normal_text;
  $acronym_like             = \&t2h_default_acronym_like;
  $sp                = \&t2h_default_sp;
  $quotation                = \&t2h_default_quotation;
  $table_list        = \&t2h_default_table_list;
  $list_item         = \&t2h_default_list_item;
  $table_line        = \&t2h_default_table_line;
  $table_item        = \&t2h_default_table_item;
  $cell              = \&t2h_default_cell;
  $row               = \&t2h_default_row;
  $def_item          = \&t2h_default_def_item;
  $def               = \&t2h_default_def;
  $def_line          = \&t2h_default_def_line;
  $cartouche         = \&t2h_default_cartouche;
  $raw               = \&t2h_default_raw;
  $format_list_item_texi      = \&t2h_default_format_list_item_texi;
  $print_index       = \&t2h_default_print_index;
  $index_summary     = \&t2h_default_index_summary;
  $index_entry       = \&t2h_default_index_entry;
  $index_letter      = \&t2h_default_index_letter;
  $foot_line_and_ref = \&t2h_default_foot_line_and_ref;
  $foot_section      = \&t2h_default_foot_section;
  $tab_item_texi     = \&t2h_default_tab_item_texi;
  $listoffloats             = \&t2h_default_listoffloats;
  $listoffloats_entry       = \&t2h_default_listoffloats_entry;
  $float                     = \&t2h_default_float;

  t2h_default_set_variables_default();
}

my %things_map_xml;
my %pre_map_xml;

sub t2h_default_set_variables_xml()
{
  t2h_default_set_variables_default();
  $ENABLE_ENCODING_USE_ENTITY = 1;
  $EXTENSION = 'xml';
  t2h_default_set_iso_symbols(1);

  $empty_line = \&t2h_default_empty_line;
  $comment = \&xml_default_comment;
  $line_command = \&xml_default_line_command;
 
  %things_map = %things_map_xml;
  %pre_map = %pre_map_xml;
  %simple_format_texi_map = %pre_map;

  %simple_format_style_map_texi = ();
  t2h_default_copy_style_map (\%default_style_map_texi, \%simple_format_style_map_texi);
  foreach my $accent_command ('tieaccent', 'dotless', keys(%unicode_accents))
  {
#    $simple_format_style_map_texi{$accent_command}->{'args'} = ['normal'];
    $simple_format_style_map_texi{$accent_command}->{'function'} = \&xml_default_accent;
  }
}

sub t2h_default_set_variables_texi2html()
{
  $USE_SETFILENAME = 0;
  $USE_SETFILENAME_EXTENSION = 0;
  $FOOTNOTESTYLE = 'separate';
  $INLINE_CONTENTS = 0;
  $FORCE = 1;
  $AVOID_MENU_REDUNDANCY = 1;
  $TOP_HEADING_AT_BEGINNING = 1;
  $TOP_FILE = '';
  $USE_ACCESSKEY = 0;
  $NODE_NAME_IN_MENU = 0;
  $OVERVIEW_LINK_TO_TOC = 0;
  $USE_UP_FOR_ADJACENT_NODES = 1;
  $USE_ACCESSKEY = 0;
  $USE_REL_REV = 0;
  $USE_LINKS = 0;
  $USE_NODES = undef;
  $USE_SECTIONS = 1;
  $NODE_FILENAMES = 0;
  $USE_NUMERIC_ENTITY = 1;
  $SPLIT = '';
  $SPLIT_INDEX = 100;
  $PROGRAM_NAME_IN_FOOTER = 1;
  $HEADER_IN_TABLE = 1;
  $SHORT_REF = 0;
  $USE_TITLEPAGE_FOR_TITLE = 1;
  $MENU_ENTRY_COLON = '';
  $INDEX_ENTRY_COLON = '';

  $ENABLE_ENCODING_USE_ENTITY = 1;
}

# specify in this array which "buttons" should appear in which order
# in the navigation panel for sections; use ' ' for empty buttons (space)
@SECTION_BUTTONS =
    (
     'FastBack', 'Back', 'Up', 'Forward', 'FastForward',
     ' ', ' ', ' ', ' ',
     'Top', 'Contents', 'Index', 'About',
    );

# buttons for misc stuff
@MISC_BUTTONS = ('Top', 'Contents', 'Index', 'About');

@TOP_BUTTONS = ( 'Back', 'Forward', ' ','Contents', 'Index', 'About');
#@TOP_BUTTONS = ('Top', 'Contents', 'Index', 'About');


# buttons for chapter file footers
# (and headers but only if HEADERS is false)
@CHAPTER_BUTTONS =
    (
     'FastBack', 'FastForward', ' ',
     ' ', ' ', ' ', ' ',
     'Top', 'Contents', 'Index', 'About',
    );

# buttons for section file footers
@SECTION_FOOTER_BUTTONS =
    (
     'FastBack', 'Back', 'Up', 'Forward', 'FastForward',
    );

@NODE_FOOTER_BUTTONS = @SECTION_BUTTONS;

@LINKS_BUTTONS =
    (
      'Top', 'Index', 'Contents', 'About', 'Up', 'NextFile', 'PrevFile'
    );


# insert here name of icon images for buttons
# Icons are used, if $ICONS and resp. value are set
%ACTIVE_ICONS =
    (
     'Top',         '',
     'Contents',    '',
     'Overview',    '',
     'Index',       '',
     'This',        '',
     'Back',        '',
     'FastBack',    '',
     'Prev',        '',
     'Up',          '',
     'Next',        '',
     'NodeUp',      '',
     'NodeNext',    '',
     'NodePrev',    '',
     'Following',   '',
     'Forward',     '',
     'FastForward', '',
     'About' ,      '',
     'First',       '',
     'Last',        '',
     'NextFile',    '',
     'PrevFile',    '',
     ' ',           '',
    );

# insert here name of icon images for these, if button is inactive
%PASSIVE_ICONS =
    (
     'Top',         '',
     'Contents',    '',
     'Overview',    '',
     'Index',       '',
     'This',        '',
     'Back',        '',
     'FastBack',    '',
     'Prev',        '',
     'Up',          '',
     'Next',        '',
     'NodeUp',      '',
     'NodeNext',    '',
     'NodePrev',    '',
     'Following',   '',
     'Forward',     '',
     'FastForward', '',
     'About',       '',
     'First',       '',
     'Last',        '',
     'NextFile',    '',
     'PrevFile',    '',
    );

%misc_pages_targets = (
   'Overview' => 'SEC_Overview',
   'Contents' => 'SEC_Contents',
   'Footnotes' => 'SEC_Foot',
   'About' => 'SEC_About'
);

# determine the null devices
my $default_null_device = File::Spec->devnull();
%null_device_file = (
 $default_null_device => 1
);
# special case, djgpp recognizes both null devices
if ($Config{osname} eq 'dos' and $Config{osvers} eq 'djgpp')
{
  $null_device_file{'/dev/null'} = 1;
  $null_device_file{'NUL'} = 1;
}

$finish_out    = \&t2h_default_finish_out;
$translate_names = \&t2h_default_translate_names;

sub t2h_default_translate_names()
{
# Names of text as alternative for icons
# FIXME maybe get those in simple_format?
    %NAVIGATION_TEXT =
    (
     'Top',         gdt('Top'),
     'Contents',    gdt('Contents'),
     'Overview',    gdt('Overview'),
     'Index',       gdt('Index'),
     ' ',           ' ',
     'This',        gdt('Current'),
     'Back',        ' < ',
     'FastBack',    ' << ',
     'Prev',        gdt('Previous'),
     'Up',          gdt('Up'),
     'Next',        gdt('Next'),
     'NodeUp',      gdt('Up'),
     'NodeNext',    gdt('Next'),
     'NodePrev',    gdt('Previous'),
     'Following',   gdt('Following'),
     'Forward',     ' > ',
     'FastForward', ' >> ',
     'About',       ' ? ',
     'First',       ' |< ',
     'Last',        ' >| ',
     'NextFile',    gdt('Next file'),
     'PrevFile',    gdt('Previous file'),
    );
    %BUTTONS_TEXT = %NAVIGATION_TEXT;

    %BUTTONS_GOTO =
    (
     'Top',         gdt('Cover (top) of document'),
     'Contents',    gdt('Table of contents'),
     'Overview',    gdt('Short table of contents'),
     'Index',       gdt('Index'),
     'This',        gdt('Current section'),
     'Back',        gdt('Previous section in reading order'),
     'FastBack',    gdt('Beginning of this chapter or previous chapter'),
     'Prev',        gdt('Previous section on same level'),
     'Up',          gdt('Up section'),
     'Next',        gdt('Next section on same level'),
     'NodeUp',      gdt('Up node'),
     'NodeNext',    gdt('Next node'),
     'NodePrev',    gdt('Previous node'),
     'Following',   gdt('Node following in node reading order'),
     'Forward',     gdt('Next section in reading order'),
     'FastForward', gdt('Next chapter'),
     'About' ,      gdt('About (help)'),
     'First',       gdt('First section in reading order'),
     'Last',        gdt('Last section in reading order'),
     'NextFile',    gdt('Forward section in next file'),
     'PrevFile',    gdt('Back section in previous file'),
    );

    %BUTTONS_NAME =
    (
     'Top',         gdt('Top'),
     'Contents',    gdt('Contents'),
     'Overview',    gdt('Overview'),
     'Index',       gdt('Index'),
     ' ',           ' ',
     'This',        gdt('This'),
     'Back',        gdt('Back'),
     'FastBack',    gdt('FastBack'),
     'Prev',        gdt('Prev'),
     'Up',          gdt('Up'),
     'Next',        gdt('Next'),
     'NodeUp',      gdt('NodeUp'),
     'NodeNext',    gdt('NodeNext'),
     'NodePrev',    gdt('NodePrev'),
     'Following',   gdt('Following'),
     'Forward',     gdt('Forward'),
     'FastForward', gdt('FastForward'),
     'About',       gdt('About'),
     'First',       gdt('First'),
     'Last',        gdt('Last'),
     'NextFile',    gdt('NextFile'),
     'PrevFile',    gdt('PrevFile'),
    );

}

sub t2h_default_set_iso_symbols($)
{
    my $value = shift;
    $USE_ISO = $value;
    if ($value)
    {
       foreach my $association ([\%things_map, \%things_map_xml],
                         [\%pre_map, \%pre_map_xml],
                        [\%simple_format_simple_map_texi, \%pre_map_xml])
       {
          foreach my $thing (keys(%{$association->[0]}))
          {
              if (defined($association->[0]->{$thing}) and $association->[0]->{$thing} !~ /^\&\w+\;$/ and defined($association->[1]->{$thing}) and $association->[1]->{$thing} =~ /^\&\w+\;$/)
              {
                  $association->[0]->{$thing} = $association->[1]->{$thing};
              }
          }
       }
       t2h_add_text_substitutions(["'", '&rsquo;'], 1, 0, 0, 1);
       t2h_add_text_substitutions(['`', '&lsquo;'], 1, 0, 0, 1);
       $OPEN_QUOTE_SYMBOL = '&lsquo;';
       $CLOSE_QUOTE_SYMBOL = '&rsquo;';
    }
    else
    {
       foreach my $association ([\%things_map, \%default_things_map],
                         [\%pre_map, \%default_things_map],
                        [\%simple_format_simple_map_texi, \%default_things_map])
       {
          foreach my $thing (keys(%{$association->[0]}))
          {
              if (defined($association->[0]->{$thing}) and $association->[0]->{$thing} =~ /^\&\w+\;$/ and defined($association->[1]->{$thing}) and $association->[1]->{$thing} !~ /^\&\w+\;$/)
              {
                  $association->[0]->{$thing} = &$protect_text($association->[1]->{$thing});
              }
          }
       }
       t2h_remove_text_substitutions("'", 1, 0, 0, 1);
       t2h_remove_text_substitutions('`', 1, 0, 0, 1);
       $OPEN_QUOTE_SYMBOL = '`';
       $CLOSE_QUOTE_SYMBOL = "'";
    }
}

# is used in main program for dumping texi too.
sub t2h_default_set_out_encoding()
{
    # these variables are used for the corresponding 
    # $Texi2HTML::THISDOC{'*_ENCODING'} to keep code shorter
    my ($out_encoding, $encoding_name, $document_encoding);

    $document_encoding = get_conf('DOCUMENT_ENCODING');

    if (defined($OUT_ENCODING))
    {
        $out_encoding = $OUT_ENCODING;
    }

    if (defined($ENCODING_NAME))
    {
        $encoding_name = $ENCODING_NAME;
    }

    if (!defined($out_encoding) and (defined($encoding_name)))
    {
        my $possible_out_encoding = main::encoding_alias ($encoding_name, undef, 'determining encoding from default encoding');
        $out_encoding = $possible_out_encoding if (defined($possible_out_encoding));
    }
    if (!defined($out_encoding) and (defined(get_conf('IN_ENCODING'))))
    {
        $out_encoding = get_conf('IN_ENCODING');
    }
    if (!defined($out_encoding) and (defined($document_encoding)))
    {
        my $possible_out_encoding = main::encoding_alias ($document_encoding, undef, 'determining encoding from documentencoding');
        $out_encoding = $possible_out_encoding if (defined($possible_out_encoding));
    }

    if (!defined($encoding_name))
    {
         if (defined($out_encoding) and defined($perl_charset_to_html{$out_encoding}))
         {
             $encoding_name = $perl_charset_to_html{$out_encoding};
         }
         elsif (defined(get_conf('IN_ENCODING')) and defined($perl_charset_to_html{get_conf('IN_ENCODING')}))
         {
             $encoding_name = $perl_charset_to_html{get_conf('IN_ENCODING')};
         }
         elsif (defined($document_encoding) and defined($perl_charset_to_html{$document_encoding}))
         {
             $encoding_name = $perl_charset_to_html{$document_encoding};
         }
         elsif (defined($out_encoding))
         {
             $encoding_name = $out_encoding;
         }
         elsif (defined(get_conf('IN_ENCODING')))
         {
             $encoding_name = get_conf('IN_ENCODING');
         }
         elsif (defined($document_encoding))
         {
             $encoding_name = $document_encoding;
         }
         elsif (defined($perl_charset_to_html{$DEFAULT_ENCODING}))
         {
             $encoding_name = $perl_charset_to_html{$DEFAULT_ENCODING};
         }
         else
         {
             $encoding_name = 'us-ascii';
         }
    }

    $Texi2HTML::THISDOC{'OUT_ENCODING'} = $out_encoding;
    $Texi2HTML::THISDOC{'ENCODING_NAME'} = $encoding_name;

    $out_encoding = 'UNDEF' if (!defined($out_encoding));
    my $in_encoding = get_conf('IN_ENCODING');
    $in_encoding = 'UNDEF' if (!defined($in_encoding));
    $document_encoding = 'UNDEF' if (!defined($document_encoding));
    print STDERR "# Encodings: doc $document_encoding, in $in_encoding out $out_encoding, name $encoding_name\n" if ($VERBOSE);
}

sub t2h_default_init_out()
{
    &$translate_names;
    # set external cross ref splitting like splitting.
    if (!defined($EXTERNAL_CROSSREF_SPLIT))
    {
        if (get_conf('SPLIT')) 
        {
            $Texi2HTML::THISDOC{'EXTERNAL_CROSSREF_SPLIT'} = 1;
        }
        else
        {
            $Texi2HTML::THISDOC{'EXTERNAL_CROSSREF_SPLIT'} = 0;
        }
    }
    else
    {
        $Texi2HTML::THISDOC{'EXTERNAL_CROSSREF_SPLIT'} = $EXTERNAL_CROSSREF_SPLIT;
    }

    
}

my %t2h_default_formats_load_table = (
  'html' => \&html_default_load,
  'info' => \&info_default_load,
  'docbook' => \&docbook_default_load,
  'xml' => \&xml_default_load,
  'plaintext' => \&plaintext_default_load,
  'raw-text' => \&t2h_default_raw_text_load,
);

sub t2h_default_load_format($;$)
{
  my $format = shift;
  my $from_command_line = shift;
  if (defined($t2h_default_formats_load_table{$format}))
  {
     $OUTPUT_FORMAT = $format;
     &{$t2h_default_formats_load_table{$format}}($from_command_line);
     $Texi2HTML::THISDOC{'format_from_command_line'} = $format if ($from_command_line);
     return 1;
  }
  else
  {
     return 0;
  }
}

sub t2h_encoding_is_entity($)
{
  my $text = shift;
  return 0 if (!$ENABLE_ENCODING_USE_ENTITY);
  return 1 if ($text =~ /^&/ and $text =~ /;$/);
}

# this is for info.init
use vars qw(%t2h_enable_encoding_default_accent);
my @t2h_enable_encoding_accents_stack;
my %t2h_enable_encoding_default_commands;

sub t2h_enable_encoding_load()
{
   t2h_default_push_handler(\&t2h_enable_encoding_init, \@command_handler_names);
   t2h_default_push_handler(\&t2h_enable_encoding_finish, \@command_handler_finish);
   #push @command_handler_process, \&t2h_enable_encoding_init;
   #push @command_handler_finish, \&t2h_enable_encoding_finish;
   foreach my $key (keys(%unicode_accents), 'dotless')
   {
     $t2h_enable_encoding_default_accent{'normal'}->{$key} = $style_map{$key}->{'function'};
     $t2h_enable_encoding_default_accent{'texi'}->{$key} = $style_map_texi{$key}->{'function'};
     $t2h_enable_encoding_default_accent{'pre'}->{$key} = $style_map_pre{$key}->{'function'};
     $style_map{$key}->{'function'} = \&t2h_enable_encoding_normal_accent;
     $style_map_texi{$key}->{'function'} = \&t2h_enable_encoding_texi_accent;
     $style_map_pre{$key}->{'function'} = \&t2h_enable_encoding_pre_accent;
   }
   foreach my $key (%things_map)
   {
     if (exists($unicode_map{$key}) and ($unicode_map{$key} ne ''))
     {
       $t2h_enable_encoding_default_commands{'normal'}->{$key} = $things_map{$key};
       $t2h_enable_encoding_default_commands{'texi'}->{$key} = $texi_map{$key};
       $t2h_enable_encoding_default_commands{'sorting'}->{$key} = $sorting_things_map{$key};
       $t2h_enable_encoding_default_commands{'pre'}->{$key} = $pre_map{$key};
     }
   }
}

sub t2h_enable_encoding_finish()
{
   foreach my $key (%things_map)
   {
     if (exists($unicode_map{$key}) and ($unicode_map{$key} ne ''))
     {
       $things_map{$key} = $t2h_enable_encoding_default_commands{'normal'}->{$key};
       $texi_map{$key} = $t2h_enable_encoding_default_commands{'texi'}->{$key};
       $sorting_things_map{$key} = $t2h_enable_encoding_default_commands{'sorting'}->{$key};
       $pre_map{$key} = $t2h_enable_encoding_default_commands{'pre'}->{$key}; 
     }
   }
}

sub t2h_enable_encoding_init()
{
  if ($Texi2HTML::THISDOC{'ENCODING_NAME'} eq 'utf-8')
  {
    foreach my $key (%things_map)
    {
      if (exists($unicode_map{$key}) and ($unicode_map{$key} ne ''))
      {
        $things_map{$key} = chr(hex($unicode_map{$key})) unless (t2h_encoding_is_entity($things_map{$key}));
        $texi_map{$key} = chr(hex($unicode_map{$key})) unless (t2h_encoding_is_entity($texi_map{$key}));
        $sorting_things_map{$key} = chr(hex($unicode_map{$key})) unless (t2h_encoding_is_entity($sorting_things_map{$key}));
        $pre_map{$key} = chr(hex($unicode_map{$key})) unless (t2h_encoding_is_entity($pre_map{$key}));
      }
    }
  }
  elsif (exists($makeinfo_encoding_to_map{$Texi2HTML::THISDOC{'ENCODING_NAME'}}))
  {
    my $enc_map = $makeinfo_encoding_to_map{$Texi2HTML::THISDOC{'ENCODING_NAME'}};

    foreach my $key (%things_map)
    {
      if (exists($unicode_map{$key}) and ($unicode_map{$key} ne '') and 
        exists($makeinfo_unicode_to_eight_bit{$enc_map}->{$unicode_map{$key}}))
      { # we let perl handle the conversion
        $things_map{$key} = chr(hex($unicode_map{$key})) unless (t2h_encoding_is_entity($things_map{$key}));
        $texi_map{$key} = chr(hex($unicode_map{$key})) unless (t2h_encoding_is_entity($texi_map{$key}));
        $sorting_things_map{$key} = chr(hex($unicode_map{$key})) unless (t2h_encoding_is_entity($sorting_things_map{$key}));
        $pre_map{$key} = chr(hex($unicode_map{$key})) unless (t2h_encoding_is_entity($pre_map{$key}));
      }
    }
    @t2h_enable_encoding_accents_stack = ();
  }
}

sub t2h_default_string_width($)
{
   my $string = shift;
   if ($USE_UNICODE)
   {
       my $width = 0;
       foreach my $character(split '', $string)
       {
          if ($character =~ /\p{Unicode::EastAsianWidth::InFullwidth}/)
          {
             $width += 2;
          }
          else 
          {
             $width += 1;
          }
       }
       return $width;
   }
   else
   {
       return length($string);
   }
}

sub t2h_default_finish_out()
{
}

#######################################################################
#
# Values guessed if not set here. The value used is in 
# $Texi2HTML::THISDOC{'VARNAME'}
#
#######################################################################

# In file encoding. The @documentencoding allows autodetection of 
# that variable.
$DOCUMENT_ENCODING = undef;

# In file encoding, understandable by perl. Set according to DOCUMENT_ENCODING 
$IN_ENCODING = undef;

# Formatted document encoding name. If undef, set in init_out based on 
# $OUT_ENCODING or $DOCUMENT_ENCODING if they are defined
$ENCODING_NAME = undef;

# Out files encoding, understandable by perl. If undef, set in init_out
# using $ENCODING_NAME or $IN_ENCODING if they are defined
$OUT_ENCODING = undef;

# Used to set $Texi2HTML::THISDOC{'DOCUMENT_DESCRIPTION'}.
# if undef set to @documentdescription. If there is no @documentdescription,
# set in page_head.
$DOCUMENT_DESCRIPTION = undef;

# if undef $Texi2HTML::THISDOC{'EXTERNAL_CROSSREF_SPLIT'} set 1 if SPLIT, 
# to 0 otherwise
$EXTERNAL_CROSSREF_SPLIT = undef;

$DATE = undef;


########################################################################
# Control of Page layout:
# You can make changes of the Page layout at two levels:
# 1.) For small changes, it is often enough to change the value of
#     some global string/hash/array variables
# 2.) For larger changes, reimplement one of the T2H_DEFAULT_<fnc>* routines,
#     give them another name, and assign them to the respective
#     $<fnc> variable.

# As a general interface, the hashes Texi2HTML::HREF, Texi2HTML::NAME, Texi2HTML::NODE, Texi2HTML::NO_TEXI, Texi2HTML::SIMPLE_TEXT hold
# href, html-name, node-name, name after removal of texi commands of
# This     -- current section (resp. html page)
# Top      -- top element
# Contents -- Table of contents element
# Overview -- Short table of contents element
# Index    -- Index page element
# About    -- page which explain "navigation buttons" element
# First    -- first node element
# Last     -- last node element
#
# Whether or not the following hash values are set, depends on the context
# (all values are w.r.t. 'This' section)
# Next        -- next element of texinfo
# Prev        -- previous element of texinfo
# NodeUp      -- up node of texinfo
# Following   -- following node in node reading order, taking menu into account
# Forward     -- next node in reading order
# Back        -- previous node in reading order
# Up          -- parent given by sectioning commands
# FastForward -- if leave node, up and next, else next node
# FastBackward-- if leave node, up and prev, else prev node
#
# Furthermore, the following global variabels are set:
# $Texi2HTML::THISDOC{title}          -- title as set by @title...
# $Texi2HTML::THISDOC{title_no_texi}  -- title without texi (without html elements)
# $Texi2HTML::THISDOC{title_texi}     -- title with texinfo @-commands
# $Texi2HTML::THISDOC{fulltitle}      -- full title as set by @title...
# $Texi2HTML::THISDOC{subtitle}       -- subtitle as set by @subtitle
# $Texi2HTML::THISDOC{author}         -- author as set by @author
# $Texi2HTML::THISDOC{copying_comment}  -- text of @copying and @end copying in comment
#
# $Texi2HTML::THISDOC{program}          -- name and version of texi2html
# $Texi2HTML::THISDOC{program_homepage} -- homepage for texi2html
# $Texi2HTML::THISDOC{program_authors}  -- authors of texi2html
# $Texi2HTML::THISDOC{today}            -- date formatted with pretty_date
# $Texi2HTML::THISDOC{toc_file}         -- table of contents file
# $Texi2HTML::THISDOC{file_base_name}   -- base name of the texinfo manual file
# $Texi2HTML::THISDOC{input_file_name}  -- name of the texinfo manual file
# $Texi2HTML::THISDOC{destination_directory}
                                 #      -- directory for the resulting files
# $Texi2HTML::THISDOC{user}             -- user running the script
# $Texi2HTML::THISDOC{css_import_lines} -- ref on @import lines in css files
# $Texi2HTML::THISDOC{css_rule_lines}   -- ref on css rules lines
# other $Texi2HTML::THISDOC keys corresponds with texinfo commands, the value
# being the command arg, for the following commands:
# kbdinputstyle, paragraphindent, setchapternewpage, headings, footnotestyle,
# exampleindent, firstparagraphindent, everyheading, everyfooting,
# evenheading, evenfooting, oddheading, oddfooting
#
# and pointer to arrays of lines which need to be printed by main::print_lines
# $Texi2HTML::THIS_SECTION  -- lines of 'This' section
# $Texi2HTML::OVERVIEW      -- lines of short table of contents
# $Texi2HTML::TOC_LINES     -- lines of table of contents
# $Texi2HTML::TITLEPAGE     -- lines of title page
#
# $Texi2HTML::THIS_ELEMENT  holds the element reference.  

# most of the functions are either reset when switching format, in 
# t2h_default_set_variables_default, or set in format, the simplest
# one being setup above in t2h_default_raw_text_load

#
# The following generic subs control the layout:
#
# misc element formatting functions. They are rather generic, 
# their call is controlled by other variables (separate or not
# footnotes, about_body, handling of table of contents...).
# print_Footnotes is the only to be redefined, in info
$print_Toc		      = \&T2H_DEFAULT_print_Toc;
$print_Overview	      = \&T2H_DEFAULT_print_Overview;
$print_About	      = \&T2H_DEFAULT_print_About;
$print_misc		      = \&T2H_DEFAULT_print_misc;
# generic enough (call print_page_head if needed)
$print_Top_header         = \&T2H_DEFAULT_print_Top_header;

# the following are less generic, but in case a specific format
# doesn't redefine them, the raw text functions are always defined.
$print_page_head              = \&T2H_DEFAULT_print_page_head;
$contents                 = \&T2H_DEFAULT_contents;
$shortcontents            = \&T2H_DEFAULT_shortcontents;
$one_section              = \&T2H_DEFAULT_one_section;
$print_Top                = \&T2H_DEFAULT_print_Top;
$print_Top_footer             = \&T2H_DEFAULT_print_Top_footer;
$print_misc_header            = \&T2H_DEFAULT_print_misc_header;
$print_misc_footer            = \&T2H_DEFAULT_print_misc_footer;
$print_section_footer     = \&T2H_DEFAULT_print_section_footer;
$print_chapter_header     = \&T2H_DEFAULT_print_chapter_header;
$print_section_header     = \&T2H_DEFAULT_print_section_header;
$print_chapter_footer     = \&T2H_DEFAULT_print_chapter_footer;
$print_page_foot              = \&T2H_DEFAULT_print_page_foot;
$print_head_navigation    = \&T2H_DEFAULT_print_head_navigation;
$print_foot_navigation    = \&T2H_DEFAULT_print_foot_navigation;
$end_section              = \&T2H_DEFAULT_end_section;
# changed in info
$print_Footnotes              = \&T2H_DEFAULT_print_Footnotes;
# used if split
$about_body                 = \&T2H_DEFAULT_about_body;
$print_navigation           = \&T2H_DEFAULT_print_navigation;

#
# generic formatting functions
#

$button_icon_img	      = \&T2H_DEFAULT_button_icon_img;
# not really needed nor relevant except for html
$print_frame              = \&T2H_DEFAULT_print_frame;
$print_toc_frame          = \&T2H_DEFAULT_print_toc_frame;
# generic
$titlepage                 = \&T2H_DEFAULT_titlepage;
$css_lines                 = \&T2H_DEFAULT_css_lines;
$print_redirection_page    = \&T2H_DEFAULT_print_redirection_page;
$node_file_name            = \&T2H_DEFAULT_node_file_name;
$inline_contents           = \&T2H_DEFAULT_inline_contents;
$program_string            = \&T2H_DEFAULT_program_string;
$element_file_name         = \&t2h_default_element_file_name;
 
########################################################################
# Layout for every sections
#

sub T2H_DEFAULT_print_section($$$$)
{
    my $fh = shift;
    my $first_in_page = shift;
    my $previous_is_top = shift;
    my $element = shift;

    my $nw = main::print_lines($fh);
}

sub T2H_DEFAULT_one_section($$)
{
    my $fh = shift;
    my $element = shift;
    main::print_lines($fh);
    &$print_page_foot($fh);
}

###################################################################
# Layout of top-page. It is possible to use @ifnothtml, @ifhtml,
# @html within the Top texinfo node to specify content of top-level
# page.
#
sub T2H_DEFAULT_print_Top_header($$)
{
    my $fh = shift;
    my $do_page_head = shift;
    &$print_page_head($fh) if ($do_page_head);
}
sub T2H_DEFAULT_print_Top_footer($$$)
{
    my $fh = shift;
    my $end_page = shift;
    my $element = shift;
    if ($end_page)
    {
        &$print_page_foot($fh);
    }
}

sub T2H_DEFAULT_print_Top($$$)
{
    my $fh = shift;
    my $has_top_heading = shift;
    my $element = shift;

    if ($Texi2HTML::THISDOC{'setshortcontentsaftertitlepage'})
    {
        my $shortcontents = &$inline_contents($fh, 'shortcontents');
        print $fh "".join('',@$shortcontents) if (defined($shortcontents));
    }
    if ($Texi2HTML::THISDOC{'setcontentsaftertitlepage'})
    {
        my $contents = &$inline_contents($fh, 'contents');
        print $fh "".join('',@$contents) if (defined($contents));
    }

    main::print_lines($fh, $Texi2HTML::THIS_SECTION);
}

###################################################################
# Layout of Toc, Overview, and Footnotes pages
# By default, we use "normal" layout
# Texi2HTML::HREF of Next, Prev, Up, Forward, Back, etc are not defined
# redefine \@MISC_BUTTONS to change the navigation
sub T2H_DEFAULT_print_Toc
{
    return &$print_misc(@_);
}
sub T2H_DEFAULT_print_Overview
{
    return &$print_misc(@_);
}
sub T2H_DEFAULT_print_Footnotes
{
    return &$print_misc(@_);
}
sub T2H_DEFAULT_print_About
{
    return &$print_misc(@_);
}

sub T2H_DEFAULT_print_misc_header($$$$)
{
    my $fh = shift;
    my $buttons = shift;
    my $new_file = shift;
    my $misc_page = shift;
    &$print_page_head($fh) if ($new_file);
}

sub T2H_DEFAULT_print_misc_footer($$$)
{
    my $fh = shift;
    my $buttons = shift;
    my $new_file = shift;
    if ($new_file)
    {
        &$print_page_foot($fh);
    }
}

use vars qw(
%t2h_default_underline_symbol
);

%t2h_default_underline_symbol = (
  0 => '*',
  1 => '*',
  2 => '=',
  3 => '-',
  4 => '.'
);

sub t2h_default_heading_text($$$)
{
    my $command = shift;
    my $text = shift;
    my $level = shift;

    return '' if ($text !~ /\S/);
    my $result = $text ."\n";
    # as seen in encodings/nodetest_utf8_no_unicode, the length can be in
    # bytes (certainly) when there hasn't been a require Encode
    #$result .=($t2h_default_underline_symbol{$level} x length($text))."\n";
    $result .=($t2h_default_underline_symbol{$level} x t2h_default_string_width($text))."\n";
    return $result;
}

sub t2h_default_heading_text_preformatted($$$)
{
    my $command = shift;
    my $text = shift;
    my $level = shift;

    return t2h_default_heading_text($command, $text, $level);
}

sub T2H_DEFAULT_print_misc($$$)
{
    my $fh = shift;
    my $new_file = shift;
    my $misc_page = shift;
    my $buttons = \@MISC_BUTTONS;
    &$print_misc_header($fh, $buttons, $new_file, $misc_page);
    print $fh "".&$heading_text('misc heading', $Texi2HTML::NAME{This}, 1) . "\n";
    main::print_lines($fh);
    &$print_misc_footer($fh, $buttons, $new_file);
}
##################################################################
# section_footer is only called if SPLIT eq 'section'
# section_footer: after print_section of last section, before print_page_foot
#

sub T2H_DEFAULT_print_section_footer
{
    my $fh = shift;
    my $element = shift;
}

###################################################################
# chapter_header and chapter_footer are only called if
# SPLIT eq 'chapter'
# chapter_header: after print_page_head, before print_section
# chapter_footer: after print_section of last section, before print_page_foot

sub T2H_DEFAULT_print_chapter_header
{
    my $fh = shift;
    my $element = shift;
}

sub T2H_DEFAULT_print_chapter_footer
{
    my $fh = shift;
    my $element = shift;
}

sub T2H_DEFAULT_print_section_header
{
    my $fh = shift;
}


###################################################################
# Layout of standard header and footer
#

sub T2H_DEFAULT_print_page_head($)
{
    my $fh = shift;
}

sub T2H_DEFAULT_program_string()
{
    my $date = $Texi2HTML::THISDOC{'today'};
    $date = '' if (!defined($date));
    if ($date ne '')
    {
        return gdt('This document was generated on @i{{date}} using @uref{{program_homepage}, @i{{program}}}.', {
           'date' => $date, 'program_homepage' => $Texi2HTML::THISDOC{'program_homepage'}, 'program' => $Texi2HTML::THISDOC{'program'} },{'duplicate'=>1});
    }
    return gdt('This document was generated using @uref{{program_homepage}, @emph{{program}}}.', {
       'program_homepage' => $Texi2HTML::THISDOC{'program_homepage'}, 'program'
=> $Texi2HTML::THISDOC{'program'} },{'duplicate'=>1});
}

sub T2H_DEFAULT_end_section($$$)
{
    my $fh = shift;
    my $misc_or_top_and_section_separation = shift;
    my $element = shift;
}

sub T2H_DEFAULT_print_page_foot($)
{
    my $fh = shift;
}

###################################################################
# Layout of navigation panel

sub T2H_DEFAULT_print_head_navigation($$$$$)
{
    my $fh = shift;
    my $buttons = shift;
    my $first_in_page = shift;
    my $previous_is_top = shift;
    my $element = shift;

    return '';
}

sub T2H_DEFAULT_print_foot_navigation
{
    my $fh = shift;
    my $buttons = shift;
    my $rule = shift;
    my $print_navigation_panel = shift;
    my $element = shift;

    $rule = '' if (!defined($rule));
    print $fh "$rule\n" if ($rule ne '');
}

######################################################################
# navigation panel
#
# how to create IMG tag
# this is only used in html, and only if ICONS is set and the button
# is active.
sub T2H_DEFAULT_button_icon_img
{
    my $button = shift;
    my $icon = shift;
    my $name = shift;
    return '' if (!defined($icon));
    $button = "" if (!defined ($button));
    $name = '' if (!defined($name));
    my $alt = ''; 
    if ($name ne '')
    {
        if ($button ne '')
        {
            $alt = "$button: $name";
        }
        else
        {
            $alt = $name;
        }  
    }
    else
    {
        $alt = $button;
    }
    return "$icon $alt";
}

sub T2H_DEFAULT_print_navigation
{
    my $buttons = shift;
    my $vertical = shift;

    return '';
}

######################################################################
# Frames: this is from "Richard Y. Kim" <ryk@coho.net>
# Should be improved to be more conforming to other _print* functions
# toc_file and main_file passed as args are relative to the texinfo manual
# location, and therefore are not used.

# no-ops in the default case, doesn't really make sense if output is 
# not html

sub T2H_DEFAULT_print_frame
{
    my $fh = shift;
    my $toc_file = shift;
    my $main_file = shift;
    $main_file = $Texi2HTML::THISDOC{'filename'}->{'top'};
    $toc_file = $Texi2HTML::THISDOC{'filename'}->{'toc_frame'};
}

sub T2H_DEFAULT_print_toc_frame
{
    my $fh = shift;
    my $stoc_lines = shift;
}

# This subroutine is intended to fill @Texi2HTML::TOC_LINES and 
# @Texi2HTML::OVERVIEW with the table of contents and short table of
# contents.
#
# arguments:
# ref on an array containing all the elements

# each element is a reference on a hash. The following keys might be of
# use:
# 'top': true if this is the top element
# 'toc_level': level of the element in the table of content. Highest level
#              is 1 for the @top element and for chapters, appendix and so on,
#              2 for section, unnumberedsec and so on... 
# 'tocid': label used for reference linking to the element in table of
#          contents
# 'file': the file containing the element, usefull to do href to that file
#         in case the document is split.
# 'text': text of the element, with section number
# 'text_nonumber': text of the element, without section number

# Relevant configuration variables are:
# $NO_BULLET_LIST_ATTRIBUTE: usefull in case a list is used
# $FRAMES: @Texi2HTML::OVERVIEW is used in one of the frames. 
# $BEFORE_OVERVIEW
# $AFTER_OVERVIEW
# $BEFORE_TOC_LINES
# $AFTER_TOC_LINES
# get_conf('contents')
# get_conf('shortcontents')

sub T2H_DEFAULT_contents($$)
{
   my $elements = shift;
   my $toc_file = shift;
   my @result;
   return unless (get_conf('contents'));
   foreach my $element (@$elements)
   {
      my $level = $element->{'toc_level'};
      $level = 1 if ($level < 1);
      my $text =  $element->{'text'};
      my $result =  (' ' x ($level - 1)) . $text ."\n";
      push @result, $result;
   }
   if (@result)
   {
      unshift @result, $BEFORE_TOC_LINES;
      push @result, $AFTER_TOC_LINES;
   }
   return \@result;
}

sub T2H_DEFAULT_shortcontents($$)
{
   my $elements = shift;
   my $stoc_file = shift;
   my @result;
   return unless (get_conf('shortcontents'));
   foreach my $element (@$elements)
   {
      my $level = $element->{'toc_level'};
      next if ($level > 1);
      $level = 1 if ($level < 1);
      my $text = $element->{'text'};
      push @result, $text ."\n";
   }
   if (@result)
   {
      unshift @result, $BEFORE_OVERVIEW;
      push @result, $AFTER_OVERVIEW;
   }
   return \@result;
}

sub T2H_DEFAULT_print_title()
{
    my $element = shift;
    return undef unless ($SHOW_TITLE);
    if ($USE_TITLEPAGE_FOR_TITLE)
    {
        my ($titlepage_text, $titlepage_no_texi, $titlepage_simple_format) = main::do_special_region_lines('titlepage',$Texi2HTML::THISDOC{'state'});

        &$titlepage([],$titlepage_text, $titlepage_no_texi, $titlepage_simple_format);
        return $Texi2HTML::TITLEPAGE;
    }
    else
    {
       my $title = '';
       $title = $Texi2HTML::THISDOC{'simpletitle'} if (defined($Texi2HTML::THISDOC{'simpletitle'}) and $Texi2HTML::THISDOC{'simpletitle'} !~ /^\s*$/);
       if ($title ne '')
       {
           return &$heading_text('@settitle', $title, 0) . "\n";
       }
    }
}

sub T2H_DEFAULT_toc_body($)
{
    my $elements_list = shift;
    my $toc_lines = &$contents($elements_list, $Texi2HTML::THISDOC{'toc_file'});
    @{$Texi2HTML::TOC_LINES} = @$toc_lines if ($toc_lines);
    my $stoc_lines = &$shortcontents($elements_list, $Texi2HTML::THISDOC{'stoc_file'});
    @{$Texi2HTML::OVERVIEW} = @$stoc_lines if ($stoc_lines);
}

# element and elements_list may not be undef when called from the 
# main program, but may be if called from other customization function,
# for example, here, print_Top.
sub T2H_DEFAULT_inline_contents($$$$)
{
    my $fh = shift;
    my $command = shift;
    my $element = shift;
    my $elements_list = shift;
    my $name;
    my $lines;

    my $toc_file;
    $toc_file = $element->{'file'} if (defined($element));

    my $result = undef;

    if ($command eq 'contents')
    {
        $name = $Texi2HTML::NAME{'Contents'};
        $toc_file = $Texi2HTML::THISDOC{'toc_file'} if (!defined($toc_file));
        if (defined($elements_list))
        {
            $lines = &$contents($elements_list, $toc_file);
        }
        else
        {
            $lines = $Texi2HTML::TOC_LINES;
        }
    }
    else
    {
        $name = $Texi2HTML::NAME{'Overview'};
        $toc_file = $Texi2HTML::THISDOC{'stoc_file'} if (!defined($toc_file));
        if (defined($elements_list))
        {
            $lines = &$shortcontents($elements_list, $toc_file);
        }
        else
        {
            $lines = $Texi2HTML::OVERVIEW;
        }
    }
    if ($lines and @{$lines})
    {
         $result = [ &$heading_text("\@$command", $name, 1), "\n" ];
         my $contents_anchor = &$anchor($element->{'id'});
         if (defined($contents_anchor) and $contents_anchor =~ /\S/)
         {
             unshift @$result, $contents_anchor."\n";
         }
         push @$result, (@$lines, "\n");
    }
    return $result;
}


sub T2H_DEFAULT_css_lines ($$)
{
    my $import_lines = shift;
    my $rule_lines = shift;
#    return if (defined($CSS_LINES) or (!@$rule_lines and !@$import_lines and (! keys(%css_map))));
    if (defined($CSS_LINES))
    { # if predefined, use CSS_LINES.
       $Texi2HTML::THISDOC{'CSS_LINES'} = $CSS_LINES;
       return;
    }
    return if ((!@$rule_lines and !@$import_lines and !keys(%css_map) and !@CSS_REFS) or $NO_CSS);
    my $css_text = "<style type=\"text/css\">\n<!--\n";
    $css_text .= join('',@$import_lines) . "\n" if (@$import_lines);
    foreach my $css_rule (sort(keys(%css_map)))
    {
        next unless ($css_map{$css_rule});
        $css_text .= "$css_rule {$css_map{$css_rule}}\n";
    }
    $css_text .= join('',@$rule_lines) . "\n" if (@$rule_lines);
    $css_text .= "-->\n</style>\n";
    foreach my $ref (@CSS_REFS)
    {
        $css_text .= "<link rel=\"stylesheet\" type=\"text/css\" href=\"$ref\">\n";
    }
    $Texi2HTML::THISDOC{'CSS_LINES'} = $css_text;
}

######################################################################
# About page
#

# PRE_ABOUT can be a function reference or a scalar.
# Note that if it is a scalar, T2H_InitGlobals has not been called,
# and all global variables like $ADDRESS are not available.
$PRE_ABOUT = sub
{
    return '  ' . &$program_string() .  "\n";
};

# If customizing $AFTER_ABOUT, be sure to put the content inside <p></p>.
$AFTER_ABOUT = '';

%BUTTONS_EXAMPLE =
    (
     'Top',         ' ',
     'Contents',    ' ',
     'Overview',    ' ',
     'Index',       ' ',
     'This',        '1.2.3',
     'Back',        '1.2.2',
     'FastBack',    '1',
     'Prev',        '1.2.2',
     'Up',          '1.2',
     'Next',        '1.2.4',
     'NodeUp',      '1.2',
     'NodeNext',    '1.2.4',
     'NodePrev',    '1.2.2',
     'Following',   '1.2.4',
     'Forward',     '1.2.4',
     'FastForward', '2',
     'About',       ' ',
     'First',       '1.',
     'Last',        '1.2.4',
     'NextFile',    ' ',
     'PrevFile',    ' ',
    );

sub T2H_DEFAULT_about_body
{
    my $about = "";
    if (ref($PRE_ABOUT) eq 'CODE')
    {
        $about .= &$PRE_ABOUT();
    }
    else
    {
        $about .= $PRE_ABOUT;
    }
    return $about;
}

# return value is currently ignored
sub T2H_DEFAULT_titlepage($$$$)
{
    my $titlepage_lines = shift;
    my $titlepage_text = shift;
    my $titlepage_no_texi = shift;
    my $titlepage_simple_format = shift;

    $Texi2HTML::TITLEPAGE = $titlepage_text;
    if ($titlepage_text eq '')
    {
       my $title = '';
       $title = $Texi2HTML::THISDOC{'simpletitle'} if (defined($Texi2HTML::THISDOC{'simpletitle'}) and $Texi2HTML::THISDOC{'simpletitle'} !~ /^\s*$/);
       if ($title ne '')
       {
           $Texi2HTML::TITLEPAGE = &$heading_text('@settitle', $title, 0);
           $Texi2HTML::TITLEPAGE .= "$DEFAULT_RULE\n";
       }
    }
    else
    {
        $Texi2HTML::TITLEPAGE .= "$DEFAULT_RULE\n";
    }

    if ($Texi2HTML::THISDOC{'setcontentsaftertitlepage'} and (defined($Texi2HTML::THISDOC{'inline_contents'}->{'contents'})) and @{$Texi2HTML::THISDOC{'inline_contents'}->{'contents'}})
    {
        foreach my $line(@{$Texi2HTML::THISDOC{'inline_contents'}->{'contents'}})
        {
            $Texi2HTML::TITLEPAGE .= $line;
        }
        $Texi2HTML::TITLEPAGE .= "$DEFAULT_RULE\n";
    }
    if ($Texi2HTML::THISDOC{'setshortcontentsaftertitlepage'} and (defined($Texi2HTML::THISDOC{'inline_contents'}->{'shortcontents'})) and @{$Texi2HTML::THISDOC{'inline_contents'}->{'shortcontents'}})
    {
        foreach my $line(@{$Texi2HTML::THISDOC{'inline_contents'}->{'shortcontents'}})
        {
            $Texi2HTML::TITLEPAGE .= $line;
        }
        $Texi2HTML::TITLEPAGE .= "$DEFAULT_RULE\n";
    }
    return $Texi2HTML::TITLEPAGE;
}


sub T2H_DEFAULT_print_redirection_page()
{
    #return "Redirection files are not of use for the current format.\n";
    return undef;
}

sub T2H_DEFAULT_node_file_name($$)
{
    my $node = shift;
    my $type = shift;
    return undef if ($node->{'external_node'}
       or ($type eq 'top' and !$NEW_CROSSREF_STYLE));
    my $node_file_base;
    if ($type eq 'top' and defined($TOP_NODE_FILE))
    {
        $node_file_base = $TOP_NODE_FILE;
    }
    elsif ($NEW_CROSSREF_STYLE)
    {
        if ($TRANSLITERATE_FILE_NAMES)
        {
            $node_file_base = $node->{'cross_manual_file'};
        }
        else
        {
            $node_file_base = $node->{'cross_manual_target'};
        }
    }
    else
    {
         $node_file_base = main::remove_texi($node->{'texi'});
         $node_file_base =~ s/[^\w\.\-]/-/g;
    }
    if (defined($NODE_FILE_EXTENSION) and $NODE_FILE_EXTENSION ne '')
    {
        return ($node_file_base . ".$NODE_FILE_EXTENSION");
    }
    return $node_file_base;
}

########################################################################
# Control of formatting:
# 1.) For some changes, it is often enough to change the value of
#     some global map. It might necessitate building a little
#     function along with the change in hash, if the change is the use
#     of another function (in style_map).
# 2.) For other changes, reimplement one of the t2h_default_<fnc>* routines,
#     give them another name, and assign them to the respective
#     $<fnc> variable (below).

%deprecated_commands = (
  'ctrl' => '',
  'allow-recursion' => N__('recursion is always allowed'),
  'quote-arg' => N__('arguments are quoted by default'),
);

#
# This hash should have keys corresponding with the nonletter command accent
# whose following character is considered to be the argument
# This hash associates an accent macro to the ISO name for the accent if any.
# The customary use of this map is to find the ISO name appearing in html
# entity (like &eacute;) associated with a texinfo accent macro.
#
# The keys of the hash are
# ": umlaut
# ~: tilda accent
# ^: circumflex accent
# `: grave accent
# ': acute accent
# =: macron accent
%accent_map = (
          '"',  'uml',
          '~',  'tilde',
          '^',  'circ',
          '`',  'grave',
          "'", 'acute',
          ",", 'cedil',
          '=', '',
          'ringaccent', 'ring',
          'H', '',
          'dotaccent', '',
          'u', '',
          'ubaraccent', '',
          'udotaccent', '',
          'v', '',
          'ogonek', 'ogon',
         );

#
# ascii representation of texinfo "simple things" @-commands
%default_simple_map = (
           '*', "\n",
           ' ', ' ',
           "\t", ' ',
           "\n", ' ',
           '-', '',  # hyphenation hint
           '|', '',  # used in formatting commands @evenfooting and friends
           '/', '',
           ':', '',
           '!', '!',
           '?', '?',
           '.', '.',
           '@', '@',
           '}', '}',
           '{', '{',
);

# texinfo "simple things" @-commands
%simple_map = %default_simple_map;

# this map is used in preformatted text
%simple_map_pre = %simple_map;

# This map is used when texi elements are removed and replaced 
# by simple text
%simple_map_texi = %default_simple_map;

# maps for the math specific commands
%simple_map_math = (
           '\\', '\\'
           );

#%simple_map_pre_math = %simple_map_math;
#%simple_map_texi_math = %simple_map_math;

$punctuation_characters = '.?!';
$after_punctuation_characters = '"\')]';


%default_things_map = (
               'TeX'          => 'TeX',
               'LaTeX'          => 'LaTeX',
               'bullet'       => '*',
               'copyright' => '(C)',
               'registeredsymbol'   => '(R)',
               'dots'         => '...',
               'enddots'      => '...',
               'equiv'        => '==',
# FIXME i18n
               'error'        => 'error-->',
               'expansion'    => '==>',
               'arrow'        => '->',
               'minus'        => '-',
               'point'        => '-!-',
               'print'        => '-|',
               'result'       => '=>',
               'today'        => '',
               'aa'           => 'aa',
               'AA'           => 'AA',
               'ae'           => 'ae',
               'oe'           => 'oe', 
               'AE'           => 'AE',
               'OE'           => 'OE',
               'o'            => '/o',
               'O'            => '/O',
               'ss'           => 'ss',
               'l'            => '/l',
               'L'            => '/L',
               'DH'           => 'D',
               'dh'           => 'd',
               'TH'           => 'TH', # http://www.evertype.com/standards/wynnyogh/thorn.html

               'th'           => 'th',
               'exclamdown'   => '!',
               'questiondown' => '?',
               'pounds'       => '#',
               'ordf'         => 'a',
               'ordm'         => 'o',
               'comma'        => ',',
               'euro'         => 'Euro',
               'geq'          => '>=',
               'leq'          => '<=',
               'tie'          => ' ',
               'textdegree'          => 'o',
               'quotedblleft'          => '``',
               'quotedblright'          => "''",
               'quoteleft'          => '`',
               'quoteright'          => "'",
               'quotedblbase'          => ',,',
               'quotesinglbase'          => ',',
               'guillemetleft'          => '<<',
               'guillemetright'          => '>>',
               'guillemotleft'          => '<<',
               'guillemotright'          => '>>',
               'guilsinglleft'          => '<',
               'guilsinglright'          => '>',
);

%things_map = %default_things_map;

# This map is used in preformatted environments
%pre_map = %things_map;

# used in math. If not found, pre_map is used.
%math_map = ();

# text replacing macros when texi commands are removed and plain text is 
# produced.
%texi_map = %default_things_map;

# used for index sorting.
%sorting_things_map = %default_things_map;
foreach my $accent_letter ('o','O','l','L')
{
  $sorting_things_map{$accent_letter} = $accent_letter;
}
$sorting_things_map{'copyright'} = 'C';
$sorting_things_map{'registeredsymbol'} = 'R';
$sorting_things_map{'today'} = 't';

%default_texi_map = %texi_map;

#
# texinfo "things" (@foo{}) to XML ones
#
%things_map_xml = (
               'TeX'          => 'TeX',
               'LaTeX'          => 'LaTeX',
# pertusus: unknown by makeinfo, not in texinfo manual (@* is the right thing)
#               'br', '<br>',     # paragraph break
               'bullet'       => '&bull;',
#               #'copyright' => '(C)',
               'copyright'    => '&copy;',
               'registeredsymbol'   => '&reg;',
               'dots'         => '&hellip;',
               'enddots'      => '...',
               'equiv'        => '&equiv;',
# FIXME i18n
               'error'        => 'error--&gt;',
               'expansion'    => '&rarr;',
               'arrow'        => '&rarr;',
               'minus'        => '-',
               'point'        => '&lowast;',
               'print'        => '-|',
               'result'       => '&rArr;',
               # set in code using the language
               # 'today', &pretty_date,
               'today'        => '',
               'aa'           => '&aring;',
               'AA'           => '&Aring;',
               'ae'           => '&aelig;',
               'oe'           => '&oelig;', #pertusus: also &#156;. &oelig; not in html 3.2
               'AE'           => '&AElig;',
               'OE'           => '&OElig;', #pertusus: also &#140;. &OElig; not in html 3.2
               'o'            =>  '&oslash;',
               'O'            =>  '&Oslash;',
               'ss'           => '&szlig;',
               'DH'           => '&ETH;',
               'dh'           => '&eth;',
               'TH'           => '&THORN;',
               'th'           => '&thorn;',
               'l'            => '&#322;',
               'L'            => '&#321;',
               'exclamdown'   => '&iexcl;',
               'questiondown' => '&iquest;',
               'pounds'       => '&pound;',
               'ordf'         => '&ordf;',
               'ordm'         => '&ordm;',
               'comma'        => ',',
               'euro'         => '&euro;',
               'geq'          => '&ge;',
               'leq'          => '&le;',
               'tie'          => '&nbsp;',
               'textdegree'          => '&deg;',
               'quotedblleft'          => '&ldquo;',
               'quotedblright'          => '&rdquo;',
               'quoteleft'          => '&lsquo;',
               'quoteright'          => '&rsquo;',
               'quotedblbase'          => '&bdquo;',
               'quotesinglbase'          => '&sbquo;',
               'guillemetleft'          => '&laquo;',
               'guillemetright'          => '&raquo;',
               'guillemotleft'          => '&laquo;',
               'guillemotright'          => '&raquo;',
               'guilsinglleft'          => '&lsaquo;',
               'guilsinglright'          => '&rsaquo;',
             );

# This map is used in preformatted environments
%pre_map_xml = %things_map_xml;

# taken from
#Latin extended additionnal
#http://www.alanwood.net/unicode/latin_extended_additional.html
#C1 Controls and Latin-1 Supplement
#http://www.alanwood.net/unicode/latin_1_supplement.html
#Latin Extended-A
#http://www.alanwood.net/unicode/latin_extended_a.html
#Latin Extended-B
#http://www.alanwood.net/unicode/latin_extended_b.html
#dotless i: 0131

#http://www.alanwood.net/unicode/arrows.html 21**
#http://www.alanwood.net/unicode/general_punctuation.html 20**
#http://www.alanwood.net/unicode/mathematical_operators.html 22**

%unicode_map = (
               'bullet'       => '2022',
               'copyright'    => '00A9',
               'registeredsymbol'   => '00AE',
               'dots'         => '2026',
               'enddots'      => '',
               'equiv'        => '2261',
               'error'        => '',
               'expansion'    => '2192',
               'arrow'        => '2192',
               'minus'        => '2212', # in mathematical operators
#               'minus'        => '002D', # in latin1
               'point'        => '2605',
               'print'        => '22A3',
               'result'       => '21D2',
               'today'        => '',
               'aa'           => '00E5',
               'AA'           => '00C5',
               'ae'           => '00E6',
               'oe'           => '0153',
               'AE'           => '00C6',
               'OE'           => '0152',
               'o'            => '00F8',
               'O'            => '00D8',
               'ss'           => '00DF',
               'DH'           => '00D0',
               'dh'           => '00F0',
               'TH'           => '00DE',
               'th'           => '00FE',
               'l'            => '0142',
               'L'            => '0141',
               'exclamdown'   => '00A1',
               'questiondown' => '00BF',
               'pounds'       => '00A3',
               'ordf'         => '00AA',
               'ordm'         => '00BA',
               'comma'        => '002C',
               'euro'         => '20AC',
               'geq'          => '2265',
               'leq'          => '2264',
               'tie'          => '',
#               'tie'          => '0020',
               'textdegree'          => '00B0',
               'quotedblleft'          => '201C',
               'quotedblright'          => '201D',
               'quoteleft'          => '2018',
               'quoteright'          => '2019',
               'quotedblbase'          => '201E',
               'quotesinglbase'          => '201A',
               'guillemetleft'          => '00AB',
               'guillemetright'          => '00BB',
               'guillemotleft'          => '00AB',
               'guillemotright'          => '00BB',
               'guilsinglleft'          => '2039',
               'guilsinglright'          => '203A',
             );

%makeinfo_encoding_to_map = (
  "iso-8859-1",  'iso8859_1',
  "iso-8859-2",  'iso8859_2',
  "iso-8859-15", 'iso8859_15',
  "koi8-r",      'koi8',
  "koi8-u",      'koi8', 
);

foreach my $encoding (keys(%makeinfo_encoding_to_map))
{
   $t2h_encoding_aliases{$encoding} = $encoding;
   $t2h_encoding_aliases{$makeinfo_encoding_to_map{$encoding}} = $encoding;
}

# cut and pasted from eigth_bit_makeinfo_maps.pl, in turn generated with
# ./parse_8bit_makeinfo_maps.pl

%makeinfo_unicode_to_eight_bit = (
   'iso8859_1' => {
      '00A0' => 'A0',
      '00A1' => 'A1',
      '00A2' => 'A2',
      '00A3' => 'A3',
      '00A4' => 'A4',
      '00A5' => 'A5',
      '00A6' => 'A6',
      '00A7' => 'A7',
      '00A8' => 'A8',
      '00A9' => 'A9',
      '00AA' => 'AA',
      '00AB' => 'AB',
      '00AC' => 'AC',
      '00AD' => 'AD',
      '00AE' => 'AE',
      '00AF' => 'AF',
      '00B0' => 'B0',
      '00B1' => 'B1',
      '00B2' => 'B2',
      '00B3' => 'B3',
      '00B4' => 'B4',
      '00B5' => 'B5',
      '00B6' => 'B6',
      '00B7' => 'B7',
      '00B8' => 'B8',
      '00B9' => 'B9',
      '00BA' => 'BA',
      '00BB' => 'BB',
      '00BC' => 'BC',
      '00BD' => 'BD',
      '00BE' => 'BE',
      '00BF' => 'BF',
      '00C0' => 'C0',
      '00C1' => 'C1',
      '00C2' => 'C2',
      '00C3' => 'C3',
      '00C4' => 'C4',
      '00C5' => 'C5',
      '00C6' => 'C6',
      '00C7' => 'C7',
      '00C7' => 'C7',
      '00C8' => 'C8',
      '00C9' => 'C9',
      '00CA' => 'CA',
      '00CB' => 'CB',
      '00CC' => 'CC',
      '00CD' => 'CD',
      '00CE' => 'CE',
      '00CF' => 'CF',
      '00D0' => 'D0',
      '00D1' => 'D1',
      '00D2' => 'D2',
      '00D3' => 'D3',
      '00D4' => 'D4',
      '00D5' => 'D5',
      '00D6' => 'D6',
      '00D7' => 'D7',
      '00D8' => 'D8',
      '00D9' => 'D9',
      '00DA' => 'DA',
      '00DB' => 'DB',
      '00DC' => 'DC',
      '00DD' => 'DD',
      '00DE' => 'DE',
      '00DF' => 'DF',
      '00E0' => 'E0',
      '00E1' => 'E1',
      '00E2' => 'E2',
      '00E3' => 'E3',
      '00E4' => 'E4',
      '00E5' => 'E5',
      '00E6' => 'E6',
      '00E7' => 'E7',
      '00E8' => 'E8',
      '00E9' => 'E9',
      '00EA' => 'EA',
      '00EB' => 'EB',
      '00EC' => 'EC',
      '00ED' => 'ED',
      '00EE' => 'EE',
      '00EF' => 'EF',
      '00F0' => 'F0',
      '00F1' => 'F1',
      '00F2' => 'F2',
      '00F3' => 'F3',
      '00F4' => 'F4',
      '00F5' => 'F5',
      '00F6' => 'F6',
      '00F7' => 'F7',
      '00F8' => 'F8',
      '00F9' => 'F9',
      '00FA' => 'FA',
      '00FB' => 'FB',
      '00FC' => 'FC',
      '00FD' => 'FD',
      '00FE' => 'FE',
      '00FF' => 'FF',
   },
   'iso8859_15' => {
      '00A0' => 'A0',
      '00A1' => 'A1',
      '00A2' => 'A2',
      '00A3' => 'A3',
      '20AC' => 'A4',
      '00A5' => 'A5',
      '0160' => 'A6',
      '00A7' => 'A7',
      '0161' => 'A8',
      '00A9' => 'A9',
      '00AA' => 'AA',
      '00AB' => 'AB',
      '00AC' => 'AC',
      '00AD' => 'AD',
      '00AE' => 'AE',
      '00AF' => 'AF',
      '00B0' => 'B0',
      '00B1' => 'B1',
      '00B2' => 'B2',
      '00B3' => 'B3',
      '017D' => 'B4',
      '00B5' => 'B5',
      '00B6' => 'B6',
      '00B7' => 'B7',
      '017E' => 'B8',
      '00B9' => 'B9',
      '00BA' => 'BA',
      '00BB' => 'BB',
      '0152' => 'BC',
      '0153' => 'BD',
      '0178' => 'BE',
      '00BF' => 'BF',
      '00C0' => 'C0',
      '00C1' => 'C1',
      '00C2' => 'C2',
      '00C3' => 'C3',
      '00C4' => 'C4',
      '00C5' => 'C5',
      '00C6' => 'C6',
      '00C7' => 'C7',
      '00C8' => 'C8',
      '00C9' => 'C9',
      '00CA' => 'CA',
      '00CB' => 'CB',
      '00CC' => 'CC',
      '00CD' => 'CD',
      '00CE' => 'CE',
      '00CF' => 'CF',
      '00D0' => 'D0',
      '00D1' => 'D1',
      '00D2' => 'D2',
      '00D3' => 'D3',
      '00D4' => 'D4',
      '00D5' => 'D5',
      '00D6' => 'D6',
      '00D7' => 'D7',
      '00D8' => 'D8',
      '00D9' => 'D9',
      '00DA' => 'DA',
      '00DB' => 'DB',
      '00DC' => 'DC',
      '00DD' => 'DD',
      '00DE' => 'DE',
      '00DF' => 'DF',
      '00E0' => 'E0',
      '00E1' => 'E1',
      '00E2' => 'E2',
      '00E3' => 'E3',
      '00E4' => 'E4',
      '00E5' => 'E5',
      '00E6' => 'E6',
      '00E7' => 'E7',
      '00E8' => 'E8',
      '00E9' => 'E9',
      '00EA' => 'EA',
      '00EB' => 'EB',
      '00EC' => 'EC',
      '00ED' => 'ED',
      '00EE' => 'EE',
      '00EF' => 'EF',
      '00F0' => 'F0',
      '00F1' => 'F1',
      '00F2' => 'F2',
      '00F3' => 'F3',
      '00F4' => 'F4',
      '00F5' => 'F5',
      '00F6' => 'F6',
      '00F7' => 'F7',
      '00F8' => 'F8',
      '00F9' => 'F9',
      '00FA' => 'FA',
      '00FB' => 'FB',
      '00FC' => 'FC',
      '00FD' => 'FD',
      '00FE' => 'FE',
      '00FF' => 'FF',
   },
   'iso8859_2' => {
      '00A0' => 'A0',
      '0104' => 'A1',
      '02D8' => 'A2',
      '0141' => 'A3',
      '00A4' => 'A4',
      '013D' => 'A5',
      '015A' => 'A6',
      '00A7' => 'A7',
      '00A8' => 'A8',
      '015E' => 'AA',
      '0164' => 'AB',
      '0179' => 'AC',
      '00AD' => 'AD',
      '017D' => 'AE',
      '017B' => 'AF',
      '00B0' => 'B0',
      '0105' => 'B1',
      '02DB' => 'B2',
      '0142' => 'B3',
      '00B4' => 'B4',
      '013E' => 'B5',
      '015B' => 'B6',
      '02C7' => 'B7',
      '00B8' => 'B8',
      '0161' => 'B9',
      '015F' => 'BA',
      '0165' => 'BB',
      '017A' => 'BC',
      '02DD' => 'BD',
      '017E' => 'BE',
      '017C' => 'BF',
      '0154' => 'C0',
      '00C1' => 'C1',
      '00C2' => 'C2',
      '0102' => 'C3',
      '00C4' => 'C4',
      '0139' => 'C5',
      '0106' => 'C6',
      '00C7' => 'C7',
      '010C' => 'C8',
      '00C9' => 'C9',
      '0118' => 'CA',
      '00CB' => 'CB',
      '011A' => 'CC',
      '00CD' => 'CD',
      '00CE' => 'CE',
      '010E' => 'CF',
      '0110' => 'D0',
      '0143' => 'D1',
      '0147' => 'D2',
      '00D3' => 'D3',
      '00D4' => 'D4',
      '0150' => 'D5',
      '00D6' => 'D6',
      '00D7' => 'D7',
      '0158' => 'D8',
      '016E' => 'D9',
      '00DA' => 'DA',
      '0170' => 'DB',
      '00DC' => 'DC',
      '00DD' => 'DD',
      '0162' => 'DE',
      '00DF' => 'DF',
      '0155' => 'E0',
      '00E1' => 'E1',
      '00E2' => 'E2',
      '0103' => 'E3',
      '00E4' => 'E4',
      '013A' => 'E5',
      '0107' => 'E6',
      '00E7' => 'E7',
      '010D' => 'E8',
      '00E9' => 'E9',
      '0119' => 'EA',
      '00EB' => 'EB',
      '011B' => 'EC',
      '00ED' => 'ED',
      '00EE' => 'EE',
      '010F' => 'EF',
      '0111' => 'F0',
      '0144' => 'F1',
      '0148' => 'F2',
      '00F3' => 'F3',
      '00F4' => 'F4',
      '0151' => 'F5',
      '00F6' => 'F6',
      '00F7' => 'F7',
      '0159' => 'F8',
      '016F' => 'F9',
      '00FA' => 'FA',
      '0171' => 'FB',
      '00FC' => 'FC',
      '00FD' => 'FD',
      '0163' => 'FE',
      '02D9' => 'FF',
   },
   'koi8' => {
      '0415' => 'A3',
      '0454' => 'A4',
      '0456' => 'A6',
      '0457' => 'A7',
      '04D7' => 'B3',
      '0404' => 'B4',
      '0406' => 'B6',
      '0407' => 'B7',
      '042E' => 'C0',
      '0430' => 'C1',
      '0431' => 'C2',
      '0446' => 'C3',
      '0434' => 'C4',
      '0435' => 'C5',
      '0444' => 'C6',
      '0433' => 'C7',
      '0445' => 'C8',
      '0438' => 'C9',
      '0439' => 'CA',
      '043A' => 'CB',
      '043B' => 'CC',
      '043C' => 'CD',
      '043D' => 'CE',
      '043E' => 'CF',
      '043F' => 'D0',
      '044F' => 'D1',
      '0440' => 'D2',
      '0441' => 'D3',
      '0442' => 'D4',
      '0443' => 'D5',
      '0436' => 'D6',
      '0432' => 'D7',
      '044C' => 'D8',
      '044B' => 'D9',
      '0437' => 'DA',
      '0448' => 'DB',
      '044D' => 'DC',
      '0449' => 'DD',
      '0447' => 'DE',
      '044A' => 'DF',
      '042D' => 'E0',
      '0410' => 'E1',
      '0411' => 'E2',
      '0426' => 'E3',
      '0414' => 'E4',
      '0415' => 'E5',
      '0424' => 'E6',
      '0413' => 'E7',
      '0425' => 'E8',
      '0418' => 'E9',
      '0419' => 'EA',
      '041A' => 'EB',
      '041B' => 'EC',
      '041C' => 'ED',
      '041D' => 'EE',
      '041E' => 'EF',
      '041F' => 'F0',
      '042F' => 'F1',
      '0420' => 'F2',
      '0421' => 'F3',
      '0422' => 'F4',
      '0423' => 'F5',
      '0416' => 'F6',
      '0412' => 'F7',
      '042C' => 'F8',
      '042B' => 'F9',
      '0417' => 'FA',
      '0428' => 'FB',
      '042D' => 'FC',
      '0429' => 'FD',
      '0427' => 'FE',
      '042A' => 'FF',
   },
);

%eight_bit_to_unicode = ();
foreach my $encoding (keys(%makeinfo_encoding_to_map))
{
   my $unicode_to_eight = $makeinfo_unicode_to_eight_bit{$makeinfo_encoding_to_map{$encoding}};
#print STDERR "$encoding, $makeinfo_encoding_to_map{$encoding}, $unicode_to_eight\n";
   foreach my $utf8_key (keys(%{$unicode_to_eight}))
   {
      $eight_bit_to_unicode{$encoding}->{$unicode_to_eight->{$utf8_key}} =
         $utf8_key;
   }
}

# currently unused
my %makeinfo_transliterate_map = (
  '0416' => 'ZH',
  '0447' => 'ch',
  '00EB' => 'e',
  '0414' => 'D',
  '0159' => 'r',
  '00E6' => 'ae',
  '042B' => 'Y',
  '00FA' => 'u',
  '043B' => 'l',
  '00DE' => 'TH',
  '00D9' => 'U',
  '00C4' => 'A',
  '0148' => 'n',
  '00F6' => 'o',
  '0434' => 'd',
  '041E' => 'O',
  '041B' => 'L',
  '044B' => 'y',
  '0107' => 'c',
  '0415' => 'E',
  '00C1' => 'A',
  '00D3' => 'O',
  '00DB' => 'U',
  '016E' => 'U',
  '013A' => 'l',
  '017B' => 'Z',
  '00F1' => 'n',
  '0428' => 'SH',
  '0153' => 'oe',
  '00F4' => 'o',
  '0144' => 'n',
  '0404' => 'IE',
  '0427' => 'CH',
  '0162' => 'T',
  '017A' => 'z',
  '0448' => 'sh',
  '0436' => 'zh',
  '00F9' => 'u',
  '0406' => 'I',
  '0103' => 'a',
  '0422' => 'T',
  '0160' => 'S',
  '0165' => 't',
  '017E' => 'z',
  '00F0' => 'd',
  '043E' => 'o',
  '043D' => 'n',
  '013E' => 'l',
  '0412' => 'V',
  '0111' => 'd',
  '0155' => 's',
  '017C' => 'z',
  '00CE' => 'I',
  '042D' => 'E',
  '00C8' => 'E',
  '00F8' => 'oe',
  '00F2' => 'o',
  '00FF' => 'y',
  '0420' => 'R',
  '0119' => 'e',
  '00D2' => 'O',
  '043C' => 'm',
  '00D0' => 'DH',
  '0179' => 'Z',
  '0110' => 'D',
  '043F' => 'p',
  '0170' => 'U',
  '011A' => 'E',
  '010C' => 'C',
  '015A' => 'S',
  '0433' => 'g',
  '00E1' => 'a',
  '010D' => 'c',
  '00CC' => 'I',
  '016F' => 'u',
  '0457' => 'yi',
  '00C2' => 'A',
  '0438' => 'i',
  '00E3' => 'a',
  '0435' => 'e',
  '0440' => 'r',
  '042A' => 'W',
  '0431' => 'b',
  '00EE' => 'i',
  '0150' => 'O',
  '00E8' => 'e',
  '0418' => 'I',
  '00CF' => 'I',
  '015F' => 's',
  '0142' => 'l',
  '0147' => 'N',
  '00DF' => 'ss',
  '00E5' => 'aa',
  '00C3' => 'A',
  '0106' => 'C',
  '0141' => 'L',
  '0164' => 'T',
  '017D' => 'Z',
  '00EC' => 'i',
  '041C' => 'M',
  '00C9' => 'E',
  '00E0' => 'a',
  '043A' => 'k',
  '00F5' => 'o',
  '042C' => 'X',
  '0449' => 'shch',
  '0444' => 'f',
  '0139' => 'L',
  '0158' => 'R',
  '00F3' => 'o',
  '00FB' => 'u',
  '0424' => 'F',
  '0446' => 'c',
  '0423' => 'U',
  '0442' => 't',
  '00FD' => 'y',
  '0102' => 'A',
  '0104' => 'A',
  '00CB' => 'E',
  '0426' => 'C',
  '00CD' => 'I',
  '0437' => 'z',
  '0178' => 'y',
  '00D4' => 'O',
  '044D' => 'e',
  '0432' => 'v',
  '013D' => 'L',
  '0163' => 't',
  '0456' => 'i',
  '011B' => 'e',
  '044F' => 'ya',
  '0429' => 'SHCH',
  '0411' => 'B',
  '044A' => 'w',
  '00C6' => 'AE',
  '041D' => 'N',
  '00DA' => 'U',
  '00C0' => 'A',
  '0152' => 'OE',
  '00DD' => 'Y',
  '0154' => 'R',
  '00E9' => 'e',
  '00D5' => 'O',
  '041F' => 'P',
  '0161' => 's',
  '0430' => 'a',
  '0445' => 'h',
  '00E2' => 'a',
  '00D6' => 'O',
  '0407' => 'YI',
  '00CA' => 'E',
  '0439' => 'i',
  '0171' => 'u',
  '00DC' => 'U',
  '042F' => 'YA',
  '0425' => 'H',
  '00FE' => 'th',
  '00D1' => 'N',
  '044C' => 'x',
  '010F' => 'd',
  '0410' => 'A',
  '0443' => 'u',
  '00EF' => 'i',
  '0105' => 'a',
  '00EA' => 'e',
  '00E4' => 'a',
  '015E' => 'S',
  '0417' => 'Z',
  '00ED' => 'i',
  '00FC' => 'u',
  '04D7' => 'IO',
  '00D8' => 'OE',
  '0419' => 'I',
  '0421' => 'S',
  '0143' => 'N',
  '010E' => 'D',
  '0413' => 'G',
  '015B' => 's',
  '0151' => 'o',
  '00E7' => 'c',
  '00C5' => 'AA',
  '0441' => 's',
  '0118' => 'E',
  '00C7' => 'C',
  '041A' => 'K',
  '0454' => 'ie',
  '042E' => 'yu',
);


%transliterate_map = (
               '00C5'  => 'AA',
               '00E5'  => 'aa',
               '00D8'  => 'O',
               '00F8'  => 'o',
               '00E6' => 'ae',
               '0153' => 'oe',
               '00C6' => 'AE',
               '0152' => 'OE',
               '00DF' => 'ss',
               '0141' => 'L',
               '0142' => 'l',
               '00D0' => 'D',
               '00F0' => 'd',
               '00DE' => 'TH',
               '00FE' => 'th',
               '0415'  => 'E',
               '0435'  => 'e',
               '0426'  => 'C',
               '042A'  => 'W',
               '044A'  => 'w',
               '042C'  => 'X',
               '044C'  => 'x',
               '042E'  => 'yu',
               '042F'  => 'YA',
               '044F'  => 'ya',
               '0433'  => 'g',
               '0446'  => 'c',
               '04D7'  => 'IO',
               '00DD'  => 'Y', # unidecode gets this wrong ?
               # following appears in tests, this is required to have
               # the same output with and without unidecode
               '4E2D'  => 'Zhong',
               '6587'  => 'Wen',
               '793A'  => 'Shi',
               '4F8B'  => 'Li',
               '7B2C'  => 'Di',
               '7AE0'  => 'Zhang',
               '53E6'  => 'Ling',
               '4E2A'  => 'Ge',
               # in http://www.cantonese.sheik.co.uk/dictionary/characters/7/
               # unidecode certainly gets it wrong
               '4E00'  => 'Yi',
               'FF08' => '(',
               'FF09' => ')',
               'FF0C' => ',',
               '5B66' => 'Xue',
               '7FD2' => 'Xi',
               '30DE' => 'ma',
               '30CB' => 'ni',
               '30E5' => 'yu',
               '30A2' => 'a',
               '30EB' => 'ru',
          );

foreach my $symbol(keys(%unicode_map))
{
    if ($unicode_map{$symbol} ne '' and !exists($transliterate_map{$symbol}))
    {
         $no_transliterate_map{$unicode_map{$symbol}} = 1;
    }
}

%ascii_character_map = (
            ' ' => '0020',
            '!' => '0021',
            '"' => '0022',
            '#' => '0023',
            '$' => '0024',
            '%' => '0025',
            '&' => '0026',
            "'" => '0027',
            '(' => '0028',
            ')' => '0029',
            '*' => '002A',
            '+' => '002B',
            ',' => '002C',
            '-' => '002D',
            '.' => '002E',
            '/' => '002F',
            ':' => '003A',
            ';' => '003B',
            '<' => '003C',
            '=' => '003D',
            '>' => '003E',
            '?' => '003F',
            '@' => '0040',
            '[' => '005B',
            '\\' => '005C',
            ']' => '005D',
            '^' => '005E',
            '_' => '005F',
            '`' => '0060',
            '{' => '007B',
            '|' => '007C',
            '}' => '007D',
            '~' => '007E',
);

%perl_charset_to_html = (
              'utf8'       => 'utf-8',
              'utf-8-strict'       => 'utf-8',
              'ascii'      => 'us-ascii',
              'shiftjis'      => 'shift_jis',
);

%t2h_encoding_aliases = (
              'latin1' => 'iso-8859-1',
);

foreach my $perl_charset (keys(%perl_charset_to_html))
{
   $t2h_encoding_aliases{$perl_charset} = $perl_charset_to_html{$perl_charset};
   $t2h_encoding_aliases{$perl_charset_to_html{$perl_charset}} = $perl_charset_to_html{$perl_charset};
}

# These are the encodings from the texinfo manual
foreach my $canonical_encoding('us-ascii', 'utf-8', 'iso-8859-1', 
  'iso-8859-15','iso-8859-2','koi8-r', 'koi8-u')
{
  $canonical_texinfo_encodings{$canonical_encoding} = 1;
}

# not used currently for html, but used in chm.init
%numeric_entity_map = ();

foreach my $symbol (keys(%unicode_map))
{
    if ($symbol ne '')
    {
        $numeric_entity_map{$symbol} = '&#' . hex($unicode_map{$symbol}) . ';';
    }
}

# When the value begins with & the function with that name is used to do the
# html. The first argument is the text enclosed within {}, the second is the
# style name (which is also the key of the hash)
#
# Otherwithe the value is the html element used to enclose the text, and if
# there is a " the resulting text is also enclosed within `'
my %old_style_map = (
      'acronym',    '',
      'asis',       '',
      'b',          'b',
      'cite',       'cite',
      'clicksequence', '',
      'code',       'code',
      'command',    'code',
      'ctrl',       '&default_ctrl', 
      'dfn',        'em', 
      'dmn',        '',   
      'email',      '&default_email', 
      'emph',       'em',
      'env',        'code',
      'file',       '"tt', 
      'i',          'i',
      'kbd',        'kbd',
      'key',        'kbd',
      'math',       'em',
      'option',     '"samp', 
      'r',          '',
      'samp',       '"samp', 
      'sc',         '&default_sc',
      'strong',     'strong',
      't',          'tt',
      'uref',       '&default_uref',
      'url',        '&default_url',
      'var',        'var',
      'verb',       'tt',
      'titlefont',  '&default_titlefont',
      'w',          '',
     );

sub t2h_default_copy_style_map ($$;$)
{
  my $from = shift;
  my $to = shift;
  my $merge = shift;

  foreach my $command (keys(%$from))
  {
     $to->{$command} = {} if (!exists($to->{$command}));
     foreach my $key (keys(%{$from->{$command}}))
     {
        next if (exists($to->{$command}->{$key}) and $merge);
        if ($key eq 'args')
        {
           $to->{$command}->{$key} = [ @{$from->{$command}->{$key}} ];
        }
        else
        {
           $to->{$command}->{$key} = $from->{$command}->{$key};
        }
     }
  }
}

# default is {'args' => ['normal'], 'attribute' => ''},   
%style_map = (
      'asis',       {},
      'b',          {},
      'cite',       {},
      'clicksequence', {},
      'click',      {'function' => \&t2h_default_click_normal, 'type' => 'simple_style'},
      'code',       {'args' => ['code']},
      'command',    {'args' => ['code']},
      'ctrl',       {'function' => \&t2h_default_ctrl,'type' => 'simple_style'}, 
      'dfn',        {}, 
      'dmn',        {'type' => 'simple_style'},   
      'email',      {'args' => ['code', 'normal'], 
                       'function' => \&t2h_default_email,
                       'type' => 'simple_style'}, 
      #'email',      {'args' => ['normal', 'normal'], 
      #                 'function' => \&t2h_default_email}, 
      'emph',       {}, 
      'env',        {'args' => ['code']},
      'file',       {'args' => ['code'], 'quote' => '"'},
      'headitemfont', {},
      'i',          {},
      'slanted',    {},
      'sansserif',  {},
      'kbd',        {'args' => ['code'], },
      'key',        {'args' => ['code'], 'begin' => '<', 'end' => '>'},
      'math',       {'function' => \&t2h_default_math, 'args' => ['math'] },
      'option',     {'args' => ['code'], 'quote' => '"'},
      'r',          {},
      'samp',       {'args' => ['code'],  'quote' => '"'},
#      'sc',         {'function' => \&t2h_default_sc},
      'sc',         {},
      'strong',     {},
      't',          {},
      'uref',       {'function' => \&t2h_default_uref, 
                      'args' => ['code', 'normal', 'normal'],
                      'type' => 'simple_style' },
      #'uref',       {'function' => \&t2h_default_uref, 
      #                'args' => ['normal', 'normal', 'normal']},
      'url',        {'function' => \&t2h_default_uref, 
                      'args' => ['code', 'normal', 'normal'],
                      'type' => 'simple_style'},
      'indicateurl', {'args' => ['code'], 'begin' => '<', 'end' => '>','type' => 'simple_style'},
      'var',        {},
      'verb',       {'args' => ['code'], },
      'titlefont',  {'function' => \&t2h_default_titlefont, 
            'type' => 'simple_style'},
      'w',          {},
      'hyphenation', {'function' => \&t2h_default_hyphenation, 'args' => ['keep']},
     );

%command_type = ();

foreach my $style (keys(%style_map))
{
   if (exists($style_map{$style}->{'type'}))
   {
       $command_type{$style} = $style_map{$style}->{'type'};
   }
   else
   {
       $command_type{$style} = 'style';
   }
}


sub t2h_default_select_substitution($$$)
{
   my $in_raw_text = shift;
   my $in_preformatted = shift;
   my $in_simple = shift;
   
   my $substitutions = \@text_substitutions_normal;
   if ($in_raw_text)
   {
      $substitutions = \@text_substitutions_texi;
   }
   elsif ($in_simple)
   {
      $substitutions = \@text_substitutions_simple_format;
   }
   elsif ($in_preformatted)
   {
      $substitutions = \@text_substitutions_pre;
   }
   return $substitutions;
}

sub t2h_text_substitutions($$$$)
{
   my $text = shift;
   my $in_raw_text = shift;
   my $in_preformatted = shift;
   my $in_simple = shift;
   
   my $substitutions = t2h_default_select_substitution($in_raw_text, $in_preformatted, $in_simple);
   foreach my $substitution_entry (@$substitutions)
   {
      my $from = quotemeta($substitution_entry->[0]);
      my $to = $substitution_entry->[1];
      $text =~ s/$from/$to/g;
   }
   return $text;
}

sub t2h_add_text_substitutions($$$$$)
{
   my $entry = shift;
   my $in_normal = shift;
   my $in_raw_text = shift;
   my $in_preformatted = shift;
   my $in_simple = shift;

   my @formats_to_be_done = ($in_normal, $in_raw_text, $in_preformatted, $in_simple);

   for (my $index = 0; $index < scalar(@formats_to_be_done); $index++)
   {
       next unless ($formats_to_be_done[$index]);
       my @args = (0, 0, 0);
       my $found = 0;
       $args[$index -1] = 1 if ($index > 0);
       my $substitutions = &t2h_default_select_substitution(@args);
       foreach my $substitution_entry (@$substitutions)
       {
           if ($substitution_entry->[0] eq $entry->[0])
           {
               $found = 1;
               $substitution_entry->[1] = $entry->[1];
           }
       }
       push @$substitutions, $entry unless ($found);
   }
}

sub t2h_remove_text_substitutions($$$$$)
{
   my $entry = shift;
   my $in_normal = shift;
   my $in_raw_text = shift;
   my $in_preformatted = shift;
   my $in_simple = shift;

   my @formats_to_be_done = ($in_normal, $in_raw_text, $in_preformatted, $in_simple);

   for (my $index = 0; $index < scalar(@formats_to_be_done); $index++)
   {
       next unless ($formats_to_be_done[$index]);
       my @args = (0, 0, 0);
       $args[$index -1] = 1 if ($index > 0);
       my $substitutions = &t2h_default_select_substitution(@args);

       @$substitutions = grep {$_->[0] ne $entry} @$substitutions;
   }
}


%unicode_diacritical = (
       'H'          => '030B', 
       'ringaccent' => '030A', 
       "'"          => '0301',
       'v'          => '030C', 
       ','          => '0327', 
       '^'          => '0302', 
       'dotaccent'  => '0307',
       '`'          => '0300',
       '='          => '0304', 
       '~'          => '0303',
       '"'          => '0308', 
       'udotaccent' => '0323', 
       'ubaraccent' => '0332', 
       'u'          => '0306',
       'tieaccent'  => '0361',
       'ogonek'     => '0328'
);

%unicode_accents = (
    'dotaccent' => { # dot above
        'A' => '0226', #C moz-1.2 
        'a' => '0227', #c moz-1.2
        'B' => '1E02',
        'b' => '1E03',
        'C' => '010A',
        'c' => '010B',
        'D' => '1E0A',
        'd' => '1E0B',
        'E' => '0116',
        'e' => '0117',
        'F' => '1E1E',
        'f' => '1E1F',
        'G' => '0120',
        'g' => '0121',
        'H' => '1E22',
        'h' => '1E23',
        'i' => '0069',
        'I' => '0130',
        'N' => '1E44',
        'n' => '1E45',
        'O' => '022E', #Y moz-1.2
        'o' => '022F', #v moz-1.2
        'P' => '1E56',
        'p' => '1E57',
        'R' => '1E58',
        'r' => '1E59',
        'S' => '1E60',
        's' => '1E61',
        'T' => '1E6A',
        't' => '1E6B',
        'W' => '1E86',
        'w' => '1E87',
        'X' => '1E8A',
        'x' => '1E8B',
        'Y' => '1E8E',
        'y' => '1E8F',
        'Z' => '017B',
        'z' => '017C',
    },
    'udotaccent' => { # dot below
        'A' => '1EA0',
        'a' => '1EA1',
        'B' => '1E04',
        'b' => '1E05',
        'D' => '1E0C',
        'd' => '1E0D',
        'E' => '1EB8',
        'e' => '1EB9',
        'H' => '1E24',
        'h' => '1E25',
        'I' => '1ECA',
        'i' => '1ECB',
        'K' => '1E32',
        'k' => '1E33',
        'L' => '1E36',
        'l' => '1E37',
        'M' => '1E42',
        'm' => '1E43',
        'N' => '1E46',
        'n' => '1E47',
        'O' => '1ECC',
        'o' => '1ECD',
        'R' => '1E5A',
        'r' => '1E5B',
        'S' => '1E62',
        's' => '1E63',
        'T' => '1E6C',
        't' => '1E6D',
        'U' => '1EE4',
        'u' => '1EE5',
        'V' => '1E7E',
        'v' => '1E7F',
        'W' => '1E88',
        'w' => '1E89',
        'Y' => '1EF4',
        'y' => '1EF5',
        'Z' => '1E92',
        'z' => '1E93',
    },
    'ubaraccent' => { # line below
        'B' => '1E06',
        'b' => '1E07',
        'D' => '1E0E',
        'd' => '1E0F',
        'h' => '1E96',
        'K' => '1E34',
        'k' => '1E35',
        'L' => '1E3A',
        'l' => '1E3B',
        'N' => '1E48',
        'n' => '1E49',
        'R' => '1E5E',
        'r' => '1E5F',
        'T' => '1E6E',
        't' => '1E6F',
        'Z' => '1E94',
        'z' => '1E95',
    },
    ',' => { # cedilla
        'C' => '00C7',
        'c' => '00E7',
        'D' => '1E10',
        'd' => '1E11',
        'E' => '0228', #C moz-1.2
        'e' => '0229', #c moz-1.2
        'G' => '0122',
        'g' => '0123',
        'H' => '1E28',
        'h' => '1E29',
        'K' => '0136',
        'k' => '0137',
        'L' => '013B',
        'l' => '013C',
        'N' => '0145',
        'n' => '0146',
        'R' => '0156',
        'r' => '0157',
        'S' => '015E',
        's' => '015F',
        'T' => '0162',
        't' => '0163',
    },
    '=' => { # macron
        'A' => '0100',
        'a' => '0101',
        'E' => '0112',
        'e' => '0113',
        'I' => '012A',
        'i' => '012B',
        'G' => '1E20',
        'g' => '1E21',
        'O' => '014C',
        'o' => '014D',
        'U' => '016A',
        'u' => '016B',
        'Y' => '0232', #? moz-1.2
        'y' => '0233', #? moz-1.2
    },
    '"' => { # diaeresis
        'A' => '00C4',
        'a' => '00E4',
        'E' => '00CB',
        'e' => '00EB',
        'H' => '1E26',
        'h' => '1E27',
        'I' => '00CF',
        'i' => '00EF',
        'O' => '00D6',
        'o' => '00F6',
        't' => '1E97',
        'U' => '00DC',
        'u' => '00FC',
        'W' => '1E84',
        'w' => '1E85',
        'X' => '1E8C',
        'x' => '1E8D',
        'y' => '00FF',
        'Y' => '0178',
    },
    'u' => { # breve
        'A' => '0102',
        'a' => '0103',
        'E' => '0114',
        'e' => '0115',
        'G' => '011E',
        'g' => '011F',
        'I' => '012C',
        'i' => '012D',
        'O' => '014E',
        'o' => '014F',
        'U' => '016C',
        'u' => '016D',
    },
    "'" => { # acute
        'A' => '00C1',
        'a' => '00E1',
        'C' => '0106',
        'c' => '0107',
        'E' => '00C9',
        'e' => '00E9',
        'G' => '01F4',
        'g' => '01F5',
        'I' => '00CD',
        'i' => '00ED',
        'K' => '1E30',
        'k' => '1E31',
        'L' => '0139',
        'l' => '013A',
        'M' => '1E3E',
        'm' => '1E3F',
        'N' => '0143',
        'n' => '0144',
        'O' => '00D3',
        'o' => '00F3',
        'P' => '1E54',
        'p' => '1E55',
        'R' => '0154',
        'r' => '0155',
        'S' => '015A',
        's' => '015B',
        'U' => '00DA',
        'u' => '00FA',
        'W' => '1E82',
        'w' => '1E83',
        'Y' => '00DD',
        'y' => '00FD',
        'Z' => '0179',
        'z' => '018A',
    },
    '~' => { # tilde
        'A' => '00C3',
        'a' => '00E3',
        'E' => '1EBC',
        'e' => '1EBD',
        'I' => '0128',
        'i' => '0129',
        'N' => '00D1',
        'n' => '00F1',
        'O' => '00D5',
        'o' => '00F5',
        'U' => '0168',
        'u' => '0169',
        'V' => '1E7C',
        'v' => '1E7D',
        'Y' => '1EF8',
        'y' => '1EF9',
    },
    '`' => { # grave
        'A' => '00C0',
        'a' => '00E0',
        'E' => '00C8',
        'e' => '00E8',
        'I' => '00CC',
        'i' => '00EC',
        'N' => '01F8',
        'n' => '01F9',
        'O' => '00D2',
        'o' => '00F2',
        'U' => '00D9',
        'u' => '00F9',
        'W' => '1E80',
        'w' => '1E81',
        'Y' => '1EF2',
        'y' => '1EF3',
    },
    '^' => { # circumflex
        'A' => '00C2',
        'a' => '00E2',
        'C' => '0108',
        'c' => '0109',
        'E' => '00CA',
        'e' => '00EA',
        'G' => '011C',
        'g' => '011D',
        'H' => '0124',
        'h' => '0125',
        'I' => '00CE',
        'i' => '00EE',
        'J' => '0134',
        'j' => '0135',
        'O' => '00D4',
        'o' => '00F4',
        'S' => '015C',
        's' => '015D',
        'U' => '00DB',
        'u' => '00FB',
        'W' => '0174',
        'w' => '0175',
        'Y' => '0176',
        'y' => '0177',
        'Z' => '1E90',
        'z' => '1E91',
    },
    'ringaccent' => { # ring
        'A' => '00C5',
        'a' => '00E5',
        'U' => '016E',
        'u' => '016F',
        'w' => '1E98',
        'y' => '1E99',
    },
    'v' => { # caron
        'A' => '01CD',
        'a' => '01CE',
        'C' => '010C',
        'c' => '010D',
        'D' => '010E',
        'd' => '010F',
        'E' => '011A',
        'e' => '011B',
        'G' => '01E6',
        'g' => '01E7',
        'H' => '021E', #K with moz-1.2
        'h' => '021F', #k with moz-1.2
        'I' => '01CF',
        'i' => '01D0',
        'K' => '01E8',
        'k' => '01E9',
        'L' => '013D', #L' with moz-1.2
        'l' => '013E', #l' with moz-1.2
        'N' => '0147',
        'n' => '0148',
        'O' => '01D1',
        'o' => '01D2',
        'R' => '0158',
        'r' => '0159',
        'S' => '0160',
        's' => '0161',
        'T' => '0164',
        't' => '0165',
        'U' => '01D3',
        'u' => '01D4',
        'Z' => '017D',
        'z' => '017E',
    },
    'H' => { # double acute
        'O' => '0150',
        'o' => '0151',
        'U' => '0170',
        'u' => '0171',
    },
    'ogonek' => {
        'A' => '0104',
        'a' => '0105',
        'E' => '0118',
        'e' => '0119',
        'I' => '012E',
        'i' => '012F',
        'U' => '0172',
        'u' => '0173',
        'O' => '01EA',
        'o' => '01EB',
    },
);

foreach my $accent_command ('tieaccent', 'dotless', keys(%unicode_accents))
{
     $style_map{$accent_command} = { 'function' => \&t2h_default_accent };
     $old_style_map{$accent_command} = '&default_accent';
     $style_map_texi{$accent_command} = { 'function' => \&t2h_default_accent };
}


%transliterate_accent_map = ();
foreach my $command (keys(%unicode_accents))
{
    foreach my $letter(keys (%{$unicode_accents{$command}}))
    {
        $transliterate_accent_map{$unicode_accents{$command}->{$letter}}
            = $letter 
          unless (exists($transliterate_map{$unicode_accents{$command}->{$letter}}));
    }
}

sub default_accent($$)
{
    my $text = shift;
    my $accent = shift;
    return "&${text}$accent_map{$accent};" if (defined($accent_map{$accent}) and defined($special_accents{$accent}) and ($text =~ /^[$special_accents{$accent}]$/));
    return '&' . $text . 'ring;' if (($accent eq 'ringaccent') and (defined($special_accents{$accent})) and ($text =~ /^[$special_accents{$accent}]$/));
    return $text . '&lt;' if ($accent eq 'v');
    return ascii_accents($text, $accent);
}

sub t2h_default_accent($$)
{
    my $accent = shift;
    my $args = shift;

    my $text = $args->[0];

    return ascii_accents($text, $accent);
}

####################################################################
# special accent/encoding commands
#
# Some functions used to override normal formatting functions in specific 
# cases. The user shouldn't want to change them, but can use them.
#

sub ascii_accents($$)
{
    my $text = shift;
    my $accent = shift;
    return $text if ($accent eq 'dotless');
    return $text . "''" if ($accent eq 'H');
    return $text . '.' if ($accent eq 'dotaccent');
    return $text . '*' if ($accent eq 'ringaccent');
    return $text . '[' if ($accent eq 'tieaccent');
    return $text . '(' if ($accent eq 'u');
    return $text . '_' if ($accent eq 'ubaraccent');
    return '.' . $text  if ($accent eq 'udotaccent');
    return $text . '<' if ($accent eq 'v');
    return $text . ';' if ($accent eq 'ogonek');
    return $text . $accent if (defined($accent_map{$accent}));
}

sub xml_default_accent($$)
{
    my $accent = shift;
    my $args = shift;

    my $text = $args->[0];

    return "&${text}$accent_map{$accent};" if (defined($accent_map{$accent}) and defined($special_accents{$accent}) and ($text =~ /^[$special_accents{$accent}]$/));
    return '&' . $text . 'ring;' if (($accent eq 'ringaccent') and (defined($special_accents{$accent})) and ($text =~ /^[$special_accents{$accent}]$/));
    return $text . '&lt;' if ($accent eq 'v');
# FIXME here there could be a conversion to the character in the right 
# encoding, like 
#    if ($USE_UNICODE and defined($OUT_ENCODING) and $OUT_ENCODING ne '' 
#        and exists($unicode_accents{$accent}) and  exists($unicode_accents{$accent}->{$text}))
#    {
#          my $encoded_char =  Encode::encode($OUT_ENCODING, chr(hex($unicode_map{$thing})), Encode::FB_QUIET);
#          return $encoded_char if ($encoded_char ne '');
#    }
    if ($USE_NUMERIC_ENTITY)
    {
        if (exists($unicode_accents{$accent}) and exists($unicode_accents{$accent}->{$text}))
        {
             return ('&#' . hex($unicode_accents{$accent}->{$text}) . ';');
        }
    }
    return ascii_accents($text, $accent);
}

# used to utf8 encode the result
sub t2h_utf8_accent($$$)
{
    my $accent = shift;
    my $args = shift;
    my $style_stack = shift;
  
    my $text = $args->[0];
    #print STDERR "$accent\[".scalar(@$style_stack) ."\] (@$style_stack)\n"; 

    # special handling of @dotless{i}
    if ($accent eq 'dotless')
    { 
        if (($text eq 'i') and (!defined($style_stack->[-1]) or (!defined($unicode_accents{$style_stack->[-1]})) or ($style_stack->[-1] eq 'tieaccent')))
        {
             return "\x{0131}";
        }
        #return "\x{}" if ($text eq 'j'); # not found !
        return $text;
    }
        
    # FIXME \x{0131}\x{0308} for @dotless{i} @" doesn't lead to NFC 00ef.
    return Unicode::Normalize::NFC($text . chr(hex($unicode_diacritical{$accent}))) 
        if (defined($unicode_diacritical{$accent}));
    return ascii_accents($text, $accent);
}

sub t2h_utf8_normal_text($$$$$$$;$)
{
    my $text = shift;
    my $in_raw_text = shift;
    my $in_preformatted = shift;
    my $in_code = shift;
    my $in_math = shift;
    my $in_simple = shift;
    my $style_stack = shift;
    my $state = shift;

    $text = &$protect_text($text) unless($in_raw_text);
    $text = uc($text) if (in_small_caps($style_stack));

    if (!$in_code and !$in_preformatted)
    {
        $text =~ s/---/\x{2014}/g;
        $text =~ s/--/\x{2013}/g;
        $text =~ s/``/\x{201C}/g;
        $text =~ s/''/\x{201D}/g;
    }
    $text = t2h_text_substitutions($text, $in_raw_text, ($in_preformatted or $in_code), $in_simple);
    return Unicode::Normalize::NFC($text);
}

sub t2h_enable_encoding_normal_accent($$$)
{
  return t2h_enable_encoding_accent ('normal', @_);
}
sub t2h_enable_encoding_texi_accent($$$)
{
  return t2h_enable_encoding_accent ('texi', @_);
}
sub t2h_enable_encoding_pre_accent($$$)
{
  return t2h_enable_encoding_accent ('pre', @_);
}

sub t2h_enable_encoding_accent($$$$)
{
  my $context = shift;
  my @other_args = @_;

  my $accent = shift;
  my $args = shift;
  my $style_stack = shift;
  my $text = $args->[0];

#print STDERR "enable_encoding_accent called($context) $accent (@$style_stack)\n";

  # in case ENCODING_NAME is not known, the accent functions saved previously
  # are used. 
  # This should happen rarely, like during @setfilename parsing.
  return &{$t2h_enable_encoding_default_accent{$context}->{$accent}}(@other_args) if (!defined($Texi2HTML::THISDOC{'ENCODING_NAME'}));

  return t2h_utf8_accent($accent,[$text],$style_stack) if ($Texi2HTML::THISDOC{'ENCODING_NAME'} eq 'utf-8');

  # use the saved default handling if this is not a known 8 bit encoding
  return &{$t2h_enable_encoding_default_accent{$context}->{$accent}}(@other_args) if (!exists($makeinfo_encoding_to_map{$Texi2HTML::THISDOC{'ENCODING_NAME'}}));

  # the following is for the handling of known 8 bit encodings.
  if (scalar(@t2h_enable_encoding_accents_stack))
  {
    # in that case, we already have a result ready that corresponds with the
    # formatting of a part of the stack mapped to 
    # t2h_enable_encoding_accents_stack, so it is emptied and the innermost
    # $text is returned as is, such that the unmodified already formatted 
    # innermost formatted accented text is returned.

    #print STDERR " doing nothing, still in stack (@t2h_enable_encoding_accents_stack), accent: $accent";
    my $stack_accent = shift @t2h_enable_encoding_accents_stack;
    #print STDERR " stack_accent $stack_accent\n";
    return $text;
  }

  # in that case there is no t2h_enable_encoding_accents_stack, so we are 
  # at the closing of the innermost accented command. We will try to format 
  # all the stack in reverse(@$style_stack) that coresponds with 
  # accent commands
  my @accents_stack = ();
  my @styles = reverse(@$style_stack);

  # accents are formatted and the intermediate results are kept, such
  # that we can return the maximum of multiaccented letters that can be
  # rendered with a given eight bit formatting.

  # first put the letter in the stack
  my @utf8_partial_results = { 'result' => $text, 
      'accents_stack' => [ @accents_stack ]};

  # then the accent that is associated with the function call
  my $current_accent = t2h_utf8_accent($accent,[$text],$style_stack);
  @accents_stack = ($accent);
  push @utf8_partial_results, { 'result' => $current_accent,
       'accents_stack' => [ @accents_stack ]};

  # and then all the other accents on the stack
  while (scalar(@styles) and (defined($unicode_accents{$styles[0]}) or $styles[0] eq 'dotless'))
  {
    my $next_style = shift @styles;
    my @new_stack = reverse(@styles);
    $current_accent = t2h_utf8_accent($next_style,[$current_accent],\@new_stack);
    push @accents_stack, $next_style;
    push @utf8_partial_results, { 'result' => $current_accent,
       'accents_stack' => [ @accents_stack ]}
        ;
  }

  my $enc_map = $makeinfo_encoding_to_map{$Texi2HTML::THISDOC{'ENCODING_NAME'}};
  my $eight_bit;
  my $result;
  # At this point we have the utf8 encoded results for the accent
  # commands stack, with all the intermediate results.
  # For each one we'll check if it is possible to encode it in the 
  # current eight bit output encoding table
  foreach my $partial_result (@utf8_partial_results)
  {
    my $char = $partial_result->{'result'};
    my $new_eight_bit = '';
    my $new_codepoint;
   
    if (ord($char) <= 128)
    {
      $new_eight_bit =  uc(sprintf("%02x",ord($char)));
      $new_codepoint = uc(sprintf("%04x",ord($char)));
    }
    elsif (ord($char) <= hex(0xFFFF))
    {
      $new_codepoint = uc(sprintf("%04x",ord($char)));
      if (exists($makeinfo_unicode_to_eight_bit{$enc_map}->{$new_codepoint}))
      {
         $new_eight_bit = $makeinfo_unicode_to_eight_bit{$enc_map}->{$new_codepoint};
      }
    }
    #my $eight_bit_txt = 'undef';
    #$eight_bit_txt = $eight_bit if (defined($eight_bit));
    #print STDERR "" . Encode::encode('utf8', "$char") . " (@{$partial_result->{'accents_stack'}}), new_codepoint: $new_codepoint 8bit: $new_eight_bit old:$eight_bit_txt\n";
    # no corresponding eight bit character found
    last if ($new_eight_bit eq '');

    # in that case, the new eight bit character is the same than the one 
    # found with one less character (and it isnt a @dotless{i}). It may
    # mean 2 things
    # -> there are 2 characters in accent. This could happen, for example
    #    if an accent that cannot be rendered is found and it leads to 
    #    appending or prepending a character. For example this happens for
    #    @={@,{@~{n}}}, where @,{@~{n}} is expanded to a 2 character:
    #    n with a tilde, followed by a , 
    #    In nthat case, the additional utf8 accent is prepended, which 
    #    means that it is composed with the , and leaves n with a tilde 
    #    untouched. 
    # -> ord(char) leads to the same for the more inner character.
    #    this, for example, happens for @ubaraccent{a}, where ord(a) is
    #    the same than ord(a with underbar).
    last if (defined($eight_bit) and (($new_eight_bit eq $eight_bit) 
       and !($partial_result->{'accents_stack'}[0] eq 'dotless' and $char eq 'i')));
    $result = $partial_result;
    $eight_bit = $new_eight_bit;
  }
  if (defined($result) and scalar(@{$result->{'accents_stack'}}))
  {
     # we got a result, return it and put in t2h_enable_encoding_accents_stack
     # the stack of accent commands that were processed. They wont be used
     # further, but only unshifted.

  #print STDERR "Result: ".Encode::encode('utf8', $result->{'result'}) ." '$eight_bit' (@{$result->{'accents_stack'}})\n" if defined($result);
     @t2h_enable_encoding_accents_stack = @{$result->{'accents_stack'}};
     # remove the first, it is the accent being processed
     shift @t2h_enable_encoding_accents_stack;
     # it should be noted that we return the 'utf8' accent (which is really
     # a codepoint, and not the eight bit representation, we leave the 
     # conversion to perl, which should handle it fine
     return $result->{'result'};
  }
  
  return &{$t2h_enable_encoding_default_accent{$context}->{$accent}}(@other_args);
}

# end special accent/encoding commands
####################################################################

####################################################################
# TeX/LaTeX, that can especially be used in @math
# To load the appropriate hash, use
# default_load_tex_math

my %tex_default_simple_map_math = (
 '{' => '\{',
 '}' => '\}',
 '\\' => '\\'
);

my %tex_default_math_things_map = %default_things_map;

$tex_default_math_things_map{'bullet'} = '\bullet';
$tex_default_math_things_map{'copyright'} = '\copyright';
$tex_default_math_things_map{'registeredsymbol'} = '\circledR';
$tex_default_math_things_map{'dots'} = '\dots';
$tex_default_math_things_map{'endots'} = '\dots';
$tex_default_math_things_map{'equiv'} = '\equiv';
$tex_default_math_things_map{'expansion'} = '\mapsto';
$tex_default_math_things_map{'arrow'} = '\rightarrow';
$tex_default_math_things_map{'point'} = '\star';
$tex_default_math_things_map{'print'} = '\dashv';
$tex_default_math_things_map{'result'} = '\Rightarrow';
$tex_default_math_things_map{'pounds'} = '\pounds';
$tex_default_math_things_map{'geq'} = '\geq';
$tex_default_math_things_map{'leq'} = '\leq';
$tex_default_math_things_map{'textdegree'} = '^\circ';

my %latex_default_math_things_map = %tex_default_math_things_map;

$latex_default_math_things_map{'aa'} = '\mathring{a}';
$latex_default_math_things_map{'AA'} = '\mathring{A}';

# FIXME Maybe this should not be there since it is not for math but
# more for a completly separate format.
my %latex_default_things_map;

foreach my $thing (keys(%default_things_map))
{
    $latex_default_things_map{$thing} = '\\'.$thing;
}

$latex_default_things_map{'error'} = '\fbox{error}';
$latex_default_things_map{'enddots'} = '\dots\@';
$latex_default_things_map{'exclamdown'} = '\textexclamdown';
$latex_default_things_map{'questiondown'} = '\textquestiondown';
$latex_default_things_map{'tie'} = '~';
$latex_default_things_map{'registeredsymbol'} = '\textregistered';
$latex_default_things_map{'ordf'} = '\textordfeminine';
$latex_default_things_map{'ordm'} = '\textordmasculine';
$latex_default_things_map{'guillemetleft'} = '\guillemotleft';
$latex_default_things_map{'guillemetright'} = '\guillemotright';

foreach my $text_prefixed_symbols ('bullet', 'exclamdown', 'questiondown', 
   'quotedblleft', 'quotedblright', 'quoteleft', 'quoteright')
{
   $latex_default_things_map{$text_prefixed_symbols} = '\text'.$text_prefixed_symbols;
}

foreach my $math_only ('equiv', 'expansion', 'arrow', 'minus', 'point',
   'print', 'result', 'geq', 'leq')
{
   $latex_default_things_map{$math_only} = '$'.$latex_default_math_things_map{$math_only}.'$';
}


# End TeX/LaTeX
#############################################################

sub default_sc($$)
{
    return uc($_[0]);
}

sub default_ctrl($$)
{
   return "^$_[0]";
}

# obsolete, no warning, but noop
sub t2h_default_ctrl($$$)
{
    shift;
    my $args = shift;
    #return "^$args->[0]";
    return "$args->[0]";
}

sub default_sc_pre($$)
{
    return uc($_[0]);
}

sub default_titlefont($$)
{
    return "<h1 class=\"titlefont\">$_[0]</h1>" if ($_[0] =~ /\S/);
    return '';
}

# Return nothing if the text is empty
sub t2h_default_titlefont($$$)
{
    shift;
    my $args = shift;
    my $heading = $args->[0];
    return '' unless ($heading =~ /\S/);
    return &$heading_text('@titlefont', $heading, 0);
}

# At some point in time (before 4.7?) according to the texinfo 
# manual, url shouldn't lead to a link but rather be formatted 
# like text. It is now what indicateurl do, url is the same that
# uref with one arg. If we did like makeinfo did it would have been
#sub url($$)
#{
#    return '&lt;<code>' . $_[0] . '</code>&gt;';
#}
# 
# This is unused, t2h_default_uref is used instead
sub t2h_default_url ($$)
{
    shift;
    my $args = shift;
    my $url = shift @$args;
    $url = main::normalise_space($url);
    return '' unless ($url =~ /\S/);
    return t2h_default_url_and_text($url);
}

sub default_url ($$)
{
    my $url = shift;
    my $command = shift;
    $url =~ s/\s*$//;
    $url =~ s/^\s*//;
    return t2h_default_url_and_text($url);
}

sub default_uref($$)
{
    my $arg = shift;
    my $command = shift;
    my ($url, $text, $replacement);
    ($url, $text, $replacement) = split /,\s*/, $arg;
    $url =~ s/\s*$//;
    $url =~ s/^\s*//;
    $text = $replacement if (defined($replacement));
    return t2h_default_url_and_text($url, $text);
}

sub t2h_default_uref($$)
{
    shift;
    my $args = shift;
    my $url = shift @$args;
    my $text = shift @$args;
    my $replacement = shift @$args;
    $url = main::normalise_space($url);
    $replacement = '' if (!defined($replacement));
    $replacement = main::normalise_space($replacement);
    $text = '' if (!defined($text));
    $text = main::normalise_space($text);
    $text = $replacement if ($replacement ne '');
    return t2h_default_url_and_text($url, $text);
}

sub t2h_default_math($$)
{
    shift;
    my $args = shift;
    my $text = shift @$args;
    return "$text";
}

sub default_email($$)
{
    my $arg = shift;
    my $command = shift;
    my ($mail, $text);
    ($mail, $text) = split /,\s*/, $arg;
    $mail =~ s/\s*$//;
    $mail =~ s/^\s*//;
    return t2h_default_url_and_text("mailto:$mail", $text);
}

sub t2h_default_email($$)
{
    my $command = shift;
    my $args = shift;
    my $mail = shift @$args;
    my $text = shift @$args;
    $mail = main::normalise_space($mail);
    if (defined($text))
    {
       #$text =~ s/^\s*//;
       #$text =~ s/^\s*$//;
        $text = main::normalise_space($text);
    }
    my $mailto = '';
    $mailto = "mailto:$mail" if ($mail ne '');
    return t2h_default_url_and_text($mailto, $text);
}

sub t2h_default_click_normal($$$)
{
    return t2h_default_click('normal', @_);
}

sub t2h_default_click_pre($$$)
{
    return t2h_default_click('pre', @_);
}

sub t2h_default_click_texi($$$)
{
    return t2h_default_click('texi', @_);
}

sub t2h_default_click($$$$$)
{
    my $context = shift;
    my $command = shift;
    my $args = shift;
    my $arg = shift @$args;
    my $cmd = $Texi2HTML::THISDOC{'clickstyle'};
    $cmd = 'arrow' if (!defined($cmd) or ($cmd eq ''));

    my $hash = \%things_map;
    if ($context eq 'pre')
    {
        $hash = \%pre_map;
    }
    elsif ($context eq 'texi')
    {
        $hash = \%texi_map;
    }
    return $hash->{$cmd} . $arg if (exists($hash->{$cmd}));
    return $arg;
}

sub t2h_default_hyphenation($$)
{
    my $command = shift;
    my $args = shift;
    my $text = shift @$args;
    $text =~ s/^\s*//;
    $text =~ s/\s*$//;
    my @list = split /\s+/, $text;
    foreach my $entry (@list)
    {
         my $word = $entry;
         $word =~ s/-//g;
         $Texi2HTML::THISDOC{'hyphenation'}->{$word} = $entry;
    }
}

sub t2h_default_no_texi_email
{
    my $command = shift;
    my $args = shift;
    my $mail = shift @$args;
    my $text = shift @$args;
    $mail = main::normalise_space($mail);
    return $text if (defined($text) and ($text ne ''));
    return $mail;
}

sub t2h_default_no_texi_image($$$$)
{
    my $command = shift;
    my $args = shift;
    my $file = $args->[0];
    $file = main::trim_around_spaces($file);
    return main::substitute_line($file, "\@$command", {'remove_texi' => 1, 'code_style' => 1});
}

sub t2h_default_no_texi_acronym_like($$)
{
    my $command = shift;
    my $args = shift;
    my $acronym_texi = $args->[0];
    return (main::remove_texi($acronym_texi)); 
}

sub t2h_remove_command($$$$)
{
    return '';
}

# This is used for style in preformatted sections
my %old_style_map_pre = %old_style_map;
$old_style_map_pre{'sc'} = '&default_sc_pre';
$old_style_map_pre{'titlefont'} = '';

foreach my $command (keys(%style_map))
{
    $style_map_texi{$command} = {} if (!exists($style_map_texi{$command}));
    $style_map_texi{$command}->{'args'} = [ @{$style_map{$command}->{'args'}} ]
        if (exists($style_map{$command}->{'args'}));
 #print STDERR "COMMAND $command";
}

%style_map_pre = ();

t2h_default_copy_style_map(\%style_map, \%style_map_pre);

$style_map_pre{'sc'} = {};
$style_map_pre{'titlefont'} = {};
$style_map_pre{'click'}->{'function'} = \&t2h_default_click_pre;

$style_map_texi{'sc'} = {};
$style_map_texi{'email'}->{'function'} = \&t2h_default_no_texi_email;
$style_map_texi{'click'}->{'function'} = \&t2h_default_click_texi;

####### special styles. You shouldn't need to change them
%special_style = (
           #'xref'      => ['keep','normal','normal','keep','normal'],
           'xref'         => { 'args' => ['keep','keep','keep','keep','keep'],
               'function' => \&main::do_xref },
           'ref'         => { 'args' => ['keep','keep','keep','keep','keep'],
               'function' => \&main::do_xref },
           'pxref'         => { 'args' => ['keep','keep','keep','keep','keep'],
               'function' => \&main::do_xref },
           'inforef'      => { 'args' => ['keep','keep','keep'], 
               'function' => \&main::do_xref },
           'image'        => { 'args' => ['keep','keep','keep','keep','keep'], 'function' => \&main::do_image },
           'anchor'       => { 'args' => ['keep'], 'function' => \&main::do_anchor_label },
           'footnote'     => { 'args' => ['keep'], 'function' => \&main::do_footnote },
           'shortcaption' => { 'args' => ['keep'], 'function' => \&main::do_caption_shortcaption },
           'caption' => { 'args' => ['keep'], 'function' => \&main::do_caption_shortcaption },
           'acronym',    {'args' => ['keep','keep'], 'function' => \&main::do_acronym_like},
           'abbr',    {'args' => ['keep','keep'], 'function' => \&main::do_acronym_like},
);

# @image is replaced by the first arg in strings
$style_map_texi{'image'} = { 'args' => ['keep','keep','keep','keep','keep'],
       'function' => \&t2h_default_no_texi_image };

$style_map_texi{'acronym'} = { 'args' => ['keep','keep'],
       'function' => \&t2h_default_no_texi_acronym_like };
$style_map_texi{'abbr'} = { 'args' => ['keep','keep'],
       'function' => \&t2h_default_no_texi_acronym_like };

foreach my $special (keys(%special_style))
{
    $style_map{$special} = $special_style{$special}
          unless (defined($style_map{$special}));
    $style_map_pre{$special} = $special_style{$special}
          unless (defined($style_map_pre{$special}));
    $style_map_texi{$special} = { 'args' => ['keep'],
        'function' => \&t2h_remove_command }
          unless (defined($style_map_texi{$special}));
}
####### end special styles.


#foreach my $command (keys(%style_map))
#{
#    print STDERR "STYLE_MAP_TEXI $command($style_map_texi{$command}) ";
#    print STDERR "ARGS $style_map_texi{$command}->{'args'} " if (defined($style_map_texi{$command}->{'args'}));
#    print STDERR "FUN $style_map_texi{$command}->{'function'} " if (defined($style_map_texi{$command}->{'function'}));
#    print STDERR "\n";
#}

# uncomment to use the old interface
#%style_map = %old_style_map;
#%style_map_pre = %old_style_map_pre;

%simple_format_simple_map_texi = %simple_map_pre;
%simple_format_texi_map = %pre_map;
%simple_format_style_map_texi = ();

t2h_default_copy_style_map(\%style_map_texi, \%simple_format_style_map_texi);

foreach my $accent_command ('tieaccent', 'dotless', keys(%unicode_accents))
{
#    $simple_format_style_map_texi{$accent_command}->{'args'} = ['normal'];
    $simple_format_style_map_texi{$accent_command}->{'function'} = \&t2h_default_accent;
}

foreach my $hash (\%style_map, \%style_map_pre, \%style_map_texi, \%simple_format_style_map_texi)
{
  foreach my $style (keys(%{$hash}))
  {
    $hash->{$style}->{'args'} = ['normal'] if (!exists($hash->{$style}->{'args'}));
  } 
}

%default_style_map = ();
%default_style_map_pre = ();
%default_style_map_texi = ();
%default_simple_format_style_map_texi = ();

t2h_default_copy_style_map(\%style_map, \%default_style_map);
t2h_default_copy_style_map(\%style_map_pre, \%default_style_map_pre);
t2h_default_copy_style_map(\%style_map_texi, \%default_style_map_texi);
t2h_default_copy_style_map(\%simple_format_style_map_texi, \%default_simple_format_style_map_texi);

# called here because %default_style_map_texi is used.
t2h_default_set_variables_default();

#################################################################
# TeX/LaTeX styles, that can be used in math

my %default_style_tex_map;
my %default_style_latex_map;

t2h_default_copy_style_map(\%default_style_map, \%default_style_tex_map);
t2h_default_copy_style_map(\%default_style_map, \%default_style_latex_map);

# common in TeX and LaTeX and both for math and normal text

$default_style_latex_map{'w'}->{'inline_begin'} = '\mbox{';
$default_style_tex_map{'w'}->{'inline_begin'} = '\mbox{';
$default_style_latex_map{'dmn'}->{'inline_begin'} = '{\thinspace ';
$default_style_tex_map{'dmn'}->{'inline_begin'} = '{\thinspace ';

my %default_style_latex_math_map;

t2h_default_copy_style_map(\%default_style_latex_map, \%default_style_latex_math_map);

my %default_tex_latex_map = (
  'bf' => [ 'b', 'strong' ],
  'tt' => [ 'code', 'command', 'env', 'file', 'option', 'samp', 't' ],
  'it' => [ 'i', 'var', 'emph' ],
  'sf' => [ 'sanserif' ],
  'rm' => [ 'r' ],
  'sl' => [ 'dfn', 'slanted' ],
);
 
foreach my $style (keys (%default_tex_latex_map))
{
   foreach my $command (@{$default_tex_latex_map{$style}})
   {
      $default_style_tex_map{$command}->{'inline_begin'} = '{\\' . $style .' ';
      $default_style_latex_map{$command}->{'inline_begin'} = '\text' . $style .'{';
      $style = 'normal' if ($style eq 'sl');
      $default_style_latex_math_map{$command}->{'inline_begin'} = '\math' . $style .'{';
   }
}

# only in text

$default_style_latex_map{'emph'}->{'inline_begin'} = '\emph{'; 
$default_style_latex_map{'var'}->{'inline_begin'} = '\emph{'; 
$default_style_latex_map{'sc'}->{'inline_begin'} = '\textsc{'; 

foreach my $hash (\%default_style_tex_map, \%default_style_latex_map, \%default_style_latex_math_map)
{
   foreach my $command (keys(%$hash))
   {
      $hash->{$command}->{'inline_end'} = '}' if ($hash->{$command}->{'inline_begin'});
   }
}

# no kbd key sc in math
#       'kbd'                -                 ?
#       'key'                -                 ?

my %default_style_tex_math_map;

t2h_default_copy_style_map(\%default_style_tex_map, \%default_style_tex_math_map);

# We don't want to override special commands in math mode for now, as long
# as they are not handled especially. Also we don't want to modify the math
# function, it is called to close the @math command and we don't want
# it to be the turned to the default one when calling 
# FIXME maybe it would be even better not to duplicate default styles in
# math, like 'email', 'uref'....
foreach my $command (keys(%special_style), 'math')
{
   delete $default_style_tex_math_map{$command};
   delete $default_style_latex_math_map{$command};
}

foreach my $accent_command ('tieaccent', 'dotless', keys(%unicode_accents))
{
     $default_style_latex_map{$accent_command} = { 'function' => \&default_tex_accent };
     $default_style_tex_map{$accent_command} = { 'function' => \&default_tex_accent };
     $default_style_tex_math_map{$accent_command} = { 'function' => \&default_tex_math_accent };
     $default_style_latex_math_map{$accent_command} = { 'function' => \&default_latex_math_accent };
}

my %tex_text_accent_map = (
 ',' => 'c',
 'ringaccent' => 'r',
 'dotaccent'  => '.',
 'ubaraccent' => 'b',
 'udotaccent' => 'd',
 'ogonek'     => 'k',
 'tieaccent'  => 'tie',
);

sub default_tex_accent($$)
{
    my $text = shift;
    my $accent = shift;
    return "\\$tex_text_accent_map{$accent}\{$text\}" if ($tex_text_accent_map{$accent});
    if ($accent eq 'dotless')
    {
        return "\\$text" if ($text eq 'i' or $text eq 'j');
        return $text;
    }
    return "\\$accent\{$text\}";
}

my %tex_math_accent_map = (
 "'" => 'acute',
 '^' => 'hat',
 '`' => 'grave',
 '~' => 'tilde',
 '"' => 'ddot',
 '=' => 'bar',
 'dotaccent'  => 'dot',
 'u' => 'breve',
 'ubaraccent' => 'underline',
);

sub default_latex_math_accent($$)
{
    my $text = shift;
    my $accent = shift;
    return '\mathring{'.$text.'}' if ($accent eq 'ringaccent');
    return default_tex_math_accent($text, $accent);
}

sub default_tex_math_accent($$)
{
    my $text = shift;
    my $accent = shift;
    return "\\$tex_text_accent_map{$accent}\{$text\}" if ($tex_text_accent_map{$accent});
    if ($accent eq 'dotless')
    {
        return "\\${text}math" if ($text eq 'i' or $text eq 'j');
        return $text;
    }
    return ascii_accent($text, $accent);
}

my $kept_normal_text;

# We assume that in @math the TeX characters have already been 
# rightly protected and so don't protect once more.
sub default_tex_normal_math_text($$$$$$$;$)
{
   my @initial_args = @_;
   my $text = shift;
   my $in_raw_text = shift; # remove_texi
   my $in_preformatted = shift;
   my $in_code = shift;
   my $in_math = shift;
   my $in_simple = shift;
   my $style_stack = shift;
   my $state = shift;

   # Don't protect text in math
   if ($in_math)
   {
       $text = uc($text) if (in_cmd($style_stack, 'sc'));
       return $text;
   }
   return &kept_normal_text(@initial_args);
}

# This is the entry point to be used by users.
sub default_load_tex_math(;$)
{
   my $style = shift;
   $style = 'latex' if (!defined($style));
   %simple_map_math = %tex_default_simple_map_math;
   if ($style eq 'tex')
   {
      %math_map = %tex_default_math_things_map;
      t2h_default_copy_style_map(\%default_style_tex_math_map, \%style_map_math);
   }
   else
   {
      %math_map = %latex_default_math_things_map;
      t2h_default_copy_style_map(\%default_style_latex_math_map, \%style_map_math);
   }
   $kept_normal_text = $normal_text;
   $normal_text = \&default_tex_normal_math_text;
}

# End TeX/LaTeX styles
#################################################################

# regions expanded or not depending on the value of this hash.
# @EXPAND sets entries in this hash, and you should better use
# @EXPAND unless you know what you are doing.
%texi_formats_map = (
     'iftex' => 0, 
     'ignore' => 0, 
     'menu' => 0, 
     'ifplaintext' => 0, 
     'ifinfo' => 0,
     'ifxml' => 0,
     'ifhtml' => 0, 
     'ifdocbook' => 0, 
#     'html' => 0, 
#     'tex' => 0, 
#     'xml' => 0,
#     'docbook' => 0,
     'titlepage' => 1, 
     'documentdescription' => 1, 
     'copying' => 1, 
     'ifnothtml' => 1, 
     'ifnottex' => 1, 
     'ifnotplaintext' => 1, 
     'ifnotinfo' => 1,
     'ifnotxml' => 1,
     'ifnotdocbook' => 1, 
     'direntry' => 'normal',
     'verbatim' => 'raw', 
     'macro' => 'raw', 
     'ifclear' => 'value', 
     'ifset' => 'value' ,
     );
    
%format_map = (
#       'quotation'   =>  'blockquote',
       # lists
#       'itemize'     =>  'ul',
       'enumerate'   =>  '',
#       'multitable'  =>  'table',
       'table'       =>  '',
       'vtable'      =>  '',
       'ftable'      =>  '',
       'group'       =>  '',
       'raggedright'       =>  '',
#       'detailmenu'  =>  '',
       );

%special_list_commands = (
       'table'        =>  {},
       'vtable'       =>  {},
       'ftable'       =>  {},
#       'itemize'      =>  { 'bullet'  => '' }
       'itemize'      =>  {},
       );

%inter_item_commands = (
  'c' => 1,
  'comment' => 1,
  'cindex' => 1
);
#
# texinfo format to align attribute of paragraphs
#

%paragraph_style = (
      'center'     => 'center',
      'flushleft'  => 'left',
      'flushright' => 'right',
      );
      
# complex formats (preformatted)
%complex_format_map = ();
foreach my $complex_format ('example', 'smallexample', 'display', 
  'smalldisplay', 'lisp', 'smalllisp', 'format', 'smallformat',
  'menu', 'detailmenu', 'direntry', 'menu_comment')
{
    $complex_format_map{$complex_format} = { 'begin' => '', 'end' => '' };
}
foreach my $code_complex_format ('example', 'smallexample', 'lisp', 'smalllisp')
{
    $complex_format_map{$code_complex_format}->{'style'} = 'code';
}

# not in code_style, according to post on bug-texinfo
foreach my $format ('menu', 'detailmenu', 'direntry')
{
   $complex_format_map{$format}->{'class'} = 'menu-preformatted';
}

# not in code_style, according to post on bug-texinfo
$complex_format_map{'menu_comment'}->{'class'} = 'menu-comment';

%def_map = (
    # basic commands
    'deffn', [ 'f', 'category', 'name', 'arg' ],
    'defvr', [ 'v', 'category', 'name' ],
    'deftypefn', [ 'f', 'category', 'type', 'name', 'argtype' ],
    'deftypeop', [ 'f', 'category', 'class' , 'type', 'name', 'argtype' ],
    'deftypevr', [ 'v', 'category', 'type', 'name' ],
    'defcv', [ 'v', 'category', 'class' , 'name' ],
    'deftypecv', [ 'v', 'category', 'class' , 'type', 'name' ],
    'defop', [ 'f', 'category', 'class' , 'name', 'arg' ],
    'deftp', [ 't', 'category', 'name', 'argtype' ],
    # shortcuts
    # FIXME i18n
    '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}',
    'deftypeivar', 'deftypecv {Instance Variable}',
    'defmethod', 'defop Method',
    'deftypemethod', 'deftypeop Method',
         );

$def_always_delimiters = "()[]";
$def_in_type_delimiters = ",;";
$def_argument_separator_delimiters = "()[],";

# basic x commands
foreach my $key (keys(%def_map))
{
    $def_map{$key . 'x'} = $def_map{$key};
}

#
# miscalleneous commands
#
# Depending on the value, the command arg or spaces following the command
#     are handled differently:
# 
# the value is a reference on a hash.
# the hash keys are
#    'arg'  if the value is 'line' then the remaining of the line is the arg
#           if it is a number it is the number of args (separated by spaces)
#    'skip' if the value is 'line' then the remaining of the line is skipped
#           if the value is 'space' space but no newline is skipped
#           if the value is 'whitespace' space is skipped
#           if the value is 'linewhitespace' space is skipped if there are 
#                 only spaces remaining on the line
#           if the value is 'linespace' space but no newline is skipped if 
#                 there are only spaces remaining on the line
#    'keep' if true the args and the macro are kept, otherwise the macro 
#          args and skipped stuffs are removed
%misc_command = (
        'bye' => {'skip' => 'line'}, # no arg
        # set, clear
        'set' => {'skip' => 'line'}, # special arg
        'clear' => {'skip' => 'line'}, # special arg
        'alias' => {'args' => 3, 'skip' => 'line'}, # special arg
        # comments
        'comment' => {'arg' => 'line'},
        'c' => {'arg' => 'line'},

        # not needed for formatting
        'raisesections' => {'skip' => 'line'},  # no arg
        'lowersections' => {'skip' => 'line'}, # no arg
        'contents' => {}, # no arg
        'shortcontents' => {}, # no arg
        'summarycontents'=> {}, # no arg
        'setcontentsaftertitlepage' => {}, # no arg
        'setshortcontentsaftertitlepage' => {}, # no arg
#        'detailmenu' => {'skip' => 'whitespace'}, # no arg
#        'end detailmenu' => {'skip' => 'whitespace'}, # no arg
        'clickstyle' => {'skip' => 'line'}, # arg should be an @-command
        # in preamble
        'novalidate' => {}, # no arg
        'dircategory'=> {'arg' => 'line'}, # line. Position with regard 
                         # with direntry is significant
        'pagesizes' => {'skip' => 'line', 'arg' => 'line'}, # can have 2 args 
                                 # or one? 200mm,150mm 11.5in
        'finalout' => {'skip' => 'line'}, # no arg
        'paragraphindent' => {'skip' => 'line', 'arg' => 1}, # arg none asis 
                             # or a number and forbids anything else on the line
        'firstparagraphindent' => {'skip' => 'line', 'arg' => 1}, # none insert
        'frenchspacing' => {'arg' => 1, 'skip' => 'line'}, # on off
                                       # not so sure about 'skip' => 'line'
        'fonttextsize' => {'arg' => 1}, # 10 11
        'allowcodebreaks' => {'arg' => 1, 'skip' => 'line'}, # false or true
        'exampleindent' => {'skip' => 'line', 'arg' => 1}, # asis or a number
        'footnotestyle'=> {'skip' => 'line', 'arg' => 1}, # end and separate
                                 # and nothing else on the line
        'afourpaper' => {'skip' => 'line'}, # no arg
        'afivepaper' => {'skip' => 'line'}, # no arg
        'afourlatex' => {'skip' => 'line'}, # no arg
        'afourwide' => {'skip' => 'line'}, # no arg
        'headings'=> {'skip' => 'line', 'arg' => 1}, 
                    #off on single double singleafter doubleafter
                    # interacts with setchapternewpage
        'setchapternewpage' => {'skip' => 'line', 'arg' => 1}, # off on odd
        'everyheading' => {'arg' => 'line'},
        'everyfooting' => {'arg' => 'line'},
        'evenheading' => {'arg' => 'line'},
        'evenfooting' => {'arg' => 'line'},
        'oddheading' => {'arg' => 'line'},
        'oddfooting' => {'arg' => 'line'},
        'smallbook' => {'skip' => 'line'}, # no arg
        'setfilename' => {'arg' => 'line'},
        'definfoenclose' => {'arg' => 'line'},
        #'shorttitle' => {'arg' => 'line', 'texi' => 1},
        #'shorttitlepage' => {'arg' => 'line', 'texi' => 1},
        #'settitle' => {'arg' => 'line', 'texi' => 1},
        #'author' => {'arg' => 'line', 'texi' => 1},
        #'subtitle' => {'arg' => 'line', 'texi' => 1},
        #'title' => {'arg' => 'line', 'texi' => 1},
        'shorttitle' => {'arg' => 'line'},
        'shorttitlepage' => {'arg' => 'line'},
        'settitle' => {'arg' => 'line'},
        'author' => {'arg' => 'line'},
        'subtitle' => {'arg' => 'line'},
        'title' => {'arg' => 'line'},
        'syncodeindex' => {'skip' => 'line', 'arg' => 2}, 
                          # args are index identifiers
        'synindex' => {'skip' => 'line', 'arg' => 2},
        'defindex' => {'skip' => 'line', 'arg' => 1}, # one identifier arg
        'defcodeindex' => {'skip' => 'line', 'arg' => 1}, # one identifier arg
        #'documentlanguage' => {'skip' => 'whitespace', 'arg' => 1}, 
        'documentlanguage' => {'skip' => 'line', 'arg' => 1}, 
                                                       # language code arg
        'kbdinputstyle' => {'skip' => 'whitespace', 'arg' => 1}, # code 
                                                        #example distinct
        'everyheadingmarks' => {'skip' => 'line', 'arg' => 1}, # top bottom
        'everyfootingmarks' => {'skip' => 'whitespace', 'arg' => 1},
        'evenheadingmarks' => {'skip' => 'whitespace', 'arg' => 1},
        'oddheadingmarks' => {'skip' => 'whitespace', 'arg' => 1},
        'evenfootingmarks' => {'skip' => 'whitespace', 'arg' => 1},
        'oddfootingmarks' => {'skip' => 'whitespace', 'arg' => 1},
        'sp' => {'skip' => 'line', 'arg' => 1}, # no arg 
                                    # at the end of line or a numerical arg
        # formatting
        'page' => {}, # no arg (pagebreak)
        'refill' => {}, # no arg (obsolete, to be ignored)
        'noindent' => {'skip' => 'whitespace'}, # no arg
        'indent' => {'skip' => 'whitespace'},
        'need' => {'skip' => 'line', 'arg' => 1}, # one numerical/real arg
        'exdent' => {'skip' => 'space'},  
        # not valid for info (should be in @iftex)
        'vskip' => {'arg' => 'line'}, # arg line in TeX
        'cropmarks' => {}, # no arg
        # miscalleneous
        'verbatiminclude'=> {'skip' => 'line'},
        'documentencoding' => {'arg' => 1, 'skip' => 'line'}, 
        # ???
        'filbreak' => {},
        # obsolete @-commands. Remove spaces and end of lines after the 
        # commands? If no, they can lead to empty lines
        'quote-arg' => {'skip' => 'line'},
        'allow-recursion' => {'skip' => 'line'},
     );

my %misc_command_old = (
        # not needed for formatting
        'raisesections', 'line',  # no arg
        'lowersections', 'line', # no arg
        'contents', 1, # no arg
        'shortcontents', 1, # no arg
        'summarycontents', 1, # no arg
        'detailmenu', 'whitespace', # no arg
        'end detailmenu', 'whitespace', # no arg
        #'end detailmenu', 1, # no arg
        'novalidate', 1, # no arg
        'bye', 'line', # no arg
        # comments
        'comment', 'line',
        'c', 'line',
        # in preamble
        'dircategory', 'line', # line. Position with regard with direntry is 
                               # significant
        'pagesizes', 'line arg2', # can have 2 args 
        'finalout', 1, # no arg
        'paragraphindent', 'line arg1', # in fact accepts only none asis 
                             # or a number and forbids anything else on the line
        'firstparagraphindent', 'line arg1', # in fact accepts only none insert
        'exampleindent', 'line arg1', # in fact accepts only asis or a number
        'footnotestyle', 'line arg1', # in fact accepts only end and separate
                                 # and nothing else on the line
        'afourpaper', 'line', # no arg
        'afourlatex', 'line', # no arg
        'afourwide', 'line',  # no arg
        'headings', 'line', # one arg, possibilities are 
                    #off on single double singleafter doubleafter
                    # interacts with setchapternewpage
        'setchapternewpage', 'line', # no arg
        'everyheading', 'line',
        'everyfooting', 'line',
        'evenheading', 'line',
        'evenfooting', 'line',
        'oddheading', 'line',
        'oddfooting', 'line',
        'smallbook', 'line', # no arg
        'setfilename', 'line',
        'shorttitle', 'linetexi',
        'shorttitlepage', 'linetexi',
        'settitle', 'linetexi',
        'author', 'linetexi',
        'subtitle', 'linetexi',
        'title','linetexi',
        'syncodeindex','linespace arg2', # args are 
        'synindex','linespace arg2',
        'defindex', 'line arg1', # one identifier arg
        'defcodeindex', 'line arg1', # one identifier arg
        'documentlanguage', 'whitespace arg1', # one language code arg
        'kbdinputstyle', 'whitespace arg1', # one arg within 
                                 #code example distnct
        'sp', 'whitespace arg1', # no arg at the en of line or a numerical arg
        # formatting
        'page', 1, # no arg (pagebreak)
        'refill', 1, # no arg (obsolete, to be ignored))
        'noindent', 'space', # no arg
        'need', 'line arg1', # one numerical/real arg
        'exdent', 'space',  
        # not valid for info (should be in @iftex)
        'vskip', 'line', # arg line in TeX
        'cropmarks', 1, # no arg
        # miscalleneous
        'verbatiminclude', 'line',
        'documentencoding', 'arg1',
        # ???
        'filbreak', 1,
     );

# The command_handler arrays are for commands formatted externally.
# The function references in @command_handler_init are called
# before the second pass, before the @-commands text collection.
# Those in @command_handler_process are called between the second pass
# and the third pass, after collection of @-commands text and before their
# expansion.
# Those in @command_handler_process are called after the third pass,
# after the document generation.
@command_handler_setup = ();
@command_handler_init = ();
@command_handler_names = ();
@command_handler_process = ();
@command_handler_output = ();
@command_handler_finish = ();


sub t2h_default_push_handler($$)
{
   my $function = shift;
   my $handlers = shift;
   push @$handlers, $function unless (grep {$_ eq $function} @$handlers);
}

# the keys of %command_handler are @-command names and the value
# is a hash reference with the following keys:
# 'init'          function reference used to collect the @-command text
# 'expand'        function reference used when expanding the @-command text
%command_handler = ();


# formatting functions

$anchor            = \&t2h_default_anchor;
$def_item          = \&t2h_default_def_item;
$def               = \&t2h_default_def;
$menu_command      = \&t2h_default_menu_command;
$menu_link         = \&t2h_default_menu_link;
#$menu_comment      = \&t2h_default_menu_comment;
$menu_description  = \&t2h_default_menu_description;
#$simple_menu_link  = \&t2h_default_simple_menu_link;
$table_item        = \&t2h_default_table_item;
$table_line        = \&t2h_default_table_line;
$table_list        = \&t2h_default_table_list;
$row               = \&t2h_default_row;
$cell              = \&t2h_default_cell;
$list_item         = \&t2h_default_list_item;
$comment           = \&t2h_default_comment;
$def_line          = \&t2h_default_def_line;
$def_line_no_texi  = \&t2h_default_def_line_no_texi;
$raw               = \&t2h_default_raw;
$raw_no_texi       = \&t2h_default_raw_no_texi;
$heading           = \&t2h_default_heading;
$heading_text      = \&t2h_default_heading_text;
$heading_text_preformatted      = \&t2h_default_heading_text_preformatted;
$element_heading   = \&t2h_default_element_heading;
$heading_no_texi   = \&t2h_default_heading_no_texi;
$external_href     = \&t2h_default_external_href;
$paragraph         = \&t2h_default_paragraph;
$preformatted      = \&t2h_default_preformatted;
$foot_line_and_ref = \&t2h_default_foot_line_and_ref;
$foot_section      = \&t2h_default_foot_section;
$image_files       = \&t2h_default_image_files;
$image             = \&t2h_default_image;
$index_entry_label = \&t2h_default_index_entry_label;
$index_summary     = \&t2h_default_index_summary;
$summary_letter    = \&t2h_default_summary_letter;
$index_entry       = \&t2h_default_index_entry;
$index_entry_command = \&t2h_default_index_entry_command;
$index_letter      = \&t2h_default_index_letter;
#$printindex       = \&t2h_default_printindex;
$print_index       = \&t2h_default_print_index;
$protect_text      = \&t2h_default_protect_text;
$normal_text       = \&t2h_default_normal_text;
$cartouche         = \&t2h_default_cartouche;
$sp                = \&t2h_default_sp;
$definition_category      = \&t2h_default_definition_category;
$definition_index_entry   = \&t2h_default_definition_index_entry;
$copying_comment          = \&t2h_default_copying_comment;
$documentdescription      = \&t2h_default_documentdescription;
$index_summary_file_entry = \&t2h_default_index_summary_file_entry;
$index_summary_file_end   = \&t2h_default_index_summary_file_end;
$index_summary_file_begin = \&t2h_default_index_summary_file_begin;
$empty_line               = \&t2h_default_empty_line;
$float                     = \&t2h_default_float;
$listoffloats             = \&t2h_default_listoffloats;
$listoffloats_entry       = \&t2h_default_listoffloats_entry;
$listoffloats_caption     = \&t2h_default_listoffloats_caption;
$listoffloats_float_style = \&t2h_default_listoffloats_float_style;
$listoffloats_style       = \&t2h_default_listoffloats_style;
$acronym_like             = \&t2h_default_acronym_like;
$quotation                = \&t2h_default_quotation;
$paragraph_style_command  = \&t2h_default_paragraph_style_command;
$heading_texi             = \&t2h_default_heading_texi;
$index_element_heading_texi = \&t2h_default_index_element_heading_texi;
$element_label              = \&t2h_default_element_label;
$anchor_label               = \&t2h_default_anchor_label;
$preserve_misc_command      = \&t2h_default_preserve_misc_command;
$format_list_item_texi      = \&t2h_default_format_list_item_texi;
$begin_format_texi          = \&t2h_default_begin_format_texi;
$insertcopying              = \&t2h_default_insertcopying;
$simple_command             = \&t2h_default_simple_command;
$thing_command              = \&t2h_default_thing_command;
$line_command               = \&t2h_default_line_command;
$internal_links             = \&t2h_default_internal_links;

# address is not used anymore
$address           = \&t2h_default_address;

# return the line after preserving things according to misc_command map.
# You should not change it. It is here, nevertheless, to be used
# in other function references if needed.
sub t2h_default_preserve_misc_command($$)
{
    my $line = shift;
    my $macro = shift;
    my $text = '';
    my $args = [];
    my $skip_spec = '';
    my $arg_spec = '';

#print STDERR "HHHHHHHHH $line $macro\n";
    $skip_spec = $misc_command{$macro}->{'skip'}
        if (defined($misc_command{$macro}->{'skip'}));
    $arg_spec = $misc_command{$macro}->{'arg'}
        if (defined($misc_command{$macro}->{'arg'}));

    if ($arg_spec eq 'line')
    {
        $text .= $line;
        $args = [ $line ];
        $line = '';
    }
    elsif ($arg_spec)
    {
        my $arg_nr = $misc_command{$macro}->{'arg'};
        while ($arg_nr)
        {
            $line =~ s/(\s+\S*)//o;
            my $argument = $1;
            if (defined($argument))
            {
                $text .= $argument;
                push @$args, $argument;
            }
            $arg_nr--;
        }
    }
   
    if ($macro eq 'bye')
    {
        $line = '';
        $text = "\n";
    }
    elsif ($skip_spec eq 'linespace')
    {
        if ($line =~ /^\s*$/o)
        {
            $line =~ s/([ \t]*)//o;
            $text .= $1;
        }
    }
    elsif ($skip_spec eq 'linewhitespace')
    {
        if ($line =~ /^\s*$/o)
        {
            $text .= $line;
            $line = '';
        }	
    }
    elsif ($skip_spec eq 'line')
    {
        $text .= $line;
        $line = '';
    }
    elsif ($skip_spec eq 'whitespace')
    {
        $line =~ s/(\s*)//o;
        $text .=  $1;
    }
    elsif ($skip_spec eq 'space')
    {
        $line =~ s/([ \t]*)//o;
        $text .= $1;
    }
    $line = '' if (!defined($line));
    return ($line, $text, $args);
}

sub t2h_default_simple_command($$$$$)
{
    my $command = shift;
    my $in_preformatted = shift;
    my $in_math = shift;
    my $line_nr = shift;
    my $state = shift;

    if ($in_math)
    {
        my $result = $simple_map_pre{$command};
        $result = $simple_map_math{$command} if (defined($simple_map_math{$command}));
        return $result;
    }
    elsif ($in_preformatted)
    {
        return $simple_map_pre{$command};
    }
    else
    {
        return $simple_map{$command};
    }
}

sub t2h_default_thing_command($$$$$$)
{
    my $command = shift;
    my $text = shift;
    my $in_preformatted = shift;
    my $in_math = shift;
    my $line_nr = shift;
    my $state = shift;

    my $result;
    if ($in_math)
    {
        $result = $pre_map{$command};
        $result = $math_map{$command} if (defined($math_map{$command}));
    }
    elsif ($in_preformatted)
    {
        $result = $pre_map{$command};
    }
    else 
    {
        $result = $things_map{$command};
    }
    return $result . $text;
}

# this is called each time a format begins. Here it is used to keep a
# record of the multitables to have a faithful count of the cell nr.
sub t2h_default_begin_format_texi($$$)
{
    my $command = shift;
    my $line = shift;
    my $state = shift;

   # remove space in front of center, unless it removes the end of line!
    $line =~ s/^\s*// if ($command eq 'center' and $line =~ /\S/);
    return $line;
}

# This function is called whenever a complex format is processed
#
# arguments:
# name of the format
# text appearing inside the format
#
# an eval of $complex_format->{format name}->{'begin'} should lead to the
# beginning of the complex format, an eval of 
# $complex_format->{format name}->{'end'}  should lead to the end of the 
# complex format.
sub t2h_default_complex_format($$)
{
    my $name = shift;
    my $text = shift;
    return '' if ($text eq '');
    return '' if ($name eq 'direntry');
    my $beginning;
    my $end;
    # FIXME obsoleted in nov 2009
    if (exists($complex_format_map->{$name}))
    {
        $beginning = eval "$complex_format_map->{$name}->{'begin'}";
        if ($@ ne '')
        {
            main::msg_debug("Evaluation of $complex_format_map->{$name}->{'begin'}: $@");
            $beginning = '';

        }
        $end = eval "$complex_format_map->{$name}->{'end'}";
        if ($@ ne '')
        {
            main::msg_debug("Evaluation of $complex_format_map->{$name}->{'end'}: $@");
            $end = '';
        }
    }
    else
    {
        $beginning = $complex_format_map{$name}->{'begin'};
        $beginning = '' if (!defined($beginning));
        $end = $complex_format_map{$name}->{'end'};
        $end = '' if (!defined($end));
    }
    return $beginning . $text . $end;	
}

sub t2h_default_empty_line($$)
{
    my $text = shift;
    my $state = shift;
    #ignore the line if it just follows a deff
    return '' if ($state->{'deff_line'});
    return $text;
}

sub t2h_default_unknown($$$$$)
{
    my $macro = shift;
    my $line = shift;
    my $pass = shift;
    my $stack = shift;
    my $state = shift;
    
    my ($result_line, $result, $result_text, $message);
    return ($line, 0, undef, undef);
}

sub t2h_default_unknown_style($$$$$)
{
    my $command = shift;
    my $text = shift;
    my $state = shift;
    my $no_close = shift;
    my $no_open = shift;
    
    my ($result, $result_text, $message);
    return (0, undef, undef);
}

sub t2h_default_caption_shortcaption($)
{
    my $float = shift;
    my $caption_lines;
    my $shortcaption_lines;
    my $style = $float->{'style_texi'};
    if (defined($float->{'nr'}))
    {
        my $nr = $float->{'nr'};
        if ($style ne '')
        {
            $style = gdt('{style} {number}', { 'style' => $style, 'number' => $nr});
        }
        else 
        {
            $style = $nr;
        }
    }
    my $empty_caption = 1;
    if (defined($float->{'caption_texi'}) and @{$float->{'caption_texi'}})
    {
        @$caption_lines = @{$float->{'caption_texi'}};
        $caption_lines->[0] =~ s/^\s*//;
        if ($caption_lines->[0] =~ /\S/ or @$caption_lines > 2)
        {
            $empty_caption = 0;
        }
    }
    
    if (!$empty_caption)
    {
        if (defined($style))
        {
            $caption_lines->[0] = '@'.$CAPTION_STYLE.'{' . gdt('{style}: {caption_first_line}', { 'style' => $style, 'caption_first_line' => $caption_lines->[0] });
        }
        else
        {
            $caption_lines->[0] = '@'.$CAPTION_STYLE.'{' .  $caption_lines->[0];
        }
        push @$caption_lines, "}\n";
    }
    elsif (defined($style))
    {
        $caption_lines->[0] = '@'.$CAPTION_STYLE.'{' . $style . '}' . "\n";
    }

    my $empty_shortcaption = 1;
    if (defined($float->{'shortcaption_texi'}) and @{$float->{'shortcaption_texi'}})
    {
        @$shortcaption_lines = @{$float->{'shortcaption_texi'}};
        $shortcaption_lines->[0] =~ s/^\s*//;
        if ($shortcaption_lines->[0] =~ /\S/ or @$shortcaption_lines > 1)
        {
            $empty_shortcaption = 0;
        }
    }
    
    if (!$empty_shortcaption)
    {
         if (defined($style))
         {
              $shortcaption_lines->[0] = '@'.$CAPTION_STYLE.'{' . gdt('{style}: {shortcaption_first_line}', { 'style' => $style, 'shortcaption_first_line' => $shortcaption_lines->[0] });
         }
         else
         {
              $shortcaption_lines->[0] = '@'.$CAPTION_STYLE.'{' .  $shortcaption_lines->[0];
         }
         push @$shortcaption_lines, "}\n";
    }
    elsif (defined($style))
    {
         $shortcaption_lines->[0] = '@'.$CAPTION_STYLE.'{' . $style . '}' . "\n";
    }
    return ($caption_lines, $shortcaption_lines);
}

# everything is done in &$float
sub t2h_default_caption_shortcaption_command($$$$)
{
   my $command = shift;
   my $text = shift;
   my $texi_lines = shift;
   my $float_element = shift;
   return '';
}

sub t2h_default_float($$$$$)
{
    my $text = shift;
    my $float = shift;
    my $caption = shift;
    my $shortcaption = shift;
    
    my $label = '';
    if (exists($float->{'id'}))
    {
        $label = &$anchor($float->{'id'});
    }
    my $caption_text = '';
    
    if (defined($float->{'caption_texi'}))
    {
        $caption_text = $caption;
    }
    elsif (defined($float->{'shortcaption_texi'}))
    {
        $caption_text = $shortcaption;
    }
    elsif (defined($caption))
    {
        $caption_text = $caption;
    }
    
    return $text . "\n" . $caption_text;
}

sub t2h_default_listoffloats_style($)
{
    my $style_texi = shift;
    return ($style_texi);
}

sub t2h_default_listoffloats_float_style($$)
{
    my $style_texi = shift;
    my $float = shift;
    
    my $style = $float->{'style_texi'};
    #print STDERR "listoffloat/float style mismatch $style_texi $style\n" if ($style_texi ne $style);
    if (defined($float->{'nr'}))
    {
         my $nr = $float->{'nr'};
         if ($style ne '')
         {
              $style = gdt('{style} {number}', { 'style' => $style, 'number' => $nr});
         }
         else 
         {
              $style = $nr;
         }
    }
    return $style;
}

sub t2h_default_listoffloats_caption($)
{
    my $float = shift;
    if (defined($float->{'shortcaption_texi'}))
    {
         return ([ @{$float->{'shortcaption_texi'}} ], 'shortcaption');
    }
    elsif (defined($float->{'caption_texi'}))
    {
         return ([ @{$float->{'caption_texi'}} ], 'caption');
    }
    return ([ ], undef);
}

sub t2h_default_listoffloats_entry($$$$)
{
    my $style_texi = shift;
    my $float = shift;
    my $float_style = shift;
    my $caption = shift;
    my $href = shift;

    my @lines = split /^/, $caption;
    $caption = $lines[0];
    $caption = '' if (!defined($caption));
    chomp ($caption);

    $caption = $float->{'text'} if ($caption eq '' and defined($float->{'text'}) and $float->{'text'} =~ /\S/);
    
    return  "* $float_style: ${caption}\n";
}

sub t2h_default_listoffloats($$$)
{
    my $style_texi = shift;
    my $style = shift;
    my $float_entries = shift;

    my $result = "* List of $style:\n";
    foreach my $float_entry (@$float_entries)
    {
         $result .= $float_entry;
    }
    return $result . "\n";
} 

sub t2h_default_insertcopying($$$)
{
    my $text = shift;
    my $comment = shift;
    my $simple_text = shift;
    return $text;
}

sub t2h_default_protect_text($)
{
   my $text = shift;
   return $text;
}

# This function is used to protect characters which are special in xml
# in inline text:  &, ", <, and >. 
#
# argument:
# text to be protected
sub xml_default_protect_text($)
{
   my $text = shift;
   $text =~ s/&/&amp;/g;
   $text =~ s/</&lt;/g;
   $text =~ s/>/&gt;/g;
   $text =~ s/\"/&quot;/g;
   return $text;
}

sub in_cmd($$)
{
   my $style_stack = shift;
   my $command = shift;
   my $result = 0;
   if ($style_stack and scalar(@{$style_stack}))
   {
       my $level = $#$style_stack;
       #print STDERR ":::$level ::@{$style_stack}\n";
       while ($level >= 0)
       {
           if ($style_stack->[$level] eq $command)
           {
               $result = 1;
               last;
           }
           $level--;
       }
   } 
   return $result;
}
#
#

sub in_small_caps($)
{
   my $style_stack = shift;
   my $in_sc = 0;
   if ($style_stack and scalar(@{$style_stack}))
   {
       my $level = $#$style_stack;
       #print STDERR ":::$level ::@{$style_stack}\n";
       while ($level >= 0)
       {
           if ($style_stack->[$level] eq 'sc')
           {
               $in_sc = 1;
               last;
           }
           $level--;
       }
   } 
   return $in_sc;
}
#
#
sub t2h_default_normal_text($$$$$$$;$)
{
   my @initial_args = @_;
   my $text = shift;
   my $in_raw_text = shift; # remove_texi
   my $in_preformatted = shift;
   my $in_code = shift;
   my $in_math = shift;
   my $in_simple = shift;
   my $style_stack = shift;
   my $state = shift;

  # like utf8.init
   if ($ENABLE_ENCODING and !$ENABLE_ENCODING_USE_ENTITY and defined($Texi2HTML::THISDOC{'ENCODING_NAME'}) and $Texi2HTML::THISDOC{'ENCODING_NAME'} eq 'utf-8' and $USE_UNICODE)
   {
      return &t2h_utf8_normal_text(@initial_args);
   }

   $text = uc($text) if (in_cmd($style_stack, 'sc'));
   if (! $in_code and !$in_preformatted)
   {
         $text =~ s/---/\x{1F}/g;
         $text =~ s/--/-/g;
         $text =~ s/\x{1F}/--/g;
         $text =~ s/``/"/g;
         $text =~ s/\'\'/"/g;
   }
   else
   {
       # to be like tex. This would be wrong, however.
#       my $special_code = 0;
#       $special_code = 1 if (in_cmd($style_stack, 'code') or 
#           in_cmd($style_stack, 'example') or in_cmd($style_stack, 'verbatim'));
#       $text =~ s/'/\&rsquo\;/g unless ($special_code and exists($main::value{'txicodequoteundirected'}));
#       $text =~ s/`/\&lsquo\;/g unless ($special_code and exists($main::value{'txicodequotebacktick'}));
   }
   $text = t2h_text_substitutions($text, $in_raw_text, ($in_preformatted or $in_code), $in_simple);
   return $text;
}

sub t2h_default_url_and_text($;$)
{
    my $url = shift;
    my $text = shift;
    if (!defined($text) or $text eq '')
    {
       return "<$url>" if (defined($url) and $url ne '');
       return '';
    }
    else
    {
        return $text if (!defined($url) or $url eq '');
        return "$text <$url>";
    }
}

# This function produces an anchor. This need is quite html specific.
#
# arguments:
# $name           :   anchor name
# $href           :   anchor href
# text            :   text displayed
# extra_attribs   :   added to anchor attributes list
sub t2h_default_anchor($;$$$)
{
    my $name = shift;
    my $href = shift;
    my $text = shift;
    my $attributes = shift;
    return $text if (defined($text));
    return '';
}

# This function is used to format the text associated with a @deff/@end deff
#
# argument:
# text
#
# $DEF_TABLE should be used to distinguish between @def formatted as table
# and as definition lists.
sub t2h_default_def_item($$$)
{
    my $text = shift;
    my $only_inter_item_commands = shift;
    my $command = shift;
    if ($text =~ /\S/)
    {
        return $text;
    }
    return '';
}

sub t2h_default_definition_category($$$$)
{
    my $name = shift;
    my $class = shift;
    my $style = shift;
    my $command = shift;
    return ($name) if (!defined($class) or $class =~ /^\s*$/);
    if ($style eq 'f')
    {
        return gdt('{name} on {class}', { 'name' => $name, 'class' => $class });
    }
    elsif ($style eq 'v')
    {
        return gdt('{name} of {class}', { 'name' => $name, 'class' => $class });
    }
    else
    {
        return $name;
    }
}

sub t2h_default_definition_index_entry($$$$)
{
    my $name = shift;
    my $class = shift;
    my $style = shift;
    my $command = shift;
    return ($name) if (!defined($class) or $class =~ /^\s*$/);
    if ($style eq 'f')
    {
        return gdt('{name} on {class}', { 'name' => $name, 'class' => $class });
    }
    elsif ($style eq 'v' and $command ne 'defcv')
    {
        return gdt('{name} of {class}', { 'name' => $name, 'class' => $class });
    }
    else
    {
        return $name;
    }
}

sub t2h_default_summary_letter($$$$$$$)
{
   my $letter = shift;
   my $file = shift;
   my $default_identifier = shift;
   my $index_element_id = shift;
   my $number = shift;
   my $index_element = shift;
   my $index_name = shift;

   return '';
}


# format the container for the @deffn line and text
# 
# argument
# text of the whole @def, line and associated text.
#
# $DEF_TABLE should be used.
sub t2h_default_def($$)
{
    my $text = shift;
    my $command = shift;
    if ($text =~ /\S/)
    {
        return $text;
    }
    return '';

}

# a whole menu
#
# argument:
# the whole menu text (entries and menu comments)
#
# argument:
# whole menu text.
# not used since menu is a normal preformatted command with SIMPLE_MENU
sub t2h_default_menu_command($$$)
{
    my $format = shift;
    my $text = shift;
    my $in_preformatted = shift;
    return "* Menu:\n".$text."\n";

}

# formats a menu entry link pointing to a node or section 
#
# arguments:
# the entry text
# the state, a hash reference holding informations about the context, with a 
#     usefull entry, 'preformatted', true if we are in a preformatted format
#     (a format keeping space between words). In that case a function
#     of the main program, main::do_preformatted($text, $state) might 
#     be used to format the text with the current format style.
# href is optionnal. It is the reference to the section or the node anchor
#     which should be used to make the link (typically it is the argument 
#     of a href= attribute in a <a> element).
sub t2h_default_menu_link($$$$$$$$)
{
    my $entry = shift;
    my $state = shift;
    my $href = shift;
    my $node = shift;
    my $title = shift;
    my $ending = shift;
    my $has_title = shift;
    my $command_stack = shift;
    my $preformatted = shift;

    $title = '' unless ($has_title);
    $title .= ':' if ($title ne '');
    return "$MENU_SYMBOL$title$node$ending" if ($NODE_NAME_IN_MENU);
    return "$MENU_SYMBOL$title$entry$ending";
}

# formats a menu entry description, ie the text appearing after the node
# specification in a menu entry an spanning until there is another
# menu entry, an empty line or some text at the very beginning of the line
# (we consider that text at the beginning of the line begins a menu comment) 
#
# arguments:
# the description text
# the state. See menu_entry.
# the heading of the element associated with the node.
# not usd since in SIMPLE_MENU
sub t2h_default_menu_description($$$$)
{
    my $text = shift;
    my $state = shift;
    my $element_text = shift;
    my $command_stack = shift;
    my $preformatted = shift;

    return $text;
}

%htmlxref_entries = (
 'node' => [ 'node', 'section', 'chapter', 'mono' ],
 'section' => [ 'section', 'chapter','node', 'mono' ],
 'chapter' => [ 'chapter', 'section', 'node', 'mono' ],
 'mono' => [ 'mono', 'chapter', 'section', 'node' ],
);


# Construct a href to an external source of information.
# node is the node with texinfo @-commands
# node_id is the node transliterated and transformed as explained in the
#         texinfo manual
# node_xhtml_id is the node transformed such that it is unique and can 
#     be used to make an html cross ref as explained in the texinfo manual
# file is the file in '(file)node'
# This is used to construct href, so is likely to be ignored oustside of
# html.
sub t2h_default_external_href($$$)
{
    my $node = shift;
    my $node_id = shift;
    my $node_xhtml_id = shift;
    my $file = shift;
    $file = '' if (!defined($file));
    my $default_target_split = $Texi2HTML::THISDOC{'EXTERNAL_CROSSREF_SPLIT'};
    my $target_split;
    #my $target_mono;
    #my $href_split;
    #my $href_mono;
    if ($file ne '')
    {
         if ($NEW_CROSSREF_STYLE)
         {
             $file =~ s/\.[^\.]*$//;
             $file =~ s/^.*\///;
             my $href;
             my $document_split = get_conf('SPLIT');
             $document_split = 'mono' if (!$document_split);
             my $split_found;
             if (exists($Texi2HTML::THISDOC{'htmlxref'}->{$file}))
             {
                  foreach my $split_ordered (@{$htmlxref_entries{$document_split}})
                  {
                        if (exists($Texi2HTML::THISDOC{'htmlxref'}->{$file}->{$split_ordered}))
                        {
                             $split_found = $split_ordered;
                             $href = $Texi2HTML::THISDOC{'htmlxref'}->{$file}->{$split_ordered}->{'href'};
                             last;
                        }
                  }
             }
             if (defined($split_found))
             {
                  $target_split = 1 unless ($split_found eq 'mono');
             }
             else
             { # nothing specified for that manual, use default
                  $target_split = $default_target_split;
             }

             if ($target_split)
             {
                  if (defined($href))
                  {
                       $file = $href;
                  }
                  elsif (defined($EXTERNAL_DIR))
                  {
                       $file = "$EXTERNAL_DIR/$file";
                  }
                  elsif (get_conf('SPLIT'))
                  {
                       $file = "../$file";
                  }
                  $file .= "/";
             }
             else
             {# target not split
                  if (defined($href))
                  {
                       $file = $href;
                  }
                  else
                  {
                       if (defined($EXTERNAL_DIR))
                       {
                            $file = "$EXTERNAL_DIR/$file";
                       }
                       elsif (get_conf('SPLIT'))
                       {
                           $file = "../$file";
                       }
                       $file .= "." . $NODE_FILE_EXTENSION;
                  }
             }
         }
         else
         {
             $file .= "/";
             if (defined($EXTERNAL_DIR))
             {
                 $file = $EXTERNAL_DIR . $file;
             }
             else
             {
                 $file = '../' . $file;
             } 
         }
    }
    else
    {
        $target_split = $default_target_split;
    }
    if ($node eq '')
    {
         if ($NEW_CROSSREF_STYLE)
         {
             if ($target_split)
             {
                 if (defined($TOP_NODE_FILE_TARGET))
                 {
                     return $file . $TOP_NODE_FILE_TARGET . '.' . $NODE_FILE_EXTENSION . '#Top';
                 }
                 else
                 {
                     return $file . '#Top';
                 }
             }
             else
             {
                  return $file . '#Top';
             }
         }
         else
         {
             return $file;
         }
    }
    my $target;
    if ($NEW_CROSSREF_STYLE)
    {
         $node = $node_id;
         $target = $node_xhtml_id;
    }
    else
    {
         $node = main::remove_texi($node);
         $node =~ s/[^\w\.\-]/-/g;
    }
    my $file_basename = $node;
    $file_basename = $TOP_NODE_FILE_TARGET if ($node =~ /^top$/i and defined($TOP_NODE_FILE_TARGET));
    if ($NEW_CROSSREF_STYLE)
    {
        if ($target_split)
        {
            return $file . $file_basename . ".$NODE_FILE_EXTENSION" . '#' . $target;
        }
        else
        {
            return $file . '#' . $target;
        }
    }
    else
    {
        return $file . $file_basename . ".$NODE_FILE_EXTENSION";
    }
}

# format a reference external to the generated manual. This produces a full 
# reference with introductive words and the reference itself.
#
# arguments:
# type of the reference: xref (reference at the beginning of a sentence),
#     pxref (reference in a parenthesis),  
# section in the book. This might be undef.
# book name.
# manual file name
# href linking to the html page containing the referenced node. A typical
#     use for this href is a href attribute in an <a> element
# cross reference name
# array of texi arguments of the reference
# array of the formatted arguments of the reference
# node name
sub t2h_default_external_ref($$$$$$$$$)
{
    my $type = shift;
    my $section = shift;
    my $book = shift;
    my $file = shift;
    #my $file_node = shift;
    my $href = shift;
    my $cross_ref = shift;
    my $args_texi = shift;
    my $formatted_args = shift;
    my $node = shift;

    my $name = $section;
    $name = $cross_ref if ($name eq '');
    $name = $node if ($name eq '');

    my $reference = $name;

    if ($book eq '' and $file ne '')
    {
       $name = "($file)$name";
    }
    $reference = &$anchor('', $href, $name) if ($href ne '');

    # Yes, this is ugly, yet this helps internationalization
    if ($type eq 'pxref')
    {
         if (($book ne '') and ($href ne ''))
         {
              return gdt('see {reference} in @cite{{book}}', { 'reference' => $reference, 'book' => $book },{'duplicate'=>1});
         }
         elsif (($book ne '') and ($reference ne ''))
         {
              return gdt('see `{section}\' in @cite{{book}}', { 'section' => $reference, 'book' => $book },{'duplicate'=>1});
         }
         elsif ($book ne '')
         { # should seldom or even never happen
              return gdt('see @cite{{book}}', { 'book' => $book },{'duplicate'=>1});
         }
         elsif ($href ne '')
         {
              return gdt('see {reference}', { 'reference' => $reference },{'duplicate'=>1});
         }
         elsif ($reference ne '')
         {
              return gdt('see `{section}\'', { 'section' => $reference },{'duplicate'=>1});
         }
    }
    if ($type eq 'xref' or $type eq 'inforef')
    {
         if (($book ne '') and ($href ne ''))
         {
              return gdt('See {reference} in @cite{{book}}', { 'reference' => $reference, 'book' => $book },{'duplicate'=>1});
         }
         elsif (($book ne '') and ($reference ne ''))
         {
              return gdt('See `{section}\' in @cite{{book}}', { 'section' => $reference, 'book' => $book },{'duplicate'=>1});
         }
         elsif ($book ne '')
         { # should seldom or even never happen
              return gdt('See @cite{{book}}', { 'book' => $book },{'duplicate'=>1});
         }
         elsif ($href ne '')
         {
              return gdt('See {reference}', { 'reference' => $reference },{'duplicate'=>1});
         }
         elsif ($reference ne '')
         {
              return gdt('See `{section}\'', { 'section' => $reference },{'duplicate'=>1});
         }
    }
    if ($type eq 'ref')
    {
         if (($book ne '') and ($href ne ''))
         {
              return gdt('{reference} in @cite{{book}}', { 'reference' => $reference, 'book' => $book },{'duplicate'=>1});
         }
         elsif (($book ne '') and ($reference ne ''))
         {
              return gdt('`{section}\' in @cite{{book}}', { 'section' => $reference, 'book' => $book },{'duplicate'=>1});
         }
         elsif ($book ne '')
         { # should seldom or even never happen
              return gdt('@cite{{book}}', { 'book' => $book },{'duplicate'=>1});
         }
         elsif ($href ne '')
         {
              return gdt('{reference}', { 'reference' => $reference },{'duplicate'=>1});
         }
         elsif ($reference ne '')
         {
              return gdt('`{section}\'', { 'section' => $reference },{'duplicate'=>1});
         }
    }
    return '';
}

# format a reference to a node or a section in the generated manual. This 
# produces a full reference with introductive words and the reference itself.
#
# arguments:
# type of the reference: xref (reference at the beginning of a sentence),
#     pxref (reference in a parenthesis),  
# href linking to the html page containing the node or the section. A typical
#     use for this href is a href attribute in an <a> element
# short name for this reference
# name for this reference
# boolean true if the reference is a reference to a section
# 
# $SHORT_REF should be used.
sub t2h_default_internal_ref($$$$$$$$)
{
    my $type = shift;
    my $href = shift;
    my $short_name = shift;
    my $name = shift;
    my $is_section = shift;
    my $args_texi = shift;
    my $formatted_args = shift;
    my $element = shift;

    if (! $SHORT_REF)
    {
        $name = &$anchor('', $href, $name);
        if ($type eq 'pxref')
        {
            return gdt('see section {reference_name}', { 'reference_name' => $name },{'duplicate'=>1}) if ($is_section);
            return gdt('see {reference_name}', { 'reference_name' => $name },{'duplicate'=>1});
        }
        elsif ($type eq 'xref' or $type eq 'inforef')
        {
            return gdt('See section {reference_name}', { 'reference_name' => $name },{'duplicate'=>1}) if ($is_section);
            return gdt('See {reference_name}', { 'reference_name' => $name },{'duplicate'=>1});
        }
        elsif ($type eq 'ref')
        {
            return gdt('{reference_name}', { 'reference_name' => $name },{'duplicate'=>1});
        }
    }
    else
    {
        $name = &$anchor('', $href, $short_name);
        if ($type eq 'pxref')
        {
            return gdt('see {reference_name}', { 'reference_name' => $name },{'duplicate'=>1});
        }
        elsif ($type eq 'xref' or $type eq 'inforef')
        {
            return gdt('See {reference_name}', { 'reference_name' => $name },{'duplicate'=>1});
        }
        elsif ($type eq 'ref')
        {
            return gdt('{reference_name}', { 'reference_name' => $name },{'duplicate'=>1});
        }
    }
    return '';
}

# text after @item in table, vtable and ftable
sub t2h_default_table_item($$$$$$$)
{
    my $text = shift;
    my $index_label = shift;
    my $format = shift;
    my $command = shift;
    my $style_stack = shift;
    my $item_cmd = shift;
    my $formatted_index_entry = shift;

    return $text . "\n";
}

# format text on the line following the @item line (in table, vtable and ftable)
sub t2h_default_table_line($$$)
{
    my $text = shift;
    my $only_inter_item_commands = shift;
    my $before_items = shift;

    $only_inter_item_commands = '' if (!defined($only_inter_item_commands));

    if ($text =~ /\S/)
    {
        return $text;
    }
    return '';
}

#my $cell_nr = -1;

# row in multitable
sub t2h_default_row($$$$$$$$)
{
    my $text = shift;
    my $macro = shift;
    my $columnfractions = shift;
    my $prototype_row = shift;
    my $prototype_lengths = shift;
    my $column_number = shift;
    my $only_inter_item_commands = shift;
    my $before_items = shift;

    $only_inter_item_commands = '' if (!defined($only_inter_item_commands));

    if ($text =~ /\S/)
    {
         return $text ."\n";
    }
    return '';
}

# cell in multitable
sub t2h_default_cell($$$$$$$$)
{
    my $text = shift;
    my $row_macro = shift;
    my $columnfractions = shift;
    my $prototype_row = shift;
    my $prototype_lengths = shift;
    my $column_number = shift;
    my $only_inter_item_commands = shift;
    my $before_items = shift;

    $only_inter_item_commands = '' if (!defined($only_inter_item_commands));

    $text =~ s/^\s*//;
    $text =~ s/\s*$//;

    return " $text";
}

# format an itemize, enumerate or @*table @item line, returning
# a texinfo line.
sub t2h_default_format_list_item_texi($$$$$)
{
    my $format = shift;
    my $line = shift;
    my $prepended = shift;
    my $command = shift;
    my $number = shift;

    my $result_line;
    my $open_command = 0;

    $command = 'bullet' if ((!defined($command) or $command eq '') and (!defined($prepended) or $prepended eq '') and $format eq 'itemize');
    $prepended = "\@$command\{\}" if (defined($command) and $command ne '');
    $prepended = "$number." if (defined($number) and $number ne '');

    if (defined($command) and $command ne '' and $format ne 'itemize')
    {
        #@*table
        $open_command = 1;
        $line =~ s/^\s*//;
        $line =~ s/\s*$//;
        if (exists ($style_map{$command}))
        {
           $result_line = "\@$command\{$line\}\n";
        }
        elsif (exists ($things_map{$command}))
        {
           $result_line = "\@$command\{\} $line\n";
        }
        else
        {
           $result_line = "\@$command $line\n";
        }
    }
    elsif (defined($prepended) and $prepended ne '')
    {
         $prepended =~ s/^\s*//;
         $prepended =~ s/\s*$//;
         $line =~ s/^\s*//;
         $result_line = $prepended . ' ' . $line;
    }
    return ($result_line, $open_command);
}


# format an item in a list
#
# argument:
# text of the item
# format of the list (itemize or enumerate)
# command passed as argument to the format
# formatted_command leading command formatted, if it is a thing command
sub t2h_default_list_item($$$$$$$$$$$$)
{
    my $text = shift;
    my $format = shift;
    my $command = shift;
    my $formatted_command = shift;
    my $item_nr = shift;
    my $enumerate_style = shift;
    my $number = shift;
    my $prepended = shift;
    my $prepended_formatted = shift;
    my $only_inter_item_commands = shift;
    my $before_items = shift;
    my $item_command = shift;

    $only_inter_item_commands = '' if (!defined($only_inter_item_commands));

    if ($text =~ /\S/)
    {
        return $text;
    }
    return '';
}

sub t2h_default_table_list($$$$$$$$$)
{
    my $format_command = shift;
    my $text = shift;
    my $command = shift;
    my $formatted_command = shift;
# enumerate
    my $item_nr = shift;
    my $enumerate_style = shift;
# itemize
    my $prepended = shift;
    my $prepended_formatted = shift;
# multitable
    my $columnfractions = shift;
    my $prototype_row = shift;
    my $prototype_lengths = shift;
    my $column_number = shift;
#    my $number = shift;
    return $text;
}

# an comment
sub t2h_default_comment($)
{
    my $text = shift;
    return '';
}

# an xml comment
sub xml_default_comment($)
{
    my $text = shift;
    $text =~ s/--+/-/go;
    return '<!-- ' . $text . ' -->' . "\n";
}

sub t2h_collect_styles($)
{
    my $cmd_stack = shift;
    my @result = ();
    foreach my $style (reverse(@$cmd_stack))
    {
#        last unless (defined($command_type{$style}) and $command_type{$style} eq 'style');
        push @result, $style if (defined($command_type{$style}) and $command_type{$style} eq 'style');
    }
    return @result;
}

sub html_default_parse_attribute($)
{
    my $element = shift;
    return ('', '', '') if (!defined($element));
    my ($class, $attributes) = ('', '');
    if ($element =~ /^(\w+)(\s+.*)/)
    {
        $element = $1;
        $attributes = $2;
        if ($attributes =~ s/^\s+class=\"([^\"]+)\"//)
        {
            $class = $1;
        }
    }
    return ($element, $class, $attributes);
}

sub t2h_get_attribute($;$)
{
    my $command = shift;
    my $map_ref = shift;
    $map_ref = \%style_map if (!defined($map_ref));
    return  unless (defined($map_ref->{$command}));
    my ($element, $class, $attributes) = ('', '', '');
    if (defined($map_ref->{$command}))
    {
        if (ref($map_ref->{$command}) eq 'HASH') 
        {
            ($element, $class, $attributes) = t2h_html_parse_attribute ($map_ref->{$command}->{'attribute'});
        }
        elsif ($map_ref->{$command} !~ /^&/)
        {
            $element = $map_ref->{$command};
            $element =~ s/^\"//;
        }
    }
    return ($element, $class, $attributes);
}

# a paragraph
# arguments:
# $text of the paragraph
# $align for the alignement
# $indent for the indent style (indent or noindent)
# The following is usefull if the paragraph is in an itemize.
# $paragraph_command is the leading formatting command (like @minus)
# $paragraph_command_formatted is the leading formatting command formatted
# $paragraph_number is a reference on the number of paragraphs appearing
#    in the format. The value should be increased if a paragraph is done
# $format is the format name (@itemize)
sub t2h_default_paragraph($$$$$$$$$$$$)
{
    my $text = shift;
    my $align = shift;
    my $indent = shift;
    my $paragraph_command = shift;
    my $paragraph_command_formatted = shift;
    my $paragraph_number = shift;
    my $format = shift;
    my $item_nr = shift;
    my $enumerate_style = shift;
    my $number = shift;
    my $command_stack_at_end = shift;
    my $command_stack_at_begin = shift;
#print STDERR "format: $format\n" if (defined($format));
#print STDERR "paragraph @$command_stack_at_end; @$command_stack_at_begin\n";
#    $paragraph_command_formatted = '' if (!defined($paragraph_command_formatted) or 
#          exists($special_list_commands{$format}->{$paragraph_command}));
    return '' if ($text =~ /^\s*$/);

    return $text;
}

# a preformatted region
# arguments:
# $text of the preformatted region
# $pre_style css style
# $class identifier for the preformatted region (example, menu-comment)
# The following is usefull if the preformatted is in an itemize.
# $leading_command is the leading formatting command (like @minus)
# $leading_command_formatted is the leading formatting command formatted
# $preformatted_number is a reference on the number of preformatteds appearing
#    in the format. The value should be increased if a preformatted is done
sub t2h_default_preformatted($$$$$$$$$$$$)
{
    my $text = shift;
    my $pre_style = shift;
    my $class = shift;
    my $leading_command = shift;
    my $leading_command_formatted = shift;
    my $preformatted_number = shift;
    my $format = shift;
    my $item_nr = shift;
    my $enumerate_style = shift;
    my $number = shift;
    my $command_stack_at_end = shift;
    my $command_stack_at_begin = shift;

#print STDERR "preformatted @$command_stack_at_end; @$command_stack_at_begin\n";
    return '' if ($text eq '');

    my $top_stack = '';
    $top_stack = $command_stack_at_begin->[-1] if (scalar (@$command_stack_at_begin));
    if ($top_stack eq 'multitable')
    {
       $text =~ s/^\s*//;
       $text =~ s/\s*$//;
    }

    # add a new line at the end in case there is none
    chomp($text);
    return $text . "\n";
}

# $new_element is set if the element is associated with a different
# reference element than the preceding element. This is where we
# do the navigation. For example it could be a @node before a @section.
#
# The heading function is always called, though  -- in the default case
# nodes don't lead to an outputted title.
sub t2h_default_element_heading($$$$$$$$$$$$)
{
    my $element = shift;
    my $command = shift;
    my $texi_line = shift;
    my $line = shift;
    my $in_preformatted = shift;
    my $one_section = shift;
    my $element_heading = shift;
    my $first_in_page = shift;
    my $is_top = shift;
    my $previous_is_top = shift;
    my $command_line = shift;
    my $element_id = shift;
    my $new_element = shift;
#print STDERR ":::::::: $element $command i_p $in_preformatted o_s $one_section e_h $element_heading f_p $first_in_page i_t $is_top p_i_t $previous_is_top id $element_id new $new_element\n";

#    my $result = '';
    my $result = &$element_label($element_id, $element, $command, $command_line);

    # in default case, print_head_navigation and print_navigation are no-ops.
    # and $print_element_header is undef, so the following nothing.
    if ($new_element and !$one_section)
    {
       main::msg_debug ("For $element->{'texi'}, element_ref not defined", $element->{'line_nr'}) if (!defined($element->{'element_ref'}));
       if (!defined($element->{'element_ref'}->{'top'}))
       {
           if (defined($print_element_header))
           { # FIXME backward compatibility, print_element_header is obsoleted in nov 2009
                $result .= &$print_element_header($first_in_page, $previous_is_top);
           }
           else
           {
               if (($first_in_page or $previous_is_top) and get_conf('headers'))
               {
                   $result .= &$print_head_navigation(undef, \@SECTION_BUTTONS, $first_in_page, $previous_is_top, $element);
               }
               else
               { # got to do this here, as it isn't done otherwise sinc 
                 # print_head_navigation is not called
                    $result .= &$print_navigation(\@SECTION_BUTTONS) if (get_conf('headers') or get_conf('SPLIT') eq 'node');
               }
           }
       }
       else
       { # this is here because we want to always print the head navigation for top
         # and use TOP_BUTTONS
           $result .= &$print_head_navigation(undef, \@TOP_BUTTONS, $first_in_page, $previous_is_top, $element) 
              if (get_conf('SPLIT') or get_conf('headers'));
       }
    }
    return $result. &$heading($element, $command, $texi_line, $line, $in_preformatted, $one_section, $element_heading);
}

# This function formats a heading for an element
#
# argument:
# an element. It is a hash reference for a node or a sectioning command.
#             it may be the wrong one in case of headings.
# The interesting keys are:
# 'text': the heading text
# 'text_nonumber': the heading text without section number
# 'node': true if it is a node
# 'level': level of the element. 0 for @top, 1 for chapter, heading, 
#      appendix..., 2 for section and so on...
# 'tag_level': the sectioning element name, raisesections and lowersections
#      taken into account
sub t2h_default_heading($$$$$;$$)
{
    my $element = shift;
    my $command = shift;
    my $texi_line = shift;
    my $line = shift;
    my $in_preformatted = shift;
    my $one_section = shift;
    my $element_heading = shift;

    my $level = $element->{'level'};
    if ($element->{'node'})
    {
        if ($element->{'text'} =~ /^top$/i)
        {
          $level = 0;
        }
        else
        {
          $level = 3;
        }
        return '' if (!$element->{'this'} or $element->{'with_section'})
    }
    else
    {
        $command = $element->{'tag_level'};
    }
    my $text = $element->{'text'};

    if ($TOC_LINKS and $command !~ /heading/ and defined($element->{'tocid'}))
    {
         $text = &$anchor ('', "$Texi2HTML::THISDOC{'toc_file'}#$element->{'tocid'}", $text);
    }

    my $result;
    if ($in_preformatted)
    {
        $result = &$heading_text_preformatted("\@$command", $text, $level);
    }
    else
    {
        $result = &$heading_text("\@$command", $text, $level);
    }
   #$result .= "\n";
   return $result;
}

sub t2h_default_heading_no_texi($$$)
{
    my $element = shift;
    my $command = shift;
    my $line = shift;
    return main::remove_texi($line) . "\n";
}

# formatting of raw regions
# if L2H is true another mechanism is used for tex
sub t2h_default_raw($$;$)
{
    my $style = shift;
    my $text = shift;
    my $line_nr = shift;
    my $expanded = 1 if (grep {$style eq $_} @EXPAND);
    if ($style eq 'verbatim' or $style eq 'verbatiminclude' or ($style eq 'tex' and $expanded))
    {
        return $text;
    }
    elsif ($expanded)
    {
        main::line_warn (sprintf(__("Raw format %s is not converted"), $style), $line_nr);
        return $text;
    }
    else
    {
        return '';
    }
}

# raw environment when removing texi (in comments) 
sub t2h_default_raw_no_texi($$)
{
    my $style = shift;
    my $text = shift;
    if ($style eq 'verbatim' or $style eq 'verbatiminclude' or grep {$style eq $_} @EXPAND)
    {
       return $text;
    }
    return '';
}

# This function formats a footnote reference and the footnote text associated
# with a given footnote.
# The footnote reference is the text appearing in the main document pointing
# to the footnote text.
#
# arguments:
# absolute number of the footnote (in the document)
# relative number of the footnote (in the page)
# identifier for the footnote
# identifier for the footnote reference in the main document
# main document file
# footnote text file
# array with the footnote text lines 
# the state. See menu entry.
#
# returns:
# reference on an array containing the footnote text lines which should
#     have been updated
# the text for the reference pointing on the footnote text
sub t2h_default_foot_line_and_ref($$$$$$$$$)
{
    my $number_in_doc = shift;
    my $number_in_page = shift;
    my $footnote_id = shift;
    my $place_id = shift;
    my $document_file = shift;
    my $footnote_file = shift;
    my $lines = shift;
    my $document_state = shift;

    $number_in_doc = $NO_NUMBER_FOOTNOTE_SYMBOL if (!$NUMBER_FOOTNOTES);
    
    if ($document_file eq $footnote_file)
    {
        $document_file = $footnote_file = '';
    }
    unshift (@$lines, "($number_in_doc)\n");
    push @$lines, "\n";
    return ($lines, "($number_in_doc)");
}

# formats a group of footnotes.
#
# argument:
# array reference on the footnotes texts lines 
#
# returns an array reference on the group of footnotes lines
sub t2h_default_foot_section($)
{
    my $lines = shift;
    my $header = &$heading_text('footnotes', gdt('Footnotes'), 3);
    unshift (@$lines, "$header\n");
    return $lines; 
}

sub t2h_default_image_files($$$$)
{
    my $base = shift;
    my $extension = shift;
    my $texi_base = shift;
    my $texi_extension = shift;
    my @files = ();
    return @files if (!defined($base) or ($base eq ''));
    if (defined($extension) and ($extension ne ''))
    {
       push @files,["$base.$extension", "$texi_base.$texi_extension"];
    }
    foreach my $ext (@IMAGE_EXTENSIONS)
    {
        push @files,["$base.$ext", "$texi_base.$ext"];
    }
    return @files;
}

# format an image
#
# arguments:
# image file name with path
# image basename
# a boolean true if we are in a preformatted format
# image file name without path
# alt text
# width
# height
# raw alt
# extension
# path to working dir
# path to file relative from working dir
sub t2h_default_image($$$$$$$$$$$$$$$$$)
{
    my $file = shift;
    my $base = shift;
    my $preformatted = shift;
    my $file_name = shift;
    my $alt = shift;
    my $width = shift;
    my $height = shift;
    my $raw_alt = shift;
    my $extension = shift;
    my $working_dir = shift;
    my $file_path = shift;
    my $in_paragraph = shift;
    my $file_locations = shift;
    my $base_simple_format = shift;
    my $extension_simple_format = shift;
    my $file_name_simple_format = shift;
    my $line_nr = shift;
 
    if (!defined($file_path) or $file_path eq '')
    {
        if (defined($extension) and $extension ne '')
        {
            $file = "$base.$extension";
        }
        else
        {
            $file = "$base.txt";
        }
    }
    elsif (! $COMPLETE_IMAGE_PATHS)
    {
        $file = $file_name;
    }
    my $alt_txt = '';
    $alt_txt = ": $alt" if (defined($alt) and $alt =~ /\S/);
    return "[ $file$alt_txt ]";
    # it is possible that $file_name is more correct as it allows the user
    # to chose the relative path.
}

# address put in footer describing when was generated and who did the manual
# not used anymore
sub t2h_default_address($)
{
    my $date = shift;
    $date = '' if (!defined($date));
    if ($date ne '')
    {
        return gdt('on @emph{{date}}', { 'date' => $date });
    }
    return '';
}

# format a target in the main document for an index entry.
#
# arguments:
# target identifier
# boolean true if in preformatted format
sub t2h_default_index_entry_label($$$$$$$$$)
{
    my $identifier = shift;
    my $preformatted = shift;
    my $entry = shift;
    my $index_name = shift;
    my $index_command = shift;
    my $texi_entry = shift;
    my $formatted_entry = shift;
    my $in_region_not_in_output = shift;
    my $index_entry_ref = shift;

    return '' if (!defined($identifier) or ($identifier !~ /\S/));
    my $label = &$anchor($identifier);
    return $label;
}

sub t2h_default_index_entry_command($$$$$$)
{
   my $command = shift;
   my $index_name = shift;
   my $label = shift;
   my $entry_texi = shift;
   my $entry_formatted = shift;
   my $index_entry_ref = shift;

   return $label;
}

# process definition commands line @deffn for example
sub t2h_default_def_line($$$$$$$$$$$$$$$$)
{
   my $category_prepared = shift;
   my $name = shift;
   my $type = shift;
   my $arguments = shift;
   my $index_label = shift;
   my $arguments_array = shift;
   my $arguments_type_array = shift;
   my $unformatted_arguments_array = shift;
   my $command = shift;
   my $class_name = shift;
   my $category = shift;
   my $class = shift;
   my $style = shift;
   my $original_command = shift;

   $name = '' if (!defined($name) or ($name =~ /^\s*$/));
   $type = '' if (!defined($type) or $type =~ /^\s*$/);
   $arguments = '' if (!defined($arguments) or $arguments =~ /^\s*$/);

   my $type_name = '';
   $type_name .= "$type " if ($type ne '');
   $type_name .= $name if ($name ne '');

   my $result = " -- $category_prepared: ${type_name}$arguments";
   $result =~ s/\s*$//;
   $result .= "\n";

}

# process definition commands line @deffn for example while removing texi
# commands
sub t2h_default_def_line_no_texi($$$$$)
{
   my $category = shift;
   my $name = shift;
   my $type = shift;
   my $arguments = shift;
   $name = '' if (!defined($name) or ($name =~ /^\s*$/));
   $type = '' if (!defined($type) or $type =~ /^\s*$/);
   if (!defined($arguments) or $arguments =~ /^\s*$/)
   {
       $arguments = '';
   }
   my $type_name = '';
   $type_name = " $type" if ($type ne '');
   $type_name .= ' ' . $name if ($name ne '');
   $type_name .= $arguments;
   if (! $DEF_TABLE)
   {
       return $category . ':' . $type_name . "\n";
   }
   else
   {
       
       return $type_name . "    " . $category . "\n";
   }
}

# a cartouche
sub t2h_default_cartouche($$)
{
    my $text = shift;

    if ($text =~ /\S/)
    {
        return $text;
    }
    return '';
} 

my $IDXFILE;
# key:          
# origin_href:  
# entry:        
# texi entry: 
# element_href: 
# element_text: 
sub t2h_default_index_summary_file_entry ($$$$$$$$$)
{
    my $index_name = shift;
    my $key = shift;
    my $origin_href = shift;
    my $entry = shift;
    my $texi_entry = shift;
    my $element_href = shift;
    my $element_text = shift;
    my $is_printed = shift;
    my $manual_name = shift;

    $element_text = 'UNDEF' if (!defined($element_text));
    print $IDXFILE "key: $key\n  origin_href: $origin_href\n  entry: $entry\n"
      . "  texi_entry: $texi_entry\n"
      . "  element_href: $element_href\n  element_text: $element_text\n";
}

sub t2h_default_index_summary_file_begin($$$)
{
    my $name = shift;
    my $is_printed = shift;
    my $manual_name = shift;

    $IDXFILE = main::open_out("$Texi2HTML::THISDOC{'destination_directory'}$Texi2HTML::THISDOC{'file_base_name'}" . "_$name.idx");
    #open(IDXFILE, ">$Texi2HTML::THISDOC{'destination_directory'}$Texi2HTML::THISDOC{'file_base_name'}" . "_$name.idx")
    #   || die "Can't open >$Texi2HTML::THISDOC{'destination_directory'}$Texi2HTML::THISDOC{'file_base_name'}" . "_$name.idx for writing: $!\n";
}

sub t2h_default_index_summary_file_end($$$)
{
    my $name = shift;
    my $is_printed = shift;
    my $manual_name = shift;

    close ($IDXFILE);
}

sub t2h_default_sp($$)
{
   my $number = shift;
   my $preformatted = shift;
   return "\n" x $number;
}

sub t2h_default_acronym_like($$$$$$)
{
    my $command = shift;
    my $acronym_texi = shift;
    my $acronym_text = shift;
    my $with_explanation = shift;
    my $explanation_lines = shift;
    my $explanation_text = shift;
    my $explanation_simply_formatted = shift;
    
   if ($with_explanation)
   {
       #return "$acronym_text ($explanation_text)";
       return gdt('{acronym_like} ({explanation})', {'acronym_like' => $acronym_text, 'explanation' => $explanation_text},{'duplicate'=>1});
   }
   else
   {
       return "$acronym_text";
   }

}

sub t2h_default_quotation_prepend_text($$)
{
    my $command = shift;
    my $text = shift;
    return undef if (!defined($text) or $text =~ /^$/);
    # If there is a @ protecting the end of line the result is, 
    # after the chomp:
    # @b{some text @:}
    # It is likely not to be what was intended, but it is certainly right.
    # this is tested in formatting/quotation.texi
    chomp($text);
    return gdt('@b{{quotation_arg}:} ', {'quotation_arg' => $text}, {'keep_texi' => 1});
}

sub t2h_default_quotation($$$$$)
{
    my $command = shift;
    my $text = shift;
    my $argument_text = shift;
    my $argument_text_texi = shift;
    my $authors = shift;
    my $class_text = '';
    # this allows to add an end of line if there was none, which can happen 
    # if there is an argument to @quotation, but an empty quotation, like
    # @quotation something
    # @end quotation
    chomp($text);
    $text .= "\n";
    return $text;
}

# format the text within a paragraph style format,
#
# argument:
# format name
# text within the format
sub t2h_default_paragraph_style_command($$)
{
    my $format = shift;
    my $text = shift;
    return $text;
}

# format a whole index
#
# argument:
# index text
# index name
sub t2h_default_print_index($$)
{
    my $text = shift;
    my $name = shift;
    return '' if (!defined($text));
    return "* Index:\n" . $text;
}

# format a letter entry in an index page. The letter entry contains
# the index entries for the words beginning with that letter. It is 
# a target for links pointing from the summary of the index.
#
# arguments:
# the letter
# identifier for the letter entry. This should be used to make the target
#     identifier
# text of the index entries
sub t2h_default_index_letter($$$)
{
     my $letter = shift;
     my $id = shift;
     my $text = shift;
     return $text;
}

# format an index entry (in a letter entry).
#
# arguments:
# href to the main text, linking to the place where the index entry appears
# entry text
# href to the main text, linking to the section or node where the index 
#      entry appears
# section or node heading
sub t2h_default_index_entry($$$$$$$$$$)
{
    my $text_href = shift;
    my $entry = shift;
    my $element_href = shift;
    my $element_text = shift;
    my $entry_file = shift;
    my $current_element_file = shift;
    my $entry_target = shift;
    my $entry_element_target = shift;
    my $in_region_not_in_output = shift;
    my $index_entry_ref = shift;
    
    return '' if ($in_region_not_in_output);
    #!$index_entry_ref->{'seen_in_output'} and defined($index_entry_ref->{'region'}));
    $entry = main::substitute_line($index_entry_ref->{'texi'}, "index entry in \@printindex");
    return '' if ($entry =~ /^\s*$/);

    my $real_element_text;
    my $element = $index_entry_ref->{'real_element'};
    # in case $element->{'text'} is not defined, it certainly means that we
    # are n a special elemet, most likely the virtual element appearing 
    # before anything else
    if (defined($element->{'text'}))
    {
       my $element_set = 0;
       if ($NODE_NAME_IN_INDEX)
       {
           if ($element->{'node'})
           {
               $element_set = 1;
           }
           elsif ($element->{'with_node'})
           {
               $element = $element->{'with_node'};
               $element_set = 1;
           }
       }
       elsif (defined($NODE_NAME_IN_INDEX))
       {
           if (!$element->{'node'})
           {
               $element_set = 1;
           }
           elsif ($element->{'with_section'})
           {
               $element = $element->{'with_section'};
               $element_set = 1;
           }
       }
       $element = $element->{'element_ref'} if ($element->{'element_ref'} and !$element_set);
       $real_element_text = $element->{'text'};
    }
    else
    {
       $real_element_text = gdt('(outside of any element)');
    }
    return "* $entry: ".$real_element_text . '.'."\n";
}


sub t2h_default_copying_comment($$$$)
{
    my $copying_lines = shift;
    my $copying_text = shift;
    my $copying_no_texi = shift;
    my $copying_simple_text = shift;
    return '' if ($copying_no_texi eq '');
    my $text = &$comment($copying_no_texi);
    return $text;
}

# return value is currently ignored
sub t2h_default_documentdescription($$$$)
{
    my $decription_lines = shift;
    my $description_text = shift;
    my $description_no_texi = shift;
    my $description_simple_text = shift;

    if (defined($DOCUMENT_DESCRIPTION))
    {
        $Texi2HTML::THISDOC{'DOCUMENT_DESCRIPTION'} = $DOCUMENT_DESCRIPTION;
        return $DOCUMENT_DESCRIPTION;
    }

    #return '' if ($description_no_texi eq ''); 
    #my @documentdescription = split (/\n/, $description_no_texi);
    if ($description_simple_text eq '')
    {
        $Texi2HTML::THISDOC{'DOCUMENT_DESCRIPTION'} = undef;
        return undef;
    }
    my @documentdescription = split (/\n/, $description_simple_text);
    my $document_description = shift @documentdescription;
    chomp $document_description;
    foreach my $line (@documentdescription)
    {
        chomp $line;
        $document_description .= ' ' . $line;
    }
    $Texi2HTML::THISDOC{'DOCUMENT_DESCRIPTION'} = $document_description;
    return $document_description;
}

# format an index summary. This is a list of letters linking to the letter
# entries.
#
# arguments:
# array reference containing the formatted alphabetical letters
# array reference containing the formatted non lphabetical letters
sub t2h_default_index_summary($$)
{
    my $alpha = shift;
    my $nonalpha = shift;

    my $join = '';
    my $nonalpha_text = '';
    my $alpha_text = '';
    return '';
}

# return the heading with number texinfo text
# also called for nodes.
sub t2h_default_heading_texi($$$)
{
    my $tag = shift;
    my $texi = shift;
    my $number = shift;
    #$texi = main::trim_around_spaces($texi);
    return "$number $texi" if ($NUMBER_SECTIONS and defined($number) and ($number !~ /^\s*$/)) ;
    return $texi;
}

# return the heading texinfo text for split index sections
sub t2h_default_index_element_heading_texi($$$)
{ # FIXME i18n
    my $heading_texi = shift;
    my $tag = shift;
    my $texi = shift;
    my $number = shift;
    my $first_letter = shift;
    my $last_letter = shift;
    return "$heading_texi: $first_letter -- $last_letter" if ($last_letter ne $first_letter);
    return "$heading_texi: $first_letter";
}

sub t2h_default_element_label($$$$)
{
    my $id = shift;
    my $element = shift;
    my $command = shift;
    my $line = shift;

    return &$anchor($id);
}

sub t2h_default_misc_element_label($$)
{
    my $id = shift;
    my $misc_page_name = shift;
    return &$anchor($id);
}

sub t2h_default_anchor_label($$$$)
{
    my $id = shift;
    my $anchor_text = shift;
    my $anchor_reference = shift;
    my $in_special_region = shift;
    return &$anchor($id);
}

sub t2h_default_colon_command($)
{
   my $punctuation_character = shift;
   return $colon_command_punctuation_characters{$punctuation_character} if defined($colon_command_punctuation_characters{$punctuation_character});
   return $punctuation_character;
}

# called each time a @tab or an @itemx is encountered.
# To be noticed that there is another function better suited for 
# formatting of an @item line: $format_list_item_texi
sub t2h_default_tab_item_texi($$$$$$)
{
   my $command = shift;
   my $commands_stack = shift;
   my $stack = shift;
   my $state = shift;
   my $line = shift;
   my $line_nr = shift;

   return undef;
}

sub xml_default_line_command($$$$)
{
    my $command = shift;
    my $arg_text = shift;
    my $arg_texi = shift;
    my $state = shift;

    my $style = $line_command_map{$command};
    return '' if ($arg_text eq '' and !defined($style) or $style eq '');
    if ($style)
    {
        my $attribute_text = '';
        if ($style =~ /^(\w+)(\s+.*)/)
        {
            $style = $1;
            $attribute_text = $2;
        }
        $arg_text = "<${style}$attribute_text>$arg_text</$style>";
    }
    $arg_text .= "\n";
    return $arg_text;
}

sub t2h_default_line_command($$$$)
{
    my $command = shift;
    my $arg_text = shift;
    my $arg_texi = shift;
    my $state = shift;

    return $arg_text;
}

# info is special, since it doesn't use the basename but directly the 
# setfilename output, contrary to all the other formats
sub t2h_default_element_file_name($$$)
{
    my $element = shift;
    my $type = shift;
    my $prefix = shift;

    my $outname;
    return unless ($USE_SETFILENAME_EXTENSION and $PREFIX eq '');
    $outname = $OUT if (defined($OUT) and $OUT ne '' and $OUT !~ /\/$/ and $Texi2HTML::THISDOC{'input_file_number'} == 0);
    if ($type eq 'doc' or !get_conf('SPLIT'))
    {
       if (defined($Texi2HTML::THISDOC{'setfilename'}) and !defined($outname))
       {
          $Texi2HTML::THISDOC{'extension'} = '';
          return $Texi2HTML::THISDOC{'setfilename'};
       }
    }

    return undef;
}

sub t2h_default_misc_command_line($$$$$)
{
   my $macro = shift;
   my $line = shift;
   my $args = shift;
   my $stack = shift;
   my $state = shift;
   
   my $result;
   return ($macro, $line, $result);
}

sub t2h_default_internal_links($$$)
{
  my $fh = shift;
  my $elements_list = shift;
  my $indices = shift;
  
  foreach my $element (@$elements_list)
  {
     my $text = $element->{'no_texi'};
     #$text =~ s/^([\w.]+)\. /$1 /;
     #$text = "Annexe ".$text if ($element->{'tag'} =~ /appendix/);
     print $fh "$element->{'file'}#$element->{'id'}\ttoc\t$text\n";
  }
  foreach my $index_name (sort(keys(%$indices)))
  {
     my $entries = $indices->{$index_name};
     
     foreach my $letter_entries (@$entries)
     {
       foreach my $entry (@{$letter_entries->{'entries'}})
       {
        #print STDERR "($index_name) key $key, t $entry->{'texi'}: $entry->{'file'}#$entry->{'target'}\n";
        print $fh "$entry->{'file'}#$entry->{'target'}\t$index_name\t$entry->{'key'}\n" if ($entry->{'key'} =~ /\S/);
       }
     }
  }
}

1;

require "$T2H_HOME/texi2html.init" 
    if ($0 =~ /\.pl$/ &&
        -e "$T2H_HOME/texi2html.init" && -r "$T2H_HOME/texi2html.init");

# @INIT_HTML@
# -*-perl-*-
# vim: set filetype=perl:
######################################################################
# File: html.init
# html output formatting
#
# A copy of this file is pasted into the beginning of texi2html by
# running './configure'.
#
# $Id: html.init,v 1.53 2010/06/26 09:54:23 pertusus Exp $

use strict;

use vars qw(@html_default_multitable_stack);
# used in mediawiki.init
#my  @html_default_multitable_stack;
# tracks menu entry index
my $html_menu_entry_index;
# the simple_formatted document title
my $html_default_title;

# initialise the html output
sub html_default_load(;$)
{
my $from_command_line = shift;

t2h_default_set_variables_xml();

###############################################################
# defaults

$HEADERS = 1;

@T2H_FORMAT_EXPAND = ('html');

# The value is the 'SystemLiteral' which identifies the canonical DTD 
# for the document.
# Definition: The SystemLiteral is called the entity's system
# identifier. It is a URI, which may be used to retrieve the entity.
# See http://www.xml.com/axml/target.html#NT-ExternalID
$DOCTYPE = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">';

# When frames are used, this SystemLiteral identifies the DTD used for
# the file containing the frame description.
$FRAMESET_DOCTYPE = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">';

# if this value is true, ISO8859 characters are used for special symbols 
# (like copyright, etc).
$USE_ISO = 1;

# if the value is true the Texinfo menus are shown.
$SHOW_MENU = 1;

$SHOW_TITLE = 1;

# default is to use nodes only as elements.
$USE_SECTIONS = undef;

$TOP_FILE = 'index.html';

# file name used for Top node when NODE_FILES is true
$TOP_NODE_FILE = 'index';

##############################################################################
#
# The following can only be set in the init file
#
##############################################################################

$INLINE_INSERTCOPYING = 0;

# if this variable is true, numeric entities are used when there is no
# corresponding textual entity.
$USE_NUMERIC_ENTITY = 1;

# if true, use the original command if the result is an entity
$ENABLE_ENCODING_USE_ENTITY = 1;

# used as identation for block enclosing command @example, etc
# If not empty, must be enclosed in <td></td>
$EXAMPLE_INDENT_CELL = '<td>&nbsp;</td>';

# same as above, only for @small
$SMALL_EXAMPLE_INDENT_CELL = '<td>&nbsp;</td>';

# font size for @small
$SMALL_FONT_SIZE = '-1';

# horizontal rules
# Not used
$SMALL_RULE = '<hr size="1">';
$MIDDLE_RULE = '<hr size="2">';
# used almost everywhere
$DEFAULT_RULE = '<hr>';
# used for top element and before misc elements
$BIG_RULE = '<hr size="6">';

# symbol put at the beginning of nodes entry in menu (and optionnaly of 
# unnumbered in menus, see next variable)
$MENU_SYMBOL = '&bull;';
#$MENU_SYMBOL = '*';

$SIMPLE_MENU = 0;

# extension for nodes files when NODE_FILES is true
$NODE_FILE_EXTENSION = 'html';	    

# extension
$EXTENSION = 'html';

# default is to split the html output
$SPLIT = 'node';

# this resets all the variables to the texi2html specific values if
# called as texi2html

t2h_default_set_variables_texi2html() if ($COMMAND_NAME eq 'texi2html');

# this controls the pre style for menus
$MENU_PRE_STYLE = 'font-family: serif';

# on bug-texinfo is has been said the the style is not code_style
# for menus (except for the node name).
# this controls the menu preformatted format
# FIXME this is not dynamic, so change in MENU_PRE_STYLE is not taken 
# into account.
# This is used if the menu appears within a preformatted format (which
# is certainly an invalid construct), and SIMPLE_MENU is not set.
$MENU_PRE_COMPLEX_FORMAT = {
              'pre_style' => $MENU_PRE_STYLE, 
              'class' => 'menu-preformatted',
#              'style' => 'code'
   };

# This controls the ul style for toc
$NO_BULLET_LIST_STYLE = 'list-style: none';
$NO_BULLET_LIST_CLASS = 'no-bullet';
$NO_BULLET_LIST_ATTRIBUTE = ' class="'.$NO_BULLET_LIST_CLASS.'"';

# These lines are inserted before and after the shortcontents 
$BEFORE_OVERVIEW = "<div class=\"shortcontents\">\n";
$AFTER_OVERVIEW = "</div>\n";

# These lines are inserted before and after the contents 
$BEFORE_TOC_LINES = "<div class=\"contents\">\n";
$AFTER_TOC_LINES = "</div>\n";

# text inserted after <body ...>
$AFTER_BODY_OPEN = '';

# text inserted before </body>, this will be automatically inside <p></p>
$PRE_BODY_CLOSE = '';

# this is added inside <head></head> after <title> and some <meta name>
# stuff, it can be used for eg. <style>, <script>, <meta> etc. tags.
$EXTRA_HEAD = '';

# Specifies the minimum page length required before a navigation panel
# is placed at the bottom of a page 
$WORDS_IN_PAGE = 300;

# html version for latex2html
$L2H_HTML_VERSION = "4.0";

# this is not set dynamically
if (!$HEADER_IN_TABLE)
{
   @SECTION_BUTTONS = ([ 'NodeNext', \&html_default_node_direction ],
         [ 'NodePrev', \&html_default_node_direction ],
         [ 'NodeUp', \&html_default_node_direction ], ' ',
         'Contents', 'Index');
   @CHAPTER_BUTTONS = @SECTION_FOOTER_BUTTONS = @NODE_FOOTER_BUTTONS =
    @MISC_BUTTONS = @TOP_BUTTONS = @SECTION_BUTTONS;
   $BIG_RULE = $DEFAULT_RULE;
}

$ICONS = 0;

%BUTTONS_ACCESSKEY =
(
 'Top',         '',
 'Contents',    '',
 'Overview',    '',
 'Index',       '',
 'This',        '',
 'Back',        'p',
 'FastBack',    '',
 'Prev',        'p',
 'Up',          'u',
 'Next',        'n',
 'NodeUp',      'u',
 'NodeNext',    'n',
 'NodePrev',    'p',
 'Following',   '',
 'Forward',     'n',
 'FastForward', '',
 'About' ,      '',
 'First',       '',
 'Last',        '',
 'NextFile',    '',
 'PrevFile',    '',
);

# see http://www.w3.org/TR/REC-html40/types.html#type-links
%BUTTONS_REL =
(
 'Top',         'start',
 'Contents',    'contents',
 'Overview',    '',
 'Index',       'index',
 'This',        '',
 'Back',        'previous',
 'FastBack',    '',
 'Prev',        'previous',
 'Up',          'up',
 'Next',        'next',
 'NodeUp',      'up',
 'NodeNext',    'next',
 'NodePrev',    'previous',
 'Following',   '',
 'Forward',     'next',
 'FastForward', '',
 'About' ,      'help',
 'First',       '',
 'Last',        '',
 'NextFile',    'next',
 'PrevFile',    'previous',
);



# PRE_ABOUT can be a function reference or a scalar.
# Note that if it is a scalar, T2H_InitGlobals has not been called,
# and all global variables like $ADDRESS are not available.
$PRE_ABOUT = sub
{
    return '  ' . &$program_string() .  "\n";
};

# If customizing $AFTER_ABOUT, be sure to put the content inside <p></p>.
$AFTER_ABOUT = '';

%BUTTONS_EXAMPLE =
    (
     'Top',         ' &nbsp; ',
     'Contents',    ' &nbsp; ',
     'Overview',    ' &nbsp; ',
     'Index',       ' &nbsp; ',
     'This',        '1.2.3',
     'Back',        '1.2.2',
     'FastBack',    '1',
     'Prev',        '1.2.2',
     'Up',          '1.2',
     'Next',        '1.2.4',
     'NodeUp',      '1.2',
     'NodeNext',    '1.2.4',
     'NodePrev',    '1.2.2',
     'Following',   '1.2.4',
     'Forward',     '1.2.4',
     'FastForward', '2',
     'About',       ' &nbsp; ',
     'First',       '1.',
     'Last',        '1.2.4',
     'NextFile',    ' &nbsp; ',
     'PrevFile',    ' &nbsp; ',
    );

@IMAGE_EXTENSIONS = ('png','jpg','jpeg','gif');
#, 'txt');

#######################################################################
#
# Values guessed if not set here. The value used is in 
# $Texi2HTML::THISDOC{'VARNAME'}
#
#######################################################################

$BODYTEXT = undef;

#$init_out    = \&html_default_init_out;
$translate_names = \&html_default_translate_names;

t2h_default_push_handler(\&html_default_initialize, \@command_handler_init);
# This must be done after language has been set
t2h_default_push_handler(\&html_default_bodytext, \@command_handler_process);
# This must be done after the fulltitle has been set
t2h_default_push_handler(\&html_default_do_title, \@command_handler_output);

########################################################################
# Control of Page layout:
# You can make changes of the Page layout at two levels:
# 1.) For small changes, it is often enough to change the value of
#     some global string/hash/array variables
# 2.) For larger changes, reimplement one of the HTML_DEFAULT_<fnc>* routines,
#     give them another name, and assign them to the respective
#     $<fnc> variable.

# As a general interface, the hashes Texi2HTML::HREF, Texi2HTML::NAME, Texi2HTML::NODE, Texi2HTML::NO_TEXI, Texi2HTML::SIMPLE_TEXT hold
# href, html-name, node-name, name after removal of texi commands of
# This     -- current section (resp. html page)
# Top      -- top element
# Contents -- Table of contents element
# Overview -- Short table of contents element
# Index    -- Index page element
# About    -- page which explain "navigation buttons" element
# First    -- first node element
# Last     -- last node element
#
# Whether or not the following hash values are set, depends on the context
# (all values are w.r.t. 'This' section)
# Next        -- next element of texinfo
# Prev        -- previous element of texinfo
# NodeUp      -- up node of texinfo
# Following   -- following node in node reading order, taking menu into account
# Forward     -- next node in reading order
# Back        -- previous node in reading order
# Up          -- parent given by sectioning commands
# FastForward -- if leave node, up and next, else next node
# FastBackward-- if leave node, up and prev, else prev node
#
# Furthermore, the following global variabels are set:
# $Texi2HTML::THISDOC{title}          -- title as set by @title...
# $Texi2HTML::THISDOC{title_no_texi}  -- title without texi (without html elements)
# $Texi2HTML::THISDOC{title_texi}     -- title with texinfo @-commands
# $Texi2HTML::THISDOC{fulltitle}      -- full title as set by @title...
# $Texi2HTML::THISDOC{subtitle}       -- subtitle as set by @subtitle
# $Texi2HTML::THISDOC{author}         -- author as set by @author
# $Texi2HTML::THISDOC{copying_comment}  -- text of @copying and @end copying in comment
#
# $Texi2HTML::THISDOC{program}          -- name and version of texi2html
# $Texi2HTML::THISDOC{program_homepage} -- homepage for texi2html
# $Texi2HTML::THISDOC{program_authors}  -- authors of texi2html
# $Texi2HTML::THISDOC{today}            -- date formatted with pretty_date
# $Texi2HTML::THISDOC{toc_file}         -- table of contents file
# $Texi2HTML::THISDOC{file_base_name}   -- base name of the texinfo manual file
# $Texi2HTML::THISDOC{input_file_name}  -- name of the texinfo manual file
# $Texi2HTML::THISDOC{destination_directory}
                                 #      -- directory for the resulting files
# $Texi2HTML::THISDOC{user}             -- user running the script
# $Texi2HTML::THISDOC{css_import_lines} -- ref on @import lines in css files
# $Texi2HTML::THISDOC{css_rule_lines}   -- ref on css rules lines
# other $Texi2HTML::THISDOC keys corresponds with texinfo commands, the value
# being the command arg, for the following commands:
# kbdinputstyle, paragraphindent, setchapternewpage, headings, footnotestyle,
# exampleindent, firstparagraphindent, everyheading, everyfooting,
# evenheading, evenfooting, oddheading, oddfooting
#
# and pointer to arrays of lines which need to be printed by main::print_lines
# $Texi2HTML::THIS_SECTION  -- lines of 'This' section
# $Texi2HTML::OVERVIEW      -- lines of short table of contents
# $Texi2HTML::TOC_LINES     -- lines of table of contents
# $Texi2HTML::TITLEPAGE     -- lines of title page
#
# $Texi2HTML::THIS_ELEMENT  holds the element reference.  

#
# There are the following subs which control the layout:
#
$print_section            = \&HTML_DEFAULT_print_section;
$end_section              = \&HTML_DEFAULT_end_section;
$one_section              = \&HTML_DEFAULT_one_section;
$print_Top_footer	      = \&HTML_DEFAULT_print_Top_footer;
$print_Top		      = \&HTML_DEFAULT_print_Top;
# changed in info format, but irrelevant for non-split formats
$print_Footnotes	      = \&T2H_DEFAULT_print_Footnotes;
$print_misc_header	      = \&HTML_DEFAULT_print_misc_header;
$print_misc_footer	      = \&HTML_DEFAULT_print_misc_footer;
$print_section_footer     = \&HTML_DEFAULT_print_section_footer;
$print_chapter_header     = \&HTML_DEFAULT_print_chapter_header;
$print_section_header     = \&HTML_DEFAULT_print_section_header;
$print_chapter_footer     = \&HTML_DEFAULT_print_chapter_footer;
$print_page_head	      = \&HTML_DEFAULT_print_page_head;
$print_page_foot	      = \&HTML_DEFAULT_print_page_foot;
$print_head_navigation    = \&HTML_DEFAULT_print_head_navigation;
$print_foot_navigation    = \&HTML_DEFAULT_print_foot_navigation;
$button_icon_img	      = \&HTML_DEFAULT_button_icon_img;
$button_formatting	      = \&HTML_DEFAULT_button_formatting;

$print_navigation	      = \&HTML_DEFAULT_print_navigation;
$about_body		      = \&HTML_DEFAULT_about_body;

$print_frame              = \&HTML_DEFAULT_print_frame;
$print_toc_frame          = \&HTML_DEFAULT_print_toc_frame;
$contents                 = \&HTML_DEFAULT_contents;
$shortcontents            = \&HTML_DEFAULT_shortcontents;
$print_redirection_page    = \&HTML_DEFAULT_print_redirection_page;

########################################################################
# Control of formatting:
# 1.) For some changes, it is often enough to change the value of
#     some global map. It might necessitate building a little
#     function along with the change in hash, if the change is the use
#     of another function (in style_map).
# 2.) For other changes, reimplement one of the t2h_default_<fnc>* routines,
#     give them another name, and assign them to the respective
#     $<fnc> variable (below).


#
# texinfo "simple things" (@foo) to HTML ones
#
%simple_map = %default_simple_map;
$simple_map{'*'} = '<br>';     # HTML+
$simple_map{' '} = '&nbsp;';
$simple_map{"\t"} = '&nbsp;';
$simple_map{"\n"} = '&nbsp;';
     # "&#173;" or "&shy;" could also be possible for @-, but it seems
     # that some browser will consider this as an always visible hyphen mark
     # which is not what we want (see http://www.cs.tut.fi/~jkorpela/shy.html)
#$simple_map{'-'} = '';  # hyphenation hint

# this map is used in preformatted text
%simple_map_pre = %simple_map;
$simple_map_pre{'*'} = "\n";

# use entities in the default case
#$things_map{'dots'} = '<small class="dots">...</small>';
$things_map{'enddots'} = '<small class="enddots">...</small>';

%style_map = ();
%style_map_pre = ();
t2h_default_copy_style_map (\%default_style_map, \%style_map);
t2h_default_copy_style_map (\%default_style_map_pre, \%style_map_pre);
# default is {'args' => ['normal'], 'attribute' => ''},   
my %style_map_html = (
      'b',          {'inline_attribute' => 'b'},
      'cite',       {'inline_attribute' => 'cite'},
      'code',       {'inline_attribute' => 'code'},
      'command',    {'inline_attribute' => 'code'},
      'dfn',        {'inline_attribute' => 'em'}, 
      'email',      {'function' => \&html_default_email},
      'emph',       {'inline_attribute' => 'em'}, 
      'env',        {'inline_attribute' => 'code'},
      'file',       {'inline_attribute' => 'tt', 'quote' => '"'},
      'headitemfont', {'inline_attribute' => 'b'}, # not really that, in fact it is 
                                           # in <th> rather than <td>
      'i',          {'inline_attribute' => 'i'},
      'slanted',    {'inline_attribute' => 'i'},
      'sansserif',  {'inline_attribute' => 'span class="sansserif"'},
      'kbd',        {'inline_attribute' => 'kbd'},
      'key',        {'begin' => '&lt;', 'end' => '&gt;'},
      'math',       {'function' => \&html_default_math},
      'option',     {'inline_attribute' => 'samp', 'quote' => '"'},
      'r',          {'inline_attribute' => 'span class="roman"'},
      'samp',       {'inline_attribute' => 'samp', 'quote' => '"'},
      'sc',         {'inline_attribute' => 'small'},
      'strong',     {'inline_attribute' => 'strong'},
      't',          {'inline_attribute' => 'tt'},
      'uref',       {'function' => \&html_default_uref}, 
      'url',        {'function' => \&html_default_uref},
      'indicateurl', {'begin' => '&lt;<code>', 'end' => '</code>&gt;'},
      'var',        {'inline_attribute' => 'var'},
      'verb',       {'inline_attribute' => 'tt'},
     );

foreach my $style_command (keys(%style_map_html))
{
    foreach my $key (keys(%{$style_map_html{$style_command}}))
    {
        $style_map_pre{$style_command}->{$key} = $style_map_html{$style_command}->{$key};
        $style_map{$style_command}->{$key} = $style_map_html{$style_command}->{$key};
    }
}

%line_command_map = (
       'title'    => 'h1',
       'subtitle' => 'h3 align="right"',
       'author'   => 'strong',
);

foreach my $accent_command ('tieaccent', 'dotless', keys(%unicode_accents))
{
     $style_map{$accent_command} = { 'function' => \&xml_default_accent };
     $style_map_pre{$accent_command} = { 'function' => \&xml_default_accent };
}

$style_map_pre{'sc'} = {};
$style_map_pre{'titlefont'} = {};
$style_map_pre{'click'}->{'function'} = \&t2h_default_click_pre;

# uncomment to use the old interface
#%style_map = %old_style_map;
#%style_map_pre = %old_style_map_pre;

%simple_format_simple_map_texi = %simple_map_pre;

%format_map = (
#       'quotation'   =>  'blockquote',
       # lists
#       'itemize'     =>  'ul',
       'enumerate'   =>  'ol',
#       'multitable'  =>  'table',
       'table'       =>  'dl compact="compact"',
       'vtable'      =>  'dl compact="compact"',
       'ftable'      =>  'dl compact="compact"',
       'group'       =>  '',
       'raggedright'       =>  '',
#       'detailmenu'  =>  '',
       );

#%special_list_commands = (
#       'table'        =>  {},
#       'vtable'       =>  {},
#       'ftable'       =>  {},
#       'itemize'      =>  { 'bullet'  => '' }
#       );

$special_list_commands{'itemize'}->{ 'bullet'}  = '';

#
# texinfo format to align attribute of paragraphs
#

%paragraph_style = (
      'center'     => 'center',
      'flushleft'  => 'left',
      'flushright' => 'right',
      );
      
# preformatted formats formatting
if ($COMPLEX_FORMAT_IN_TABLE)
{
   foreach my $indented_format ('example', 'display', 'lisp')
   {
      $complex_format_map{"small$indented_format"}->{'begin'} = "<table><tr>$SMALL_EXAMPLE_INDENT_CELL<td>";
      $complex_format_map{$indented_format}->{'begin'} = "<table><tr>$EXAMPLE_INDENT_CELL<td>";
      $complex_format_map{$indented_format}->{'end'} = "</td></tr></table>\n";
      $complex_format_map{"small$indented_format"}->{'end'} = "</td></tr></table>\n";
   }

   foreach my $non_indented_formats ('format', 'smallformat')
   {
      $complex_format_map{$non_indented_formats}->{'begin'} = '';
      $complex_format_map{$non_indented_formats}->{'end'} = "\n";
   }
}
else
{
   foreach my $format ('example', 'display', 'lisp', 'format')
   {
      $complex_format_map{$format}->{'begin'} = html_default_attribute_class('div', $format).">\n";
      $complex_format_map{"small$format"}->{'begin'} = html_default_attribute_class('div', "small$format").">\n";
      $complex_format_map{$format}->{'end'} = '</div>'."\n";
      $complex_format_map{"small$format"}->{'end'} = '</div>'."\n";
   }
}

foreach my $format ('menu', 'detailmenu', 'direntry')
{
   $complex_format_map{$format} = { 'begin' => '' , 'end' => '',
     'class' => 'menu-preformatted',
   };
}

$complex_format_map{'menu_comment'} = {
   'begin' => "<tr><th colspan=\"3\" align=\"left\" valign=\"top\">",
   'end' => "</th></tr>", 'class' => 'menu-comment',
};


%format_in_paragraph = (
        'html'  => 1,
);
# map mapping css specification to style

%css_map = 
     (
         "ul.$NO_BULLET_LIST_CLASS" => "$NO_BULLET_LIST_STYLE",
         'pre.menu-comment'       => "$MENU_PRE_STYLE",
         'pre.menu-preformatted'  => "$MENU_PRE_STYLE",
         'a.summary-letter'       => 'text-decoration: none',
         'blockquote.smallquotation' => 'font-size: smaller',
#         'pre.display'            => 'font-family: inherit',
#         'pre.smalldisplay'       => 'font-family: inherit; font-size: smaller',
         'pre.display'            => 'font-family: serif',
         'pre.smalldisplay'       => 'font-family: serif; font-size: smaller',
         'pre.smallexample'       => 'font-size: smaller',
         'span.sansserif'         => 'font-family:sans-serif; font-weight:normal',
         'span.roman'         => 'font-family:serif; font-weight:normal',
         'span.nocodebreak'   => 'white-space:pre',
         'span.nolinebreak'   => 'white-space:pre'
     );

$css_map{'pre.format'} = $css_map{'pre.display'};
$css_map{'pre.smallformat'} = $css_map{'pre.smalldisplay'}; 
$css_map{'pre.smalllisp'} = $css_map{'pre.smallexample'};

foreach my $indented_format ('example', 'display', 'lisp')
{
   $css_map{"div.$indented_format"} = 'margin-left: 3.2em';
   $css_map{"div.small$indented_format"} = 'margin-left: 3.2em';
}

# formatting functions

$acronym_like      = \&html_default_acronym_like;
$anchor            = \&html_default_anchor;
$anchor_label      = \&html_default_anchor_label;
$begin_format_texi = \&html_default_begin_format_texi;
$caption_shortcaption     = \&html_default_caption_shortcaption;
$caption_shortcaption_command  = \&html_default_caption_shortcaption_command;
$cartouche         = \&html_default_cartouche;
$cell              = \&html_default_cell;
$def               = \&html_default_def;
$def_item          = \&html_default_def_item;
$def_line          = \&html_default_def_line;
$element_label     = \&html_default_element_label;
$float             = \&html_default_float;
$foot_line_and_ref = \&html_default_foot_line_and_ref;
$foot_section      = \&html_default_foot_section;
$format_list_item_texi      = \&html_default_format_list_item_texi;
$heading           = \&t2h_default_heading;
$heading_text      = \&html_default_heading_text;
$heading_text_preformatted      = \&html_default_heading_text_preformatted;
$image             = \&html_default_image;
$image_files       = \&html_default_image_files;
$index_entry       = \&html_default_index_entry;
$index_entry_command = \&html_default_index_entry_command;
$index_entry_label = \&html_default_index_entry_label;
$index_letter      = \&html_default_index_letter;
$index_summary     = \&html_default_index_summary;
$insertcopying              = \&html_default_insertcopying;
$line_command      = \&html_default_line_command;
$list_item         = \&html_default_list_item;
$listoffloats             = \&html_default_listoffloats;
$listoffloats_entry       = \&html_default_listoffloats_entry;
$listoffloats_caption     = \&html_default_listoffloats_caption;
$listoffloats_float_style = \&html_default_listoffloats_float_style;
$menu_command      = \&html_default_menu_command;
$menu_link         = \&html_default_menu_link;
$menu_description  = \&html_default_menu_description;
$misc_element_label         = \&html_default_misc_element_label;
$normal_text       = \&html_default_normal_text;
$paragraph         = \&html_default_paragraph;
$preformatted      = \&html_default_preformatted;
$print_index       = \&html_default_print_index;
$protect_text      = \&xml_default_protect_text;
$quotation         = \&html_default_quotation;
$sp                = \&html_default_sp;
$summary_letter    = \&html_default_summary_letter;
$tab_item_texi     = \&html_default_tab_item_texi;
$table_item        = \&html_default_table_item;
$table_line        = \&html_default_table_line;
$table_list        = \&html_default_table_list;
$raw               = \&html_default_raw;
$row               = \&html_default_row;

}



# The functions

sub html_default_initialize()
{
    @html_default_multitable_stack = ();
    $html_default_title = undef;
}

# We have to do this dynamically because of internationalization and because
# in body $DOCUMENTLANGUAGE could be used.
sub html_default_bodytext()
{
    # Set the default body text, inserted between <body ... >
    if (defined($BODYTEXT))
    {
        $Texi2HTML::THISDOC{'BODYTEXT'} = $BODYTEXT;
    }
    else
    {
        $Texi2HTML::THISDOC{'BODYTEXT'} = 'lang="' . get_conf('documentlanguage') . '" bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#800080" alink="#FF0000"';
    }
}

sub html_default_translate_names()
{
    t2h_default_translate_names();

    %NAVIGATION_TEXT =
    (
     'Top',         gdt('Top'),
     'Contents',    gdt('Contents'),
     'Overview',    gdt('Overview'),
     'Index',       gdt('Index'),
     ' ',           ' &nbsp; ',
     'This',        gdt('current'),
     'Back',        ' &lt; ',
     'FastBack',    ' &lt;&lt; ',
     'Prev',        gdt('Prev'),
     'Up',          gdt(' Up '),
     'Next',        gdt('Next'),
     'NodeUp',      gdt('Node up'),
     'NodeNext',    gdt('Next node'),
     'NodePrev',    gdt('Previous node'),
     'Following',   gdt('Following node'),
     'Forward',     ' &gt; ',
     'FastForward', ' &gt;&gt; ',
     'About',       ' ? ',
     'First',       ' |&lt; ',
     'Last',        ' &gt;| ',
     'NextFile',    gdt('Next file'),
     'PrevFile',    gdt('Previous file'),
    );

}

sub html_default_do_title()
{
    $html_default_title = "$Texi2HTML::THISDOC{'fulltitle_simple_format'}";
    if ($html_default_title !~ /\S/)
    {
       $html_default_title = gdt('Untitled Document',{},{'simple_format' => 1});
       main::document_warn("Must specify a title with a title command or \@top");
    }
}

########################################################################
# Page formatting functions
#

########################################################################
# Layout for html for every sections
#

sub HTML_DEFAULT_print_section
{
    my $fh = shift;
    my $first_in_page = shift;
    my $previous_is_top = shift;
    my $element = shift;
    my $buttons = \@SECTION_BUTTONS;

    my $nw = main::print_lines($fh);
    if ((get_conf('SPLIT') eq 'node') && get_conf('headers'))
    {
        my $buttons = \@NODE_FOOTER_BUTTONS;
        &$print_foot_navigation($fh, $buttons, $DEFAULT_RULE,
          (!defined($WORDS_IN_PAGE) or (defined ($nw) and $nw >= $WORDS_IN_PAGE)),
          $element);
    }
}

sub HTML_DEFAULT_one_section($$)
{
    my $fh = shift;
    my $element = shift;
    main::print_lines($fh);
    print $fh "$DEFAULT_RULE\n";
    &$print_page_foot($fh);
}

###################################################################
# Layout of top-page I recommend that you use @ifnothtml, @ifhtml,
# @html within the Top texinfo node to specify content of top-level
# page.
#
sub HTML_DEFAULT_print_Top_footer($$$)
{
    my $fh = shift;
    my $end_page = shift;
    my $element = shift;
    my $buttons = \@TOP_BUTTONS;
    my $rule = $DEFAULT_RULE;
    $rule = $BIG_RULE if (!$end_page);
    #print STDERR "end_page: $end_page\n";
    &$print_foot_navigation($fh, $buttons, $rule, 
       ($end_page and (get_conf('headers') or (get_conf('SPLIT') and get_conf('SPLIT') ne 'node'))), $element);
    if ($end_page)
    {
        &$print_page_foot($fh);
    }
}

sub HTML_DEFAULT_print_Top($$$)
{
    my $fh = shift;
    my $has_top_heading = shift;
    my $element = shift;

    main::print_lines($fh, $Texi2HTML::THIS_SECTION);
}

###################################################################
# Layout of Toc, Overview, and Footnotes pages
# By default, we use "normal" layout
# Texi2HTML::HREF of Next, Prev, Up, Forward, Back, etc are not defined
# use: my $buttons = [...] to redefine navigation buttons
sub HTML_DEFAULT_print_Footnotes
{
    return &$print_misc(@_);
}

sub HTML_DEFAULT_print_misc_header
{
    my $fh = shift;
    my $buttons = shift;
    my $new_file = shift;
    my $misc_page = shift;
    &$print_page_head($fh) if ($new_file);
    print $fh "".&$misc_element_label($misc_pages_targets{$misc_page}, $misc_page);
    &$print_head_navigation($fh, $buttons) if ($new_file or get_conf('headers'));
}

sub HTML_DEFAULT_print_misc_footer
{
    my $fh = shift;
    my $buttons = shift;
    my $new_file = shift;
    &$print_foot_navigation($fh, $buttons, $DEFAULT_RULE, 
        ($new_file and (get_conf('headers') or (get_conf('SPLIT') and get_conf('SPLIT') ne 'node'))), undef);
    if ($new_file)
    {
        &$print_page_foot($fh);
    }
}

##################################################################
# section_footer is only called if SPLIT eq 'section'
# section_footer: after print_section of last section, before print_page_foot
#

sub HTML_DEFAULT_print_section_footer
{
    my $fh = shift;
    my $element = shift;
    my $buttons = \@SECTION_FOOTER_BUTTONS;
    &$print_foot_navigation($fh, $buttons, $DEFAULT_RULE, 1, $element);
}

###################################################################
# chapter_header and chapter_footer are only called if
# SPLIT eq 'chapter'
# chapter_header: after print_page_head, before print_section
# chapter_footer: after print_section of last section, before print_page_foot
#
# If you want to get rid of navigation stuff after each section,
# redefine print_section such that it does not call print_navigation,
# and put print_navigation into print_chapter_header
sub HTML_DEFAULT_print_chapter_header
{
    my $fh = shift;
    my $element = shift;
    # nothing to do there, by default, the navigation panel 
    # is the element navigation panel
    if (! get_conf('headers'))
    { # in this case print_navigation is called here. 
        my $buttons = \@CHAPTER_BUTTONS;
        &$print_head_navigation($fh, $buttons);
        print $fh "\n$DEFAULT_RULE\n" unless ($VERTICAL_HEAD_NAVIGATION);
    }
}

sub HTML_DEFAULT_print_chapter_footer
{
    my $fh = shift;
    my $element = shift;
    my $buttons = \@CHAPTER_BUTTONS;
    &$print_foot_navigation($fh, $buttons, $DEFAULT_RULE, 1, $element);
}

sub HTML_DEFAULT_print_section_header
{
    # nothing to do there, by default
    if (! get_conf('headers'))
    { # in this case print_navigation is called here. 
        my $fh = shift;
        my $buttons = \@SECTION_BUTTONS;
        &$print_head_navigation($fh, $buttons); 
    }
}


###################################################################
# Layout of standard header and footer
#

sub HTML_DEFAULT_print_page_head($)
{
    my $fh = shift;
    my $longtitle = $html_default_title;
    $longtitle .= ": $Texi2HTML::SIMPLE_TEXT{'This'}" if (defined ($Texi2HTML::SIMPLE_TEXT{'This'}) and ($Texi2HTML::SIMPLE_TEXT{'This'} !~ /^\s*$/) and get_conf('SPLIT') and ($html_default_title ne $Texi2HTML::SIMPLE_TEXT{'This'}));
    my $description = $Texi2HTML::THISDOC{'DOCUMENT_DESCRIPTION'};
    $description = $longtitle if (!defined($description));
    $description = "<meta name=\"description\" content=\"$description\">" if
         ($description ne '');
    my $encoding = '';
    $encoding = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$Texi2HTML::THISDOC{'ENCODING_NAME'}\">" if (defined($Texi2HTML::THISDOC{'ENCODING_NAME'}) and ($Texi2HTML::THISDOC{'ENCODING_NAME'} ne ''));
    my $date = '';
    my $today = $Texi2HTML::THISDOC{'today'};
    $today = '' if (!defined($today));
    $date = "\n<meta name=\"date\" content=\"$today\">" if ($DATE_IN_HEADER and $today ne '');
    my $links = '';
    if ($USE_LINKS)
    {
        foreach my $link (@LINKS_BUTTONS)
        {
#print STDERR "$link!!$Texi2HTML::HREF{$link}\n";
            if (defined($Texi2HTML::HREF{$link}) and $Texi2HTML::HREF{$link} ne '')
            {
                my $title = '';
                $title = " title=\"$Texi2HTML::SIMPLE_TEXT{$link}\"" if (defined($Texi2HTML::SIMPLE_TEXT{$link}));
                my $rel = '';
                $rel = " rel=\"$BUTTONS_REL{$link}\"" if (defined($BUTTONS_REL{$link}));
                $links .= "<link href=\"$Texi2HTML::HREF{$link}\"${rel}${title}>\n";
            }
        }
    }
    
    my $css_text = '';
    $css_text = $Texi2HTML::THISDOC{'CSS_LINES'} if (defined($Texi2HTML::THISDOC{'CSS_LINES'}));
    my $doctype = get_conf('doctype');
    print $fh <<EOT;
$doctype
<html>
$Texi2HTML::THISDOC{'copying_comment'}<!-- Created on $Texi2HTML::THISDOC{today} by $Texi2HTML::THISDOC{program}
$Texi2HTML::THISDOC{program_authors}-->
<head>
<title>$longtitle</title>

$description
<meta name="keywords" content="$longtitle">
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="$Texi2HTML::THISDOC{program}">$date
$encoding
${links}$css_text
$EXTRA_HEAD
</head>

<body $Texi2HTML::THISDOC{'BODYTEXT'}>
$AFTER_BODY_OPEN
EOT
}

sub HTML_DEFAULT_end_section($$$)
{
    my $fh = shift;
    my $misc_or_top_and_section_separation = shift;
    my $element = shift;
    if ($misc_or_top_and_section_separation)
    {
        my $rule = $BIG_RULE;
        # in that case we are almost surely at the end of the document
        $rule = $DEFAULT_RULE if (! $MONOLITHIC);
        &$print_foot_navigation($fh, undef, $rule, 0, $element, 1);
    }
    else
    {
        print $fh "$DEFAULT_RULE\n";
    }
}

sub HTML_DEFAULT_print_page_foot($)
{
    my $fh = shift;
    my $program_text = '';
    if ($PROGRAM_NAME_IN_FOOTER)
    {
        my $program_string = &$program_string();
        $program_text = " <font size=\"-1\">
  $program_string
 </font>
 <br>";
    }
    print $fh <<EOT;
<p>
$program_text
$PRE_BODY_CLOSE
</p>
</body>
</html>
EOT
}

###################################################################
# Layout of navigation panel

sub HTML_DEFAULT_print_head_navigation($$$$$)
{
    my $fh = shift;
    my $buttons = shift;
    my $first_in_page = shift;
    my $previous_is_top = shift;
    my $element = shift;

    my $result = '';
    if ($VERTICAL_HEAD_NAVIGATION)
    {
        $result .= <<EOT;
<table border="0" cellpadding="0" cellspacing="0">
<tr valign="top">
<td align="left">
EOT
    }
    $result .= &$print_navigation($buttons, $VERTICAL_HEAD_NAVIGATION);
    if ($VERTICAL_HEAD_NAVIGATION)
    {
        $result .= <<EOT;
</td>
<td align="left">
EOT
    }
    elsif (get_conf('SPLIT') eq 'node')
    {
        $result .= "$DEFAULT_RULE\n";
    }
 
    print $fh $result if (defined($fh));
    return $result;
}

sub HTML_DEFAULT_print_foot_navigation
{
    my $fh = shift;
    my $buttons = shift;
    my $rule = shift;
    my $print_navigation_panel = shift;
    my $element = shift;
    # set if called between sections and top or between sections and misc. 
    # could also be the last element
    my $maybe_in_page = shift;

    $rule = '' if (!defined($rule));
    $print_navigation_panel = 1 if (!defined($print_navigation_panel)
             and defined($buttons));

    # avoid the rule if at the end of a page and there is nothing below
    $rule = '' if (!$PROGRAM_NAME_IN_FOOTER and !$print_navigation_panel and !$maybe_in_page);

    if ($VERTICAL_HEAD_NAVIGATION)
    {
        print $fh <<EOT;
</td>
</tr>
</table>
EOT
    }
    print $fh "$rule\n" if ($rule ne '');
    print $fh "".&$print_navigation($buttons) if ($print_navigation_panel);
}

######################################################################
# navigation panel
#
# how to create IMG tag
sub HTML_DEFAULT_button_icon_img
{
    my $button = shift;
    my $icon = shift;
    my $name = shift;
    return '' if (!defined($icon));
    $button = "" if (!defined ($button));
    $name = '' if (!defined($name));
    my $alt = ''; 
    if ($name ne '')
    {
        if ($button ne '')
        {
            $alt = "$button: $name";
        }
        else
        {
            $alt = $name;
        }  
    }
    else
    {
        $alt = $button;
    }
    return qq{<img src="$icon" border="0" alt="$alt" align="middle">};
}

sub HTML_DEFAULT_button_formatting($$)
{
   my $button = shift;
   my $vertical = shift;

   my ($active, $passive);
   if (ref($button) eq 'CODE')
   {
       $active = &$button($vertical);
   }
   elsif (ref($button) eq 'SCALAR')
   {
       $active = "$$button" if defined($$button);
   }
   elsif (ref($button) eq 'ARRAY')
   {
       my $text = $button->[1];
       my $button_href = $button->[0];
       # verify that $button_href is simple text and text is a reference
       if (defined($button_href) and !ref($button_href) 
          and defined($text) and (ref($text) eq 'SCALAR') and defined($$text))
       {             # use given text
           if ($Texi2HTML::HREF{$button_href})
           {
               my $anchor_attributes = '';
               if ($USE_ACCESSKEY and (defined($BUTTONS_ACCESSKEY{$button_href})) and ($BUTTONS_ACCESSKEY{$button_href} ne ''))
               {
                   $anchor_attributes = "accesskey=\"$BUTTONS_ACCESSKEY{$button_href}\"";
               }
               if ($USE_REL_REV and (defined($BUTTONS_REL{$button_href})) and ($BUTTONS_REL{$button_href} ne ''))
               {
                    $anchor_attributes .= " rel=\"$BUTTONS_REL{$button_href}\"";
               }
               $active =  "" .
                    &$anchor('',
                               $Texi2HTML::HREF{$button_href},
                               $$text,
                               $anchor_attributes
                             );
           }
           else
           {
               $passive = $$text;
           }
       }
       elsif (defined($button_href) and !ref($button_href)
          and defined($text) and (ref($text) eq 'CODE'))
       {
           $active = &$text($button_href);
       }
    }
    elsif ($button eq ' ')
    {                       # handle space button
        $active = 
            ($ICONS && $ACTIVE_ICONS{' '}) ?
               &$button_icon_img($BUTTONS_NAME{$button}, $ACTIVE_ICONS{' '}) :
                   $NAVIGATION_TEXT{' '};
            #next;
    }
    elsif ($Texi2HTML::HREF{$button})
    {                       # button is active
        my $btitle = $BUTTONS_GOTO{$button} ?
           'title="' . $BUTTONS_GOTO{$button} . '"' : '';
        if ($USE_ACCESSKEY and (defined($BUTTONS_ACCESSKEY{$button})) and ($BUTTONS_ACCESSKEY{$button} ne ''))
        {
            $btitle .= " accesskey=\"$BUTTONS_ACCESSKEY{$button}\"";
        }
        if ($USE_REL_REV and (defined($BUTTONS_REL{$button})) and ($BUTTONS_REL{$button} ne ''))
        {
            $btitle .= " rel=\"$BUTTONS_REL{$button}\"";
        }
        if ($ICONS && $ACTIVE_ICONS{$button})
        {                   # use icon
            $active = '' .
              &$anchor('',
                   $Texi2HTML::HREF{$button},
                   &$button_icon_img($BUTTONS_NAME{$button},
                              $ACTIVE_ICONS{$button},
                              $Texi2HTML::SIMPLE_TEXT{$button}),
                   $btitle
              );
        }
        else
        {                   # use text
            $active = 
               '[' .
                  &$anchor('',
                        $Texi2HTML::HREF{$button},
                        $NAVIGATION_TEXT{$button},
                        $btitle
                     ) .
                ']';
        }
    }
    else
    {                       # button is passive
        $passive = 
          $ICONS && $PASSIVE_ICONS{$button} ?
               &$button_icon_img($BUTTONS_NAME{$button},
                                 $PASSIVE_ICONS{$button},
                                 $Texi2HTML::SIMPLE_TEXT{$button}) :
               "[" . $NAVIGATION_TEXT{$button} . "]";
    }
    return ($active, $passive);
}

my %html_default_node_directions;
foreach my $node_directions ('NodeNext', 'NodePrev', 'NodeUp')
{
   $html_default_node_directions{$node_directions} = 1;
}

sub HTML_DEFAULT_print_navigation($;$)
{
    my $buttons = shift;
    my $vertical = shift;

    my $first_button = 1;
    my $result = '';
    if ($HEADER_IN_TABLE)
    {
        $result .= html_default_attribute_class('table', 'header').' cellpadding="1" cellspacing="1" border="0">'."\n";
        $result .= "<tr>" unless $vertical;
    }
    else
    {
        $result .= html_default_attribute_class('div', 'header').">\n<p>\n";
    }
    for my $button (@$buttons)
    {
        if ($HEADER_IN_TABLE)
        {
            $result .= qq{<tr valign="top" align="left">\n} if $vertical;
            $result .=  qq{<td valign="middle" align="left">};
        }
        my $direction;
        if (ref($button) eq 'ARRAY' and defined($button->[0]) and !ref($button->[0]))
        {
           $direction = $button->[0];
        }
        elsif (defined($button) and !ref($button))
        {
           $direction = $button;
        }
        
        my ($active, $passive) = &$button_formatting($button, $vertical);
        if ($HEADER_IN_TABLE)
        {
            if (defined($active))
            {
                $first_button = 0 if ($first_button);
                $result .= $active;
            }
            elsif (defined($passive))
            {
                $first_button = 0 if ($first_button);
                $result .= $passive;
            }
            $result .= "</td>\n";
            $result .= "</tr>\n" if $vertical;
        }
        elsif (defined($active))
        { # only active buttons are print out when not in table
            if (defined($direction) and $html_default_node_directions{$direction} and !$first_button)
            {
                $active = ', ' .$active;
            }
            $result .= $active;
            $first_button = 0 if ($first_button);
        }
    }
    if ($HEADER_IN_TABLE)
    {
        $result .= "</tr>" unless $vertical;
        $result .= "</table>\n";
    }
    else
    {
        $result .= "</p>\n</div>\n";
    }
    return $result;
}

sub html_default_node_direction($)
{
    my $direction = shift;
    my $result = undef;
    if ($Texi2HTML::HREF{$direction} and $Texi2HTML::NODE{$direction})
    {
         my $anchor_attributes = '';
         if ($USE_ACCESSKEY and (defined($BUTTONS_ACCESSKEY{$direction})) and ($BUTTONS_ACCESSKEY{$direction} ne ''))
         {
              $anchor_attributes = "accesskey=\"$BUTTONS_ACCESSKEY{$direction}\"";
         }
         if ($USE_REL_REV and (defined($BUTTONS_REL{$direction})) and ($BUTTONS_REL{$direction} ne ''))
         {
              $anchor_attributes .= " rel=\"$BUTTONS_REL{$direction}\"";
         }
         my $anchor = &$anchor('',
                            $Texi2HTML::HREF{$direction},
                            $Texi2HTML::NODE{$direction},
                            $anchor_attributes
                          ) 
                        ;
         # i18n
         $result = "$BUTTONS_TEXT{$direction}: $anchor";
    }
    return $result;
}

######################################################################
# Frames: this is from "Richard Y. Kim" <ryk@coho.net>
# Should be improved to be more conforming to other _print* functions
# toc_file and main_file passed as args are relative to the texinfo manual
# location, and therefore are not used.

sub HTML_DEFAULT_print_frame
{
    my $fh = shift;
    my $toc_file = shift;
    my $main_file = shift;
    $main_file = $Texi2HTML::THISDOC{'filename'}->{'top'};
    $toc_file = $Texi2HTML::THISDOC{'filename'}->{'toc_frame'};
    print $fh <<EOT;
$FRAMESET_DOCTYPE
<html>
<head><title>$Texi2HTML::THISDOC{'fulltitle'}</title></head>
<frameset cols="140,*">
  <frame name="toc" src="$toc_file">
  <frame name="main" src="$main_file">
</frameset>
</html>
EOT
}

sub HTML_DEFAULT_print_toc_frame
{
    my $fh = shift;
    my $stoc_lines = shift;
    &$print_page_head($fh);
    print $fh <<EOT;
<h2>Content</h2>
EOT
    print $fh map {s/\bhref=/target="main" href=/; $_;} @$stoc_lines;
    print $fh "</body></html>\n";
}

######################################################################
# About page
#

sub HTML_DEFAULT_about_body
{
    return undef if (!$HEADER_IN_TABLE);
    my $about = "<p>\n";
    if (ref($PRE_ABOUT) eq 'CODE')
    {
        $about .= &$PRE_ABOUT();
    }
    else
    {
        $about .= $PRE_ABOUT;
    }
    $about .= <<EOT;
</p>
<p>
EOT
    $about .= gdt('  The buttons in the navigation panels have the following meaning:') . "\n";
    $about .= <<EOT;
</p>
<table border="1">
  <tr>
EOT
    $about .= '    <th> ' . gdt('Button') . " </th>\n" .
'    <th> ' . gdt('Name') . " </th>\n" .
'    <th> ' . gdt('Go to') . " </th>\n" .
'    <th> ' . gdt('From 1.2.3 go to') . "</th>\n" . "  </tr>\n";

    for my $button (@SECTION_BUTTONS)
    {
        next if $button eq ' ' || ref($button) eq 'CODE' || ref($button) eq 'SCALAR' || ref($button) eq 'ARRAY';
        $about .= "  <tr>\n    <td align=\"center\">";
        $about .=
            ($ICONS && $ACTIVE_ICONS{$button} ?
             &$button_icon_img($BUTTONS_NAME{$button}, $ACTIVE_ICONS{$button}) :
             ' [' . $NAVIGATION_TEXT{$button} . '] ');
        $about .= "</td>\n";
        $about .= <<EOT;
    <td align="center">$BUTTONS_NAME{$button}</td>
    <td>$BUTTONS_GOTO{$button}</td>
    <td>$BUTTONS_EXAMPLE{$button}</td>
  </tr>
EOT
    }

    $about .= <<EOT;
</table>

<p>
EOT
    $about .= gdt('  where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:') . "\n";

#  where the <strong> Example </strong> assumes that the current position
#  is at <strong> Subsubsection One-Two-Three </strong> of a document of
#  the following structure:
    $about .= <<EOT;
</p>

<ul>
EOT
    $about .= '  <li> 1. ' . gdt('Section One') . "\n" .
"    <ul>\n" .
'      <li>1.1 ' . gdt('Subsection One-One') . "\n";
    $about .= <<EOT;
        <ul>
          <li>...</li>
        </ul>
      </li>
EOT
    $about .= '      <li>1.2 ' . gdt('Subsection One-Two') . "\n" .
"        <ul>\n" .
'          <li>1.2.1 ' . gdt('Subsubsection One-Two-One') . "</li>\n" .
'          <li>1.2.2 ' . gdt('Subsubsection One-Two-Two') . "</li>\n" .
'          <li>1.2.3 ' . gdt('Subsubsection One-Two-Three') . " &nbsp; &nbsp;\n"
.
'            <strong>&lt;== ' . gdt('Current Position') . " </strong></li>\n" .
'          <li>1.2.4 ' . gdt('Subsubsection One-Two-Four') . "</li>\n" .
"        </ul>\n" .
"      </li>\n" .
'      <li>1.3 ' . gdt('Subsection One-Three') . "\n";
    $about .= <<EOT;
        <ul>
          <li>...</li>
        </ul>
      </li>
EOT
    $about .= '      <li>1.4 ' . gdt('Subsection One-Four') . "</li>\n";
    $about .= <<EOT;
    </ul>
  </li>
</ul>
$AFTER_ABOUT
EOT
    return $about;
}

sub HTML_DEFAULT_print_redirection_page()
{
    #my $fh = shift;
    my $longtitle = $html_default_title;
    $longtitle .= ": $Texi2HTML::SIMPLE_TEXT{'This'}" if (defined ($Texi2HTML::SIMPLE_TEXT{'This'}) and ($Texi2HTML::SIMPLE_TEXT{'This'} !~ /^\s*$/) and ($html_default_title ne $Texi2HTML::SIMPLE_TEXT{'This'}));
    my $description = $Texi2HTML::THISDOC{'DOCUMENT_DESCRIPTION'};
    $description = $longtitle if (!defined($description));
    my $encoding = '';
    $encoding = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$Texi2HTML::THISDOC{'ENCODING_NAME'}\">" if (defined($Texi2HTML::THISDOC{'ENCODING_NAME'}) and ($Texi2HTML::THISDOC{'ENCODING_NAME'} ne ''));
    my $href = &$anchor('', $Texi2HTML::HREF{'This'}, $Texi2HTML::NAME{'This'}); 
    my $string = gdt('The node you are looking for is at {href}.',
       { 'href' => $href });
    my $doctype = get_conf('doctype');
    my $css_text = '';
    $css_text = $Texi2HTML::THISDOC{'CSS_LINES'} if (defined($Texi2HTML::THISDOC{'CSS_LINES'}));
    #print $fh <<EOT;
    my $result = <<EOT;
$doctype
<html>
<!-- Created on $Texi2HTML::THISDOC{'today'} by $Texi2HTML::THISDOC{'program'} -->
<!--
$Texi2HTML::THISDOC{'program_authors'}
-->
<head>
<title>$longtitle</title>

<meta name="description" content="$description">
<meta name="keywords" content="$longtitle">
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="$Texi2HTML::THISDOC{program}">
$encoding
$css_text
<meta http-equiv="Refresh" content="2; url=$Texi2HTML::HREF{'This'}">
$EXTRA_HEAD
</head>

<body $Texi2HTML::THISDOC{'BODYTEXT'}>
$AFTER_BODY_OPEN
<p>$string</p>
</body>
EOT
   return $result;
}

sub html_default_uref($$)
{
    shift;
    my $args = shift;
    my $url = shift @$args;
    my $text = shift @$args;
    my $replacement = shift @$args;
    $url = main::normalise_space($url);
    $replacement = '' if (!defined($replacement));
    $replacement = main::normalise_space($replacement);
    $text = '' if (!defined($text));
    $text = main::normalise_space($text);
    $text = $replacement if ($replacement ne '');
    $text = $url unless ($text ne '');
    return $text if ($url eq '');
    return &$anchor('', $url, $text);
}

sub html_default_math($$)
{
    shift;
    my $args = shift;
    my $text = shift @$args;
    return "<em>$text</em>";
}

sub html_default_email($$)
{
    my $command = shift;
    my $args = shift;
    my $mail = shift @$args;
    my $text = shift @$args;
    $mail = main::normalise_space($mail);
    $text = $mail unless (defined($text) and ($text ne ''));
    $text = main::normalise_space($text);
    return $text if ($mail eq '');
    return &$anchor('', "mailto:$mail", $text);
}

sub html_default_attribute_class($$)
{
    my $element = shift;
    my $class = shift;
    return "<$element" if (!defined($class) or $class eq '' or $NO_CSS);
    my $style = '';
    if ($INLINE_CSS_STYLE and defined($css_map{"$element.$class"}))
    {
        $style = ' style="'.$css_map{"$element.$class"}.'"';
    }
    return "<$element class=\"$class\"$style";
}

# this is called each time a format begins. Here it is used to keep a
# record of the multitables to have a faithful count of the cell nr.
sub html_default_begin_format_texi($$$)
{
    my $command = shift;
    my $line = shift;
    my $state = shift;

    # first array element is the number of cell in a row
    # second is the number of paragraphs in a cell
    push (@html_default_multitable_stack, [-1,-1]) if ($command eq 'multitable');

    return $line;
}

sub html_default_caption_shortcaption($)
{
    my $float = shift;
    my $caption_lines;
    my $shortcaption_lines;
    my $style = $float->{'style_texi'};
    if (defined($float->{'nr'}))
    {
        my $nr = $float->{'nr'};
        if ($style ne '')
        {
            $style = gdt('{style} {number}', { 'style' => $style, 'number' => $nr});
        }
        else 
        {
            $style = $nr;
        }
    }
    
    if (defined($float->{'caption_texi'}))
    {
        @$caption_lines = @{$float->{'caption_texi'}};
        $caption_lines->[0] =~ s/^\s*//;
        if (defined($style))
        {
            $caption_lines->[0] = '@'.$CAPTION_STYLE.'{' . gdt('{style}: {caption_first_line}', { 'style' => $style, 'caption_first_line' => $caption_lines->[0] });
        }
        else
        {
            $caption_lines->[0] = '@'.$CAPTION_STYLE.'{' .  $caption_lines->[0];
        }
        push @$caption_lines, "}\n";
    }
    elsif (defined($style))
    {
        $caption_lines->[0] = '@'.$CAPTION_STYLE.'{' . $style . '}' . "\n";
    }
    if (defined($float->{'shortcaption_texi'}))
    {
         @$shortcaption_lines = @{$float->{'shortcaption_texi'}};
         if (defined($style))
         {
              $shortcaption_lines->[0] = '@'.$CAPTION_STYLE.'{' . gdt('{style}: {shortcaption_first_line}', { 'style' => $style, 'shortcaption_first_line' => $shortcaption_lines->[0] });
         }
         else
         {
              $shortcaption_lines->[0] = '@'.$CAPTION_STYLE.'{' .  $shortcaption_lines->[0];
         }
         push @$shortcaption_lines, "}\n";
    }
    elsif (defined($style))
    {
         $shortcaption_lines->[0] = '@'.$CAPTION_STYLE.'{' . $style . '}' . "\n";
    }
    return ($caption_lines, $shortcaption_lines);
}

# everything is done in &$float
sub html_default_caption_shortcaption_command($$$$)
{
   my $command = shift;
   my $text = shift;
   my $texi_lines = shift;
   my $float_element = shift;
   return '';
}

sub html_default_float($$$$$)
{
    my $text = shift;
    my $float = shift;
    my $caption = shift;
    my $shortcaption = shift;
    
    my $label = '';
    if (exists($float->{'id'}))
    {
        $label = &$anchor($float->{'id'});
    }
    my $caption_text = '';
    
    if (defined($float->{'caption_texi'}))
    {
        $caption_text = $caption;
    }
    elsif (defined($float->{'shortcaption_texi'}))
    {
        $caption_text = $shortcaption;
    }
    elsif (defined($caption))
    {
        $caption_text = $caption;
    }
    
    return html_default_attribute_class('div','float'). '>' . "$label\n" . $text . '</div>' . $caption_text;
}

sub html_default_listoffloats_float_style($$)
{
    my $style_texi = shift;
    my $float = shift;
    
    my $style = $float->{'style_texi'};
    #print STDERR "listoffloat/float style mismatch $style_texi $style\n" if ($style_texi ne $style);
    if (defined($float->{'nr'}))
    {
         my $nr = $float->{'nr'};
         if ($style ne '')
         {
              $style = gdt('{style} {number}', { 'style' => $style, 'number' => $nr});
         }
         else 
         {
              $style = $nr;
         }
    }
    return $style;
}

sub html_default_listoffloats_caption($)
{
    my $float = shift;
    if (defined($float->{'shortcaption_texi'}))
    {
         return ([ @{$float->{'shortcaption_texi'}} ], 'shortcaption');
    }
    elsif (defined($float->{'caption_texi'}))
    {
         return ([ @{$float->{'caption_texi'}} ], 'caption');
    }
    return ([ ], undef);
}

sub html_default_listoffloats_entry($$$$)
{
    my $style_texi = shift;
    my $float = shift;
    my $float_style = shift;
    my $caption = shift;
    my $href = shift;

    return '<dt>' . &$anchor('', $href, $float_style) . '</dt><dd>' . $caption
. '</dd>' . "\n";
}

sub html_default_listoffloats($$$)
{
    my $style_texi = shift;
    my $style = shift;
    my $float_entries = shift;

    my $result = html_default_attribute_class('dl', 'listoffloats').">\n" ;
    foreach my $float_entry (@$float_entries)
    {
         $result .= $float_entry;
    }
    return $result . "</dl>\n";
} 

sub html_default_insertcopying($$$)
{
    my $text = shift;
    my $comment = shift;
    my $simple_text = shift;
    return $text;
}

sub html_default_protect_space_codebreak($$$$$)
{
   my $text = shift;
   my $in_raw_text = shift; # remove_texi
   my $in_preformatted = shift;
   my $in_code = shift;
   my $style_stack = shift;

   return $text if ($in_preformatted or $in_raw_text);

   my $in_w = 1 if (in_cmd($style_stack, 'w'));

   if ($in_w or ($in_code and get_conf('allowcodebreaks') eq 'false'))
   {
      my $class = 'nolinebreak';
      $class = 'nocodebreak' if ($in_code and get_conf('allowcodebreaks') eq 'false');
      my $open = html_default_attribute_class('span', $class).'>';
      # protect spaces in the html leading attribute in case we are in 'w'
      $open =~ s/ /\x{1F}/g if ($in_w);
      $text =~ s/(\S*[_-]\S*)/${open}$1<\/span>/g;
   }

   if ($in_w)
   {
      $text .= '&nbsp;' if (chomp($text));
      # protect spaces within text
      $text =~ s/ /&nbsp;/g;
      # revert protected spaces in leading html attribute
      $text =~ s/\x{1F}/ /g;
   }
   return $text;
}

sub html_default_normal_text($$$$$$$;$)
{
   my @initial_args = @_;
   my $text = shift;
   my $in_raw_text = shift; # remove_texi
   my $in_preformatted = shift;
   my $in_code = shift;
   my $in_math = shift;
   my $in_simple = shift;
   my $style_stack = shift;
   my $state = shift;

  # like utf8.init
   if ($ENABLE_ENCODING and !$ENABLE_ENCODING_USE_ENTITY and defined($Texi2HTML::THISDOC{'ENCODING_NAME'}) and $Texi2HTML::THISDOC{'ENCODING_NAME'} eq 'utf-8')
   {
      my $result = &t2h_utf8_normal_text(@initial_args);
      $result = html_default_protect_space_codebreak($result, $in_raw_text, $in_preformatted, $in_code, $style_stack);
      return $result;
   }

   $text = uc($text) if (in_cmd($style_stack, 'sc'));
   $text = &$protect_text($text) unless($in_raw_text);
   #$text =~ s/ /&nbsp;/g
   #  if (!$in_raw_text and !$in_preformatted and in_cmd($style_stack, 'w'));
   if (! $in_code and !$in_preformatted)
   {
       if ($USE_ISO and !$in_raw_text)
       {
           $text =~ s/---/\&mdash\;/g;
           $text =~ s/--/\&ndash\;/g;
           $text =~ s/``/\&ldquo\;/g;
           $text =~ s/''/\&rdquo\;/g;
       }
       else
       {
            if ($in_raw_text) #FIXME really do that ? It is done by makeinfo
            {
                 $text =~ s/``/"/g;
                 $text =~ s/''/"/g;
            }
            else
            {
                $text =~ s/``/&quot;/g;
                $text =~ s/''/&quot;/g;
                # to be like texinfo
                #$text =~ s/'/\&rsquo\;/g;
                #$text =~ s/`/\&lsquo\;/g;
            }
            # FIXME really do that in raw text?
            $text =~ s/---/\x{1F}/g;
            $text =~ s/--/-/g; 
            $text =~ s/\x{1F}/--/g;
       }
   }
   $text = html_default_protect_space_codebreak($text, $in_raw_text, $in_preformatted, $in_code, $style_stack);
   $text = t2h_text_substitutions($text, $in_raw_text, ($in_preformatted or $in_code), $in_simple);
   return $text;
}

# This function produces an anchor 
#
# arguments:
# $name           :   anchor name
# $href           :   anchor href
# text            :   text displayed
# extra_attribs   :   added to anchor attributes list
sub html_default_anchor($;$$$)
{
    my $name = shift;
    my $href = shift;
    my $text = shift;
    my $attributes = shift;
    my $class = '';
#print STDERR "!$name!$href!$text!$attributes!\n";
    if (!defined($attributes) or ($attributes !~ /\S/))
    {
        $attributes = '';
    }
    else 
    {
        if ($attributes =~ s/^class=\"([^\"]+)\"//)
        {
            $class = $1;
        }

        $attributes = ' ' . $attributes if ($attributes ne '');
    }
    $name = '' if (!defined($name) or ($name !~ /\S/));
    $href = '' if (!defined($href) or ($href !~ /\S/));
    $text = '' if (!defined($text));
    return $text if (($name eq '') and ($href eq ''));
    $name = "name=\"$name\"" if ($name ne '');
    $href = "href=\"$href\"" if ($href ne '');
    $href = ' ' . $href if (($name ne '') and ($href ne ''));
#print STDERR "!!!$name!$href!$text!$attributes!\n";
    return html_default_attribute_class('a', $class). " ${name}${href}${attributes}>$text</a>";
}

# This function is used to format the text associated with a @deff/@end deff
#
# argument:
# text
#
# $DEF_TABLE should be used to distinguish between @def formatted as table
# and as definition lists.
sub html_default_def_item($$$)
{
    my $text = shift;
    my $only_inter_item_commands = shift;
    my $command = shift;
    if ($text =~ /\S/)
    {
        if (! $DEF_TABLE)
        {
            return '<dd>' . $text . '</dd>';# unless $only_inter_item_commands;
            #return $text; # invalid without dd in ul
        }
        else
        {
            return '<tr><td colspan="2">' . $text . '</td></tr>';
        }
    }
    return '';
}

# format the container for the @deffn line and text
# 
# argument
# text of the whole @def, line and associated text.
#
# $DEF_TABLE should be used.
sub html_default_def($$)
{
    my $text = shift;
    my $command = shift;
    if ($text =~ /\S/)
    {
        if (! $DEF_TABLE)
        {
            return "<dl>\n" . $text . "</dl>\n";
        }
        else
        {
            return "<table width=\"100%\">\n" . $text . "</table>\n";
        }
    }
    return '';

}

# a whole menu
#
# argument:
# the whole menu text (entries and menu comments)
#
# argument:
# whole menu text.
sub html_default_menu_command($$$)
{
    my $format = shift;
    my $text = shift;
    my $in_preformatted = shift;

    $html_menu_entry_index=0;

    my $begin_row = '';
    my $end_row = '';
    if ($in_preformatted)
    {
        $begin_row = '<tr><td>';
        $end_row = '</td></tr>';
    }
    if ($text =~ /\S/)
    {
        return '' if  ($format eq 'direntry');
        return $text if ($format eq 'detailmenu');
        return html_default_attribute_class('table', 'menu')." border=\"0\" cellspacing=\"0\">${begin_row}\n" 
        . $text . "${end_row}</table>\n";
    }
}

# formats a menu entry link pointing to a node or section 
#
# arguments:
# the entry text
# the state, a hash reference holding informations about the context, with a 
#     usefull entry, 'preformatted', true if we are in a preformatted format
#     (a format keeping space between words). In that case a function
#     of the main program, main::do_preformatted($text, $state) might 
#     be used to format the text with the current format style.
# href is optionnal. It is the reference to the section or the node anchor
#     which should be used to make the link (typically it is the argument 
#     of a href= attribute in a <a> element).
sub html_default_menu_link($$$$$$$$)
{
    my $element_name = shift;
    my $state = shift;
    my $href = shift;
    my $node = shift;
    my $title = shift;
    my $ending = shift;
    my $has_title = shift;
    my $command_stack = shift;
    my $preformatted = shift;

    my $in_commands = 0;
    $in_commands = 1 if ($command_stack->[-1] and $command_stack->[-1] ne 'menu' and $command_stack->[-1] ne 'detailmenu' and $command_stack->[-1] ne 'direntry');

    $title = '' unless ($has_title);
#print STDERR  "MENU_LINK($in_commands)($state->{'preformatted'})\n";
    my $entry;
    my $symbol = '';
    if ($preformatted)
    {
        $title .= ':' if ($title ne '');
        $entry = "$MENU_SYMBOL$title$node";
    }
    elsif ($element_name eq '' or $NODE_NAME_IN_MENU)
    {
         if ($has_title)
         {
             $entry = "$title";
         }
         else
         {
             $entry = "$node";
         }
         $entry =~ s/^\s*//;
         $symbol = "$MENU_SYMBOL ";
    }
    else
    {
         $entry = $element_name;
    }
    $html_menu_entry_index++;
    my $accesskey;
    $accesskey = "accesskey=\"$html_menu_entry_index\"" if ($USE_ACCESSKEY and ($html_menu_entry_index < 10));
    $entry = &$anchor ('', $href, $entry, $accesskey) if (defined($href));

    return $entry.$ending if ($preformatted);
    # FIXME conditionalise to not having a description
    return "$symbol$entry$MENU_ENTRY_COLON" .'&nbsp;' if ($in_commands);
    return "<tr><td align=\"left\" valign=\"top\">$symbol$entry$MENU_ENTRY_COLON</td><td>&nbsp;&nbsp;</td>";
}

sub html_simplify_text($)
{
    my $text = shift;
    $text =~ s/[^\w]//og;
    return $text;
}

# formats a menu entry description, ie the text appearing after the node
# specification in a menu entry an spanning until there is another
# menu entry, or empty line
#
# arguments:
# the description text
# the state. See menu_entry.
# the heading of the element associated with the node.
sub html_default_menu_description($$$$)
{
    my $text = shift;
    my $state = shift;
    my $element_text = shift;
    my $command_stack = shift;
    my $preformatted = shift;

    my $in_commands = 0;
    $in_commands = 1 if ($command_stack->[-1] and $command_stack->[-1] ne 'menu' and $command_stack->[-1] ne 'detailmenu' and $command_stack->[-1] ne 'direntry');
    return $text if ($preformatted);
    return $text."<br>" if ($in_commands);
    if ($AVOID_MENU_REDUNDANCY)
    {
        $text = '' if (html_simplify_text($element_text) eq html_simplify_text($text));
    }
    return "<td align=\"left\" valign=\"top\">$text</td></tr>\n";
}

sub html_teletyped_in_stack($)
{
    my $stack = shift;
    foreach my $element(reverse(@$stack))
    {
        return 1 if ($complex_format_map{$element} and 
            $complex_format_map{$element}->{'style'} and
            $complex_format_map{$element}->{'style'} eq 'code');
    }
    return 0;
}

# text after @item in table, vtable and ftable
sub html_default_table_item($$$$$$$)
{
    my $text = shift;
    my $index_label = shift;
    my $format = shift;
    my $command = shift;
#    my $formatted_command = shift;
    my $style_stack = shift;
#    my $text_formatted = shift;
#    my $text_formatted_leading_spaces = shift;
#    my $text_formatted_trailing_spaces = shift;
    my $item_cmd = shift;
    my $formatted_index_entry = shift;

#    if (defined($text_formatted) and !exists $special_list_commands{$format}->{$command})
#    {
#        $text = $text_formatted_leading_spaces . $text_formatted .$text_formatted_trailing_spaces;
#    }
#    $formatted_command = '' if (!defined($formatted_command) or 
#          exists($special_list_commands{$format}->{$command}));
    if (html_teletyped_in_stack($style_stack))
    {
#       $text .= '</tt>';
#       $formatted_command = '<tt>' . $formatted_command;
        $text = '<tt>' . $text . '</tt>';
    }
    $text .= "\n" . $index_label  if (defined($index_label));
#    return '<dt>' . $formatted_command . $text . '</dt>' . "\n";
    return '<dt>' . $text . '</dt>' . "\n";
}

# format text on the line following the @item line (in table, vtable and ftable)
sub html_default_table_line($$$)
{
    my $text = shift;
    my $only_inter_item_commands = shift;
    my $before_items = shift;

    $only_inter_item_commands = '' if (!defined($only_inter_item_commands));

    if ($text =~ /\S/)
    {
        return '<dd>' . $text . '</dd>' . "\n";# unless ($only_inter_item_commands);
        #return $text; # invalid without dd in ul
    }
    return '';
}

#my $cell_nr = -1;

# row in multitable
sub html_default_row($$$$$$$$)
{
    my $text = shift;
    my $macro = shift;
    my $columnfractions = shift;
    my $prototype_row = shift;
    my $prototype_lengths = shift;
    my $column_number = shift;
    my $only_inter_item_commands = shift;
    my $before_items = shift;

    $only_inter_item_commands = '' if (!defined($only_inter_item_commands));

    # this is used to keep the cell number
    $html_default_multitable_stack[-1]->[0] = -1;

    if ($text =~ /\S/)
    {
         if ($macro eq 'headitem')
         {
              return '<thead><tr>' . $text . '</tr></thead>' . "\n";
         }
         return '<tr>' . $text . '</tr>' . "\n";
    }
    return '';
}

# cell in multitable
sub html_default_cell($$$$$$$$)
{
    my $text = shift;
    my $row_macro = shift;
    my $columnfractions = shift;
    my $prototype_row = shift;
    my $prototype_lengths = shift;
    my $column_number = shift;
    my $only_inter_item_commands = shift;
    my $before_items = shift;

    $only_inter_item_commands = '' if (!defined($only_inter_item_commands));

    $html_default_multitable_stack[-1]->[0]++;
    my $cell_nr = $html_default_multitable_stack[-1]->[0];
    my $fractions = '';

    if (defined($columnfractions) and (ref($columnfractions) eq 'ARRAY')
         and exists($columnfractions->[$cell_nr]))
    {
        my $fraction = sprintf('%d', 100*$columnfractions->[$cell_nr]);
        $fractions = " width=\"$fraction%\"";
    }
   
    # in constructs like 
    # @strong{
    # @multitable ....
    # }
    # the space won't be removed since the <strong> is put before the space.
    $text =~ s/^\s*//;
    $text =~ s/\s*$//;

    if ($row_macro eq 'headitem')
    {
        return "<th${fractions}>" . $text . '</th>';
    }
    return "<td${fractions}>" . $text . '</td>';
}

sub html_default_format_list_item_texi($$$$$)
{
    my $format = shift;
    my $line = shift;
    my $prepended = shift;
    my $command = shift;
    my $number = shift;

    my $result_line;
    my $open_command = 0;
    if (defined($command) and $command ne '' and !exists $special_list_commands{$format}->{$command} and $format ne 'itemize')
    {
        #@*table
        $open_command = 1;
        $line =~ s/^\s*//;
        $line =~ s/\s*$//;
        if (exists ($style_map{$command}))
        {
           $result_line = "\@$command\{$line\}\n";
        }
        elsif (exists ($things_map{$command}))
        {
           $result_line = "\@$command\{\} $line\n";
        }
        else
        {
           $result_line = "\@$command $line\n";
        }
    }
    elsif (defined($prepended) and $prepended ne '')
    {
         $prepended =~ s/^\s*//;
         $prepended =~ s/\s*$//;
         $line =~ s/^\s*//;
         $result_line = $prepended . ' ' . $line;
    }
    return ($result_line, $open_command);
}


# format an item in a list
#
# argument:
# text of the item
# format of the list (itemize or enumerate)
# command passed as argument to the format
# formatted_command leading command formatted, if it is a thing command
sub html_default_list_item($$$$$$$$$$$)
{
    my $text = shift;
    my $format = shift;
    my $command = shift;
    my $formatted_command = shift;
    my $item_nr = shift;
    my $enumerate_style = shift;
    my $number = shift;
    my $prepended = shift;
    my $prepended_formatted = shift;
    my $only_inter_item_commands = shift;
    my $before_items = shift;

    $only_inter_item_commands = '' if (!defined($only_inter_item_commands));

    $formatted_command = '' if (!defined($formatted_command) or 
          exists($special_list_commands{$format}->{$command}));
    my $prepend = '';
#    if (defined($prepended) and $prepended ne '')
#    {
#        $prepend = $prepended;
#    }
#    elsif ($formatted_command ne '')
    if ($formatted_command ne '')
    {
        $prepend = $formatted_command;
    }
    if ($text =~ /\S/)
    {
        return '<li>' . $prepend . $text . '</li>';
    }
    return '';
}

sub html_default_table_list($$$$$$$$$)
{
    my $format_command = shift;
    my $text = shift;
    my $command = shift;
    my $formatted_command = shift;
# enumerate
    my $item_nr = shift;
    my $enumerate_style = shift;
# itemize
    my $prepended = shift;
    my $prepended_formatted = shift;
# multitable
    my $columnfractions = shift;
    my $prototype_row = shift;
    my $prototype_lengths = shift;
    my $column_number = shift;
#    my $number = shift;
    $formatted_command = '' if (!defined($formatted_command) or 
          exists($special_list_commands{$format}->{$command}));
    if ($format_command eq 'itemize')
    {
        return "<ul>\n" . $text . "</ul>\n" if (($command eq 'bullet') or (($command eq '') and ($prepended eq '')));
        return html_default_attribute_class('ul',$NO_BULLET_LIST_CLASS).">\n" . $text . "</ul>\n";
    }
    elsif ($format_command eq 'multitable')
    {
        pop @html_default_multitable_stack;
        return &$format('multitable', 'table', $text);
    }
}

# a paragraph
# arguments:
# $text of the paragraph
# $align for the alignement
# $indent for the indent style (indent or noindent)
# The following is usefull if the paragraph is in an itemize.
# $paragraph_command is the leading formatting command (like @minus)
# $paragraph_command_formatted is the leading formatting command formatted
# $paragraph_number is a reference on the number of paragraphs appearing
#    in the format. The value should be increased if a paragraph is done
# $format is the format name (@itemize)
sub html_default_paragraph($$$$$$$$$$$$)
{
    my $text = shift;
    my $align = shift;
    my $indent = shift;
    my $paragraph_command = shift;
    my $paragraph_command_formatted = shift;
    my $paragraph_number = shift;
    my $format = shift;
    my $item_nr = shift;
    my $enumerate_style = shift;
    my $number = shift;
    my $command_stack_at_end = shift;
    my $command_stack_at_begin = shift;
#print STDERR "format: $format\n" if (defined($format));
#print STDERR "paragraph @$command_stack_at_end; @$command_stack_at_begin\n";
#    $paragraph_command_formatted = '' if (!defined($paragraph_command_formatted) or 
#          exists($special_list_commands{$format}->{$paragraph_command}));
    return '' if ($text =~ /^\s*$/);

    if (defined($paragraph_number) and defined($$paragraph_number))
    {
         $$paragraph_number++;
         return $text  if (($format eq 'itemize' or $format eq 'enumerate') and
            ($$paragraph_number == 1));
    }

    my $top_stack = '';
    $top_stack = $command_stack_at_begin->[-1] if (scalar (@$command_stack_at_begin));
    if ($top_stack eq 'multitable')
    {
       $html_default_multitable_stack[-1]->[1]++;
       if ($html_default_multitable_stack[-1]->[1] == 0)
       {
           return $text;
       }
    }

    my $open = '<p>';
    if ($align)
    {
        $open = "<p align=\"$paragraph_style{$align}\">";
    }
    return $open.$text.'</p>';
}

# a preformatted region
# arguments:
# $text of the preformatted region
# $pre_style css style
# $class identifier for the preformatted region (example, menu-comment)
# The following is usefull if the preformatted is in an itemize.
# $leading_command is the leading formatting command (like @minus)
# $leading_command_formatted is the leading formatting command formatted
# $preformatted_number is a reference on the number of preformatteds appearing
#    in the format. The value should be increased if a preformatted is done
sub html_default_preformatted($$$$$$$$$$$$)
{
    my $text = shift;
    my $pre_style = shift;
    my $class = shift;
    my $leading_command = shift;
    my $leading_command_formatted = shift;
    my $preformatted_number = shift;
    my $format = shift;
    my $item_nr = shift;
    my $enumerate_style = shift;
    my $number = shift;
    my $command_stack_at_end = shift;
    my $command_stack_at_begin = shift;

#print STDERR "preformatted @$command_stack_at_end; @$command_stack_at_begin\n";
    return '' if ($text eq '');
    $leading_command_formatted = '' if (!defined($leading_command_formatted) or 
          exists($special_list_commands{$format}->{$leading_command}));
    if (defined($preformatted_number) and defined($$preformatted_number))
    {
        $$preformatted_number++;
    }
    my $top_stack = '';
    $top_stack = $command_stack_at_begin->[-1] if (scalar (@$command_stack_at_begin));
    if ($top_stack eq 'multitable')
    {
       $text =~ s/^\s*//;
       $text =~ s/\s*$//;
    }

    return html_default_attribute_class('pre', $class).">".$text."</pre>";
}

sub html_default_heading_text($$$)
{
    my $command = shift;
    my $text = shift;
    my $level = shift;

    return '' if ($text !~ /\S/);
    # FIXME use a class=*contents?
    my $class = '';
    if ($command =~ /^@/ and $command !~ /^@.*contents$/)
    {
       $class = $command;
       $class =~ s/^@//;
       $class = 'node-heading' if ($command eq '@node');
    }
    my $align = '';
    $align = ' align="center"' if ($command eq '@centerchap' or $command eq '@settitle');
    $level = 1 if ($level == 0);
    my $result = html_default_attribute_class ("h$level", $class) ."$align>$text</h$level>";
    # FIXME titlefont appears inline in text, so no end of line is
    # added. The end of line should be added by the user if needed.
    $result .= "\n" unless ($command eq '@titlefont');
    $result .= $DEFAULT_RULE . "\n" if ($command eq '@part' and defined($DEFAULT_RULE) and $DEFAULT_RULE ne '');
    return $result;
}

sub html_default_heading_text_preformatted($$$)
{
    my $command = shift;
    my $text = shift;
    my $level = shift;

    return '' if ($text !~ /\S/);
    return '<strong>'.$text.'</strong>'."\n";
}

# formatting of raw regions
# if L2H is true another mechanism is used for tex
sub html_default_raw($$;$)
{
    my $style = shift;
    my $text = shift;
    my $line_nr = shift;
    my $expanded = 1 if (grep {$style eq $_} @EXPAND);
    if ($style eq 'verbatim' or $style eq 'verbatiminclude' or ($style eq 'tex' and $expanded))
    {
        $style = 'verbatim' if ($style eq 'verbatiminclude');
        return html_default_attribute_class('pre', $style).">" . &$protect_text($text) . '</pre>';
    }
    elsif ($style eq 'html' and $expanded)
    {
        chomp ($text);
        return $text;
    }
    elsif ($expanded)
    {
        main::line_warn (sprintf(__("Raw format %s is not converted"), $style), $line_nr);
        return &$protect_text($text);
    }
    else
    {
        return '';
    }
}

# This function formats a footnote reference and the footnote text associated
# with a given footnote.
# The footnote reference is the text appearing in the main document pointing
# to the footnote text.
#
# arguments:
# absolute number of the footnote (in the document)
# relative number of the footnote (in the page)
# identifier for the footnote
# identifier for the footnote reference in the main document
# main document file
# footnote text file
# array with the footnote text lines 
# the state. See menu entry.
#
# returns:
# reference on an array containing the footnote text lines which should
#     have been updated
# the text for the reference pointing on the footnote text
sub html_default_foot_line_and_ref($$$$$$$$$)
{
    my $number_in_doc = shift;
    my $number_in_page = shift;
    my $footnote_id = shift;
    my $place_id = shift;
    my $document_file = shift;
    my $footnote_file = shift;
    my $lines = shift;
    my $document_state = shift;
    
    if ($document_file eq $footnote_file)
    {
        $document_file = $footnote_file = '';
    }

    $number_in_doc = $NO_NUMBER_FOOTNOTE_SYMBOL if (!$NUMBER_FOOTNOTES);

    unshift (@$lines, '<h3>' . 
          &$anchor($footnote_id, $document_file . "#$place_id",
                   "($number_in_doc)")
          . "</h3>\n");
    # this is a bit obscure, this allows to add an anchor only if formatted
    # as part of the document.
    #$place_id = '' if ($document_state->{'outside_document'} or $document_state->{'multiple_pass'} or $document_state->{'expansion'});
    $place_id = '' if ($document_state->{'outside_document'} or (defined($document_state->{'multiple_pass'}) and  $document_state->{'multiple_pass'} > 0));
    return ($lines, &$anchor($place_id,  $footnote_file . "#$footnote_id", 
           "($number_in_doc)"));
}

# formats a group of footnotes.
#
# argument:
# array reference on the footnotes texts lines 
#
# returns an array reference on the group of footnotes lines
sub html_default_foot_section($)
{
    my $lines = shift;
    unshift (@$lines, html_default_attribute_class('div', 'footnote').">\n" ,"$DEFAULT_RULE\n", 
       &$heading_text('footnotes', gdt('Footnotes'), 3)
      );
    push (@$lines, "</div>\n"); 
    return $lines; 
}

sub html_default_image_files($$$$)
{
    my $base = shift;
    my $extension = shift;
    my $texi_base = shift;
    my $texi_extension = shift;
    my @files = ();
    return @files if (!defined($base) or ($base eq ''));
    if (defined($extension) and ($extension ne ''))
    {
       push @files,["$base.$extension", "$texi_base.$texi_extension"];
    }
    foreach my $ext (@IMAGE_EXTENSIONS)
    {
        push @files,["$base.$ext", "$texi_base.$ext"];
    }
    return @files;
}

# format an image
#
# arguments:
# image file name with path
# image basename
# a boolean true if we are in a preformatted format
# image file name without path
# alt text
# width
# height
# raw alt
# extension
# path to working dir
# path to file relative from working dir
sub html_default_image($$$$$$$$$$$$$$$$$)
{
    my $file = shift;
    my $base = shift;
    my $preformatted = shift;
    my $file_name = shift;
    my $alt = shift;
    my $width = shift;
    my $height = shift;
    my $raw_alt = shift;
    my $extension = shift;
    my $working_dir = shift;
    my $file_path = shift;
    my $in_paragraph = shift;
    my $file_locations = shift;
    my $base_simple_format = shift;
    my $extension_simple_format = shift;
    my $file_name_simple_format = shift;
    my $line_nr = shift;
 
    if (!defined($file_path) or $file_path eq '')
    {
        if (defined($extension) and $extension ne '')
        {
            $file = "$base.$extension";
        }
        else
        {
            $file = "$base.jpg";
        }
        main::line_warn (sprintf(__("\@image file `%s' (for HTML) not found, using `%s'"), $base, $file), $line_nr);
    }
    elsif (! $COMPLETE_IMAGE_PATHS)
    {
        $file = $file_name;
    }
    $alt = &$protect_text($base) if (!defined($alt) or ($alt eq ''));
    return "[ $alt ]" if ($preformatted);
    # it is possible that $file_name is more correct as it allows the user
    # to chose the relative path.
    $file = &$protect_text($file);
    return "<img src=\"$file\" alt=\"$alt\">";
}

# format a target in the main document for an index entry.
#
# arguments:
# target identifier
# boolean true if in preformatted format
# FIXME document the remaining 
sub html_default_index_entry_label($$$$$$$$$)
{
    my $identifier = shift;
    my $preformatted = shift;
    my $entry = shift;
    my $index_name = shift;
    my $index_command = shift;
    my $texi_entry = shift;
    my $formatted_entry = shift;
    my $in_region_not_in_output = shift;
    my $index_entry_ref = shift;

    return '' if (!defined($identifier) or ($identifier !~ /\S/));
    my $label = &$anchor($identifier);
    return $label . "\n" if (!$preformatted);
    return $label;
}

sub html_default_index_entry_command($$$$$$)
{
   my $command = shift;
   my $index_name = shift;
   my $label = shift;
   my $entry_texi = shift;
   my $entry_formatted = shift;
   my $index_entry_ref = shift;

   return $label;
}

# process definition commands line @deffn for example
sub html_default_def_line($$$$$$$$$$$$$$$$)
{
   my $category_prepared = shift;
   my $name = shift;
   my $type = shift;
   my $arguments = shift;
   my $index_label = shift;
   my $arguments_array = shift;
   my $arguments_type_array = shift;
   my $unformatted_arguments_array = shift;
   my $command = shift;
   my $class_name = shift;
   my $category = shift;
   my $class = shift;
   my $style = shift;
   my $original_command = shift;

   $index_label = '' if (!defined($index_label));
   chomp($index_label);
   $category_prepared = '' if (!defined($category_prepared) or ($category_prepared =~ /^\s*$/));
   $name = '' if (!defined($name) or ($name =~ /^\s*$/));
   $type = '' if (!defined($type) or $type =~ /^\s*$/);
   if (!defined($arguments) or $arguments =~ /^\s*$/)
   {
       $arguments = '';
   }
   else
   {
       chomp ($arguments);
       $arguments = '<em>' . $arguments . '</em>';
   }
   my $type_name = '';
   $type_name = " <em>$type</em>" if ($type ne '');
   $type_name .= ' <strong>' . $name . '</strong>' if ($name ne '');
   $type_name .= $arguments;
   if (! $DEF_TABLE)
   {
       return '<dt>'. $index_label. $category_prepared . ':' . $type_name . "</dt>\n";
   }
   else
   {
       return "<tr><td align=\"left\">" . $type_name . 
       "</td><td align=\"right\">" . $category_prepared . $index_label . "</td></tr>\n";
   }
}

# a cartouche
sub html_default_cartouche($$)
{
    my $text = shift;

    if ($text =~ /\S/)
    {
        return html_default_attribute_class('table', 'cartouche')." border=\"1\"><tr><td>\n" . $text . "</td></tr></table>\n";
    }
    return '';
} 

sub html_default_sp($$)
{
   my $number = shift;
   my $preformatted = shift;
   return "<br>\n" x $number if (!$preformatted);
   return "\n" x $number;
}

sub html_default_acronym_like($$$$$$)
{
    my $command = shift;
    my $acronym_texi = shift;
    my $acronym_text = shift;
    my $with_explanation = shift;
    my $explanation_lines = shift;
    my $explanation_text = shift;
    my $explanation_simply_formatted = shift;
    
    my $attribute = $command;
    my $opening = "<$attribute>";
    if (defined($explanation_simply_formatted)) 
    {
        $opening = "<$attribute title=\"$explanation_simply_formatted\">";
    }
    if ($with_explanation)
    {
        return gdt('{acronym_like} ({explanation})', {'acronym_like' => $opening . $acronym_text . "</$attribute>", 'explanation' => $explanation_text},{'duplicate'=>1})
    }
    else
    {
        return  $opening . $acronym_text . "</$attribute>";
    }
}

sub html_default_quotation($$$$$)
{
    my $command = shift;
    my $text = shift;
    my $argument_text = shift;
    my $argument_text_texi = shift;
    my $authors = shift;
    my $class = '';
    $class = $command if ($command ne 'quotation');
    my $attribution = '';
    if ($authors)
    {
       foreach my $author (@$authors)
       {
           my $author_texi = $author->{'author_texi'};
           chomp($author_texi);
           $attribution .= gdt("\@center --- \@emph{{author}}\n", {'author' => $author_texi}, {'duplicate' => 1, 'allow_paragraph' => 1});
       }
    }
    return html_default_attribute_class('blockquote', $class).">\n" . $text ."</blockquote>\n" . $attribution;
}

# format a whole index
#
# argument:
# index text
# index name
sub html_default_print_index($$)
{
    my $text = shift;
    my $name = shift;
    return '' if (!defined($text));
    return html_default_attribute_class('table', "index-$name")." border=\"0\">\n" .
    "<tr><td></td><th align=\"left\">" . gdt('Index Entry') . "</th><td>&nbsp;</td><th align=\"left\"> " . gdt('Section') . "</th></tr>\n"
    . "<tr><td colspan=\"4\"> $DEFAULT_RULE</td></tr>\n" . $text .
    "</table>\n";
}

# format a letter entry in an index page. The letter entry contains
# the index entries for the words beginning with that letter. It is 
# a target for links pointing from the summary of the index.
#
# arguments:
# the letter
# identifier for the letter entry. This should be used to make the target
#     identifier
# text of the index entries
sub html_default_index_letter($$$)
{
     my $letter = shift;
     my $id = shift;
     my $text = shift;
     return $text if ($letter =~ /^\s*$/);
     return '<tr><th>' . &$anchor($id,'',&$normal_text($letter, 0, 0, 0, 0, 0, [])) . 
     "</th><td></td><td></td></tr>\n" . $text . 
     "<tr><td colspan=\"4\"> $DEFAULT_RULE</td></tr>\n";
}

# format an index entry (in a letter entry).
#
# arguments:
# href to the main text, linking to the place where the index entry appears
# entry text
# href to the main text, linking to the section or node where the index 
#      entry appears
# section or node heading
sub html_default_index_entry($$$$$$$$$$)
{
    my $text_href = shift;
    my $entry = shift;
    my $element_href = shift;
    my $element_text = shift;
    my $entry_file = shift;
    my $current_element_file = shift;
    my $entry_target = shift;
    my $entry_element_target = shift;
    my $in_region_not_in_output = shift;
    my $index_entry_ref = shift;

    return '' if ($entry !~ /\S/);
    my $element = $index_entry_ref->{'real_element'};
    if (defined($element))
    {
       my $element_set = 0;
       if ($NODE_NAME_IN_INDEX)
       {
           if ($element->{'node'})
           {
               $element_set = 1;
           }
           elsif ($element->{'with_node'})
           {
               $element = $element->{'with_node'};
               $element_set = 1;
           }
       }
       elsif (defined($NODE_NAME_IN_INDEX))
       {
           if (!$element->{'node'})
           {
               $element_set = 1;
           }
           elsif ($element->{'with_section'})
           {
               $element = $element->{'with_section'};
               $element_set = 1;
           }
       }
       if ($element_set)
       {
           $element_href = main::href($element, $Texi2HTML::THIS_ELEMENT->{'file'},
                 $Texi2HTML::THISDOC{'line_nr'});
           $element_text = $element->{'text'};
       }
    }
    
    return '<tr><td></td><td valign="top">' . &$anchor('', $text_href, $entry)
    . $INDEX_ENTRY_COLON . '</td><td>&nbsp;</td><td valign="top">' .  &$anchor('', $element_href, $element_text)
    . "</td></tr>\n";
}


# format an index summary. This is a list of letters linking to the letter
# entries.
#
# arguments:
# array reference containing the formatted alphabetical letters
# array reference containing the formatted non lphabetical letters
sub html_default_index_summary($$)
{
    my $alpha = shift;
    my $nonalpha = shift;

    my $join = '';
    my $nonalpha_text = '';
    my $alpha_text = '';
    $join = " &nbsp; \n<br>\n" if (@$nonalpha and @$alpha);
    if (@$nonalpha)
    {
       $nonalpha_text = join("\n &nbsp; \n", @$nonalpha) . "\n";
    }
    if (@$alpha)
    {
       $alpha_text = join("\n &nbsp; \n", @$alpha) . "\n &nbsp; \n";
    }
    return "<table><tr><th valign=\"top\">" . gdt('Jump to') .": &nbsp; </th><td>" .
    $nonalpha_text . $join . $alpha_text . "</td></tr></table>\n";
}

sub html_default_element_label($$$$)
{
    my $id = shift;
    my $element = shift;
    my $command = shift;
    my $line = shift;

    return &$anchor($id) . "\n";
}

sub html_default_misc_element_label($$)
{
    my $id = shift;
    my $misc_page_name = shift;
    return &$anchor($id) . "\n";
}

sub html_default_anchor_label($$$$)
{
    my $id = shift;
    my $anchor_text = shift;
    my $anchor_reference = shift;
    my $in_special_region = shift;
    return &$anchor($id);
}

sub html_default_tab_item_texi($$$$$$)
{
   my $command = shift;
   my $commands_stack = shift;
   my $stack = shift;
   my $state = shift;
   my $line = shift;
   my $line_nr = shift;

   if (defined($commands_stack) and @$commands_stack and $commands_stack->[-1] eq 'multitable' and @html_default_multitable_stack)
   {
      $html_default_multitable_stack[-1]->[1] = -1;
   }
   return undef;
}

sub html_default_line_command($$$$)
{
    my $command = shift;
    my $arg_text = shift;
    my $arg_texi = shift;
    my $state = shift;

    return '' if ($arg_text eq '' or ($command eq 'author' and (!$state->{'region'} or $state->{'region'} ne 'titlepage')));
    my $style = $line_command_map{$command};
    if ($style)
    {
        my $attribute_text = '';
        if ($style =~ /^(\w+)(\s+.*)/)
        {
            $style = $1;
            $attribute_text = $2;
        }
        $arg_text = "<${style}$attribute_text>$arg_text</$style>";
    }
    $arg_text .= "<br>" if ($command eq 'author');
    $arg_text .= "\n";
    return $arg_text;
}

1;

require "$T2H_HOME/formats/html.init" 
    if ($0 =~ /\.pl$/ &&
        -e "$T2H_HOME/formats/html.init" && -r "$T2H_HOME/formats/html.init");

# @INIT_INFO@
# vim: set filetype=perl: 
#
#+##############################################################################
#
# info.init: convert to info
#
#    Copyright (C) 2008, 2009  Patrice Dumas <pertusus@free.fr>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
#    02110-1301  USA
#
# Some error messages come from texinfo (makeinfo), so copyright holder 
# is the FSF or the individual who wrote them. All come from before the 
# switch of texinfo to GPLv3+.
#
#-##############################################################################

use Data::Dumper;

use strict;

$Data::Dumper::Maxdepth = 25;

my %info_default_indented_commands;
my %info_default_format;
my %info_default_enable_encoding_accents;
my @simple_quoted_commands;
my @asis_commands;
my @chevron_commands;
my %info_default_accent_commands = ();
my %info_default_leaf_command = ();
my $info_default_end_sentence_character;
my $info_default_after_punctuation_characters;
my $info_default_indent_length;
my %info_default_indent_format_length;
my $info_default_index_length_to_node;
my $info_default_listoffloat_caption_entry_length;
my $info_default_listoffloat_append;
my %info_default_index_entries_counts;

sub info_default_load(;$)
{
my $from_command_line = shift;

t2h_default_set_variables_default();
$USE_SECTIONS = 0;
$USE_NODES = 1;
#set_conf('SPLIT', 0, 1);
$SPLIT = '';
@T2H_FORMAT_EXPAND = ('info', 'direntry');
$EXTENSION = 'info';
$SHOW_MENU = 1;
$SHOW_TITLE = 0;
$USE_SETFILENAME_EXTENSION = 1;
$INLINE_INSERTCOPYING = 1;
$SIMPLE_MENU = 1;
$MENU_SYMBOL = '*';
$USE_ISO = 0;
$ENABLE_ENCODING_USE_ENTITY = 0;
$ENABLE_ENCODING = 1;
@IMAGE_EXTENSIONS = ('png', 'jpg', 'txt');
$CAPTION_STYLE = 'asis';
$DEFAULT_ENCODING = 'ascii';
$HEADERS = 1;
$INLINE_CONTENTS = 0;


$no_paragraph_commands{'anchor'} = 1;

%simple_map = %default_simple_map;
%simple_map_pre = %simple_map;
%simple_map_texi = %simple_map;

%things_map = %default_things_map;
%pre_map = %things_map;

%line_command_map = ( 
   'dircategory' => ''
);

# sc and var upcase.
@simple_quoted_commands = ('cite', 'code', 'command', 'env', 'file', 'kbd',
  'option', 'samp');
@asis_commands = ('asis', 'w', 'b', 'ctrl', 'i', 'math', 'sc', 't', 'r', 
  'slanted', 'sansserif', 'var', 'titlefont', 'verb', 'clickstyle', 
  'headitemfont');
@chevron_commands = ('key', 'indicateurl');

%info_default_accent_commands = ();
%info_default_leaf_command = ();

%style_map = ();
t2h_default_copy_style_map (\%default_style_map, \%style_map);

foreach my $accent_command ('tieaccent', 'dotless', keys(%unicode_accents), keys(%accent_map))
{
     $info_default_accent_commands{$accent_command} = 1;
     $style_map{$accent_command} = { 'function' => \&info_default_accent };
}

foreach my $command (keys(%style_map))
{
    delete $style_map{$command}->{'quote'} if (exists($style_map{$command}->{'quote'}));
    if (grep {$_ eq $command} @simple_quoted_commands)
    {
        delete $style_map{$command}->{'function'} if (exists($style_map{$command}->{'function'}));
        $style_map{$command}->{'begin'} = '`';
        $style_map{$command}->{'end'} = "'";
        next;
    }
    elsif (grep {$_ eq $command} @asis_commands)
    {
        delete $style_map{$command}->{'function'} if (exists($style_map{$command}->{'function'}));
        delete $style_map{$command}->{'begin'} if  (exists($style_map{$command}->{'begin'}));
        delete $style_map{$command}->{'end'} if  (exists($style_map{$command}->{'end'}));
    }
    if (grep {$_ eq $command} @chevron_commands)
    {
        delete $style_map{$command}->{'function'} if (exists($style_map{$command}->{'function'}));
        $style_map{$command}->{'begin'} = '<';
        $style_map{$command}->{'end'} = '>';
        next;
    }
    $info_default_leaf_command{$command} = 1 if ($style_map{$command}->{'type'} and $style_map{$command}->{'type'} eq 'simple_style');
}

$style_map{'strong'}->{'begin'} = '*';
$style_map{'strong'}->{'end'} = '*';
$style_map{'dfn'}->{'begin'} = '"';
$style_map{'dfn'}->{'end'} = '"';
$style_map{'emph'}->{'begin'} = '_';
$style_map{'emph'}->{'end'} = '_';


foreach my $command (keys(%info_default_leaf_command))
{
   if (defined ($style_map{$command}->{'args'}))
   {
      $style_map{$command}->{'orig_args'} = [ @{$style_map{$command}->{'args'}} ];
   }
   else
   {
      $style_map{$command}->{'orig_args'} = [ 'normal' ];
   }
   $style_map{$command}->{'args'} = [];
   foreach my $arg (@{$style_map{$command}->{'orig_args'}})
   {
      push  @{$style_map{$command}->{'args'}}, 'keep';
   }
}

$style_map{'uref'}->{'function'} = \&info_default_uref;
$style_map{'url'}->{'function'} = \&info_default_uref;
$style_map{'email'}->{'function'} = \&info_default_email;

%style_map_pre = ();
%style_map_texi = ();
t2h_default_copy_style_map (\%style_map, \%style_map_pre);
t2h_default_copy_style_map (\%style_map, \%style_map_texi);

$special_list_commands{'itemize'} = {};

%info_default_indent_format_length = ('enumerate' => 2,
    'itemize' => 3,
    'table' => 0,
    'vtable' => 0,
    'ftable' => 0,
 );


%format_map = ();
foreach my $format ('group', 'raggedright', 'cartouche')
{
    $format_map{$format} = '';
}

foreach my $menu_command('menu', 'detailmenu', 'direntry', 'menu_comment')
{
  $complex_format_map{$menu_command} = {'begin' => '' , 'end' => ''};
}

foreach my $command (keys (%complex_format_map), keys(%info_default_indent_format_length), 'quotation', 'smallquotation', 'deff_item', 'deff_itemx')
{
    $info_default_indented_commands{$command} = 1;
}

foreach my $command (keys(%info_default_indented_commands), 'multitable', 'float', 'flushright', 'flushleft', 'center')
{
    $info_default_format{$command} = 1;
}

# it doesn't change anything for multitable
foreach my $non_indented_command('format', 'smallformat', 'menu', 
  'detailmenu', 'direntry', 'multitable')
{
    $info_default_indented_commands{$non_indented_command} = 0;
}

$info_default_end_sentence_character = quotemeta($punctuation_characters);
$info_default_after_punctuation_characters = quotemeta($after_punctuation_characters);
$info_default_indent_length = 5;

$info_default_index_length_to_node = 41;

$info_default_listoffloat_caption_entry_length = 41;
#$info_default_listoffloat_append = '...:    ';
$info_default_listoffloat_append = '...';

t2h_default_push_handler(\&info_default_init_accent_enable_encoding, \@command_handler_init);
t2h_default_push_handler(\&info_default_init_variables, \@command_handler_init);


$style = \&info_default_style;
$print_page_head   = \&info_default_print_page_head;
$contents = \&info_default_noop;
$shortcontents = \&info_default_noop;
$about_body = \&info_default_noop;
$print_Footnotes = \&info_default_noop;
$copying_comment   = \&info_default_copying_comment;
$element_heading   = \&info_default_element_heading;
$heading           = \&info_default_heading;
$normal_text       = \&info_default_normal_text;
$paragraph         = \&info_default_paragraph;
$preformatted      = \&info_default_preformatted;
$empty_preformatted      = \&info_default_preformatted;
$empty_line               = \&info_default_empty_line;
# maybe should not be called from the main program?
$print_page_foot       = \&info_default_print_page_foot;
$print_Top_footer      = \&info_default_print_Top_footer;
$print_Top             = \&info_default_print_section;
$print_section         = \&info_default_print_section;
$end_section           = \&info_default_end_section;
$one_section           = \&info_default_one_section;
$begin_format_texi     = \&info_default_begin_format_texi;
$begin_style_texi      = \&info_default_begin_style_texi;
$begin_paragraph_texi  = \&info_default_begin_paragraph_texi;
$simple_command        = \&info_default_simple_command;
$thing_command         = \&info_default_thing_command;
$begin_special_region  = \&info_default_begin_special_region;
$end_special_region    = \&info_default_end_special_region;
$anchor_label          = \&info_default_anchor_label;
$element_label         = \&info_default_noop;
$menu_link             = \&info_default_menu_link;
#$menu_command          = \&info_default_menu_command;
$complex_format        = \&info_default_complex_format;
$quotation             = \&info_default_quotation;
$misc_command_line     = \&info_default_misc_commands;
$external_ref          = \&info_default_external_ref;
$internal_ref          = \&info_default_internal_ref;
$image                 = \&info_default_image;
$image_files           = \&info_default_image_files;
$index_summary      = \&info_default_index_summary;
$summary_letter     = \&info_default_summary_letter;
$index_entry        = \&info_default_index_entry;
$index_entry_command        = \&t2h_default_index_entry_command;
$index_letter       = \&info_default_index_letter;
$printindex         = \&info_default_printindex;
$print_index        = \&info_default_print_index;
$index_entry_label  = \&info_default_index_entry_label;
$foot_section       = \&info_default_foot_lines;
$foot_line_and_ref  = \&info_default_foot_line_and_ref;
$footnote_texi      = \&info_default_footnote_texi;
$list_item          = \&info_default_list_item;
$format_list_item_texi = \&info_default_format_list_item_texi;
$format             = \&info_default_format;
$tab_item_texi      = \&info_default_tab_item_texi;
$acronym_like       = \&info_default_acronym_like;
$sp                 = \&info_default_sp;
$paragraph_style_command = \&info_default_paragraph_style_command;
$cell               = \&info_default_cell;
$row                = \&info_default_row;
$table_list         = \&info_default_table_list;
$def_item           = \&info_default_def_item;
$def                = \&info_default_def;
$def_line           = \&info_default_def_line;
$float              = \&info_default_float;
$listoffloats_entry = \&info_default_listoffloats_entry;
$listoffloats       = \&info_default_listoffloats;
$colon_command      = \&info_default_colon_command;
$raw                = \&info_default_raw;
$line_command       = \&info_default_line_command;
$comment            = \&t2h_default_comment;
$unknown_style      = \&info_default_unknown_style;
$heading_text       = \&t2h_default_heading_text;

}

my %info_default_state_map = ();
my $info_default_out_file_nr = 1;
my $info_default_dir_specification = '';
my @info_default_pending_indirect = ();
my @info_default_pending_footnotes = ();
my $info_default_state_nr = 0;

# maximal length of index entries line number information. Each entry is 
# an index name.
my %info_default_index_line_string_length = ();
my %info_default_index_entries = ();
my $info_default_footnote_index = 0;
my $info_default_current_node = undef;

my %info_default_command_handler_expand;

sub info_default_intercept_handler
{
    my $command = $_[0];
    my $result = &{$info_default_command_handler_expand{$command}}(@_);
    return info_default_store_text (undef, $result, $command);
}

sub info_default_init_variables()
{
   %info_default_state_map = ();
   $info_default_out_file_nr = 1;
   $info_default_dir_specification = '';
   @info_default_pending_indirect = ();
   @info_default_pending_footnotes = ();
   $info_default_state_nr = 0;

   %info_default_index_line_string_length = ();
   %info_default_index_entries = ();
   $info_default_footnote_index = 0;
   $info_default_current_node = undef;
   $Texi2HTML::THISDOC{'SPLIT'} = 0 if ($OUTPUT_FORMAT eq 'info');
   $FRAMES = 0 if ($OUTPUT_FORMAT eq 'info');

   foreach my $command (keys (%command_handler))
   {
      if ($command_handler{$command}->{'expand'})
      {
         $info_default_command_handler_expand{$command} = $command_handler{$command}->{'expand'};
         $command_handler{$command}->{'expand'} = \&info_default_intercept_handler;
      }
   }
}

# this is put in command_handler_init such that it sets things right
# in case $ENABLE_ENCODING is set and has lead to modification of the 
# accent functions
sub info_default_init_accent_enable_encoding()
{
   return unless ($ENABLE_ENCODING and $USE_UNICODE);
   foreach my $key (keys(%unicode_accents), 'dotless')
   {
     $info_default_enable_encoding_accents{$key} = 1;
     $t2h_enable_encoding_default_accent{'normal'}->{$key} = \&t2h_default_accent;
     $t2h_enable_encoding_default_accent{'texi'}->{$key} = \&t2h_default_accent;
     $t2h_enable_encoding_default_accent{'pre'}->{$key} = \&t2h_default_accent;
     $style_map{$key}->{'function'} = \&info_default_accent;
     $style_map_texi{$key}->{'function'} = \&info_default_accent;
     $style_map_pre{$key}->{'function'} = \&info_default_accent;
   }
}

sub info_default_uref($$)
{
    shift;
    my $args = shift;
    my $url = shift @$args;
    my $text = shift @$args;
    my $replacement = shift @$args;
    $url = main::normalise_space($url);
    $replacement = '' if (!defined($replacement));
    $replacement = main::normalise_space($replacement);
    return $replacement if ($replacement ne '');
    $text = '' if (!defined($text));
    $text = main::normalise_space($text);
    return "`$url'" if ($text eq '');
    return "$text ($url)";
}

sub info_default_email($$)
{
    my $command = shift;
    my $args = shift;
    my $mail = shift @$args;
    my $text = shift @$args;
    $mail = main::normalise_space($mail);
    $text = '' if (!defined($text));
    $text = main::normalise_space($text);
    $mail = "<$mail>";
    return $mail unless ($text ne '');
    return "$text $mail";
}


sub info_default_accent($$$)
{
    my @args = @_;
    my $command = shift;
    my $args = shift;
    my $text = $args->[0];
    my $style_stack = shift;
    my $state = shift;

    my $result;
    if ($ENABLE_ENCODING and $info_default_enable_encoding_accents{$command})
    {
        $result = &t2h_enable_encoding_normal_accent(@args);
    }
    else
    {
        $result = &t2h_default_accent(@args);
    }
    if (scalar(@$style_stack) and $info_default_accent_commands{$style_stack->[-1]})
    { # still more accents on the stack
        return $result;
    }
    return info_default_store_text($state,$result,'accents_commands');
}

sub info_default_noop
{
    return '';
}

sub info_default_copying_comment($$$$)
{
    my $copying_lines = shift;
    my $copying_text = shift;
    my $copying_no_texi = shift;
    my $copying_simple_text = shift;
    return '' if ($copying_text eq '');
    return $copying_text;
}

sub info_default_byte_count($)
{
    my $string = shift;
    my $out_encoding = Texi2HTML::Config::get_conf('OUT_ENCODING');
    if ($out_encoding and lc($out_encoding) ne 'us-ascii' and $USE_UNICODE)
    {
       return length (Encode::encode($out_encoding, $string));
    }
    # There is no default encoding. We assume it is us-ascii. Not sure
    # about what perl thinks it is...
    #print STDERR "Unknown encoding for: $string\n" if (!$out_encoding);
    return length($string);
}

sub info_default_count_lines($;$$)
{
      my $text = shift;
      my $indent_length = shift;
      my $indentation_done = shift;

      my $blank_line;
      my $no_indentation = 0;
 
      if (!defined($indentation_done) or $indentation_done)
      {
          $no_indentation = 1;
          $indent_length = 0;
      }
      my @lines = split /^/, $text;
      # don't accept empty text.
      @lines = ('') if (!@lines);
      my $line_passed = scalar(@lines);
      $line_passed-- if ($line_passed);

      my $end_of_line = 0;
      if (($#lines > 1) and !$end_of_line and ($lines[-1] !~ /\S/) and ($lines[-2] !~ /\S/))
      {
         $blank_line = 1;
      }
      my $last_line = $lines[-1];

      my $indented_text = shift (@lines);
      #print STDERR "COUNT info_default_count_lines(i_done $no_indentation, i_l $indent_length) i_t `$indented_text'\n";
      foreach my $line (@lines)
      {
         if ($indent_length and $line =~ /\S/)
         {
            $indented_text .= ' ' x $indent_length . $line;
         }
         else
         {
            $indented_text .= $line;
         }
      }
      if (chomp($text))
      {
         $line_passed++;
         $end_of_line = 1;
      }
      return ($line_passed, $end_of_line, $last_line, $indented_text, $blank_line);
}

sub info_default_get_state($)
{
   my $state = shift;
   if (!exists $info_default_state_map{$state})
   {
      #print STDERR "NEW state $info_default_state_nr\n";
      my ($current_command, $top_stack);
      $info_default_state_map{$state} = {};
      info_default_reset_state($info_default_state_map{$state});
      # since the page head always leave a blank line, and the state may be
      # used for text right after the page head, we set it to 1 here. 
      # it may be wrong in other contexts, to be seen.
      $info_default_state_map{$state}->{'blank_line'} = 1;
      $info_default_state_map{$state}->{'only_spaces'} = 1;
      # this is the first line, so set to 1. This is reset later in 
      # most cases, when a node is seen, but may still be useful in 
      # @footnote, for example
      $info_default_state_map{$state}->{'line_count'} = 1;
      $info_default_state_map{$state}->{'offset_in_file'} = 0;
      $info_default_state_map{$state}->{'nr'} = $info_default_state_nr;
      $info_default_state_map{$state}->{'state'} = $state;
      $info_default_state_map{$state}->{'multitable_stack'} = [];
      @{$info_default_state_map{$state}->{'align_stack'}} = ({'command'=>'normal'});
      $info_default_state_nr++;
   }
   #print STDERR "RETURN state $state $info_default_state_map{$state} $info_default_state_map{$state}->{'nr'}\n";
   return $info_default_state_map{$state};
}

sub info_default_reset_state($)
{
    my $info_state = shift;
    $info_state->{'top'} = {};
    $info_state->{'current'} = $info_state->{'top'};
}

sub info_default_iterator_next($$$)
{
   my $current_command = shift;
   my $command_index = shift;
   my $command_close = shift;
   #print STDERR "NNNNNNNNNNNNNN iterator_next current $current_command idx $command_index close $command_close\n";
   
   my $sub_command = $current_command->{'content'}->[$command_index];
   
   if ($sub_command->{'content'} and !$command_close)
   {
      return ($sub_command, 0, 0);
   }
   
   if ($current_command->{'content'}->[$command_index+1])
   {
      return ($current_command, $command_index+1, 0);
   }
   elsif (defined($current_command->{'parent'}))
   {
      return ($current_command->{'parent'}, $current_command->{'index_in_parent'}, 1);
   }
   else
   {
      return (undef, undef, undef);
   }
}

# return ($current_next, $index_next, $close_next, $text, $command);
# 
# returns the next in tree, identified by the triplet 
# ($current_next, $index_next, $close_next) and also the command 
# and/or text if defined, in $text and $command.
sub info_default_next($$$)
{
    my $current = shift;
    my $index = shift;
    my $close = shift;

    my $text;
    my $command;

    my ($current_next, $index_next, $close_next) = info_default_iterator_next($current, $index, $close);
    return ($current_next, $index_next, $close_next, $text, $command) if (!defined($current_next));

    my $content = $current_next->{'content'}->[$index_next];
    $command = $content->{'command'} if (defined($content->{'command'}));
    if ($close_next)
    {
        return ($current_next, $index_next, $close_next, $content->{'end'}, $command);
    }
    if (defined($content->{'text'}))
    {
        return ($current_next, $index_next, $close_next, $content->{'text'}, $command);
    }
    if (defined($content->{'begin'}))
    {
        $text = $content->{'begin'};
    }
    if (defined($content->{'end'}) and !defined($content->{'content'}))
    {
        if (!defined($text))
        {
            $text = $content->{'end'};
        }
        else
        {
            $text .= $content->{'end'};
        }
    }
    return ($current_next, $index_next, $close_next, $text, $command);
}


sub info_default_process_line_text($$$)
{
   my $text = shift;
   my $line_width_counter = shift;
   my $indent_length = shift;
   $indent_length = 0 if (!defined($indent_length));

   my $line_passed = 0;
   my $chomped_text = $text;
   my $end_of_line = chomp($chomped_text);
   if ($indent_length > $line_width_counter and $chomped_text ne '')
   {
      $text = ' ' x ($indent_length - $line_width_counter) . $text;
   }
   $line_width_counter += t2h_default_string_width($text);
   # it seems like it never happens in the tests.
   if ($end_of_line)
   {
      $line_passed = 1;
      $line_width_counter = 0;
   }
   return ($line_width_counter, $line_passed, $text);
}

# Beware that there is a pending word if the text doesn't end with
# a space
sub info_default_process_para_text($$$$$;$$)
{
   my $text = shift;
   my $line_char_counter = shift;
   my $pending_spaces_word = shift;
   my $indent_length = shift;
   my $max_column = shift;
   my $keep_end_of_lines = shift;
   $keep_end_of_lines = 0 if (!$keep_end_of_lines);
# indentation for the lines except for the first one
   my $indent_length_next = shift;
   $indent_length = 0 if (!defined($indent_length));
   $indent_length_next = $indent_length if (!defined($indent_length_next));
   
   my $line_passed = 0;
   my $result = '';

   #print STDERR "process_text(indent($indent_length,$indent_length_next),keep_eol $keep_end_of_lines)  spaces `$pending_spaces_word->{'spaces'}') line_char_counter $line_char_counter |$text|\n";
   
   while ($text ne '')
   {
      #print STDERR "l_c_c $line_char_counter  pending_word ".var_to_str($pending_spaces_word->{'word'}).", pending_spaces `$pending_spaces_word->{'spaces'}', result `$result'\n";
      if (!$keep_end_of_lines and $text =~ s/^(\s+)//)
      {
          my $new_spaces = $1;
          # in general there are no end of lines in the lines cut, since they
          # are replaced by spaces in the main loop. However, it may happen 
          # with @* in @def* lines
          my @lines = split /^/, $new_spaces;
          my $eol_spaces;
          # last line is in $new_spaces, other lines are in $eol_spaces
          if (@lines > 1)
          {
              $new_spaces = pop @lines;
              $eol_spaces = join ("", @lines);
              #print STDERR "EOL_SPACES[$line_char_counter](+$pending_spaces_word->{'spaces'}) `$eol_spaces'\n";
          }
          if (defined($pending_spaces_word->{'word'}))
          {
             # add spaces in front if needed for the indentation
             if ($indent_length > $line_char_counter + t2h_default_string_width($pending_spaces_word->{'spaces'}))
             {
                 $pending_spaces_word->{'spaces'} = ' ' x ($indent_length - $line_char_counter) . $pending_spaces_word->{'spaces'};
             }
             $result .= $pending_spaces_word->{'spaces'} . $pending_spaces_word->{'word'};
             $line_char_counter += t2h_default_string_width($pending_spaces_word->{'spaces'})+t2h_default_string_width($pending_spaces_word->{'word'});
             $pending_spaces_word->{'spaces'} = $new_spaces;
             $pending_spaces_word->{'word'} = undef;
         }
         elsif (!$eol_spaces)
         {
             $pending_spaces_word->{'spaces'} .= $new_spaces;
         }
         if ($eol_spaces)
         { 
             $result .= $eol_spaces;
             $line_passed += scalar(@lines);
             $indent_length = $indent_length_next;
             $line_char_counter = 0;
             $pending_spaces_word->{'spaces'} = '';
         }
         if ((t2h_default_string_width($pending_spaces_word->{'spaces'}) +  $line_char_counter > $max_column))
         {
             $pending_spaces_word->{'spaces'} = '';
             $result .= "\n";
             $line_passed++;
             $indent_length = $indent_length_next;
             $line_char_counter = 0;
         }
      }
      else
      {
         my $word;
         if ($keep_end_of_lines)
         {
             $word = $text;
             $text = '';
         }
         elsif ($text =~ s/^([^\s]+)//)
         {
            $word = $1;
         }
         #else
         #{
         #    die "BUG: Impossible situation.\n";
         #}
         $pending_spaces_word->{'word'} = '' if (!defined($pending_spaces_word->{'word'}));
         $pending_spaces_word->{'word'} .= $word;
         # The $line_char_counter != 0 is here to cope with the case of a 
         # word longer than $line_char_counter followed by more text:
         # a line would be passed each time some piece text is appended.
         if ((t2h_default_string_width($pending_spaces_word->{'spaces'})+t2h_default_string_width($pending_spaces_word->{'word'}) + $line_char_counter > $max_column) and $line_char_counter != 0)
         {
             $pending_spaces_word->{'spaces'} = '';
             $result .= "\n";
             $line_passed++;
             $indent_length = $indent_length_next;
             $line_char_counter = 0;
         }
      }
   }
   return ($line_char_counter, $pending_spaces_word, $line_passed, $result)
}

sub info_default_skip_spaces($$$)
{
    my $current = shift;
    my $index = shift;
    my $close = shift;

    #print STDERR "SKIP_SPACES\n";
    while(1)
    {
       my ($current_next, $index_next, $close_next) = info_default_iterator_next($current, $index, $close);
        return if ($close_next or (!defined($current_next)));
        my $content = $current_next->{'content'}->[$index_next];
        if (defined($content->{'begin'}))
        {
            $content->{'begin'} =~ s/^\s*//;
            #print STDERR "SKIP_SPACES begin\n";
            return if ($content->{'begin'} ne '');
        } 
        if (defined($content->{'content'}) or defined($content->{'format_name'})
            or $content->{'definition_line'})
        { # non empty commands stop space skipping, even if they contain 
          # only spaces, like @asis{ }
          # also for item(x) that have format_name defined
            #print STDERR "SKIP_SPACES command?\n";
            return;
        }
        if (defined($content->{'text'}))
        {
            my $command = '';
            $command = $content->{'command'} if (defined($content->{'command'}));
            #print STDERR "SKIP_SPACES($command) text\n";
            $content->{'text'} =~ s/^\s*//;
            return if ($content->{'text'} ne '');
        }
        if (defined($content->{'end'}))
        {
            #print STDERR "SKIP_SPACES end\n";
            $content->{'end'} =~ s/^\s*//;
            return if ($content->{'end'} ne '');
        }
        ($current, $index, $close) = ($current_next, $index_next, $close_next);
    }
}

sub info_default_store_pending($$;$)
{
   my $line_char_counter = shift;
   my $pending_spaces_word = shift;
   my $indent_length = shift;

   $indent_length = 0 if (!defined($indent_length));
   my $indent_text = '';
   $indent_text = ' ' x $indent_length;

   #print STDERR "store_pending(spaces `$pending_spaces_word->{'spaces'}', indent($indent_length) `$indent_text' word `".var_to_str($pending_spaces_word->{'word'})."'\n";
   my $result = $pending_spaces_word->{'spaces'};
   $pending_spaces_word->{'spaces'} = '';
   if (defined($pending_spaces_word->{'word'}))
   {
      $result .= $pending_spaces_word->{'word'};
      $pending_spaces_word->{'word'} = undef;
   }

   my $chomped_result = $result;
   chomp ($chomped_result);
   if ($line_char_counter == 0 and $chomped_result ne '')
   {
      $result = $indent_text . $result;
   }

   $line_char_counter += t2h_default_string_width($result);
   return ($line_char_counter, $pending_spaces_word, $result);
}

sub info_default_output($)
{
   my $info_state = shift;
   my $result = '';
   #print STDERR "Storing the stack\n";
   print STDERR "" . Data::Dumper->Dump([$info_state->{'top'}]) if ($DEBUG);
   my ($bytes_count, $lines_count);
   ($bytes_count, $result, $lines_count) = info_default_process_content($info_state->{'top'}, $info_state);
   $info_state->{'offset_in_file'} += $bytes_count;
   $info_state->{'line_count'} += $lines_count;
   #print STDERR "HHHHHH($lines_count) $info_state->{'line_count'}: $result\n";
   info_default_reset_state($info_state) 
       if (!defined($info_state->{'current'}->{'command'}));
   return $result;
}

sub info_default_process_content($$)
{
   my $current_command = shift;
   my $info_state = shift;

   my $length = 0;
   my $result = '';

   my $line_char_counter = 0;
   my $all_line_passed = 0;

   my $pending_spaces_word;
   $pending_spaces_word->{'spaces'} = '';
   my $preformatted = 0;
   my $indent_level = 0;
   my $item_pending;
   my $in_exdent = 0;
   my $in_para = 0;
   my $in_w = 0;
   my $table_item_line = 0;
   my $in_table_item = 0;
   my $max_column = get_conf('fillcolumn');
   my $direntry = 0;
   my $preformatted_format = 0;
   my $indent_length = 0;

   # for formats that needs to process a full line (center and flushright) 
   # to know the line length before outputing
   my $current_line = undef;

   my ($current, $index, $close) = ($current_command, 0, 0);

   #print STDERR "info_default_process_content: $current_command\n";
   while(1)
   {
      last if (!defined($current));
      my $content = $current->{'content'}->[$index];
      my $text_added = '';
      my $line_added_before_item = 0;
      my $indentation_done = 0;
      my $prepend_newline;

      if ($DEBUG)
      {
         my $text_item_pending = '';
         $text_item_pending = $item_pending if (defined($item_pending));
         my $text_length = '';
         $text_length = "$content->{'text'}" if defined($content->{'text'});
         my $text_command = '';
         $text_command = $content->{'command'} if defined($content->{'command'});
         my $in_node_count = 0;
         $in_node_count = $info_state->{'line_count'} if defined($info_state->{'line_count'});
         print STDERR "($text_command|$text_length|$close|${all_line_passed}+$in_node_count|l_c_cnt $line_char_counter)  prfrmted $preformatted para $in_para indent_lvl $indent_level($indent_length) in_exdent $in_exdent in_w $in_w only_spaces $info_state->{'only_spaces'} blank_line $info_state->{'blank_line'} table_item_line $table_item_line in_table_item $in_table_item item_pending $text_item_pending spaces: `$pending_spaces_word->{'spaces'}' word: ".main::var_to_str($pending_spaces_word->{'word'})."\n";
      }
      
      if ($close)
      {
          if (defined($content->{'end'}))
          {
              $text_added .= $content->{'end'};
          }
          if ($complex_format_map{$content->{'command'}} and $content->{'content'})
          {
              $preformatted_format--;
          }
          # the format is always empty in the main program so the warning 
          # has to be done here
          if (defined($content->{'total_item_nr'}) and !$content->{'total_item_nr'} and $content->{'content'})
          {
              main::line_warn (sprintf(__("\@%s has text but no \@item"), $content->{'command'}), $content->{'line_nr'});
          }
          # check whether there is a blank line following, to avoid adding
          # one when closing a format.
          # This is not a required check if not in preformatted since doubled
          # blank lines are discarded.
          my $followed_by_blank_line = 0;
          if ($preformatted_format)
          {
              my ($current_next, $index_next, $close_next, $text_next, $command_next) = info_default_next ($current, $index, $close);
              if (defined($command_next) and $command_next eq 'preformatted')
              {
                 ($current_next, $index_next, $close_next, $text_next, $command_next) = info_default_next ($current_next, $index_next, $close_next);
                 $followed_by_blank_line = 1 if (defined($text_next) and $text_next =~ /^\s*$/);
              }
          }
          if ($info_default_indented_commands{$content->{'command'}})
          {
              $indent_level--;
              $indent_length = $indent_level * $info_default_indent_length;
              # $preformatteed cannot be used here since preformatted 
              # is closed before the end of a format
              #if ($indent_level > 0 and !$info_state->{'blank_line'} and $content->{'command'} !~ /^deff_item/ and !$preformatted_format)
              if ($indent_level > 0 and !$info_state->{'blank_line'} and $content->{'command'} !~ /^deff_item/ and !$followed_by_blank_line)
              {
                 $text_added .= "\n";
              }
              # this nullify a potential noindent in a random format
              $info_state->{'indent_para'} = undef;
          }
          elsif (($complex_format_map{$content->{'command'}} and $content->{'command'} ne 'menu') or $content->{'command'} eq 'cartouche')
          {
              if (!$info_state->{'blank_line'} and $info_state->{'only_spaces'} and ($indent_level > 0) and !$followed_by_blank_line)
              {
                 $text_added .= "\n";
              }
          }
          if ($content->{'command'} eq 'paragraph' and $info_state->{'align_stack'}->[-1]->{'command'} eq 'normal')
          {
              # if there is no space at the end of a paragraph, there may be 
              # pending text, for example, if there is an ending line like
              #         Some text@c a comment
              my $pending;
              ($line_char_counter, $pending_spaces_word, $pending) = info_default_store_pending($line_char_counter, $pending_spaces_word, $indent_length);
              $text_added .= $pending if (defined($pending));
              $text_added =~ s/\s*$//;
              $pending_spaces_word->{'spaces'} = '';
              $in_para = 0;
              $info_state->{'indent_para'} = undef;
              $text_added .= "\n" unless (($line_char_counter + t2h_default_string_width($text_added)) == 0);
          }
          elsif ($content->{'command'} eq 'preformatted')
          {
           # if preformatted doesn't end with a newline, it is added here
              $text_added .= "\n" unless ($line_char_counter == 0);
              $preformatted--;
          }
          elsif ($content->{'command'} eq 'menu')
          {
              $text_added .= "\n" unless ($info_state->{'blank_line'});
          }
          elsif ($content->{'command'} eq 'float')
          {
              #$text_added = "\n" . $text_added unless ($info_state->{'blank_line'});
              $prepend_newline = 1 unless ($info_state->{'blank_line'});
          }
          elsif ($content->{'command'} eq 'w')
          {
              $in_w--;
          }
          elsif ($paragraph_style{$content->{'command'}})
          {
              my $popped = pop @{$info_state->{'align_stack'}};
              print STDERR "BUG".main::format_line_number().": align_stack, popped $popped->{'command'} ne command $content->{'command'}\n" if ($popped->{'command'} ne $content->{'command'});
          }
          elsif ($content->{'command'} eq 'multitable')
          {
              my $multitable = pop @{$info_state->{'multitable_stack'}};
              if (!defined($multitable->{'cells'}) and ($result ne ''))
              {
                  $multitable->{'result'} .= $result;
                  $multitable->{'length'} += $length;
                  $multitable->{'line_count'} += $all_line_passed;
              }
              $max_column = $multitable->{'max_column_kept'};
              $result = $multitable->{'result_kept'};
              $line_char_counter = $multitable->{'line_char_counter_kept'};
              $all_line_passed = $multitable->{'all_line_passed_kept'};
              $indent_level = $multitable->{'indent_level_kept'};
              $indent_length = $multitable->{'indent_length_kept'};
              #$indent_length_next_line = undef;
              $length = $multitable->{'length_kept'};
              $info_state->{'offset_in_file'} = $multitable->{'offset_in_file_kept'};
              $info_state->{'line_count'} = $multitable->{'line_count_kept'};
              #print STDERR "MULTITABLE close, lines: $multitable->{'line_count_kept'} + $all_line_passed\n";
              foreach my $anchor_and_index (@{$multitable->{'anchors'}}, @{$multitable->{'index_entries'}})
              {
                  $anchor_and_index->{'line_nr'} += $multitable->{'line_count_kept'} + $all_line_passed;
              }
              if (! scalar(@{$info_state->{'multitable_stack'}}))
              {
                  #print STDERR "MULTITABLE close, lengths: $multitable->{'offset_in_file_kept'} + $length\n";
                  foreach my $anchor (@{$multitable->{'anchors'}})
                  {
                      $anchor->{'info_offset'} += $multitable->{'offset_in_file_kept'} + $length;
                  }
              }
              else 
              {
                  push @{$info_state->{'multitable_stack'}->[-1]->{'anchors'}}, @{$multitable->{'anchors'}};
                  push @{$info_state->{'multitable_stack'}->[-1]->{'index_entries'}}, @{$multitable->{'index_entries'}};
              }
              $text_added .= $multitable->{'result'};
              $indentation_done = 1;

              goto new_text;
          }
          elsif ($content->{'command'} eq 'multitable_cell')
          {
              my $cell = $info_state->{'multitable_stack'}->[-1]->{'cells'}->[-1];
              $cell->{'result'} = $result;
              $cell->{'length'} = $length;
              $cell->{'line_passed'} = $all_line_passed;
          }
          elsif ($content->{'command'} eq 'direntry')
          {
              $direntry--;
              # this has to be done here, otherwise, at the end, $direntry 
              # would be 0
              $info_default_dir_specification .= $text_added;
              $text_added = '';
          }
          elsif ($content->{'command'} eq 'multitable_row')
          {
              my $multitable = $info_state->{'multitable_stack'}->[-1];
              my $indent_len = $multitable->{'indent_length_kept'};
              #print STDERR "INDENT: $indent_len\n";
              my $row_length = 0;
              my $row = '';
              my $max_lines = 0;
              my $cell_beginning = 0;
              my @anchor_lines_array;
              my $cell_idx = 0;
              my @anchors;
              my @indices;
              foreach my $cell (@{$multitable->{'cells'}})
              {
                  $cell->{'beginning'} = $cell_beginning; 
                  $cell_beginning += $cell->{'cell_width'}+1;
                  @{$cell->{'lines'}} = split /^/, $cell->{'result'};
                  $max_lines = scalar(@{$cell->{'lines'}}) if (scalar(@{$cell->{'lines'}}) > $max_lines);
                  foreach my $anchor (@{$cell->{'anchors'}})
                  {
                      push @{$anchor_lines_array[$anchor->{'line_nr'}]}, $anchor;
                      $anchor->{'cell_idx'} = $cell_idx;
                      push @anchors, $anchor;
                  }
                  push @indices, @{$cell->{'index_entries'}};
                  $cell_idx++;
              }
              my $previous_last_cell = scalar(@{$multitable->{'cells'}});
              #print STDERR "ROW cell_beginning $cell_beginning, max_lines $max_lines, previous_last_cell $previous_last_cell\n";
              for (my $line_idx = 0; $line_idx < $max_lines; $line_idx++)
              {
                  my $line_width = $indent_len;
                  my $line_bytes = info_default_byte_count(' ' x$indent_len);
                  my $line = '';
                  # determine the last cell in the line, to fill spaces in 
                  # cells preceding that cell on the line
                  my $last_cell = 0;
                  for (my $cell_idx = 0; $cell_idx < $previous_last_cell; $cell_idx++)
                  {
                      $last_cell = $cell_idx+1 if (defined($multitable->{'cells'}->[$cell_idx]->{'lines'}->[$line_idx]));
                  }
                  #print STDERR "  L(last_cell $last_cell): $line_idx\n";
                  for (my $cell_idx = 0; $cell_idx < $last_cell; $cell_idx++)
                  {
                      my $cell_text = $multitable->{'cells'}->[$cell_idx]->{'lines'}->[$line_idx];
                      #print STDERR "   C($cell_idx) ";
                      if (defined($cell_text))
                      {
                          chomp($cell_text);
                          #print STDERR "$cell_text";
                          if ($line eq '' and $cell_text ne '')
                          {
                              $line = ' ' x $indent_len;
                          }
                          $line .= $cell_text;
                          $line_width += t2h_default_string_width($cell_text);
                          $line_bytes += info_default_byte_count($cell_text);
                      }
                      if ($cell_idx+1 < $last_cell)
                      {
                          if ($line_width < $indent_len + $multitable->{'cells'}->[$cell_idx+1]->{'beginning'})
                          {
                              if ($line eq '')
                              {
                                  $line = ' ' x $indent_len;
                              }
                              my $spaces = ' ' x ($indent_len + $multitable->{'cells'}->[$cell_idx+1]->{'beginning'} - $line_width);
                              $line_width += t2h_default_string_width($spaces);
                              $line_bytes += info_default_byte_count($spaces);
                              $line .= $spaces;
                              #print STDERR "   Csp($line_width) `$spaces'";
                          }
                      }
                  }
                  if (defined($anchor_lines_array[$line_idx]))
                  {
                      foreach my $anchor (@{$anchor_lines_array[$line_idx]})
                      {
                          my $anchor_position = $indent_len + $anchor->{'line_char_counter'} + $multitable->{'cells'}->[$anchor->{'cell_idx'}]->{'beginning'};
                          if ($anchor_position > $line_width)
                          {
                              my $spaces = ' ' x ($anchor_position - $line_width);
                              $line .= $spaces;
                              $line_width += t2h_default_string_width($spaces);
                              $line_bytes += info_default_byte_count($spaces);
                          }
                          $anchor->{'info_offset'} = $line_bytes + $row_length + $multitable->{'length'};
                          #print STDERR "ROW anchor close: anchor[$anchor->{'cell_idx'}]($multitable->{'cells'}->[$anchor->{'cell_idx'}]->{'beginning'}+$anchor->{'line_char_counter'}) $anchor_position $anchor->{'info_offset'}\n";
                          $anchor->{'line_char_counter'} = $anchor_position;
                      }
                  }
                  $line .= "\n";
                  $row_length += info_default_byte_count($line);
                  #print STDERR "  ($line_width,".length($line).") $line";
                  $row .= $line;
                  $previous_last_cell = $last_cell;
              }
              foreach my $anchor_and_index (@anchors, @indices)
              {
                  $anchor_and_index->{'line_nr'} += $multitable->{'line_count'};
                  #print STDERR "ROW close: new line count: $anchor_and_index->{'line_nr'} + \n";
              }
              if ($content->{'item_command'} eq 'headitem')
              {
                  # at this point cell_beginning is at the beginning of
                  # the cell following the end of the table -> full width
                  my $line = ' ' x $indent_len . '-' x $cell_beginning . "\n";
                  $row .= $line;
                  $row_length += info_default_byte_count($line);
              }
              #print STDERR "ROW_LENGTH $row_length\n";
              $multitable->{'result'} .= $row;
              $multitable->{'length'} += $row_length;
              $multitable->{'line_count'} += $max_lines;
              $multitable->{'cells'} = [];
              push @{$multitable->{'anchors'}}, @anchors;
              push @{$multitable->{'index_entries'}}, @indices;
          }
      }
      else
      {
          if ($content->{'command'})
          {
              # if processing a paragraph, there may be some pending text 
              # and spaces, as the idea is to write them down only when
              # there is a space in case of pending text, or when there is some
              # text in case of pending space. So all the commands 
              # that should write something within paragraph must flush the
              # pending text/spaces _before_ they output something, or the
              # text order will be reversed, with the pending things output
              # after the other commands text.
              my $pending_added_length = 0;
              my $pending_added_bytes = 0;

              if ($content->{'command'} eq 'anchor' or $content->{'command'} eq 'image' or $content->{'command'} eq 'index_command' or $content->{'command'} eq 'sp' or $content->{'raw_command'})
              {
                  my $pending;
                  ($line_char_counter, $pending_spaces_word, $pending) = info_default_store_pending($line_char_counter, $pending_spaces_word, $indent_length);
                  # here spaces out of any environment are ignored.
                  if ($in_para or $preformatted or $pending =~ /\S/)
                  { # this has to be done before the anchor related code
                    # to have the right count.
                    # FIXME this is wrong if an end of line was passed.
                    # in that case line_char_counter has been increased and 
                    # $pending ends with an end of line
                      $pending_added_length += t2h_default_string_width($pending);
                      $pending_added_bytes += info_default_byte_count($pending);
                      $text_added .= $pending;
                  }
              }
              if ($content->{'command'} eq 'strong')
              {
                  my ($current_next, $index_next, $close_next, $text_next, $command_next) = info_default_next ($current, $index, $close);
                  if (defined($text_next) and $text_next =~ /^Note\b/i)
                  {
                     main::line_warn(__("\@strong{Note...} produces a spurious cross-reference in Info; reword to avoid that"), $content->{'line_nr'});
                  }
              }
              elsif ($content->{'command'} eq 'w')
              {
                  $in_w++ if ($content->{'content'});
              }
              elsif ($content->{'command'} eq 'anchor' or ($content->{'command'} eq 'float' and $content->{'anchor_reference'}))
              {
                  #print STDERR "anchor: offset_in_file $info_state->{'offset_in_file'}, line_count $info_state->{'line_count'}, line_char_counter $line_char_counter pending_added_length $pending_added_length\n";
                  $content->{'anchor_reference'}->{'info_offset'} = $length + $info_state->{'offset_in_file'} + $pending_added_bytes;
                  $content->{'anchor_reference'}->{'line_nr'} = $all_line_passed + $info_state->{'line_count'};
                  $content->{'anchor_reference'}->{'line_char_counter'} = $line_char_counter + $pending_added_length;
                  if (@{$info_state->{'multitable_stack'}})
                  {
                      if ($info_state->{'multitable_stack'}->[-1]->{'cells'})
                      {
                          push @{$info_state->{'multitable_stack'}->[-1]->{'cells'}->[-1]->{'anchors'}}, $content->{'anchor_reference'};
                      }
                      else
                      {
                          push @{$info_state->{'multitable_stack'}->[-1]->{'anchors'}},  $content->{'anchor_reference'};
                      }
                  }
                  push @{$info_state->{'pending_tags'}}, $content->{'anchor_reference'};
                  push @{$info_state->{'align_stack'}->[-1]->{'anchors'}}, $content->{'anchor_reference'} if ($info_state->{'align_stack'}->[-1]->{'command'} eq 'center' or $info_state->{'align_stack'}->[-1]->{'command'} eq 'flushright');
              }
              elsif ($content->{'command'} eq 'index_label')
              {
                  #print STDERR "FFFFFFFFF($content->{'index_command'}) $all_line_passed + $info_state->{'line_count'} `$content->{'texi_entry'}'\n";
                  my $index_line_nr = $all_line_passed + $info_state->{'line_count'};
                  if ($info_state->{'blank_line'} and $content->{'index_command'} =~ /index$/)
                  {
                     my ($current_next, $index_next, $close_nex) = info_default_iterator_next($current, $index, $close);
                     $index_line_nr-- if (!defined($current_next));
                  }
                  elsif ($content->{'index_command'} =~ /^[vf]table$/)
                  {
                  # if in a table, index label is systematically entered after
                  # the line is processed, as the line is processed with the 
                  # item command, while the index entry is entered with the
                  # index_label callback that is done much later.
                     $index_line_nr--;
                  }
                  #print STDERR "index in a blank_line $content->{'index_command'} `$content->{'texi_entry'}'\n" if ($info_state->{'blank_line'});
                  my $index_name = $content->{'index_entry_reference'}->{'index_name'};
                  $info_default_index_line_string_length{$index_name} = t2h_default_string_width($index_line_nr) 
                      if (!defined($info_default_index_line_string_length{$index_name}) or $info_default_index_line_string_length{$index_name} < t2h_default_string_width($index_line_nr));
                  #print STDERR "RRRRRRRRRRRRR($content->{'index_entry_reference'}) $content->{'index_entry_reference'}->{'texi'}   name: $index_name line: $index_line_nr max: $info_default_index_line_string_length{$index_name}\n";
                  my $index_ref = { 'index_entry_reference' => $content->{'index_entry_reference'}, 'line_nr' => $index_line_nr };
#print STDERR "INDEX($index_name) line $index_line_nr\n";
                  $info_default_index_entries{$content->{'index_entry_reference'}} = $index_ref;
                  # there may be no cell in case of an empty multitable
                  if (@{$info_state->{'multitable_stack'}})
                  {
                      if ($info_state->{'multitable_stack'}->[-1]->{'cells'})
                      {
                         push @{$info_state->{'multitable_stack'}->[-1]->{'cells'}->[-1]->{'index_entries'}}, $index_ref;
                      }
                      else
                      {
                         push @{$info_state->{'multitable_stack'}->[-1]->{'index_entries'}}, $index_ref;
                      }
                  }
                  push @{$info_state->{'pending_index_entries'}}, $index_ref;
              }
              elsif ($content->{'command'} eq '*' and !$preformatted)
              {
                 if (defined($pending_spaces_word->{'word'}))
                 {
                    $text_added .= $pending_spaces_word->{'spaces'} . $pending_spaces_word->{'word'};
                    $pending_spaces_word->{'word'} = undef;
                 }
                 # spaces preceding @* are skipped
                 $pending_spaces_word->{'spaces'} = '';
                 $text_added .=  $content->{'text'};
                 # just like following spaces
                 info_default_skip_spaces($current, $index, $close);
                 # this isn't done otherwise, though, here it is not important
                 # since this end the line
                 $line_char_counter += t2h_default_string_width($content->{'text'});
                 goto new_text;
              }
              elsif ($content->{'command'} eq 'paragraph' and $info_state->{'align_stack'}->[-1]->{'command'} eq 'normal')
              {
                 # empty paragraph
                 goto new_text if (!$content->{'content'});
                 my $paragraphindent = get_conf('paragraphindent');
                 $paragraphindent = 0 if ($paragraphindent eq 'none');
                 if ($paragraphindent ne 'asis')
                 {
                    info_default_skip_spaces($current, $index, $close);
                 }
                 # if within a format $content->{'paragraph_in_element_nr'} 
                 # should not be defined so no indentation will take place
                 if ($paragraphindent ne 'asis' and $paragraphindent and $line_char_counter == 0 and (defined($content->{'paragraph_in_element_nr'})) and ($info_state->{'indent_para'} or (!defined($info_state->{'indent_para'}) and ($content->{'paragraph_in_element_nr'} or (get_conf('firstparagraphindent') eq 'insert')))))
                 {
                    $text_added .= ' ' x $paragraphindent;
                 }
                 $in_para = 1;
              }
              elsif ($content->{'command'} eq 'preformatted')
              {
                  $preformatted++ if ($content->{'content'});
              }
              elsif ($content->{'command'} eq 'exdent')
              {
                  # if an end of line is added, in_exdent is set to 2 and
                  # set to one when processing the end of line that was just
                  # added, and set to 0 at the end of the line.
                  # if there is no end of line added, it is only set to 1.
                  if ($line_char_counter != 0)
                  {
                     $text_added .= "\n";
                     $in_exdent = 2;
                  } 
                  else
                  {
                     $in_exdent = 1;
                  }
                  $indent_length = ($indent_level -1) * $info_default_indent_length if ($indent_level > 0);
                 #goto new_text;
              }
              elsif ($content->{'command'} eq 'indent')
              {
                  $info_state->{'indent_para'} = 1;
              }
              elsif ($content->{'command'} eq 'noindent')
              {
                  $info_state->{'indent_para'} = 0;
              }
              elsif ($content->{'command'} eq 'sp')
              {
                  $text_added .= $content->{'text'};
                  goto new_text;
              }
              elsif ($content->{'command'} eq 'image')
              {
                  # @image result count isn't counted in line_char_counter
                  # since it is not displayed in info
                  my $indent_added = 0;
                  $indent_added = ($indent_length - $line_char_counter) if ($indent_length - $line_char_counter > 0);
                  $text_added .= ' ' x $indent_added . $content->{'text'};
                  $line_char_counter += $indent_added;
                  goto new_text;
              }
              elsif ($content->{'command'} eq 'ref')
              { # adds a . if needed.
                  if ($content->{'text'} !~ /[\.,]$/ and $content->{'text'} !~ /::$/)
                  {
                     my ($current_next, $index_next, $close_next, $text_next, $command_next) = info_default_next ($current, $index, $close);
                     if (!defined($text_next) or $text_next !~ /^[\.,]/)
                     {
                         $content->{'text'} .= '.';
                     }
                  }
              }
              elsif ($content->{'command'} eq 'xref')
              { # warn if there is no punctuation following
                  my ($current_next, $index_next, $close_next, $text_next, $command_next) = info_default_next ($current, $index, $close);
                  if (!defined($text_next) or $text_next !~ /^./)
                  { # in makeinfo it is 
                    # "End of file reached while looking for `.' or `,'"
                    # but maybe it may not be true.
                      main::line_warn(__("`.' or `,' must follow \@xref."), $Texi2HTML::THISDOC{'line_nr'});
                  }
                  elsif ($text_next !~ /^[\.,]/)
                  {
                      my $char = substr($text_next, 0, 1);
                      main::line_warn(sprintf(__("`.' or `,' must follow \@xref, not %s"), $char), $Texi2HTML::THISDOC{'line_nr'});
                  }
              }
              elsif ($content->{'definition_line'})
              {
                  
                  my $dummy_line_passed;
                  print STDERR "BUG: defined pending_word before DEFINITION_LINE\n" if defined($pending_spaces_word->{'word'});
                  #print STDERR "DEFINITION_LINE($line_char_counter,$pending_spaces_word->{'spaces'},$indent_length,$in_para,$max_column): $content->{'text'}";
                  ($line_char_counter, $pending_spaces_word, $dummy_line_passed, $text_added) = info_default_process_para_text($content->{'text'}, $line_char_counter, $pending_spaces_word, $indent_length, $max_column, 0, $indent_length+2*$info_default_indent_length);
                  $text_added .= $pending_spaces_word->{'spaces'};
                  $pending_spaces_word->{'spaces'} = '';
                  #print STDERR "DEFINITION_LINE($line_char_counter,$pending_spaces_word->{'spaces'}) -> $text_added";
                  print STDERR "BUG: defined pending_word after DEFINITION_LINE\n" if defined($pending_spaces_word->{'word'});
                  $indentation_done = 1;
                  
                  goto new_text;
              }
              elsif (($content->{'command'} eq 'item' or $content->{'command'} eq 'itemx') and exists $info_default_indent_format_length{$content->{'format_name'}})
              {
                  $item_pending = $content->{'format_name'};
                  #if (!$info_state->{'blank_line'} and $content->{'command'} eq 'item')
                  my $first_item = 0;
                  
                  if ($content->{'command'} eq 'item')
                  {
                      if (!defined($content->{'parent'}->{'item_nr'}))
                      {
                          $content->{'parent'}->{'item_nr'} = 1;
                          $first_item = 1;
                      }
                      else
                      {
                          $content->{'parent'}->{'item_nr'}++;
                      }
                  }

                  if ($item_pending =~ /table$/)
                  {
                      $table_item_line = 1;
                      $indent_length = ($indent_level -1) * $info_default_indent_length if ($indent_level > 0);
                      $in_table_item = 0;
                  }
                  else
                  {
                      $indent_length = ($info_default_indent_format_length{$item_pending}
                        +($indent_level -1)* $info_default_indent_length);
                  }
                  if (!$info_state->{'blank_line'} and ($content->{'command'} ne 'itemx') and (!$first_item or $indent_level > 1))
                  {
                      my $dummy_line_passed;
                      ($line_char_counter, $dummy_line_passed, $text_added) = info_default_process_line_text($text_added, $line_char_counter, $indent_length);
                      $indentation_done = 1;
                      $line_added_before_item = 1;
                      $prepend_newline = 1;
                      #$text_added = "\n" . $text_added;
                  }
                  
                  if ($item_pending =~ /table$/)
                  {
                  # one less indentation level and no line break
                  # adding line_added_before_item allows the table_item_line to 
                  # still be active after the additional blank line
                      $table_item_line = 1+$line_added_before_item;
                  }
                  else
                  { 
                      info_default_skip_spaces($current, $index, $close);
                  }
              }
              elsif ($content->{'command'} eq 'menu' or $content->{'command'} eq 'listoffloats' or $content->{'heading_command'})
              {
                  $text_added .= "\n" unless ($info_state->{'blank_line'});
              }
              elsif ($content->{'command'} eq 'direntry')
              {
                  if ($content->{'content'})
                  {
                      $direntry++; 
                  }
              }
              elsif ($paragraph_style{$content->{'command'}})
              {
                 goto new_text if (!$content->{'content'});
                 push @{$info_state->{'align_stack'}}, {'command' => $content->{'command'}};
              }
              elsif ($content->{'command'} eq 'verbatim' or $content->{'command'} eq 'verbatiminclude')
              {
                  # $preformatted cannot be used here since preformatted 
                  # is closed before a verbatim, $preformatted_format is used
                  if (!$preformatted_format and $indent_level != 0)
                  {
                      if (!$info_state->{'blank_line'} and $info_state->{'only_spaces'})
                      {
                           $text_added .= "\n";
                      }
                      my $verb_text = $content->{'text'};
                      my ($line_passed, $end_of_line, $last_line, $text_indented, $blank_line) = info_default_count_lines($verb_text);
                      $content->{'text'} .= "\n" unless ($blank_line or ($last_line =~ /^\s*$/));
                  }
              }
              # other raw commands
              elsif ($content->{'raw_command'})
              {
                  # not considered as in a paragraph even if in a paragraph 
                  $text_added .= $content->{'text'};
                  goto new_text;
              }
              elsif ($content->{'command'} eq 'multitable' and $content->{'content'})
              {
                  my $indent_length_kept = $indent_level * $info_default_indent_length;
                  my $multitable = {
                     'offset_in_file_kept' => $info_state->{'offset_in_file'},
                     'line_count_kept'     => $info_state->{'line_count'},
                     'columns_size'        => [ @{$content->{'columns_size'}} ],
                     'result'              => '',
                     'length'              => 0,
                     'line_count'          => 0,
                     'result_kept'         => $result,
                     'length_kept'         => $length,
                     'all_line_passed_kept' => $all_line_passed,
                     'line_char_counter_kept' => $line_char_counter,
                     'max_column_kept'     => $max_column,
                     'indent_level_kept'   => $indent_level,
                     'indent_length_kept'  => $indent_length_kept,
                  };
                  push @{$info_state->{'multitable_stack'}}, $multitable;
                  $info_state->{'offset_in_file'} = 0;
                  $info_state->{'line_count'} = 0;
                  $result = '';
                  $length = 0;
                  $all_line_passed = 0;
                  $line_char_counter = 0;
                  $indent_level = 0;
                  $indent_length = 0;
              }
              elsif ($content->{'command'} eq 'multitable_row')
              {
                  my $multitable = $info_state->{'multitable_stack'}->[-1];
                  if (!defined($multitable->{'cells'}) and ($result ne ''))
                  {
                      $multitable->{'result'} .= $result;
                      $multitable->{'length'} += $length;
                      $multitable->{'line_count'} += $all_line_passed;
                      $multitable->{'cells'} = [];
                  }
                  $multitable->{'cell_index'} = -1;
              }
              elsif ($content->{'command'} eq 'multitable_cell')
              {
                  my $multitable = $info_state->{'multitable_stack'}->[-1];
                  $multitable->{'cell_index'}++;
                  my $cell_width = $content->{'parent'}->{'parent'}->{'columns_size'}->[$multitable->{'cell_index'}];
                  #$max_column = $cell_width-1;
                  $max_column = $cell_width -2;
                  my $cell = {'cell_width' => $cell_width, 'index_entries' => [], 'anchors' => []};
                  push @{$multitable->{'cells'}}, $cell;
                  $result = '';
                  $length = 0;
                  $all_line_passed = 0;
                  $line_char_counter = 0;
                  $indent_level = 0;
                  $indent_length = 0;
                  if (!$content->{'content'})
                  {# empty cell
                      $cell->{'result'} = $result;
                      $cell->{'length'} = $length;
                      $cell->{'line_passed'} = $all_line_passed;
                  }
                  #info_default_skip_spaces($current, $index, $close);
              }
              if ($info_default_indented_commands{$content->{'command'}})
              {
                  if ($content->{'command'} =~ /^deff_item/)
                  {
                     info_default_skip_spaces($current, $index, $close);
                  }
                  #elsif (!$info_state->{'blank_line'} and $info_state->{'only_spaces'} and ($indent_level != 0) and !$preformatted)
                  elsif (!$info_state->{'blank_line'} and $info_state->{'only_spaces'} and ($indent_level != 0))
                  {
                     $text_added .= "\n";
                  }
                  # there is no close if !$content->{'content'}
                  $indent_level++ if ($content->{'content'});
                  $indent_length = $indent_level * $info_default_indent_length;
              }
              elsif (($complex_format_map{$content->{'command'}} and $content->{'command'} ne 'menu') or $content->{'command'} eq 'cartouche')
              {
                  #if (!$info_state->{'blank_line'} and $info_state->{'only_spaces'} and ($indent_level != 0) and !$preformatted_format)
                  if (!$info_state->{'blank_line'} and $info_state->{'only_spaces'} and ($indent_level != 0))
                  {
                     $text_added .= "\n";
                  }
              }
              if ($complex_format_map{$content->{'command'}} and $content->{'content'})
              {
                  $preformatted_format++;
              }
          }

          if (defined($content->{'text'}))
          {
              if ($in_para and !$in_exdent)
              {
                  #print STDERR "IN_PARA text\n";
                  my $new_text = $content->{'text'};
                  # first find if in a context of no puncutation related 
                  # modification: code style command or @var, @cite, @math
                  # acceptable for punctuation related modifications: 
                  # asis b dfn emph i slanted sansserif r sc strong t w
                  my $current_tested = $content;
                  my $no_punctation_munging_command;
                  while ($current_tested)
                  {
                     if (defined($current_tested->{'command'}) and (($style_map{$current_tested->{'command'}} and $style_map{$current_tested->{'command'}}->{'args'} and $style_map{$current_tested->{'command'}}->{'args'}->[0] and $style_map{$current_tested->{'command'}}->{'args'}->[0] eq 'code') or $current_tested->{'command'} eq 'var' or $current_tested->{'command'} eq 'cite' or $current_tested->{'command'} eq 'math'))
                     {
                        $no_punctation_munging_command = 1;
                        last; 
                     }
                     $current_tested = $current_tested->{'parent'};
                  }
                  # a punctuation at the end of line in a command is treated 
                  # like a punctuation in plain text, except for @:,
                  # accent commands, @dots, 'simple_style' command, and if in
                  # a command as found out just above.

                  if (!$no_punctation_munging_command and (!defined($content->{'command'}) or ($content->{'command'} ne ':' and $content->{'command'} ne 'accents_commands' and $content->{'command'} ne 'dots') and !$info_default_leaf_command{$content->{'command'}}) and get_conf('frenchspacing') ne 'on' and $new_text =~ /([$info_default_end_sentence_character])([$info_default_after_punctuation_characters]*)(\s*)$/)
                  {
                      my $spaces = $3;
                      if (chomp($new_text))
                      {
                          $new_text =~ s/(\s*)$/  /;
                      }
                      else
                      {
                          # these variables hold the place where the end 
                          # of line characters are normalized.
                          my ($current_start_from, $index_start_from, $close_start_from) = ($current, $index, $close);
                          my $only_after_punctuation_characters = 1;
                          my $spaces_to_normalize = 0;

                          # first find whether there are only 
                          # after_punctuation_characters followed by spaces
                          # and find the place where the 
                          # after_punctuation_characters end
                          my ($current_next, $index_next, $close_next, $text_next, $command_next) = info_default_next ($current, $index, $close);
                          # go through the text as long as there are after_punctuation_characters
                          if (!$spaces)
                          {
                              while (1)
                              {
                                  # !defined($text_next) catches many special 
                                  # commands, like anchor, index. Not sure if 
                                  # it is right or wrong.
                                  # Also a style_map command never stops
                                  # the search, so that @emph{ or @strong{
                                  # begin and end are not taken into account
                                  if (!defined($current_next) or (!defined($text_next)) or (defined($command_next) and $command_next eq '*') or ($text_next !~ /^[$info_default_after_punctuation_characters]*(\s*)$/ and (!defined($command_next) or !$style_map{$command_next})))
                                  {
                                      $only_after_punctuation_characters = 0;
                                      last;
                                  }
                                  my $text_next_kept = $text_next;
                                  # begin normalizing spaces at the last place
                                  # where there are after_punctuation_characters
                                  $current_start_from = $current_next;
                                  $index_start_from = $index_next;
                                  $index_start_from = $index_next;
                                  ($current_next, $index_next, $close_next, $text_next, $command_next) = info_default_next ($current_next, $index_next, $close_next);
                                  if ($text_next_kept =~ /^[$info_default_after_punctuation_characters]*\s+$/)
                                  {
                                      if (chomp($text_next_kept))
                                      {
                                          $spaces_to_normalize = 1;
                                      }
                                      last;
                                  }
                              }
                          }
                          # check if there are only spaces until end of line
                          if ($only_after_punctuation_characters and !$spaces_to_normalize)
                          {
                              while (1)
                              {
                                  # !defined($text_next) catches many special 
                                  # commands, like anchor, index. Not sure if 
                                  # it is right or wrong.
                                  last if (!defined($current_next) or (!defined($text_next)) or (defined($command_next) and $command_next eq '*'));
                                  if ($text_next =~ /\S/ and (!defined($command_next) or !$style_map{$command_next}))
                                  {
                                      last;
                                  }
                                  else
                                  {
                                      if (chomp($text_next))
                                      {
                                           $spaces_to_normalize = 1;
                                           last;
                                      }
                                  }
                                  ($current_next, $index_next, $close_next, $text_next, $command_next) = info_default_next ($current_next, $index_next, $close_next);
                              }
                              
                          }
                          if ($spaces_to_normalize)
                          {
                              # now do the spaces normalization
                              info_default_skip_spaces($current_start_from, $index_start_from, $close_start_from);
                              my $content = $current_start_from->{'content'}->[$index_start_from];
                              $content->{'text'} =~ s/(\s*)$/  /;
                          }
                      }
                  }
                  elsif (chomp($new_text))
                  {
                      $new_text =~ s/(\s*)$/ /;
                  }
                  $text_added .= $new_text;
              } # ignore spaces outside of paragraphs and preformatted
              elsif ($preformatted or $info_state->{'align_stack'}->[-1]->{'command'} ne 'normal')
              {
                  #print STDERR "IN_PREFORMATTED or ALIGN text\n";
                  $text_added .= $content->{'text'};
              }
              else
              {
                  my $chomped_text = $content->{'text'};
                  if ($chomped_text !~ /\S/ and chomp($chomped_text) and !$item_pending)
                  {
                      if ($in_table_item and $info_state->{'only_spaces'})
                      {
                          # in a blank_line
                          #print STDERR "IN_ITEM ignored: `$content->{'text'}'\n";
                      }
                      elsif (!$info_state->{'blank_line'} or !$info_state->{'only_spaces'})
                      {
                         #print STDERR "IN_ADDING_BLANK_LINE because no line before or text before\n";
                          $text_added .= "\n";
                      }
                      else
                      {
                          #print STDERR "IN_NOT_ADDING_BLANK_LINE\n";
                      }
                  }
                  else
                  { # exdent, item not in paragraph nor in preformatted
                       #print STDERR "NOWHERE and not end of line (or item_pending) `$content->{'text'}'\n";
                       $text_added .= $content->{'text'};
                  }
              }
          }
          else
          {
              if (defined($content->{'begin'}))
              {
                  $text_added .= $content->{'begin'};
              }
              # command that won't be closed, so the end has to be added 
              # here. It should mostly happen for empty style @-commands.
              if (defined($content->{'end'}) and !defined($content->{'content'}))
              {
                  $text_added .= $content->{'end'};
              }
          }
      }
      if (!$preformatted and !$in_exdent and $info_state->{'align_stack'}->[-1]->{'command'} eq 'normal' and $in_para)
      {
          # the line_passed returned here are not used, since they are computed
          # below.
          $indentation_done = 1;
          my $dummy_line_passed;
          ($line_char_counter, $pending_spaces_word, $dummy_line_passed, $text_added) = info_default_process_para_text($text_added, $line_char_counter, $pending_spaces_word, $indent_length, $max_column, $in_w, $indent_level * $info_default_indent_length) if ($text_added ne '');
      }
      elsif ($info_state->{'align_stack'}->[-1]->{'command'} ne 'center' and $info_state->{'align_stack'}->[-1]->{'command'} ne 'flushright')
      {
          my $dummy_line_passed;
          ($line_char_counter, $dummy_line_passed, $text_added) = info_default_process_line_text($text_added, $line_char_counter, $indent_length);
          #$indentation_done = 1;
      }
      else
      {
          $line_char_counter += t2h_default_string_width($text_added);
      }
    new_text:
      if ($text_added ne '')
      {
         if ($item_pending and !$line_added_before_item)
         {
            #info_default_skip_spaces($current, $index, $close);
            $item_pending = undef;
         }
      }
      if ($text_added =~ /\S/)
      {
         $in_table_item = 0 if ($in_table_item);
         $info_state->{'blank_line'} = 0;
      }
      $text_added = "\n" . $text_added if ($prepend_newline);
      print STDERR "TEXT_ADDED($indent_length) `$text_added'\n" if ($text_added ne '' and $DEBUG);
      #print STDERR "TEXT_ADDED($indent_length) `$text_added'\n";
      # from here, the next cmmand is available
      ($current, $index, $close) = info_default_iterator_next($current, $index, $close);

      my ($line_passed, $end_of_line, $last_line, $text_indented, $blank_line) = info_default_count_lines($text_added, $indent_length, ($indentation_done
        or $info_state->{'align_stack'}->[-1]->{'command'} eq 'center' 
        or $info_state->{'align_stack'}->[-1]->{'command'} eq 'flushright'));
      $info_state->{'blank_line'} = 1 if ($blank_line);
      print STDERR "ADDING `$text_indented'\n" if ($text_indented ne '' and $DEBUG);
      # only_space is set in all the conditionals
      if ($end_of_line)
      {
         $line_char_counter = 0;
         if ($in_exdent)
         {
            $in_exdent--;
         }
         if ($table_item_line)
         {
            $table_item_line--;
            $in_table_item = 1;
         }
         if (!$table_item_line and !$in_exdent and !$item_pending)
         {
            $indent_length = $indent_level * $info_default_indent_length;
         }
         $info_state->{'blank_line'} = 1 if ($info_state->{'only_spaces'} and ($last_line !~ /\S/));
         $info_state->{'only_spaces'} = 1;
      }
      else
      {
         if ($line_passed)
         {# in that case we added more than one line, the $line_char_counter
          # is reset to the last line length.
            $line_char_counter = t2h_default_string_width($last_line);
            $in_exdent = 0;
            $indent_length = $indent_level * $info_default_indent_length;
            if ($last_line !~ /\S/)
            {
               $info_state->{'only_spaces'} = 1;
            }
            else
            {
               $info_state->{'only_spaces'} = 0;
            }
         }
         else
         {
            $info_state->{'only_spaces'} = 0 if ($last_line =~ /\S/);
         }
      }
      if ($info_state->{'align_stack'}->[-1]->{'command'} eq 'center' 
        or $info_state->{'align_stack'}->[-1]->{'command'} eq 'flushright')
      {
          if (defined($current_line))
          {
              $text_added = $current_line . $text_added;
          }
          $text_indented = '';
          $current_line = undef;
          my $spaces_prepended = undef;
          foreach my $line (split /^/, $text_added) 
          {
             my $chomped_line = $line;
             if (chomp($chomped_line))
             {
                $line =~ s/^\s*//;
                $line =~ s/\s*$//;
                
                if (t2h_default_string_width($line) eq 0)
                {
                    $spaces_prepended = 0;
                    $text_indented .= "\n";
                }
                else
                {
                    my $line_width = t2h_default_string_width($line);
                    if ($line_width > $max_column)
                    {
                        $spaces_prepended = 0;
                    }
                    elsif ($info_state->{'align_stack'}->[-1]->{'command'} eq 'center')
                    {
                        $spaces_prepended = (($max_column -1 - $line_width) /2);
                    }
                    else
                    {
                         $spaces_prepended = ($max_column -1 - $line_width);
                    }
                    $text_indented .= ' ' x$spaces_prepended . $line ."\n";
                }
             }
             else
             {
                $current_line = $line;
             }
          }
          if (defined ($spaces_prepended) and defined($info_state->{'align_stack'}->[-1]->{'anchors'}))
          {
             while (@{$info_state->{'align_stack'}->[-1]->{'anchors'}})
             {
                my $anchor = shift @{$info_state->{'align_stack'}->[-1]->{'anchors'}};
                $anchor->{'info_offset'} += info_default_byte_count(' ' x$spaces_prepended);
             }
          }
      }
      
      if ($direntry)
      {
         $info_default_dir_specification .= $text_indented;
      }
      else
      {
         $result .= $text_indented;
         $length += info_default_byte_count($text_indented);
         $all_line_passed += $line_passed;
      }
   }
   return ($length, $result, $all_line_passed);
}

sub info_default_open_command($$;$)
{
   my $state = shift;
   my $command = shift;
   my $additional_entries = shift;

   my $index = 0;
   
   my $info_state = info_default_get_state($state);
   # index in the parent content list
   $index = scalar(@{$info_state->{'current'}->{'content'}}) 
       if (defined($info_state->{'current'}->{'content'}));
   my $new_command = {'command' => $command, 'parent' => $info_state->{'current'}, 'index_in_parent' => $index };
   if (defined($additional_entries))
   {
       foreach my $key (keys(%$additional_entries))
       {
           $new_command->{$key} = $additional_entries->{$key};
       }
   }

   push @{$info_state->{'current'}->{'content'}}, $new_command;
   $info_state->{'current'} = $new_command;
   print STDERR "TREE($info_state->{'nr'}): Opened $command\n" if ($DEBUG); 
}

sub info_default_close_command($$;$$$)
{
   my $state = shift;
   my $command = shift;
   my $begin = shift;
   my $end = shift;
   my $command_entries = shift;

   $state = $Texi2HTML::THISDOC{'state'} if (!defined($state));
   my $info_state = info_default_get_state($state);
   print STDERR "TREE($info_state->{'nr'}): Closing $command\n" if ($DEBUG);
   if (!defined($info_state->{'current'}))
   {
      print STDERR "info_state->{'current'} not defined (closing $command)\n";
   }
   elsif (!defined($info_state->{'current'}->{'command'}))
   {
      print STDERR "info_state->{'current'}->{'command'} not defined (closing $command)\n";
   }
   elsif ($command ne $info_state->{'current'}->{'command'})
   {
     print STDERR "Was waiting for $info_state->{'current'}->{'command'} (closing $command)\n";
   }
   #return if $no_close;
   $command_entries->{'begin'} = $begin;
   $command_entries->{'end'} = $end;
   $command_entries->{'line_nr'} = $Texi2HTML::THISDOC{'line_nr'};
   foreach my $key (keys(%$command_entries))
   {
      $info_state->{'current'}->{$key} = $command_entries->{$key} 
           if (defined($command_entries->{$key}));
   }

   $info_state->{'current'} = $info_state->{'current'}->{'parent'};

   return info_default_output($info_state)
     if (!defined($info_state->{'current'}->{'command'}));
   return '';
}

sub info_default_store_text($$;$$)
{
   my $state = shift;
   my $text = shift;
   my $command = shift;
   my $text_entries = shift;

   $state = $Texi2HTML::THISDOC{'state'} if (!defined($state));
   my $info_state = info_default_get_state($state);
   return '' if ((!defined($text) or $text eq '') and !defined($command));

   ################################## debug
   my $command_text = '';
   $command_text = "\[$command\]" if (defined($command));
   $command_text .= $text if (defined($text));
   print STDERR "TREE($info_state->{'nr'}) Storing: ${command_text}\n" if ($DEBUG);
   ################################## end debug

   $text_entries->{'text'} = $text if (defined($text));
   $text_entries->{'command'} = $command if (defined($command));
   $text_entries->{'parent'} = $info_state->{'current'};
   $text_entries->{'line_nr'} = $Texi2HTML::THISDOC{'line_nr'};
   push @{$info_state->{'current'}->{'content'}}, $text_entries;
   return info_default_output($info_state)
     if (!defined($info_state->{'current'}->{'command'}));
   return '';
}

sub info_default_increment_paragraph ($$$;$)
{
    my $in_format = shift;
    my $parent_format = shift; 
    my $info_state = shift;
    my $command = shift;

    if ($in_format)
    {
        $parent_format->{'paragraph_in_format_nr'} = 0 if (!defined($parent_format->{'paragraph_in_format_nr'}));
        $parent_format->{'paragraph_in_format_nr'}++;
    }
    else
    {
        $info_state->{'paragraph_in_element_nr'}++;
    }
    ####################### debug
    $command = 'PARA' if (!defined($command));
    if (0)
    #if (1)
    {
        my $format_info = '';
        if ($in_format)
        {
           $format_info = "format: [$parent_format->{'command'}],$parent_format->{'paragraph_in_format_nr'}"
        }
        print STDERR "INCREMENT_PARA($command) $info_state->{'paragraph_in_element_nr'} $format_info\n";
    }
    ####################### end debug
}

sub info_default_begin_format_texi($$$)
{
   my $command = shift;
   my $line = shift;
   my $state = shift;

   my $info_state = info_default_get_state ($state);
   my ($parent_format, $in_format);
   ($parent_format, $in_format) = info_default_parent_format($info_state->{'current'});
   info_default_increment_paragraph ($in_format, $parent_format, $info_state, $command);
   # remove space in front of center, unless it removes the end of line!
   $line =~ s/^\s*// if ($command eq 'center' and $line =~ /\S/);
   # don't open a format if it is a @def*x command and we are already in the 
   # corresponding @def* command
   info_default_open_command($state,$command) unless ($def_map{$command} and $command =~ /x$/ and defined($info_state->{'current'}->{'command'}) and "$info_state->{'current'}->{'command'}x" eq $command);
   return $line;
}

sub info_default_begin_style_texi($$$$$)
{
   my $command = shift;
   my $state = shift;
   my $stack = shift;
   my $real_style_command = shift;
   my $remove_texi = shift;

   info_default_open_command($state,$command)
     unless ($info_default_accent_commands{$command} or exists $things_map{$command} 
      or $command =~ /^special_(\w+)_(\d+)$/);
#      if ($real_style_command);
}

sub info_default_begin_paragraph_texi($$$)
{
   my $command = shift;
   my $paragraph_macros = shift;
   my $paragraph_command = shift;
   #print STDERR "begin_paragraph $command\n";
   my $state = shift;
   my $stack = shift;
   info_default_open_command($state,$command);
   foreach my $style_command (@$paragraph_macros)
   {
     #print STDERR "para stack: $style_command->{'style'}\n";
     info_default_open_command($state,$style_command->{'style'});
   }
}

sub info_default_simple_command($$$$$)
{
    my $command = shift;
    my $in_preformatted = shift;
    my $in_math = shift;
    my $line_nr = shift;
    my $state = shift;

    my $result = $simple_map{$command};
    $result = $simple_map_math{$command} if ($in_math and defined($simple_map_math{$command}));
    # discards '-' '|' '/' and ':'. If ':' is associated with a punctuation
    # character it is added to the tree in info_default_colon_command
    return info_default_store_text($state,$result,$command) if ($result ne '');
    return '';
}

sub info_default_colon_command($)
{
   my $punctuation_character = shift;
   if (defined($colon_command_punctuation_characters{$punctuation_character})
         and $punctuation_character =~ /^[$punctuation_characters]$/)
   {
      return info_default_store_text(undef,$colon_command_punctuation_characters{$punctuation_character}, ':');
   }
   else
   {
      return info_default_store_text(undef,$punctuation_character);
   }
}

sub info_default_thing_command($$$$$$)
{
    my $command = shift;
    my $text = shift;
    my $in_preformatted = shift;
    my $in_math = shift;
    my $line_nr = shift;
    my $state = shift;

    my $result = $things_map{$command};
    #return info_default_close_command($state, $command, $result, $text, '');
    return info_default_store_text($state, $result, $command);
#    return $result . $text;
}


sub info_default_style($$$$$$$$$$)
{
   my $style = shift; 
   my $command = shift;
   my $text = shift;
   my $args = shift;
   my $no_close = shift;
   my $no_open = shift;
   my $line_nr = shift;
   my $state = shift;
   my $command_stack = shift;
   my $kept_line_nrs = shift;

   my $begin = '';
   my $end = '';

   # note that the $text is always discarded for closed commands

   # the formatting is done right here, and the result is entered as text below.
   if ($info_default_leaf_command{$command})
   {
      my $style_index = 0;
      my @formatted_args = ();
      foreach my $arg (@$args)
      {
         # we don't use style, since we only set 'orig_args' in style_map
         # and not in style_map_pre.
         my $arg_style = $style_map{$command}->{'orig_args'}->[$style_index];
         my $new_state = main::duplicate_formatting_state($state);
         if ($arg_style eq 'normal')
         {
            push @formatted_args, main::substitute_line($arg, "\@$command", $new_state);
         }
         elsif ($arg_style eq 'code')
         {
            $new_state->{'code_style'} = 1;
            push @formatted_args, main::substitute_line($arg, "\@$command", $new_state);
         }
         else
         {
            print STDERR "Unknown arg style($style_index) $arg_style for $command, $state->{'remove_texi'}\n";
         }
         $style_index++;
      }
      $args = \@formatted_args; 
   }
   if (defined($style->{'function'}))
   { # in case of an accent, some text is returned here if there are still
     # more accents on the command_stack, otherwise it is put in the tree.
     # Other commands text results are put in the tree below.
      $text = &{$style->{'function'}}($command, $args, $command_stack, $state, $line_nr, $kept_line_nrs);
   }
   elsif ($info_default_leaf_command{$command})
   { # no formatting function but a leaf command, it is just replaced 
     # by the formatted argument, and put in the tree below.
      $text = $args->[0];
   }
   if (defined($style->{'begin'}) and !$no_open)
   {
      $begin = $style->{'begin'};
   }
   if (defined($style->{'end'}) and !$no_close)
   {
      $end = $style->{'end'};
   }
   # normal style commands
   unless($special_style{$command} or $info_default_accent_commands{$command} or ($command eq 'hyphenation') or $info_default_leaf_command{$command})
   {
      return info_default_close_command($state, $command, $begin, $end);
   }
   # this is for *ref, images and footnotes text registering and putting
   # in the tree.
   # anchor is already in the tree, from anchor_label.
   if (($special_style{$command} or $info_default_leaf_command{$command}) and $command ne 'anchor')
   {
       return info_default_store_text ($state, $begin.$text.$end, $command);
   }
   # for accents, hyphenation and anchor
   # (though the result for anchor is always an empty string).
   return $begin.$text.$end;
}

sub info_default_header ()
{
    return $Texi2HTML::THISDOC{'info_header'} if (defined($Texi2HTML::THISDOC{'info_header'}));
# $Texi2HTML::THISDOC{'program'}
    my $input_basename = $Texi2HTML::THISDOC{'input_file_name'};
    $input_basename =~ s/^.*\///; # if ($TEST);
    $input_basename = $STDIN_DOCU_NAME if ($input_basename eq '-');
    my $output_basename = $Texi2HTML::THISDOC{'filename'}->{'top'};
    $output_basename =~ s/^.*\///;
    my $result = "This is $output_basename, produced by makeinfo version 4.13 from $input_basename. ";
    my $dummy;
    ($dummy, $dummy, $dummy, $result) = info_default_process_para_text($result, 0, {'spaces' => ''}, undef, get_conf('fillcolumn'));
    $result .= "\n\n";
    $result .= "$Texi2HTML::THISDOC{'copying_comment'}";
    if ($info_default_dir_specification)
    {
        $result .= "$info_default_dir_specification\n";
    }
    $Texi2HTML::THISDOC{'info_header'} = $result;
    return $result;
}

sub info_default_print_page_head($)
{
    my $fh = shift;
    my $header = info_default_header();
    print $fh "".$header;

    my $state = $Texi2HTML::THISDOC{'state'};
    my $info_state = info_default_get_state ($state);
    $info_state->{'offset_in_file'} += info_default_byte_count($header);
    $info_state->{'blank_line'} = 1 if ($Texi2HTML::THISDOC{'copying_comment'} eq '');
}

sub info_default_parent_format($)
{
    my $parent_format = shift;
    my $in_format = 0;
    while (1)
    {
        if (defined($parent_format->{'command'}) and $info_default_format{$parent_format->{'command'}})
        {
            $in_format = 1;
            last;
        }
        last if (!defined($parent_format->{'parent'}));

        $parent_format = $parent_format->{'parent'};
    }
    return ($parent_format, $in_format);
}

sub info_default_paragraph($$$$$$$$$$$$)
{
    my $text = shift;
    my $align = shift;
    my $indent = shift;
    my $paragraph_command = shift;
    my $paragraph_command_formatted = shift;
    my $paragraph_number = shift;
    my $format = shift;
    my $item_nr = shift;
    my $enumerate_style = shift;
    my $number = shift;
    my $command_stack_at_end = shift;
    my $command_stack_at_begin = shift;

    my $top_stack = '';
    $top_stack = $command_stack_at_begin->[-1] if (scalar (@$command_stack_at_begin));

    my $state = $Texi2HTML::THISDOC{'state'};
    my $info_state = info_default_get_state ($state);
    my ($parent_format, $in_format);
    ($parent_format, $in_format) = info_default_parent_format($info_state->{'current'}->{'parent'});
    info_default_increment_paragraph ($in_format, $parent_format, $info_state);
    my $additional_args = {'top_stack' => $top_stack, 'parent_format' => $parent_format};
    $additional_args->{'paragraph_in_element_nr'} = ($info_state->{'paragraph_in_element_nr'} - 1) if (!$in_format);
    
    return info_default_close_command(undef, 'paragraph', undef, undef, $additional_args);
}

# currently not used, but could be used if info_default_preformatted
# return something that is not 'false', for example spaces, though we
# want the preformatted to be ignored. Though it is not sure that if there
# are spaces we want to ignore the preformatted.
sub info_default_empty_preformatted($)
{
    my $text = shift;
    my $result = info_default_preformatted($text, undef, undef, undef, undef,
            undef, undef, undef, undef, undef, undef, undef);
    return 0;
}

sub info_default_preformatted($$$$$$$$$$$$)
{
    my $text = shift;
    my $pre_style = shift;
    my $class = shift;
    my $leading_command = shift;
    my $leading_command_formatted = shift;
    my $preformatted_number = shift;
    my $format = shift;
    my $item_nr = shift;
    my $enumerate_style = shift;
    my $number = shift;
    my $command_stack_at_end = shift;
    my $command_stack_at_begin = shift;

    return info_default_close_command(undef, 'preformatted');
} 


sub info_default_node_line($$)
{
    my $element = shift;
    my $info_state = shift;
    my $outfile = $Texi2HTML::THISDOC{'filename'}->{'top'};
    $outfile = $STDOUT_DOCU_NAME if ($outfile eq '-');
    my $result = "\x{1F}\nFile: $outfile,  Node: $element->{'text'}";
    if (defined($element->{'NodeNext'}))
    { # This is not translatable
       $result .= ",  Next: $element->{'NodeNext'}->{'text'}";
    }
    if (defined($element->{'NodePrev'}))
    {
       $result .= ",  Prev: $element->{'NodePrev'}->{'text'}";
    }
    if (defined($element->{'NodeUp'}))
    {
       $result .= ",  Up: $element->{'NodeUp'}->{'text'}";
    }
    $result .= "\n\n";
    # the line_count is ahead from the number of lines by one.
    $info_state->{'line_count'} = 3;
    $info_state->{'offset_in_file'} += info_default_byte_count($result);
    $info_state->{'blank_line'} = 1;
    return $result;
}

sub info_default_element_heading($$$$$$$$$$$$)
{
    my $element = shift;
    my $command = shift;
    my $texi_line = shift;
    my $line = shift;
    my $in_preformatted = shift;
    my $one_section = shift;
    my $element_heading = shift;
    my $first_in_page = shift;
    my $is_top = shift;
    my $previous_is_top = shift;
    my $command_line = shift;
    my $element_id = shift;
    my $new_element = shift;

    my $state = $Texi2HTML::THISDOC{'state'};
    my $info_state = info_default_get_state ($state);

    # FIXME use $element or $Texi2HTML::THIS_ELEMENT? Main program should 
    # ensure they are the same. 
    if ($new_element and ($element ne $new_element and $element->{'node'}))
    {
        die "There is a new element, but element `$element->{'texi'}' is not the new element\n";
    }
    # FIXME
    # non node element may appear if the element appears before the first
    # node/section element. For example `element not associated with a node'
    # won't be associated with a node.
    # @unnumbered element not associated with a node
    # @node Top
    # @top Top element
    if (!$element->{'node'})
    {
        return &$heading($element, $command, $texi_line, $line, $in_preformatted, $one_section, $element_heading);
    }

    my $before = '';
    $element->{'info_offset'} = $info_state->{'offset_in_file'};
    push @{$info_state->{'pending_tags'}}, $element;

    my $result = info_default_node_line($element, $info_state);

    $info_default_footnote_index = 0;
    $info_default_current_node = $element;
    
    return $before.$result;
}

sub info_default_heading($$$$$;$$)
{
    my $element = shift;
    my $command = shift;
    my $texi_line = shift;
    my $line = shift;
    my $in_preformatted = shift;
    my $one_section = shift;
    my $element_heading = shift;

    die "Heading called for a node\n" if ($element->{'node'});
    my $state = $Texi2HTML::THISDOC{'state'};
    my $info_state = info_default_get_state ($state);
    $info_state->{'paragraph_in_element_nr'} = 0;
    if (!defined($element->{'texi'}))
    {
       main::msg_debug("for $element, element->{'texi'} not defined, texi_line: $texi_line");
    }
    elsif (!defined($element->{'text'}))
    {
       main::msg_debug("for $element, $element->{'texi'}, element->{'text'} not defined");
    }
    return '' if ($element->{'tag'} eq 'part');

    my $text = "$element->{'text'}";
    # when @top is empty, use settitle
    $text = $Texi2HTML::THISDOC{'settitle'} if (!length($text) and $element->{'tag'} eq 'top' and defined ($Texi2HTML::THISDOC{'settitle'}) and length($Texi2HTML::THISDOC{'settitle'}));
    my $result = &$heading_text ("\@$command", $text, $element->{'level'});

    $result .= "\n";

    return info_default_store_text($state, $result, $command, {'heading_command' => 1});
}

sub info_default_normal_text($$$$$$$;$)
{
   my @initial_args = @_;
   my $text = shift;
   my $in_raw_text = shift; # remove_texi
   my $in_preformatted = shift;
   my $in_code = shift;
   my $in_math = shift;
   my $in_simple = shift;
   my $style_stack = shift;
   my $state = shift;

   # $Texi2HTML::THISDOC{'ENCODING_NAME'}) should be defined, but maybe 
   # not when parsing commands in first or second pass, and removeing texi
   # like what is done for @setfilename.
   if ($ENABLE_ENCODING and defined($Texi2HTML::THISDOC{'ENCODING_NAME'}) and ($Texi2HTML::THISDOC{'ENCODING_NAME'} eq 'utf-8') and $USE_UNICODE)
   {
      $text = &t2h_utf8_normal_text(@initial_args);
   }
   else
   {
      #print STDERR "info_default_normal_text $text $in_preformatted $in_code \n";
      $text = uc($text) if (in_cmd($style_stack, 'sc'));
      $text = uc($text) if (in_cmd($style_stack, 'var'));
      if (! $in_code and !$in_preformatted)
      {
         $text =~ s/---/\x{1F}/g;
         $text =~ s/--/-/g;
         $text =~ s/\x{1F}/--/g;
         $text =~ s/``/"/g;
         $text =~ s/\'\'/"/g;
      }
   }
   # accented characters are not handled as normal text, but when the last 
   # accent command on the stack is closed.
   if ($style_stack and @$style_stack and $info_default_accent_commands{$style_stack->[-1]})
   {
      return $text;
   }
#print STDERR "NORMAL\n";
   return info_default_store_text($state,$text);
}

# this is not called in preformatted
sub info_default_empty_line($$)
{
    my $text = shift;
    my $state = shift;
    #ignore the line if it just follows a deff
    #return '' if ($state->{'deff_line'});
    return info_default_store_text($state,$text);
#    return '';
}

# change interface?
sub info_default_anchor_label($$$$)
{
    my $id = shift;
    my $anchor_text = shift;
    my $anchor_reference = shift;
    my $in_special_region = shift;
    return '' if ($in_special_region);
    #print STDERR "Storing anchor $anchor_reference->{'text'}\n";
    main::line_warn(__("anchor outside of any node, it won't be registered"), $Texi2HTML::THISDOC{'line_nr'}) if (!defined($info_default_current_node));
   return info_default_store_text(undef,undef,'anchor',{'anchor_reference' => $anchor_reference});
}

sub info_default_acronym_like($$$$$$)
{
    my $command = shift;
    my $acronym_texi = shift;
    my $acronym_text = shift;
    my $with_explanation = shift;
    my $explanation_lines = shift;
    my $explanation_text = shift;
    my $explanation_simply_formatted = shift;

   if ($with_explanation)
   {
       return "$acronym_text ($explanation_text)";
   }
   else
   {
       return "$acronym_text";
   }
}


sub info_default_print_page_foot($)
{
   my $fh = shift;
   my $state = $Texi2HTML::THISDOC{'state'};
   my $info_state = info_default_get_state ($state);
   my $indirect = 0;
   if (!defined ($info_state->{'pending_tags'}))
   { # i18n
      main::document_warn ("Document without nodes.");
   }
   else
   {
       $indirect = 1 if ($info_default_out_file_nr > 1);
       if ($indirect)
       {
          close ($Texi2HTML::THISDOC{'FH'});
          unless (rename ("$Texi2HTML::THISDOC{'destination_directory'}$Texi2HTML::THISDOC{'filename'}->{'top'}", "$Texi2HTML::THISDOC{'destination_directory'}$Texi2HTML::THISDOC{'filename'}->{'top'}-1"))
          {
              main::document_warn ("Rename $Texi2HTML::THISDOC{'destination_directory'}$Texi2HTML::THISDOC{'filename'}->{'top'} failed: $!");
          }
          
          my $INDIRECT = main::open_out("$Texi2HTML::THISDOC{'destination_directory'}$Texi2HTML::THISDOC{'filename'}->{'top'}");
          print $INDIRECT "".info_default_header();
          print $INDIRECT "\x{1F}\nIndirect:";
          foreach my $indirect (@info_default_pending_indirect)
          {
              print $INDIRECT "\n$indirect->{'file'}: $indirect->{'offset'}";
          }
          $fh = $INDIRECT;
      }
      # makeinfo seems to add systematically an additional \n, done just below
      print $fh "\n\x{1F}\nTag Table:\n";
      
      if ($indirect)
      {
          print $fh "(Indirect)\n";
      }
      my $Top_seen;
      foreach my $element (@{$info_state->{'pending_tags'}})
      {
         my $prefix;
         $prefix = 'Node' if ($element->{'node'});
         $prefix = 'Ref' if ($element->{'anchor'} or $element->{'float'});
         print $fh "$prefix: $element->{'text'}\x{7F}$element->{'info_offset'}\n";
         $Top_seen = 1 if ($element->{'text'} =~ /^top$/i);
      }
      if (!$Top_seen)
      {# i18n
         main::document_warn ("Document without Top node.");
      }
      print $fh "\x{1F}\nEnd Tag Table\n";
   }

   # IN_ENCODING is the documentencoding transformed to the encoding names
   # usually seen in html. This is what the info readers should understand.
   my $coding = get_conf('IN_ENCODING');
   $coding = get_conf('DOCUMENT_ENCODING') if (!defined($coding));
   if (defined($coding))
   {
      print $fh "\n\x{1F}\nLocal Variables:\ncoding: $coding\nEnd:\n";
   }
}

sub info_default_print_Top_footer($$$)
{
    my $fh = shift;
    my $end_page = shift;
    my $element = shift;
    if ($end_page)
    {
        &$print_page_foot($fh);
    }
    info_default_end_section($fh, $end_page, $element);
}

sub info_default_footnote_texi($$$)
{
    my $text = shift;
    my $state = shift;
    my $style_stack = shift;
    
    unless ($state->{'outside_document'} or (defined($state->{'multiple_pass'}) and $state->{'multiple_pass'} > 0))
    {
       $info_default_footnote_index++;
    }
    my $footnote_number = $info_default_footnote_index;
    $footnote_number = $NO_NUMBER_FOOTNOTE_SYMBOL if (!$NUMBER_FOOTNOTES);
    return "($footnote_number) $text";
    #return undef;
}

sub info_default_print_section
{
    my $fh = shift;
    my $first_in_page = shift;
    my $previous_is_top = shift;
    my $element = shift;
    my $nw = main::print_lines($fh);
    my $state = $Texi2HTML::THISDOC{'state'};
    my $info_state = info_default_get_state ($state);
    if (!$info_state->{'blank_line'})
    {
       my $end = "\n";
       $info_state->{'offset_in_file'} += info_default_byte_count($end);
       $info_state->{'line_count'}++;
       print $fh "$end";
    }
    if (@info_default_pending_footnotes)
    {
        my $footnote_text;
        my $footnote_element;
        if (get_conf('footnotestyle') eq 'separate')
        {
            my $node_ref = $info_default_current_node;
            # thee is a warning when processing the footnote, like
            # "Footnote defined without parent node"
            $node_ref = {'text' => 'no node', 'file' => ''} if (!defined($node_ref));
            $footnote_element = { 'NodeUp' => $node_ref, 
                       'text' => $node_ref->{'text'} . "-Footnotes", 
                       'file' => $node_ref->{'file'},
                       'info_offset' => $info_state->{'offset_in_file'},
                       'node' => 1,
                 };
            $footnote_element->{'element_ref'} = $footnote_element;
            push @{$info_state->{'pending_tags'}}, $footnote_element;
            $footnote_text = info_default_node_line($footnote_element, $info_state); 
        }
        else
        { # FIXME i18n?
            $footnote_text = "   ---------- Footnotes ----------\n\n";
            $info_state->{'offset_in_file'} += info_default_byte_count($footnote_text);
            $info_state->{'line_count'} += 2;
            #print STDERR "MMMMMMMMMMMMMMMMMM $info_state->{'line_count'}\n";
        }
        while (@info_default_pending_footnotes)
        {
    #push @info_default_pending_footnotes, [$lines, $footnote_text, ${info_default_footnote_index}, $node_name, $footnote_info_state];
            my $footnote = shift @info_default_pending_footnotes;
            my $foot_nr = $footnote->{'footnote_index'};
            my $node_name = $footnote->{'node_name'};
            my $lines = $footnote->{'lines'};
            push @{$info_state->{'pending_tags'}}, {'anchor' => 1, 'text' => "${node_name}-Footnote-${foot_nr}", 'info_offset' => $info_state->{'offset_in_file'} };
            my $footnote_info_state = $footnote->{'footnote_info_state'};
            my $footnote_result = shift @{$lines};
            # this is used to keep track of the size when there were 
            # leading spaces that will be removed below. This is only used
            # to get the difference, the value itself is not of use.
            my $initial_length = info_default_byte_count($footnote_result);
            
            $footnote_result =~ s/^\s*//;
            #$footnote_result = "   ($foot_nr) " . $footnote_result;
            $footnote_result = ' ' x get_conf('paragraphindent') . $footnote_result;
            foreach my $footnote_pending_tags(@{$footnote_info_state->{'pending_tags'}})
            {
               $footnote_pending_tags->{'info_offset'} += $info_state->{'offset_in_file'} + info_default_byte_count($footnote_result) - $initial_length;
               push @{$info_state->{'pending_tags'}}, $footnote_pending_tags;
            }
            foreach my $footnote_pending_index_entry(@{$footnote_info_state->{'pending_index_entries'}})
            {
               #print STDERR "TTTTTTTTTTT($footnote_pending_index_entry->{'index_entry_reference'}->{'entry'}) $footnote_pending_index_entry->{'line_nr'} $info_state->{'line_count'}\n";
               $footnote_pending_index_entry->{'line_nr'} += $info_state->{'line_count'};
               $footnote_pending_index_entry->{'index_entry_reference'}->{'real_element'} = $footnote_element if (get_conf('footnotestyle') eq 'separate');
            }
            my $line;
            while (@$lines)
            {
               $line = shift @$lines;
               $footnote_result .= $line;
            }
            my ($line_passed, $end_of_line, $last_line, $text_indented, $blank_line) = info_default_count_lines($footnote_result);
            if ($line_passed == 0)
            {# certainly out of paragraph commands
               $footnote_result =~ s/\s*$//;
               $footnote_result .= "\n";
               $line_passed = 1;
            }
            unless (($last_line !~ /\S/ and $end_of_line) or ($blank_line)) 
            {
               $footnote_result .= "\n";
               $line_passed += 1;
            }
            
            $info_state->{'offset_in_file'} += info_default_byte_count($footnote_result);
            $info_state->{'line_count'} += $line_passed;
            $footnote_text .= $footnote_result;
        }
        print $fh "$footnote_text";
    }
}

sub info_default_end_section($$$)
{
    my $fh = shift;
    my $end_foot_navigation = shift;
    my $element = shift;
    my $state = $Texi2HTML::THISDOC{'state'};
    my $info_state = info_default_get_state ($state);

    if (defined($Texi2HTML::THISDOC{'SPLIT_SIZE'}) and 
   $info_state->{'offset_in_file'} > ($info_default_out_file_nr) * $Texi2HTML::THISDOC{'SPLIT_SIZE'})
    {
       if ($info_default_out_file_nr == 1)
       { # push also the first node, which is always the first pending_tags
          push @info_default_pending_indirect, {'file'=>"$Texi2HTML::THISDOC{'filename'}->{'top'}-$info_default_out_file_nr", 'offset' => $info_state->{'pending_tags'}->[0]->{'info_offset'} };
       }
       $info_default_out_file_nr++;
       # these file descriptors leak, but this allows the user to write a 
       # foot navigation himself, otherwise he would write on a closed file
       # descriptor
       #close($Texi2HTML::THISDOC{'FH'});
       if (!$end_foot_navigation)
       {
           main::open_out_file("$Texi2HTML::THISDOC{'filename'}->{'top'}-$info_default_out_file_nr");
           #print STDERR "X-$info_default_out_file_nr: $info_state->{'offset_in_file'}\n";
           &$print_page_head($Texi2HTML::THISDOC{'FH'});
           push @info_default_pending_indirect, {'file'=>"$Texi2HTML::THISDOC{'filename'}->{'top'}-$info_default_out_file_nr", 'offset' => $info_state->{'offset_in_file'}};
       }
    }
}

sub info_default_one_section($$)
{
    my $fh = shift;
    my $element = shift;
    &$print_section($fh, 1, 0, $element);
    &$print_page_foot($fh);
}

sub info_default_begin_special_region($$$)
{
    my $region = shift;
    my $state = shift;
    my $lines = shift;
    my $info_state = info_default_get_state ($state);
    # reset paragraph_in_element_nr if out ofdocument formatting
    if ($state->{'outside_document'})
    {
        $info_state->{'paragraph_in_element_nr'} = 0;
    }
}

sub info_default_end_special_region($$$)
{
    my $region = shift;
    my $state = shift;
    my $text = shift;
    my $info_state = info_default_get_state ($state);
    my $end = '';
    if (!$info_state->{'blank_line'})
    {
       $end = "\n";
       $info_state->{'offset_in_file'} += info_default_byte_count($end);
    }
    return $text.$end;
}

sub info_default_menu_link($$$$$$$$)
{
    my $entry = shift;
    my $state = shift;
    my $href = shift;
    my $node = shift;
    my $title = shift;
    my $ending = shift;
    my $has_title = shift;
    my $command_stack = shift;
    my $preformatted = shift;

    $title = '' unless ($has_title);
    $title .= ':' if ($title ne '');
    my $result = "$MENU_SYMBOL$title$node$ending";
    return info_default_store_text($state,$result,'menu_entry');
}

# not used, menu is a normal preformatted command
#sub info_default_menu_command($$$)
#{
#    my $format = shift;
#    my $text = shift;
#    my $in_preformatted = shift;
#    return info_default_close_command(undef, $format, "* Menu:\n", undef, "\n");
#}   

sub info_default_complex_format($$)
{
    my $name = shift;
    my $text = shift;
    my ($begin, $end);
    if ($name eq 'menu')
    {
        main::line_warn(__("\@menu before first node"), $Texi2HTML::THISDOC{'line_nr'}) if (!defined($info_default_current_node));
        $begin = "* Menu:\n\n";
    }
    elsif ($name eq 'direntry')
    {
        main::line_warn(__("\@direntry after first node"), $Texi2HTML::THISDOC{'line_nr'}) if (defined($info_default_current_node));
        $begin = "START-INFO-DIR-ENTRY\n"; 
        $end = "END-INFO-DIR-ENTRY\n";
    }
    return info_default_close_command(undef, $name, $begin, $end);
}

sub info_default_quotation($$$$$)
{
    my $command = shift;
    my $text = shift;
    my $argument_text = shift;
    my $argument_text_texi = shift;
    my $authors = shift;

    my $attribution;
    if ($authors)
    {
       $attribution = '';
       foreach my $author (@$authors)
       {
           my $author_texi = $author->{'author_texi'};
           chomp($author_texi);
           $attribution .= gdt("\@center --- \@emph{{author}}\n", {'author' => $author_texi}, {'duplicate' => 1, 'allow_paragraph' => 1});
       }
    }
    
    return info_default_close_command(undef, $command, undef, $attribution);
}

sub info_default_misc_commands($$$$$)
{
    my $command = shift;
    my $line = shift;
    my $args = shift;
    my $stack = shift;
    my $state = shift;

    info_default_store_text($state,undef,$command) if ($command eq 'exdent' or $command eq 'noindent' or $command eq 'indent');
    return ($command, $line, undef);
}

sub info_default_external_ref($$$$$$$$$)
{
    my $type = shift;
    my $section = shift;
    my $book = shift;
    my $file = shift;
    my $href = shift;
    my $cross_ref = shift;
    my $args_texi = shift;
    my $formatted_args = shift;
    my $node = shift;

    return info_default_inforef($formatted_args) if ($type eq 'inforef');
    return info_default_normal_reference($type, $formatted_args);
}

sub info_default_internal_ref($$$$$$$$)
{
    my $type = shift;
    my $href = shift;
    my $short_name = shift;
    my $name = shift;
    my $is_section = shift;
    my $args_texi = shift;
    my $formatted_args = shift;
    my $element = shift;

    $formatted_args->[1] = $name if ($element->{'float'} and (!defined($formatted_args->[1]) or $formatted_args->[1] eq ''));
    return info_default_inforef($formatted_args) if ($type eq 'inforef');
    return info_default_normal_reference($type, $formatted_args);
}

sub info_default_normal_reference($$)
{
    my $command = shift;
    my $formatted_args = shift;
    for (my $i = 0; $i < scalar(@$formatted_args); $i++)
    {
       $formatted_args->[$i] = undef if (defined($formatted_args->[$i]) and 
          $formatted_args->[$i] =~ /^\s*$/);
    }
    my $node = $formatted_args->[0];
    # an error, should trigger the message: Undefined node `' in @ref.
    # avoid undef value and use an empty string instead.
    $node = '' if (!defined($node));
    my $name = $formatted_args->[1];
    $name =  $formatted_args->[2] if (!defined($name));
    my $file = $formatted_args->[3];
    $file = '' if (!defined($file) and defined($formatted_args->[4]));
    $name = $node if (!defined($name) and defined($file));
    my $result = '*note ';
    $result = '*Note ' if ($command eq 'xref');
    if (defined($name))
    {
       $result .= "${name}: ";
       $result .= "($file)" if (defined($file));
       $result .= "$node";
       $result .= '.' if ($command eq 'pxref');
    }
    else
    {
       $result .= "${node}::";
    }
    return $result;
}

sub info_default_inforef($)
{
    my $formatted_args = shift;
    return info_default_normal_reference('ref', [$formatted_args->[0], $formatted_args->[1], undef, $formatted_args->[2], 'dumb manual name']);
}

sub info_default_image_files($$$$)
{
    my $base = shift;
    my $extension = shift;
    my $texi_base = shift;
    my $texi_extension = shift;
    my @files = ();
    return @files if (!defined($base) or ($base eq ''));

    if (defined($extension) and ($extension ne ''))
    {
        push @files, ["${base}$extension", "${texi_base}$extension"];
        push @files, ["$base.$extension", "$texi_base.$extension"];
    }
    foreach my $ext (@IMAGE_EXTENSIONS)
    {
        push @files, ["$base.$ext", "$texi_base.$ext"];
    }
    return @files;
}

sub info_default_image($$$$$$$$$$$$$$$$$)
{
    my $file = shift;
    my $base = shift;
    my $preformatted = shift;
    my $file_name = shift;
    my $alt = shift;
    my $width = shift;
    my $height = shift;
    my $raw_alt = shift;
    my $extension = shift;
    my $working_dir = shift;
    my $file_path = shift;
    my $in_paragraph = shift;
    my $file_locations = shift;
    my $base_simple_format = shift;
    my $extension_simple_format = shift;
    my $file_name_simple_format = shift;
    my $line_nr = shift;

    my $txt_path;
    my $found_file;

    my @extensions = @IMAGE_EXTENSIONS;
    if (defined($extension) and ($extension ne ''))
    {
        unshift @extensions, ".$extension";
        unshift @extensions, "$extension";
    }
    else
    {
        $extension = undef;
    }
    my $file_found_index = undef;
    my $file_index = 0;
    foreach my $file_location (@$file_locations)
    {
        my ($file_located, $path, $file_simple_format) = @$file_location;
        my $extension = shift @extensions;
        if (defined($path))
        {
           if ($extension eq 'txt' and !defined($txt_path))
           {
              $txt_path = $path;
           }
           elsif (!defined($found_file))
           {
              $found_file = [$file_located, $extension, $file_simple_format];
              $file_found_index = $file_index;
           }
        }
        $file_index++;
    }

    my $text;
    if (defined($txt_path))
    {
       if (open(TXT, "<$txt_path"))
       {
          if (defined($Texi2HTML::THISDOC{'IN_ENCODING'}) and $USE_UNICODE)
          {
              binmode(TXT, ":encoding($Texi2HTML::THISDOC{'IN_ENCODING'})");
          }
          $text='[' if ($in_paragraph or $preformatted);
          while (my $img_txt = <TXT>)
          {
              $text .= $img_txt;
          }
          # remove last end of line
          chomp ($text);
          $text .= ']' if ($in_paragraph or $preformatted);
          close(TXT);
       }
       else
       {
          main::line_warn (sprintf(__("\@image file `%s' unreadable: %s"), $txt_path, $!), $line_nr);
       }
    }
    elsif (!defined($found_file))
    {
        main::line_warn (sprintf(__("Cannot find \@image file `%s.txt'"), $base), $line_nr);
    }
    if (defined($found_file) and (!defined($extension) or $file_found_index <= 1))
    {
        my $filename = $found_file->[2];
        $filename =~ s/\\/\\\\/g;
        $filename =~ s/\"/\\\"/g;
        my $result = "\x{00}\x{08}[image src=\"$filename\"";
        if (defined($alt))
        {
            $alt =~ s/\\/\\\\/g;
            $alt =~ s/\"/\\\"/g;
            $result .= " alt=\"$alt\"";
        }
        if (defined($text))
        {
            $text =~ s/\\/\\\\/g;
            $text =~ s/\"/\\\"/g;
            $result .= " text=\"$text\"";
        }
        $result .= "\x{00}\x{08}]";
        return $result;
    }
    return $text if (defined($text));
    return '';
}

sub info_default_printindex($$)
{
   my $index_name = shift;
   my $printindex = shift;
   %info_default_index_entries_counts = ();
   return info_default_store_text(undef,t2h_GPL_default_printindex($index_name,$printindex),'printindex');
}

sub info_default_print_index($$)
{
    my $text = shift;
    my $name = shift;
    my $state = $Texi2HTML::THISDOC{'state'};
    my $info_state = info_default_get_state ($state);
    my $before = '';
    if (!$info_state->{'blank_line'})
    {
       $before = "\n";
    }
    return $before if (!defined($text));
    my $result = "\x{00}\x{08}[index\x{00}\x{08}]\n* Menu:\n\n" .$text."\n";
    return $before.$result;
}

sub info_default_index_letter($$$)
{
     my $letter = shift;
     my $id = shift;
     my $text = shift;
     return $text;
}

sub info_default_index_entry_label($$$$$$$$$)
{
    my $identifier = shift;
    my $preformatted = shift;
    my $entry = shift;
    my $index_name = shift;
    my $index_command = shift;
    my $texi_entry = shift;
    my $formatted_entry = shift;
    my $in_region_not_in_output = shift;
    my $index_entry_ref = shift;

    #return '' if ($index_entry_ref->{'hidden'});
    #return '' if (!$index_entry_ref->{'seen_in_output'} and defined($index_entry_ref->{'region'}));
    return '' if ($in_region_not_in_output or !defined($index_entry_ref->{'index_name'}));
    main::line_warn(sprintf(__("Entry for index `%s' outside of any node"), $index_entry_ref->{'index_name'}), $Texi2HTML::THISDOC{'line_nr'}) if (!defined($info_default_current_node) and !$Texi2HTML::THISDOC{'state'}->{'outside_document'});
    my $index_entry_stored = {'index_entry_reference' => $index_entry_ref, 'index_command' => $index_command, 'texi_entry' => $texi_entry};
    return info_default_store_text(undef, undef, 'index_label', $index_entry_stored);
}

sub info_default_index_entry($$$$$$$$$$)
{
    my $text_href = shift;
    my $entry = shift;
    my $element_href = shift;
    my $element_text = shift;
    my $entry_file = shift;
    my $current_element_file = shift;
    my $entry_target = shift;
    my $entry_element_target = shift;
    my $in_region_not_in_output = shift;
    my $index_entry_ref = shift;

    #return '' if ($index_entry_ref->{'hidden'});
    #return '' if (!$index_entry_ref->{'seen_in_output'} and defined($index_entry_ref->{'region'}));
    return '' if ($in_region_not_in_output);
    $entry = main::substitute_line($index_entry_ref->{'texi'}, "index entry in \@printindex");
    return '' if ($entry =~ /^\s*$/);

    my $entry_nr = '';
    if (!defined($info_default_index_entries_counts{$entry}))
    {
       $info_default_index_entries_counts{$entry} = 0;
    }
    else
    {
       $info_default_index_entries_counts{$entry} ++;
       $entry_nr = ' <'.$info_default_index_entries_counts{$entry}.'>';
    }

    my $result = "* $entry${entry_nr}: ";
    if (t2h_default_string_width($result) < $info_default_index_length_to_node)
    {
       $result .= ' ' x($info_default_index_length_to_node - t2h_default_string_width($result));
    }

    #print STDERR "DDDDDDDDDDD $index_entry_ref `$index_entry_ref->{'texi'}'\n";
    my $info_index_entry_ref = $info_default_index_entries{$index_entry_ref};
    my $line_nr = $info_index_entry_ref->{'line_nr'};

    my $real_element_text;
    my $element = $index_entry_ref->{'real_element'};
    # in case $element->{'text'} is not defined, it certainly means that we
    # are n a special elemet, most likely the virtual element appearing 
    # before anything else
    if (!defined($element->{'text'}))
    {
       $real_element_text = gdt('(outside of any node)');
       $line_nr = 0;
    }
    else
    {
       $element = $element->{'element_ref'} if ($element->{'element_ref'});
       $real_element_text = $element->{'text'};
       # this happens for index entries appearing after @printindex. In that case
       # it is considered that they are at the beginning of the node.
       $line_nr = 3 if (defined($line_nr) and $line_nr < 3);
       $line_nr = 4 if (!defined($line_nr));
    }
    $result .= $real_element_text . '.';
    my $max_len = $info_default_index_line_string_length{$index_entry_ref->{'index_name'}};
    $max_len = t2h_default_string_width($line_nr) if (!defined($max_len));
    my $line_nr_spaces = sprintf("%${max_len}d", $line_nr);
    my $line_part = "(line ${line_nr_spaces})";
    #print STDERR "GGGGGGGGGG name: $index_entry_ref->{'index_name'} max: ${max_len} line_nr: `$line_nr' line_nr_spaces `$line_nr_spaces' $line_part \n";
    if (t2h_default_string_width($result)+t2h_default_string_width($line_part) +1 >  get_conf('fillcolumn'))
    {
        $result .= "\n" . ' ' x (get_conf('fillcolumn') - t2h_default_string_width($line_part)) ;
    }
    else
    {
        $result .= ' ' x (get_conf('fillcolumn') - t2h_default_string_width($line_part) - t2h_default_string_width($result));
    }
    $result .= "$line_part\n";

    return $result;
}

sub info_default_index_summary($$)
{
    my $alpha = shift;
    my $nonalpha = shift;

    return '';
}

sub info_default_summary_letter
{
    return '';
}

sub info_default_foot_line_and_ref($$$$$$$$)
{
    my $foot_num = shift;
    my $relative_num = shift;
    my $footid = shift;
    my $docid = shift;
    my $from_file = shift;
    my $footnote_file = shift;
    my $lines = shift;
    my $state = shift;
 
    my $footnote_state = $Texi2HTML::THISDOC{'state'};
    my $footnote_info_state = info_default_get_state ($footnote_state);

    my $footnote_text = "($info_default_footnote_index)";
    $footnote_text = "($NO_NUMBER_FOOTNOTE_SYMBOL)" if (!$NUMBER_FOOTNOTES);
    my $node_name;
    $node_name = '';
    if (defined($info_default_current_node))
    {
        $node_name = $info_default_current_node->{'text'};
    }
    else
    { # i18n
        # no warning when outside of document, for footnotes in 
        # titlepage and copying
        main::line_error(__("Footnote defined without parent node"), $Texi2HTML::THISDOC{'line_nr'}) unless ($footnote_state->{'outside_document'});
        #print STDERR "".main::context_string()."\n";
    }
    if (get_conf('footnotestyle') eq 'separate')
    {
        $footnote_text .=  ' (' . info_default_normal_reference('pxref', ["${node_name}-Footnote-${info_default_footnote_index}"]) . ')';
    }
    push @info_default_pending_footnotes, {'lines' => $lines, 
         'footnote_text' => $footnote_text, 
         'footnote_index' => ${info_default_footnote_index}, 
         'node_name' => $node_name, 
         'footnote_info_state' => $footnote_info_state}
    unless ($state->{'outside_document'} or (defined($state->{'multiple_pass'}) and $state->{'multiple_pass'} > 0));
    return ([],  $footnote_text);
}

sub info_default_foot_lines($)
{
    my $lines = shift;
    #my $state = $Texi2HTML::THISDOC{'state'};
    #my $info_state = info_default_get_state ($state);
    @$lines = ();
}

# remark: table_item is the html one, but it gets added to the table text
# on the stack, and is ignored there (in info_default_format).
sub info_default_format_list_item_texi($$$$)
{
    my $format = shift;
    my $line = shift;
    my $prepended = shift;
    my $command = shift;
    my $number = shift;

    my $open_command = 0;
    my $result_line;
    $command = 'bullet' if ((!defined($command) or $command eq '') and (!defined($prepended) or $prepended eq '') and $format eq 'itemize');
    $prepended = "\@$command\{\}" if (defined($command) and $command ne '');
    $prepended = "$number." if (defined($number) and $number ne '');
    
    $line =~ s/^\s*//;
 
    if (defined($command) and $command ne '' and $format ne 'itemize')
    {
        #@*table
        $line =~ s/\s*$//;
        if (exists ($style_map{$command}))
        {
           $result_line = "\@$command\{$line\}\n";
        }
        elsif (exists ($things_map{$command}))
        {
           $result_line = "\@$command\{\} $line\n";
        }
        else
        {
           $result_line = "\@$command $line\n";
        }
    }
#    elsif (defined($prepended) and $prepended ne '')
#    { # @enumerate and @itemize
#         $prepended =~ s/^\s*//;
#         $prepended =~ s/\s*$//;
#         $result_line = $prepended . ' ' . $line;
#    }

    return ($result_line, $open_command);
}

sub info_default_list_item($$$$$$$$$$$$)
{
    my $text = shift;
    my $format = shift;
    my $command = shift;
    my $formatted_command = shift;
    my $item_nr = shift;
    my $enumerate_style = shift;
    my $number = shift;
    my $prepended = shift;
    my $prepended_formatted = shift;
    my $only_inter_item_commands = shift;
    my $before_items = shift;
    my $item_command = shift;

#    my $prepend = '';
#    if (defined($formatted_command) and $formatted_command ne '')
#    {
#        $prepend = $formatted_command;
#    }
#    return $prepend . $text;
#    $command = 'bullet' if ((!defined($command) or $command eq '') and (!defined($prepended) or $prepended eq '') and $format eq 'itemize');
    $formatted_command = $things_map{'bullet'} if ((!defined($command) or $command eq '') and (!defined($prepended) or $prepended eq '') and $format eq 'itemize');

    if ($format !~ /table$/)
    {
       my $result = '';
       if ($format eq 'enumerate')
       {
          $result = $number.'.';
       }
       elsif ($format eq 'itemize')
       {
          if (defined($formatted_command) and $formatted_command ne '')
          {
             $result = $formatted_command;
          }
          elsif (defined ($prepended_formatted) and $prepended_formatted ne '')
          {
             $prepended_formatted =~ s/^\s*//;
             $prepended_formatted =~ s/\s*$//;
             $result = $prepended_formatted;
          }
       }
       else
       {
          $result = '';
       }
       $result .= ' ' if ($result ne '');
       return info_default_close_command (undef, $item_command, $result);
    }
    return $text;
}

sub info_default_format($$$)
{
    my $tag = shift;
    my $element = shift;
    my $text = shift;

    # currently no command has something else than '' as $element.
    # notice that any text is discarded
    $element = undef if ($element eq '');
    my $element_end = $element;
    if (defined($element) and $element =~ /^(\w+)(\s+)(.+)/)
    {
        $element = $1;
        $element_end = $2;
    }
    return info_default_close_command(undef, $tag, $element, $element_end);
}

sub info_default_tab_item_texi($$$$$$)
{
   my $command = shift;
   my $commands_stack = shift;
   my $stack = shift;
   my $state = shift;
   my $line = shift;
   my $line_nr = shift;

   $line =~ s/^\s*//;
   my $format;
   my $info_state = info_default_get_state ($state);
   #$format = $commands_stack->[-1] if (defined($commands_stack) and @$commands_stack and $commands_stack->[-1]);
   my ($parent_format, $in_format) = info_default_parent_format($info_state->{'current'});
   print STDERR "Not in_format in info_default_tab_item_texi\n" if (!$in_format);
   $format = $parent_format->{'command'};
   # in case of an @item or @tab outside of any format $format will be
   # undefined, or not multitable for a @tab.
   # however the main program still do as if something was opened, plus
   # it is checked there that the nesting is correct
   #return $line if (!defined($format) or $command eq 'tab' and $format ne 'multitable');
   #print STDERR "tab_item_texi $format $command $commands_stack, $stack, $state, $line, ".main::format_line_number($line_nr)."\n";
   if ($format eq 'multitable')
   { # even if it is a tab, if it is not already in a multitable_row, one
     # should be started
       if ($command ne 'tab' or $info_state->{'current'}->{'command'} ne 'multitable_row')
       {
           info_default_open_command($state, 'multitable_row');
       }
       info_default_open_command($state, 'multitable_cell');
   }
   elsif ($format =~ /table$/)
   {
       info_default_store_text ($state, undef, $command, {'format_name' => $format});
   }
   else
   {
       info_default_open_command ($state, $command, {'format_name' => $format});
   }
   # this should have already been done for @item when the line
   # is modified by the @-command and so on.
   return $line;
}

sub info_default_sp($$)
{
   my $number = shift;
   my $preformatted = shift;
   my $result = "\n" x $number;
   return info_default_store_text(undef,$result,'sp');
}

sub info_default_paragraph_style_command($$)
{
    my $format = shift;
    my $text = shift;
    return info_default_close_command(undef, $format);
}

sub info_default_row($$$$$$$$)
{
    my $text = shift;
    my $macro = shift;
    my $columnfractions = shift;
    my $prototype_row = shift;
    my $prototype_lengths = shift;
    my $column_number = shift;
    my $only_inter_item_commands = shift;
    my $before_items = shift;
    #print STDERR "info_default_row: $text\n";

    return info_default_close_command(undef, 'multitable_row', undef, undef, {'item_command' => $macro});
}

sub info_default_cell($$$$$$$$)
{
    my $text = shift;
    my $row_macro = shift;
    my $columnfractions = shift;
    my $prototype_row = shift;
    my $prototype_lengths = shift;
    my $column_number = shift;
    my $only_inter_item_commands = shift;
    my $before_items = shift;

    # in general, when before_items, there will be no call to the function
    # since there should never be a text sent back, so that this 
    # function will not be called for the first row (the multitable title).
    # However, if there is a @tab before the first @item, the main program
    # is less careful and closes the cell in any case, so before_items
    # has to be checked for that case.
    return info_default_close_command(undef, 'multitable_cell') unless ($before_items);
}

sub info_default_table_list($$$$$$$$$)
{
    my $format_command = shift;
    my $text = shift;
    my $command = shift;
    my $formatted_command = shift;
# enumerate
    my $item_nr = shift;
    my $enumerate_style = shift;
# itemize
    my $prepended = shift;
    my $prepended_formatted = shift;
# multitable
    my $columnfractions = shift;
    my $prototype_row = shift;
    my $prototype_lengths = shift;
    my $column_number = shift;

    die "BUG: $format_command item_nr undef\n" if (!defined($item_nr));

    return info_default_close_command(undef, $format_command, undef, undef, {'total_item_nr' => $item_nr}) if ($format_command ne 'multitable');

    my $columnsize = [];
    if (defined($prototype_lengths) and @$prototype_lengths)
    {
       $columnsize = [ @$prototype_lengths ];
    }
    elsif (defined($columnfractions) and @$columnfractions)
    {
       foreach my $fraction (@$columnfractions)
       {
          push @$columnsize, int($fraction * get_conf('fillcolumn') +0.5);
       }
    }
    else 
    { # empty multitable
       #print STDERR "Empty multitable?\n";
    }

    return info_default_close_command(undef, $format_command, undef, undef, {'columns_size' => $columnsize, 'total_item_nr' => $item_nr});
}

sub info_default_def_item($$$)
{
    my $text = shift;
    my $only_inter_item_commands = shift;
    my $command = shift;

    my $format = 'deff_item';
    $format = 'deff_itemx' if ($command =~ /x$/);
    return info_default_close_command(undef, $format);
}

sub info_default_def_line($$$$$$$$$$$$$$$$)
{
   my $category_prepared = shift;
   my $name = shift;
   my $type = shift;
   my $arguments = shift;
   my $index_label = shift;
   my $arguments_array = shift;
   my $arguments_type_array = shift;
   my $unformatted_arguments_array = shift;
   my $command = shift;
   my $class_name = shift;
   my $category = shift;
   my $class = shift;
   my $style = shift;
   my $original_command = shift;

   $name = '' if (!defined($name) or ($name =~ /^\s*$/));
   $type = '' if (!defined($type) or $type =~ /^\s*$/);
   $arguments = '' if (!defined($arguments) or $arguments =~ /^\s*$/);

   my $type_name = '';
   $type_name .= "$type " if ($type ne '');
   $type_name .= $name if ($name ne '');

   my $result = " -- $category_prepared: ${type_name}$arguments";
   $result =~ s/\s*$//;
   $result .= "\n";
   my $state = $Texi2HTML::THISDOC{'state'};
    info_default_store_text(undef,$result,"${command}_line",{'definition_line' => 1});
    my $format = 'deff_item';
    $format = 'deff_itemx' if ($original_command =~ /x$/);
    return info_default_open_command($state, $format);
}

sub info_default_def($$)
{
    my $text = shift;
    my $command = shift;
    return info_default_close_command(undef, $command);
}

sub info_default_float($$$$$)
{
    my $text = shift;
    my $float = shift;
    my $caption = shift;
    my $shortcaption = shift;

    my $additional_arguments;
    if (exists($float->{'id'}))
    {
        $additional_arguments->{'anchor_reference'} = $float;
        main::line_warn(__("float reference outside of any node, it won't be registered"), $Texi2HTML::THISDOC{'line_nr'}) if (!defined($info_default_current_node) and !$Texi2HTML::THISDOC{'state'}->{'outside_document'});
    }
    my $caption_text = '';

    if (defined($float->{'caption_texi'}))
    {
        $caption_text = $caption;
    }
    elsif (defined($float->{'shortcaption_texi'}))
    {
        $caption_text = $shortcaption;
    }
    elsif (defined($caption))
    {
        $caption_text = $caption;
    }

    #return $caption_text;
    return info_default_close_command(undef, 'float', undef, $caption_text, $additional_arguments);
}

sub info_default_listoffloats_entry($$$$)
{
    my $style_texi = shift;
    my $float = shift;
    my $float_style = shift;
    my $caption = shift;
    my $href = shift;

    my @lines = split /^/, $caption;
    $caption = $lines[0];
    $caption = '' if (!defined($caption));
    chomp ($caption);

    my $result = '';
    #$caption .= ':' if ($caption ne '');
    my $caption_entry = "* $float_style: $float->{'text'}.";
    if (t2h_default_string_width($caption_entry) > $info_default_listoffloat_caption_entry_length)
    {
        $caption_entry .= "\n" . ' ' x $info_default_listoffloat_caption_entry_length;
    }
    else
    {
        $caption_entry .= ' ' x ($info_default_listoffloat_caption_entry_length - length($caption_entry));
    }
    my $width = $info_default_listoffloat_caption_entry_length;
    while ($caption =~ s/^(\S+\s*)//)
    { 
        my $new_word = $1;
        if ((t2h_default_string_width($new_word) + $width) > get_conf('fillcolumn') - 3)
        {
            $caption_entry .= $info_default_listoffloat_append;
            last;
        }
        else
        {
           $caption_entry .= $new_word; 
           $width += t2h_default_string_width($new_word);
        }
    }
    return $caption_entry. "\n";
}

sub info_default_listoffloats($$$)
{
   my $style_texi = shift;
   my $style = shift;
   my $float_entries = shift;

   my $state = $Texi2HTML::THISDOC{'state'};
   my $info_state = info_default_get_state ($state);
   my $result = "* Menu:\n\n";
   foreach my $float_entry (@$float_entries)
   {
       $result .= $float_entry;
   }
   my ($parent_format, $in_format);
   ($parent_format, $in_format) = info_default_parent_format($info_state->{'current'});
   #print STDERR "\@listoffloats not at top level\n" if ($in_format);
   info_default_increment_paragraph ($in_format, $parent_format, $info_state, 'listoffloats');
   return info_default_store_text($state,$result,'listoffloats');
}

sub info_default_raw($$)
{
    my $style = shift;
    my $text = shift;
    my $expanded = 1 if (grep {$style eq $_} @EXPAND);
    # no warning for unknown raw formats
    if ($style eq 'verbatim' or $style eq 'verbatiminclude' or $expanded)
    {
        return info_default_store_text(undef, $text, $style, {'raw_command' => 1});
    }
    return '';
}

sub info_default_line_command($$$$)
{
    my $command = shift;
    my $arg_text = shift;
    my $arg_texi = shift;
    my $state = shift;

    main::line_warn(__("\@dircategory after first node"), $Texi2HTML::THISDOC{'line_nr'}) if (defined($info_default_current_node));
    return '' if ($arg_text eq '');
    $info_default_dir_specification .= "INFO-DIR-SECTION $arg_text\n";
    return '';
}

sub info_default_unknown_style($$$$$)
{
    my $command = shift;
    my $text = shift;
    my $state = shift;
    my $no_close = shift;
    my $no_open = shift;
    
    my ($result, $result_text, $message);
    $result_text = info_default_close_command(undef, $command, undef, undef, undef);
    $message = "Unknown command with braces `\@$command'" if (!$no_open);
    return (1, $result_text, $message);
}

1;

require "$T2H_HOME/formats/info.init" 
    if ($0 =~ /\.pl$/ &&
        -e "$T2H_HOME/formats/info.init" && -r "$T2H_HOME/formats/info.init");

# @INIT_DOCBOOK@
#+##############################################################################
#
# docbook.init: convert to docbook
#
#    Copyright (C) 2008, 2009  Patrice Dumas <pertusus@free.fr>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
#    02110-1301  USA
#
#-##############################################################################


# regarding sections and nodes, in docbook we don't care at all about the
# splitting done in the main program. When there is a node, it is recorded as
# being pending. When there is a section it is opened, and closed when 
# there is the next section or end of file.

use strict;

my %docbook_complex_format;
my $kept_footnote_function;
my $docbook_in_footnote;
my %docbook_sections;
my %def_format_docbook;
my %def_argument_types_docbook;

my $docbook_pending_node_id;
my $docbook_current_section;
my @docbook_multitable_stack = ();
my @docbook_table_stack = ();
my @docbook_special_quotation;


sub docbook_default_load(;$)
{
my $from_command_line = shift;

t2h_default_set_variables_xml();
$DOCTYPE = '<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
  <!ENTITY tex "TeX">
  <!ENTITY latex "LaTeX">
]>';
@T2H_FORMAT_EXPAND = ('docbook');
@IMAGE_EXTENSIONS = ('eps', 'gif', 'jpg', 'jpeg', 'pdf', 'png', 'svg', 'txt');
$INLINE_INSERTCOPYING = 1;
# this should lead to end_section being only called at the end of sectioning
$USE_NODES = 0;
$USE_SECTIONS = 1;

$SHOW_MENU = 0;
$SHOW_TITLE = 0;
$HEADERS = 0;
# certainly irrelevant
$SIMPLE_MENU = 0;

t2h_default_push_handler(\&docbook_initialize_variables, \@command_handler_init);

%style_map = ();
t2h_default_copy_style_map (\%default_style_map, \%style_map);
foreach my $accent_command ('tieaccent', 'dotless', keys(%unicode_accents))
{
     $style_map{$accent_command} = { 'function' => \&xml_default_accent };
}

delete $style_map{'sc'}->{'inline_attribute'};
# FIXME there is a code element in v4.3 
$style_map{'code'}->{'inline_attribute'} = 'literal';
$style_map{'strong'}->{'inline_attribute'} = 'emphasis role="bold"';
$style_map{'kbd'}->{'inline_attribute'} = 'userinput';
$style_map{'w'}->{'end'} = '<!-- /@w -->';
$style_map{'='}->{'function'} = \&docbook_macron;
$style_map{'b'}->{'inline_attribute'} = 'emphasis role="bold"';
$style_map{'cite'}->{'inline_attribute'} = 'citetitle';
$style_map{'command'}->{'inline_attribute'} = 'command';
$style_map{'dfn'}->{'inline_attribute'} = 'firstterm';
$style_map{'emph'}->{'inline_attribute'} = 'emphasis';
$style_map{'env'}->{'inline_attribute'} = 'envar';
$style_map{'file'}->{'inline_attribute'} = 'filename';
$style_map{'i'}->{'inline_attribute'} = 'wordasword';
$style_map{'key'}->{'inline_attribute'} = 'keycap';
delete $style_map{'key'}->{'begin'};
delete $style_map{'key'}->{'end'};
$style_map{'option'}->{'inline_attribute'} = 'option';
$style_map{'t'}->{'inline_attribute'} = 'literal';
delete $style_map{'sansserif'}->{'inline_attribute'};
delete $style_map{'r'}->{'inline_attribute'};
$style_map{'indicateurl'}->{'inline_attribute'} = 'wordasword';
delete $style_map{'indicateurl'}->{'begin'};
delete $style_map{'indicateurl'}->{'end'};
$style_map{'var'}->{'inline_attribute'} = 'replaceable';
delete $style_map{'verb'}->{'inline_attribute'};
$style_map{'email'}->{'function'} = \&docbook_email;
$style_map{'math'}->{'function'} = \&docbook_math;
$style_map{'uref'}->{'function'} = \&docbook_uref;
$style_map{'url'}->{'function'} = \&docbook_uref;
$style_map{'titlefont'}->{'function'} = \&docbook_titlefont;
#$style_map{'samp'}->{'function'} = \&docbook_samp;
#delete $style_map{'samp'}->{'inline_attribute'};
$style_map{'samp'}->{'inline_attribute'} = 'literal';
$style_map{'samp'}->{'begin'} = '&lsquo;';
$style_map{'samp'}->{'end'} = '&rsquo;';

$kept_footnote_function = $style_map{'footnote'}->{'function'};
$style_map{'footnote'}->{'function'} = \&docbook_footnote;

foreach my $style (keys(%style_map))
{
   delete ($style_map{$style}->{'quote'});
}

#use Data::Dumper;
%style_map_pre = ();
t2h_default_copy_style_map (\%style_map, \%style_map_pre);

$style_map_pre{'r'}->{'inline_attribute'} = 'lineannotation';

$colon_command_punctuation_characters{'.'} = '&period;';
$colon_command_punctuation_characters{':'} = '&colon;';
$colon_command_punctuation_characters{'?'} = '&quest;';
$colon_command_punctuation_characters{'!'} = '&excl;';

$stop_paragraph_command{'titlefont'} = 0;

# FIXME
#$no_paragraph_commands{'anchor'} = 0;

# FIXME
delete $special_accents{'ringaccent'};
$special_accents{'ogonek'} = 'aeiuAEIU';

%simple_map = %default_simple_map;
%simple_map_pre = %simple_map;

# FIXME right? &lstrok; &Lstrok;
$things_map{'l'} = '/l';
$things_map{'L'} = '/L';
$things_map{'TeX'} = '&tex;';
$things_map{'LaTeX'} = '&latex;';
$things_map{'enddots'} = '&hellip;.';
$things_map{'minus'} = '&minus;';
# FIXME &lowast;
$things_map{'point'} = '-!-';
# FIXME &equiv;
$things_map{'equiv'} = '==';
# FIXME no &lsaquo; nor &rsaquo;
$things_map{'guilsinglright'} = '&gt;';
$things_map{'guilsinglleft'} = '&lt;';
# The following is unneeded because normal_text is redefined.
# FIXME it should certainly be better to leave those substitutions,
# or even hardcodes them in normal_text.
# t2h_remove_text_substitutions("'", 1, 0, 0, 1);
# t2h_remove_text_substitutions('`', 1, 0, 0, 1);

$things_map{'quotedblbase'} = '&ldquor;';
$things_map{'quotesinglbase'} = '&lsquor;';

%pre_map = %things_map;

#delete $inter_item_commands{'cindex'};

#$no_paragraph_commands{'cindex'} = 0;
$no_paragraph_commands{'float'} = 0;

%docbook_complex_format = (
   'example' => 'screen',
   'smallexample' => 'screen',
   'display' => 'literallayout',
   'smalldisplay' => 'literallayout',
   'lisp' => 'programlisting',
   'smalllisp' => 'programlisting',
   'format' => 'abstract',
   'smallformat' => 'screen'
);

%docbook_sections = (
  'top'  => 'chapter',
  'part' => 'part',
  'chapter'  => 'chapter',
  'unnumbered'  => 'chapter',
  'centerchap'  => 'chapter',
  'appendix' => 'appendix',
  'majorheading' => 'other',
  'chapheading' => 'other',
  'heading' => 'sect1',
  'subheading' => 'sect2',
  'subsubheading' => 'sect3',
  2 => 'sect1',
  3 => 'sect2',
  4 => 'sect3'
);

%def_format_docbook = (
  'deffn' => [ ['function', 'name'] ],
   'defvr' => [ ['varname', 'name'] ],
   'deftypefn' => [ [ 'returnvalue', 'type' ], ['function', 'name'] ], 
   'deftypeop' => [ ['returnvalue', 'type'], ['methodname', 'name'] ], 
   'deftypevr' => [ ['returnvalue', 'type'], ['varname', 'name'] ], 
   'defcv' => [ ['classname', 'class'], ['property', 'name'] ], 
   'deftypecv' => [ ['returnvalue', 'type'], ['property', 'name'] ], 
   'defop' => [ ['classname', 'class'], ['methodname', 'name'] ], 
   'deftp' => [ ['structname', 'name'] ] 
);

%def_argument_types_docbook = (
  'param' => 'replaceable', 
  'paramtype' => 'type', 
  'delimiter' => ''
);

@docbook_special_quotation = ('note', 'caution', 'important', 'tip', 'warning');

$region_formats_kept{'copying'} = 1;

%format_map = (
       'group'       =>  '',
       'raggedright'       =>  '',
       'copying'     =>  'copying',
       );

$print_Top = \&docbook_print_Top;
$print_Top_footer = \&docbook_print_Top_footer;
$print_page_head = \&docbook_print_page_head;
$print_foot_navigation = \&docbook_noop;
$contents = \&docbook_noop;
$shortcontents = \&docbook_noop;
$about_body = \&docbook_noop;
$print_page_foot = \&docbook_print_page_foot;
$end_section = \&docbook_end_section;
$one_section = \&docbook_one_section;

$acronym_like          = \&docbook_acronym_like;
$anchor_label          = \&docbook_anchor_label;
$begin_format_texi     = \&docbook_begin_format_texi;
$cartouche             = \&docbook_cartouche;
$cell                  = \&docbook_cell;
$complex_format        = \&docbook_complex_format;
$def                   = \&docbook_def;
$def_line              = \&docbook_def_line;
$def_item              = \&docbook_def_item;
$element_label         = \&docbook_element_label;
$external_ref          = \&docbook_external_ref;
$float                 = \&docbook_float;
$foot_line_and_ref     = \&docbook_foot_line_and_ref;
$format                = \&docbook_format;
$format_list_item_texi = \&docbook_format_list_item_texi;
$heading               = \&docbook_heading;
$image                 = \&docbook_image;
$image_files           = \&docbook_image_files;
$index_entry_command   = \&docbook_index_entry_command;
$index_entry_label     = \&docbook_index_entry_label;
$index_summary         = \&docbook_index_summary;
$internal_ref          = \&docbook_internal_ref;
$insertcopying         = \&docbook_insertcopying;
$list_item             = \&docbook_list_item;
$misc_element_label    = \&docbook_noop;
$normal_text           = \&docbook_normal_text;
$paragraph             = \&docbook_paragraph;
$preformatted          = \&docbook_preformatted;
$printindex            = \&docbook_printindex;
$protect_text          = \&xml_default_protect_text;
$quotation              = \&docbook_quotation;
$quotation_prepend_text = \&docbook_quotation_prepend_text;
$listoffloats          = \&docbook_noop;
$raw                   = \&docbook_raw;
$row                   = \&docbook_row;
$sp                    = \&docbook_sp;
$style                 = \&docbook_style;
$table_item            = \&docbook_table_item;
$table_line            = \&docbook_table_line;
$table_list            = \&docbook_table_list;
$misc_command_line     = \&docbook_misc_commands;


}

sub docbook_footnote
{
    $docbook_in_footnote = 1;
    my $result = &$kept_footnote_function(@_);
    $docbook_in_footnote = 0;
    return $result;
}

sub docbook_macron($$)
{
    my $accent = shift;
    my $args = shift;
    return $args->[0] . "&macr;";
}

sub docbook_samp($$)
{
    shift;
    my $args = shift;
    return "&lsquo;<literal>$args->[0]</literal>&rsquo;";
}

sub docbook_email($$)
{
    my $command = shift;
    my $args = shift;
    my $mail = shift @$args;
    my $text = shift @$args;
    $mail = main::normalise_space($mail);
    if (defined($text) and $text =~ /\S/)
    {
        # FIXME normalise_space would be more legible.
        #return docbook_add_id('ulink').' url="mailto:'.$mail.'">'.main::normalise_space($text).'</ulink>';
        return docbook_add_id('ulink').' url="mailto:'.$mail.'">'.$text.'</ulink>';
    }
    return docbook_add_id('email').">$mail</email>";
}

sub docbook_uref($$)
{
    shift;
    my $args = shift;
    my $url = shift @$args;
    my $text = shift @$args;
    my $replacement = shift @$args;
    $url = main::normalise_space($url);
    $text = '' if (!defined($text));
    $replacement = '' if (!defined($replacement));
    $replacement = $text if ($replacement eq '');
    $replacement = $url if ($replacement eq '');
    $replacement = main::normalise_space($replacement);
    
    return docbook_add_id('ulink')." url=\"$url\">$replacement</ulink>";
}

# FIXME
sub docbook_titlefont($$)
{
    shift;
    my $args = shift;
    return "$args->[0]";
}

# FIXME there ought to be something better... Like use tex4ht mathml
# output or something like that
sub docbook_math($$)
{
    shift;
    my $args = shift;
    my $text = shift @$args;
    return $text;
}


sub docbook_print_page_head($)
{
    my $fh = shift;
    my $language = get_conf('documentlanguage');
    my $doctype = get_conf('doctype');
    print $fh <<EOT;
<?xml version="1.0"?>
$doctype
<book id="$Texi2HTML::THISDOC{file_base_name}.$EXTENSION" lang="$language">
EOT
}

sub docbook_print_page_foot($)
{
    my $fh = shift;
    print $fh "". docbook_close_section();
    print $fh <<EOT;
</book>
EOT
}

sub docbook_print_Top($$$)
{
    my $fh = shift;
    my $has_top_heading = shift;
    my $element = shift;
    main::print_lines($fh, $Texi2HTML::THIS_SECTION);
}

sub docbook_element_tag($)
{
   my $element = shift;
#print STDERR "$element->{'texi'}, $element->{'tag_level'}, $element->{'level'}\n";
   return $docbook_sections{$element->{'tag_level'}} if (exists($docbook_sections{$element->{'tag_level'}}));
   return $docbook_sections{$element->{'level'}} if (exists($docbook_sections{$element->{'level'}}));
}

sub docbook_node_id($)
{
   my $node_texi = shift;
   my $node = main::substitute_line($node_texi, 'docbook node id', {'code_style' => 1, 'remove_texi' => 1});
   $node =~ s/[\s\"]/-/g;
   return &$protect_text($node);
}

sub docbook_initialize_variables()
{
   $docbook_pending_node_id = undef;
   $docbook_current_section = undef;
   @docbook_multitable_stack = ();
   @docbook_table_stack = ();
   $Texi2HTML::THISDOC{'SPLIT'} = 0 if ($OUTPUT_FORMAT eq 'docbook');
}

sub docbook_add_id($)
{
    my $element = shift;
    my $result = "<$element";
    if (defined($docbook_pending_node_id) and (!$docbook_in_footnote or $element eq 'footnote'))
    {
        $result .= " id=\"$docbook_pending_node_id\"";
        $docbook_pending_node_id = undef;
    }
    return $result;
}

sub docbook_heading($$$$$)
{
    my $element = shift;
    my $command = shift;
    my $texi_line = shift;
    my $line = shift;
    my $in_preformatted = shift;

    if (defined($command) and $command =~ /heading/)
    {
        my $text = '';
        if (defined($line))
        {
            $text = $line;
            # this isn't done in main program in that case...
            chomp ($text);
            $text =~ s/^\s*//;
        }
        return docbook_add_id('bridgehead')." renderas=\"$docbook_sections{$command}\">$text</bridgehead>\n";
    }

    my $result = '';

# FIXME verify xreflabel 
    if ($command ne 'node')
    {
        # close previous section
        $result .= docbook_close_section();
        my $title = $element->{'text_nonumber'};
        my $label = '';
        my $xreflabel = '';
        if ($element->{'number'})
        {
            my $label_nr = $element->{'number'};
            #$label_nr =~ s/\.$//;
            $label = $label_nr;
        }
        else
        {
            my $xreftitle = $title;
            $xreflabel = " xreflabel=\"$xreftitle\"";
        }
        $result .= docbook_add_id(docbook_element_tag($element) . " label=\"${label}\"${xreflabel}");
        $result .= ">\n<title>$title</title>\n";
        $docbook_current_section = $element;
    }
    return $result;
}

sub docbook_element_label($$$$)
{
    my $id = shift;
    my $element = shift;
    my $command = shift;
    my $line = shift;

    if ($command eq 'node')
    {
        $docbook_pending_node_id = docbook_node_id($element->{'texi'});
    }
    return '';
}

sub docbook_paragraph($$$$$$$$$$$$)
{
    my $text = shift;
    my $align = shift;
    my $indent = shift;
    my $paragraph_command = shift;
    my $paragraph_command_formatted = shift;
    my $paragraph_number = shift;
    my $format = shift;
    my $item_nr = shift;
    my $enumerate_style = shift;
    my $number = shift;
    my $command_stack_at_end = shift;
    my $command_stack_at_begin = shift;

    if (defined($paragraph_number) and defined($$paragraph_number))
    {
       $$paragraph_number++;
    }

    # no para in multitables, caption and shortcaptions.
    my $top_stack = '';
    $top_stack = $command_stack_at_begin->[-1] if (scalar (@$command_stack_at_begin));
    return $text if ($top_stack eq 'multitable' or $top_stack eq 'shortcaption' or $top_stack eq 'caption' or $top_stack eq 'documentdescription');

    if ($text =~ /\S/)
    {
       #return docbook_add_id('para').">$text</para>";
       return "<para>$text</para>";
    }
    return $text;
}


sub docbook_def_line($$$$$$$$$$$$$$$)
{
   my $category_prepared = shift;
   my $name = shift;
   my $type = shift;
   my $arguments = shift;
   my $index_label = shift;
   my $arguments_array = shift;
   my $arguments_type_array = shift;
   my $unformatted_arguments_array = shift;
   my $command = shift;
   my $class_name = shift;
   my $category = shift;
   my $class = shift;
   my $style = shift;
   my $original_command = shift;

   my %unformatted_arguments = ();

   my @unformatted_args = @$unformatted_arguments_array;
   foreach my $type (@$arguments_type_array)
   {
      my $unformatted_arg = shift @unformatted_args;
      $unformatted_arguments{$type} = $unformatted_arg;
   }
   # FIXME unformatted!
   my $result = "<synopsis role=\"$unformatted_arguments{'category'}\"><indexterm role=\""
    .$main::index_prefix_to_name{$style}."\"><primary>$class_name</primary></indexterm>";

   my %arguments = ( 'prepared_category' => $category_prepared,
         'category' => $category,
         'name' => $name,
         'type' => $type,
         'class' => $class
    );
   foreach my $type (keys(%arguments))
   {
      $arguments{$type} = '' if (!defined($arguments{$type}));
   }

   foreach my $mandatory_arg (@{$def_format_docbook{$command}})
   {
      my $elem = $mandatory_arg->[0];
      #if ($elem eq 'returnvalue' and $unformatted_arguments{$mandatory_arg->[1]} =~ /^\s*\@code\{/)
      if ($elem eq 'returnvalue' and $unformatted_arguments{$mandatory_arg->[1]} =~ /\@code\{/)
      {
      # FIXME unformatted
          my $arg_without_at_command = $unformatted_arguments{$mandatory_arg->[1]};
          #$arg_without_at_command =~ s/\s*\@code\{//;
          #$arg_without_at_command =~ s/\}\s*$//;
          while ($arg_without_at_command =~ /\@code\{([^\{\}]*)\}/)
          {
              $arg_without_at_command =~ s/\@code\{([^\{\}]*)\}/$1/;
          }
          $result .= "<$elem>$arg_without_at_command</$elem>";
      }
      else
      {
          $result .= "<$elem>$arguments{$mandatory_arg->[1]}</$elem>";
      }
   }

   my @types = @$arguments_type_array;
   @unformatted_args = @$unformatted_arguments_array;
   foreach my $arg (@$arguments_array)
   {
      my $type = shift @types;
      my $unformatted = shift @unformatted_args;
      if (exists ($def_argument_types_docbook{$type}))
      {
         if ($def_argument_types_docbook{$type} and
                ($type eq 'paramtype' or ($unformatted !~ /^\s*\@var\{/)))
         {
            $result .= "<$def_argument_types_docbook{$type}>$arg</$def_argument_types_docbook{$type}>";
         }
         else
         {
            $result .= $arg;
         }
      }
   }

   $result .= "</synopsis>\n";
   return $result;
}

# FIXME 
# @deffn 
# @c comment
# @end deffn
# leads to the creation of a <definitionitem> with a comment within, 
# while there should be no definitionitem 
sub docbook_def_item($)
{
    my $text = shift;
    my $only_inter_item_commands = shift;

    if ($text =~ /\S/)
    {
       return '<blockquote>' . $text . '</blockquote>' unless $only_inter_item_commands;
       return $text;
    }
    return '';
}

sub docbook_def($)
{
   my $text = shift;
   return docbook_add_id('informalfigure').'>'.$text.'</informalfigure>';
}

sub docbook_preformatted($$$$$$$$$$$$)
{
    my $text = shift;
    my $pre_style = shift;
    my $class = shift;
    my $leading_command = shift;
    my $leading_command_formatted = shift;
    my $preformatted_number = shift;
    my $format = shift;
    my $item_nr = shift;
    my $enumerate_style = shift;
    my $number = shift;
    my $command_stack_at_end = shift;
    my $command_stack_at_begin = shift;

    return $text;
}

sub docbook_misc_commands($$$$$)
{
    my $macro = shift;
    my $line = shift;
    my $args = shift;
    my $stack = shift;
    my $state = shift;
#print STDERR "$macro $line";
#print STDERR "ARGS @$args\n" if defined ($args);
    my $result_text = undef;
    if ($macro eq 'c' or $macro eq 'comment' and scalar(@$args))
    {
       my $comment_line = $args->[0];
       chomp ($comment_line);
       # makeinfo remove all the leading spaces
       $comment_line =~ s/^\s//;
       $result_text = &$comment ($comment_line);
    }
    elsif ($macro eq 'settitle')
    {
     # FIXME to be formatted? Also maybe in line_command. And in html, it
     # is handled by heading _text
       my $arg = $args->[0];
       $arg =~ s/^\s*//;
       chomp($arg);
       $result_text = "<title>$arg</title>\n";
    }
    return ($macro, $line, $result_text);
}

sub docbook_foot_line_and_ref($$$$$$$)
{
    my $number_in_doc = shift;
    my $number_in_page = shift;
    my $footnote_id = shift;
    my $place_id = shift;
    my $document_file = shift;
    my $footnote_file = shift;
    my $lines = shift;
    my $state = shift;

    my $result = docbook_add_id('footnote').'>';
    foreach my $line (@$lines)
    {
       $result .= $line;
    }
    return ([], $result . '</footnote>');
}

sub docbook_any_ref($$$)
{
    my $type = shift;
    my $args = shift;
    my $unformatted_args = shift;

    # FIXME?
    if ($type eq 'inforef')
    {
        my $node_file = "($args->[2])$args->[0]";
        if ($args->[1] ne '')
        {
            return "*note $args->[1]: $node_file";
        }
        else
        {
            return "*note ${node_file}::";
        }
    }
    else
    {
        if (($args->[3] ne '') or ($args->[4] ne ''))
        {
            return '' if ($args->[4] eq '');
            my $section_name = $args->[2];
            $section_name = $args->[0] if ($section_name eq '');
            if ($type eq 'ref')
            {
                return gdt('section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}', { 'section_name' => $section_name, 'book' => $args->[4] },{'duplicate'=>1});
            }
            elsif ($type eq 'xref')
            {
                return gdt('See section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}', { 'section_name' => $section_name, 'book' => $args->[4] },{'duplicate'=>1});
            }
            elsif ($type eq 'pxref')
            {
                return gdt('see section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}', { 'section_name' => $section_name, 'book' => $args->[4] },{'duplicate'=>1});
            }
        }
        my $link = docbook_node_id($unformatted_args->[0]);
        my $title = $args->[2];
        $title = $args->[1] if ($title eq '');
        if ($title eq '')
        {
            if ($type eq 'ref')
            {
                return gdt('{ref}', {'ref' => docbook_add_id('xref')." linkend=\"$link\"></xref>"});
            }
            elsif ($type eq 'pxref')
            {
                return gdt('see {ref}', {'ref' => docbook_add_id('xref')." linkend=\"$link\"></xref>"});
            }
            elsif ($type eq 'xref')
            {
                return gdt('See {ref}', {'ref' => docbook_add_id('xref')." linkend=\"$link\"></xref>"});
            }
        }
        else
        {
            if ($type eq 'ref')
            {
                return gdt('{title_ref}', {'title_ref' => docbook_add_id('link')." linkend=\"$link\">$title</link>"});
            }
            elsif ($type eq 'pxref')
            {
                return gdt('see {title_ref}', {'title_ref' => docbook_add_id('link')." linkend=\"$link\">$title</link>"},{'duplicate'=>1});
            }
            elsif ($type eq 'xref')
            {
                return gdt('See {title_ref}', {'title_ref' => docbook_add_id('link')." linkend=\"$link\">$title</link>"},{'duplicate'=>1});
            }
        }
    }
}

sub docbook_external_ref($$$$$$$$$)
{
    my $type = shift;
    my $section = shift;
    my $book = shift;
    my $file = shift;
    my $href = shift;
    my $cross_ref = shift;
    my $args_texi = shift;
    my $formatted_args = shift;
    my $node = shift;
    
    return docbook_any_ref ($type, $formatted_args, $args_texi);
}

sub docbook_internal_ref($$$$$)
{
    my $type = shift;
    my $href = shift;
    my $short_name = shift;
    my $name = shift;
    my $is_section = shift;
    my $args_texi = shift;
    my $formatted_args = shift;

    return docbook_any_ref ($type, $formatted_args, $args_texi );
}

sub docbook_index_entry_command($$$$$)
{               
   my $command = shift;
   my $index_name = shift;
   my $label = shift;
   my $entry_texi = shift;
   my $entry_formatted = shift;

   return $label if (defined($label) and $label ne '');
   return docbook_index_entry_label('','','',$main::index_prefix_to_name{$index_name}, '', '', $entry_formatted, {});
}

sub docbook_index_entry_label($$$$$$$$$)
{   
    my $identifier = shift;
    my $preformatted = shift;
    my $entry = shift;
    my $index_name = shift;
    my $index_command = shift;
    my $texi_entry = shift;
    my $formatted_entry = shift;
    my $in_region_not_in_output = shift;
    my $index_entry = shift;

    return "<indexterm role=\"${index_name}\"><primary>${formatted_entry}</primary></indexterm>";
}

sub docbook_close_section()
{
    my $element = $docbook_current_section;

    if (!defined($element))
    {
        return '';
    }

    my $result = '';

    # there is a special case for a @chapter that is a child of @top
    # but should not be considered as is, since it is also toplevel.
    # @part, however may have other toplevel elements as children.
    return '' if ($element->{'child'} and (!$element->{'child'}->{'toplevel'} or $element->{'tag'} ne 'top'));
    $result .= '</'.docbook_element_tag($element).">\n";

    my $current = $element;
    # the second condition is such that top is closed only if it has
    # sub-elements below chapter.
    # the third condition is such that elements with a next element are
    # only closed for the last element, except when the next element is 
    # toplevel and below top, such that @top is closed before the first 
    # @chapter if there are @section or the like below @top
    while ($current->{'sectionup'} and !($current->{'sectionup'}->{'tag'} eq 'top' and $current->{'toplevel'}) and (!$current->{'childnext'} or ($current->{'childnext'}->{'toplevel'} and $current->{'sectionup'}->{'tag'} eq 'top')))
    {
        $current = $current->{'sectionup'};
        $result .= '</'.docbook_element_tag($current).">\n";
    }
    return $result;
}

sub docbook_end_section($$$)
{
    my $fh = shift;
    my $end_foot_navigation = shift;
    my $element = shift;
}

sub docbook_print_Top_footer($$)
{
    my $fh = shift;
    my $end_page = shift;
    my $element = shift;
}

sub docbook_one_section($$)
{
    my $fh = shift;
    my $element = shift;
    main::print_lines($fh);
    &$print_page_foot($fh);
}

sub docbook_insertcopying($)
{
    my $text = shift;
    my $comment = shift;
    my $simple_text = shift;

    return $text;
}

sub docbook_acronym_like($$$$$$)
{
    my $command = shift;
    my $acronym_texi = shift;
    my $acronym_text = shift;
    my $with_explanation = shift;
    my $explanation_lines = shift;
    my $explanation_text = shift;
    my $explanation_simply_formatted = shift;

    $command = 'abbrev' if ($command eq 'abbr');
    my $result = docbook_add_id($command).">$acronym_text</${command}>";
    if ($with_explanation)
    {
        $result .= " ($explanation_text)";
    }
    return $result;
}


sub docbook_image_files($$$$)
{
    my $base = shift;
    my $extension = shift;
    my $texi_base = shift;
    my $texi_extension = shift;
    my @files = ();
    return @files if (!defined($base) or ($base eq ''));
# FIXME should look at extension argument? makeinfo doesn't
#    push @files,"$base.$extension" if (defined($extension) and ($extension ne ''));
    foreach my $ext (@IMAGE_EXTENSIONS)
    {
        push @files, ["$base.$ext", "$texi_base.$ext"];
    }
    return @files;
}


sub docbook_image($$$$$$$$$$$$$$$$;$)
{
    my $file = shift;
    my $base = shift;
    my $preformatted = shift;
    my $file_name = shift;
    my $alt = shift;
    my $width = shift;
    my $height = shift;
    my $raw_alt = shift;
    my $extension = shift;
    my $working_dir = shift;
    my $file_path = shift;
    my $in_paragraph = shift;
    my $file_locations = shift;
    my $base_simple_format = shift;
    my $extension_simple_format = shift;
    my $file_name_simple_format = shift;
    my $line_nr = shift;

#    if (!defined($file_path) or $file_path eq '' or $file_path =~ /\.txt$/)
#    {
#        if (defined($extension) and $extension ne '')
#        {
#            $file = "$base.$extension";
#        }
#        else
#        {
#            $file = "$base.jpg";
#            $extension = 'jpg';
#        }
#        main::line_warn ("no image file for $base, (using $file)");
#    }
    my $txt_path;
    my @files = ();
    my @extensions = @IMAGE_EXTENSIONS;
    foreach my $file_location (@$file_locations)
    {
        my ($file_located, $path, $file_simple_format) = @$file_location;
        my $extension = shift @extensions;
        if (defined($path))
        {
           if ($extension eq 'txt' and !defined($txt_path))
           {
              $txt_path = $path;
           }
           else
           {
              push @files, [$file_located, uc($extension), $file_simple_format];
           }
        }
    }
    push @files, ["$base.jpg", 'JPG', "$base_simple_format.jpg" ] unless (@files);

    my $begin = docbook_add_id('inlinemediaobject').'>';
    my $end = '</inlinemediaobject>';
    if ($preformatted or !$in_paragraph)
    {
         $begin = docbook_add_id('informalfigure').'><mediaobject>';
         $end = '</mediaobject></informalfigure>';
    }
    my $result = $begin;
    foreach my $file_spec (@files)
    {
       $result .= "<imageobject><imagedata fileref=\"$file_spec->[2]\" format=\"$file_spec->[1]\"></imagedata></imageobject>";
    }
    if (defined($txt_path))
    {
       if (open(TXT, "<$txt_path"))
       {
          if (defined($Texi2HTML::THISDOC{'IN_ENCODING'}) and $USE_UNICODE)
          {
              binmode(TXT, ":encoding($Texi2HTML::THISDOC{'IN_ENCODING'})");
          }
          $result.="<textobject><literallayout>";
          while (my $img_txt = <TXT>)
          {
              $result .= $img_txt;
          }
          $result .= '</literallayout></textobject>';
          close(TXT);
       } 
       else
       {
          main::line_warn (sprintf(__("\@image file `%s' unreadable: %s"), $txt_path, $!), $line_nr);
       }
    }
    else
    {
        main::line_warn (sprintf(__("Cannot find \@image file `%s.txt'"), $base), $line_nr);
    }

    return "$result$end";
}

sub docbook_format_list_item_texi($$$$)
{
    my $format = shift;
    my $line = shift;
    my $prepended = shift;
    my $command = shift;

    my $result_line = undef;

    if (defined($command) and $command ne '' and !exists $special_list_commands{$format}->{$command} and $format ne 'itemize')
    {
        #@*table
        $line =~ s/^\s*//;
        $line =~ s/\s*$//;
        if (exists ($style_map{$command}))
        {
           $result_line = "\@$command\{$line\}\n";
        }
        elsif (exists ($things_map{$command}))
        {           
           $result_line = "\@$command\{\} $line\n";
        }           
        else        
        {           
           $result_line = "\@$command $line\n";
        }
    }

    return ($result_line, 0);
}


# row in multitable
sub docbook_row($$;$$)
{
    my $text = shift;
    my $macro = shift;
    my $columnfractions = shift;
    my $prototype_row = shift;
    my $prototype_lengths = shift;
    my $column_number = shift;

    my $result = '';
    if ($macro eq 'headitem')
    {
         if ($docbook_multitable_stack[-1] != 0)
         {
             $result .= "<thead>";
             $result = "</tbody>" . $result if ($docbook_multitable_stack[-1] == 1);
             $docbook_multitable_stack[-1] = 0;
         }
    }
    elsif ($docbook_multitable_stack[-1] != 1)
    {
         $result .= "<tbody>";
         $result = "</thead>" . $result if ($docbook_multitable_stack[-1] == 0);
         $docbook_multitable_stack[-1] = 1;
    }
    $result .= "<row>$text</row>";
    
    return $result;
}

# cell in multitable
sub docbook_cell($$;$$)
{
    my $text = shift;
    my $row_macro = shift;
    my $columnfractions = shift;
    my $prototype_row = shift;
    my $prototype_lengths = shift;
    my $column_number = shift;

    return "<entry>" . $text . '</entry>';
}

# if varlistentry_state is > 0 it means that a varlistentry is opened.
# if varlistentry_state is == 2 it means that we are in a succession
#          of term
# if varlistentry_state is == 1 it means that we are in the line
# Having a listitem in a varlistentry is a must, so an empty
# listitem is added if a varlistentry is closed and varlistentry_state == 2
#
# varlistentry acceps only term and listitem, so inter_item_commands
# are put in the next term, or, if at the end of the table in a last
# listitem
sub docbook_table_item($$$$$$)
{
    my $text = shift;
    my $index_label = shift;
    my $format = shift;
    my $command = shift;
#    my $formatted_command = shift;
    my $style_stack = shift;
#    my $text_formatted = shift;
#    my $text_formatted_leading_spaces = shift;
#    my $text_formatted_trailing_spaces = shift;
    my $item_cmd = shift;

#    $formatted_command = '' if (!defined($formatted_command));

#    if (defined($text_formatted))
#    {
#        $text_item = $text_formatted_leading_spaces . $text_formatted .$text_formatted_trailing_spaces;
#    }
#    else
#    {
#        $text_item = $text;
#    }

    my $result = '';
    my $prepended = '';
    if (defined($docbook_table_stack[-1]->{'inter_item'}))
    {
        #$formatted_command = $docbook_table_stack[-1]->{'inter_item'} . $formatted_command;
        $prepended = $docbook_table_stack[-1]->{'inter_item'};
        delete $docbook_table_stack[-1]->{'inter_item'};
    }
    if ($item_cmd eq 'item')
    {
        if ($docbook_table_stack[-1]->{'varlistentry_state'} == 2)
        {
            $result .= "<listitem><para><!-- empty table line --></para></listitem>";
        }
        if ($docbook_table_stack[-1]->{'varlistentry_state'} >= 1)
        {
            $result .= '</varlistentry>';
        }
        $docbook_table_stack[-1]->{'varlistentry_state'} = 2;
        $result .= '<varlistentry>';
    }
    $result .= '<term>';
    $result .= $prepended . $text ."</term>\n";
    return $result;
}

sub docbook_table_line($$$)
{
    my $text = shift;
    my $only_inter_item_commands = shift;
    my $before_items = shift;

    $only_inter_item_commands = '' if (!defined($only_inter_item_commands));

#print STDERR 

    if ($text =~ /\S/)
    {
        if ($before_items)
        {
            return $text;
        }

        if ($only_inter_item_commands)
        {
            $docbook_table_stack[-1]->{'inter_item'} = $text;
            return '';
        }
        else
        {
            $docbook_table_stack[-1]->{'varlistentry_state'} = 1;
            return "<listitem>$text</listitem>";
        }
        #return $text;
    }
    else
    {
        return '';
    }
}

sub docbook_list_item($$$$$$$$$)
{
    my $text = shift;
    my $format = shift;
    my $command = shift;
    my $formatted_command = shift;
    my $item_nr = shift;
    my $enumerate_style = shift;
    my $number = shift;
    my $prepended = shift;
    my $prepended_formatted = shift;
    my $only_inter_item_commands = shift;
    my $before_items = shift;

    $only_inter_item_commands = '' if (!defined($only_inter_item_commands));

#my $prep_t = 'UNDEF'; $prep_t = $prepended if (defined($prepended));
#$item_nr = 0 if (!defined($item_nr));
#print STDERR "  $item_nr --> $prep_t|${text}!!!!!\n";
    #return $text if ($only_inter_item_commands and $before_items);
    return  $text if ($before_items);
    return '<listitem>' . $text . "</listitem>\n";
}

sub docbook_table_list($$$$$$$$$)
{
    my $format_command = shift;
    my $text = shift;
    my $command = shift;
    my $formatted_command = shift;
# enumerate
    my $item_nr = shift;
    my $enumerate_style = shift;
# itemize
    my $prepended = shift;
    my $prepended_formatted = shift;
# multitable
    my $columnfractions = shift;
    my $prototype_row = shift;
    my $prototype_lengths = shift;
    my $number = shift;
    
    my $result = "<$format_command>";
    if ($format_command eq 'itemize')
    {
        my $itemfunction;
        #$prepended_formatted =~ s/^\s*// if (defined($prepended_formatted));
        $prepended =~ s/^\s*// if (defined($prepended));
        #if (defined($formatted_command) and $formatted_command ne '')
        if (defined($command) and $command ne '')
        {
            #$itemfunction = $formatted_command;
            $itemfunction = $command;
            #$itemfunction .= " $prepended_formatted" if (defined($prepended_formatted) and $prepended_formatted ne '');
            $itemfunction .= " $prepended" if (defined($prepended) and $prepended ne '');
        }
        #elsif (defined($prepended_formatted))
        elsif (defined($prepended))
        {
            #$itemfunction = $prepended_formatted;
            $itemfunction = $prepended;
        }
        my $mark = '';
       $mark = " mark=\"$itemfunction\"" if (defined($itemfunction) and $itemfunction ne '');
        return docbook_add_id('itemizedlist')."${mark}>$text</itemizedlist>";
    }
    elsif ($format_command eq 'enumerate')
    {
        my $numeration='arabic';
        if (defined($enumerate_style) and $enumerate_style ne '')
        {
           if ($enumerate_style =~ /^[A-Z]/)
           {
               $numeration = 'upperalpha';
           }
           elsif ($enumerate_style =~ /^[a-z]/)
           {
               $numeration = 'loweralpha';
           }
        }
        return docbook_add_id('orderedlist') ." numeration=\"$numeration\">$text</orderedlist>";
    }
    elsif ($format_command eq 'multitable')
    {
       my $result = docbook_add_id('informaltable').'><tgroup cols="'.$number.'">';
       my $fractions;
       my $multiply = 1;
       if (defined($columnfractions) and (ref($columnfractions) eq 'ARRAY')
           and scalar(@$columnfractions))
       {
           $fractions = [ @$columnfractions ];
           $multiply = 100;
       }
       elsif (defined($prototype_lengths) and (ref($prototype_lengths) eq 'ARRAY')
           and scalar(@$prototype_lengths))
       {
           $fractions = [ @$prototype_lengths ];
       }
       
       if (defined ($fractions))
       {
           foreach my $fraction (@$fractions)
           {
               $result .= '<colspec colwidth="'.($fraction*$multiply).'*"></colspec>';
           }
       }
       $text .= "</tbody>" if ($docbook_multitable_stack[-1] == 1);
       $text .= "</thead>" if ($docbook_multitable_stack[-1] == 0);
       pop @docbook_multitable_stack;
       return $result . "$text</tgroup></informaltable>";
    }
    elsif ($format_command =~ /^(v|f)?table$/)
    {
       $result = docbook_add_id('variablelist').'>';
       if (defined($docbook_table_stack[-1]->{'inter_item'}))
       { # there is a para in case there is only a comment, to avoid
         # an empty listitem
           $text .= "<listitem><para>$docbook_table_stack[-1]->{'inter_item'}</para></listitem>";
       }
       elsif ($docbook_table_stack[-1]->{'varlistentry_state'} == 2)
       {
           $text .= "<listitem><para><!-- empty table line --></para></listitem>";
       }
       $text .= '</varlistentry>' if ($docbook_table_stack[-1]->{'varlistentry_state'} >= 1);
       pop @docbook_table_stack;
       return $result . "$text</variablelist>\n";
    }
}

sub docbook_begin_format_texi($$$)
{
    my $command = shift;
    my $line = shift;
    my $state = shift;

    push (@docbook_multitable_stack, -1) if ($command eq 'multitable');
    push (@docbook_table_stack, {'varlistentry_state' => 0}) if ($command =~ /^(v|f)?table/);
    return $line;
}

# FIXME
sub docbook_sp($$)
{
   my $number = shift;
   my $preformatted = shift;
   return "";
}

sub docbook_index_summary($$)
{
    my $alpha = shift;
    my $nonalpha = shift;
    return '';
}

sub docbook_printindex($$)
{
    my $name = shift;
    my $printindex = shift;
    return docbook_add_id('index')."></index>\n";
}

sub docbook_complex_format($$)
{
    my $name = shift;
    my $text = shift;
    return '' if ($text eq '');
    my $result = docbook_add_id($docbook_complex_format{$name}).'>' .$text."</$docbook_complex_format{$name}>";
    return $result;
}

sub docbook_format($$)
{
    my $name = shift;
    my $element = shift;
    my $text = shift;
    return '' if ($text eq '');
    return $text if ($format_map{$name} eq '');
    if ($name eq 'copying')
    {
        # FIXME is info in docbook 5.0
        return "<bookinfo>\n<legalnotice>\n$text</legalnotice>\n</bookinfo>\n";
    }
    return docbook_add_id($format_map{$name}).'>' .$text."</$format_map{$name}>";
}

sub docbook_quotation_prepend_text($$)
{
    my $command = shift;
    my $argument_text = shift;

    return undef if (!defined($argument_text) or $argument_text =~ /^$/);

    chomp($argument_text);

    return undef if (grep {lc($argument_text) eq $_} @docbook_special_quotation);
    return gdt('@b{{quotation_arg}:} ', {'quotation_arg' => $argument_text}, {'keep_texi' => 1});
}


sub docbook_quotation($$$$$)
{
    my $command = shift;
    my $text = shift;
    my $argument_text = shift;
    my $argument_text_texi = shift;
    my $authors = shift;

    $argument_text_texi = '' if (!defined($argument_text_texi));
    chomp($argument_text_texi);
    my $docbook_command = 'blockquote';
    if (grep {lc($argument_text_texi) eq $_} @docbook_special_quotation)
    {
       $docbook_command = lc($argument_text_texi);
    }
    my $attribution = '';
    if ($authors)
    {
       foreach my $author (@$authors)
       {
           $attribution .= $author->{'author_text'};
       }
       $attribution = '<attribution>' .$attribution. '</attribution>' . "\n";
    }
    return  docbook_add_id($docbook_command).'>' .$attribution . $text . "</$docbook_command>\n";
}

sub docbook_style($$$$$$$$$)
{
    my $style = shift;
    my $command = shift;
    my $text = shift;
    my $args = shift;
    my $no_close =shift;
    my $no_open = shift;
    my $line_nr = shift;
    my $state = shift;
    my $command_stack = shift;
    my $kept_line_nrs = shift;

    my $result = $text;
    if (exists($style->{'function'}))
    {
        my $function = $style->{'function'};
        $result = &$function($command, $args, $command_stack, $state, $line_nr, $kept_line_nrs);
    }
    elsif (exists($style->{'inline_attribute'}))
    {
        my $element = $style->{'inline_attribute'};
        my $attribute_text = '';
        if ($element =~ /^(\w+)(\s+.*)/)
        {
            $element = $1;
            $attribute_text = $2;
        }

        if ($no_open)
        {
            $result = "<$element";
        }
        else
        {
            $result = docbook_add_id($element);
        }
        $result .= "$attribute_text>$text</$element>";
    }
    if (exists($style->{'begin'}) and !$no_open)
    {
        $result = $style->{'begin'} . $result;
    }
    if (exists($style->{'end'}) and !$no_close)
    {
        $result .= $style->{'end'};
    }
    return $result;
}

sub docbook_raw($$$)
{
    my $style = shift;
    my $text = shift;
    my $line_nr = shift;

    if ($style eq 'verbatim' or $style eq 'verbatiminclude')
    {
        return docbook_add_id('screen').'>' . &$protect_text($text) . '</screen>';
    }
    return '' unless (grep {$style eq $_} @EXPAND);
    if ($style eq 'docbook')
    {
        chomp ($text);
        return $text;
    }
    else
    {
        main::line_warn (sprintf(__("Raw format %s is not converted"), $style), $line_nr);
        return &$protect_text($text);
    }
}

sub docbook_cartouche($$)
{
    my $text = shift;

    return $text;
}

sub docbook_anchor_label($$)
{
    my $id = shift;
    my $anchor_text = shift;
    # FIXME use docbook_node_id
    return '<anchor id="'. &$protect_text($anchor_text) . '"></anchor>';
}

sub docbook_float($$$$$)
{
    my $text = shift;
    my $float = shift;
    my $caption = shift;
    my $shortcaption = shift;

    my $label_texi = $float->{'texi'};
    return $text if (!defined($label_texi) or $label_texi eq '');

    return docbook_anchor_label('',$label_texi) . $text;
}

sub docbook_normal_text($$$$$$$;$)
{
   my $text = shift;
   my $in_raw_text = shift; # remove_texi
   my $in_preformatted = shift;
   my $in_code = shift;
   my $in_math = shift;
   my $in_simple = shift;
#print STDERR "Bug: in_raw_text in_simple $text\n" if ($in_raw_text and $in_simple);
   my $style_stack = shift;
   my $state = shift;

   #$text = uc($text) if (in_cmd($style_stack, 'sc'));
   $text = &$protect_text($text) unless($in_raw_text);
   if (! $in_code and !$in_preformatted)
   {
       if (!$in_raw_text)
       {
           $text =~ s/---/\&mdash\;/g;
           $text =~ s/--/\&ndash\;/g;
           $text =~ s/``/\&ldquo\;/g;
           $text =~ s/''/\&rdquo\;/g;
       }
       else
       {
           #FIXME really do that ? It is done by makeinfo in html
            $text =~ s/``/"/g;
            $text =~ s/''/"/g;
            # FIXME really do that in raw text?
            $text =~ s/---/\x{1F}/g;
            $text =~ s/--/-/g;
            $text =~ s/\x{1F}/--/g;
       }
   }
   return $text;
}

sub docbook_noop
{
    return '';
}

1;

require "$T2H_HOME/formats/docbook.init"
    if ($0 =~ /\.pl$/ &&
        -e "$T2H_HOME/formats/docbook.init" && -r "$T2H_HOME/formats/docbook.init");

# @INIT_XML@
# vim: set filetype=perl: 

use strict;

my @xml_multitable_stack = ();
my @xml_table_stack = ();

my @xml_ignored_misc_commands;
my %xml_misc_command_output;
my %xml_misc_elements_with_arg_map;
my @xml_misc_elements_with_arg;
my %def_format_xml; 
my $xml_current_section;

sub xml_default_load(;$)
{
my $from_command_line = shift;

t2h_default_set_variables_xml();
$DOCTYPE = '<!DOCTYPE texinfo PUBLIC "-//GNU//DTD TexinfoML V4.12//EN" "http://www.gnu.org/software/texinfo/dtd/4.12/texinfo.dtd">';
$SIMPLE_MENU = 0;
$SEPARATE_DESCRIPTION = 1;
@T2H_FORMAT_EXPAND = ('xml', 'direntry');
$USE_ISO = 0;
$HEADERS = 0;
$INLINE_INSERTCOPYING = 0;
$SHOW_MENU = 1;
$SHOW_TITLE = 0;
$NUMBER_SECTIONS = 0;
$USE_NODES = 1;
$USE_SECTIONS = 1;

t2h_default_push_handler(\&xml_init_variables, \@command_handler_init);

$colon_command_punctuation_characters{'.'} = '&period;';
$colon_command_punctuation_characters{':'} = '&colon;';
$colon_command_punctuation_characters{'?'} = '&quest;';
$colon_command_punctuation_characters{'!'} = '&excl;';

$simple_map{'*'} = '&linebreak;';
$simple_map{' '} = '&space;';
$simple_map{"\t"} = '&space;';
$simple_map{"\n"} = '&space;';
$simple_map{'.'} = '&eosperiod;';
$simple_map{'!'} = '&eosexcl;';
$simple_map{'?'} = '&eosquest;';

%simple_map_pre = %simple_map;

# FIXME right?
$things_map{'l'} = '/l';
$things_map{'L'} = '/L';
$things_map{'enddots'} = '&enddots;';
$things_map{'dots'} = '&dots;';
# FIXME equiv, point, expansion could be ameliorated
$things_map{'equiv'} = '==';
$things_map{'point'} = '-!-';
$things_map{'expansion'} = '==&gt;'; # &rarr;?

$things_map{'minus'} = '&minus;';
$things_map{'result'} = '&rArr;';
$things_map{'bullet'} = '&bullet;';
$things_map{'copyright'} = '&copyright;';
$things_map{'registeredsymbol'} = '&registered;';
$things_map{'arrow'} = '&rarr;';
$things_map{'TeX'} = '&tex;';
$things_map{'LaTeX'} = '&latex;';

%pre_map = %things_map;

$stop_paragraph_command{'caption'} = 1;
$stop_paragraph_command{'shortcaption'} = 1;

%line_command_map = ();
foreach my $command ('contents', 'shortcontents', 'summarycontents')
{
   $line_command_map{$command} = $command;
}

%format_map = ();

$format_map{'copying'} = '';
$format_map{'titlepage'} = 'titlepage';
$format_map{'documentdescription'} = 'documentdescription';
$format_map{'group'} = 'group';
$format_map{'raggedright'} = 'raggedright';

foreach my $region ('titlepage', 'documentdescription', 'copying')
{
   $region_formats_kept{$region} = 1;
}

%style_map = ();
t2h_default_copy_style_map (\%default_style_map, \%style_map);

foreach my $style (keys(%style_map))
{
    next if grep {$style eq $_} ('asis', 'ctrl', 'w');
    if (grep {$style eq $_} ('tieaccent', 'dotless', keys(%unicode_accents)))
    {
     $style_map{$style} = { 'function' => \&xml_default_accent };
    }
    elsif (!exists($style_map{$style}->{'args'}) or (scalar(@{$style_map{$style}->{'args'}}) eq 1 and ($style_map{$style}->{'args'}->[0] eq 'code' or $style_map{$style}->{'args'}->[0] eq 'normal')))
    {
        $style_map{$style}->{'inline_attribute'} = $style;
        delete ($style_map{$style}->{'quote'});
        delete ($style_map{$style}->{'begin'});
        delete ($style_map{$style}->{'end'});
        delete ($style_map{$style}->{'function'});
    }
}

foreach my $complex_format (keys(%complex_format_map))
{
   my $style = $complex_format_map{$complex_format}->{'style'};
   delete $complex_format_map{$complex_format};
   $complex_format_map{$complex_format}->{'begin'} = "<$complex_format xml:space=\"preserve\">";
   $complex_format_map{$complex_format}->{'end'} = "</$complex_format>";
   $complex_format_map{$complex_format}->{'style'} = $style if (defined($style));
}
foreach my $menu_command('menu', 'detailmenu', 'direntry', 'menu_comment')
{
  $complex_format_map{$menu_command} = undef;
  delete $complex_format_map{$menu_command};
}

# this is not needed because normal_text isn't the same than in html
#t2h_remove_text_substitutions("'", 1, 0, 0, 1);
#t2h_remove_text_substitutions('`', 1, 0, 0, 1);

$style_map{'w'}->{'end'} = '<!-- /@w -->';
$style_map{'='}->{'function'} = \&xml_macron;
$style_map{'email'}->{'function'} = \&xml_email;
$style_map{'titlefont'}->{'function'} = \&xml_titlefont;
$style_map{'math'}->{'function'} = \&xml_math;
$style_map{'uref'}->{'function'} = \&xml_uref;
$style_map{'url'}->{'function'} = \&xml_uref;
$style_map{'t'}->{'inline_attribute'} = 'tt';
# FIXME
delete $special_accents{'ringaccent'};
$special_accents{'ogonek'} = 'aeiuAEIU';

%style_map_pre = %style_map;

$no_paragraph_commands{'cindex'} = 0;

#my @xml_ignored_misc_commands = ('bye', 'sp', 'verbatiminclude');

@xml_ignored_misc_commands = ('bye', 'sp', 'verbatiminclude', 'clickstyle', 
  'defcodeindex',
  'syncodeindex', 'paragraphindent', 'shorttitlepage', 'refill', 'noindent');

# we want to proceed all the misc commands
# makeinfo ignores clickstyle, changes setfilename. Not sure it is right.
foreach my $misc_command (keys(%misc_command))
{
    next if (grep {$misc_command eq $_} @xml_ignored_misc_commands);
    $xml_misc_command_output{$misc_command} = 1;
}

$format_map{'menu'} = 'menu';
# checked on bug-texinfo, only node is in code_style, as with makeinfo --xml
#$format_code_style{'menu'} = 1;
#$format_code_style{'menu_name'} = 1;
#$format_code_style{'menu_description'} = 1;
$format_map{'detailmenu'} = 'detailmenu';
$format_map{'direntry'} = 'direntry';
$format_map{'menu_comment'} = '';

$menu_description = \&xml_menu_description;
$menu_link = \&xml_menu_link;
$element_heading = \&xml_heading;
$heading = \&xml_heading;
$paragraph = \&xml_paragraph;
$preformatted = \&xml_preformatted;
$misc_element_label = \&xml_noop;
$element_label = \&xml_noop;
$anchor_label = \&xml_anchor_label;
$index_entry_label = \&xml_index_entry_label;
$index_entry_command = \&xml_index_entry_command;
$listoffloats = \&xml_listoffloats;
$acronym_like = \&xml_acronym_like;
$foot_line_and_ref = \&xml_foot_line_and_ref;
$image = \&xml_image;
$sp = \&xml_sp;
$quotation = \&xml_quotation;
$table_list = \&xml_table_list;
$row = \&xml_row;
$cell = \&xml_cell;
$list_item = \&xml_list_item;
$format_list_item_texi = \&xml_format_list_item_texi;
$misc_command_line = \&xml_misc_commands;
$begin_format_texi = \&xml_begin_format_texi;
$def_line = \&xml_def_line;
$def = \&xml_def;
$def_item = \&xml_def_item;
$printindex = \&xml_printindex;
$index_summary = \&xml_index_summary;
$external_ref = \&xml_external_ref;
$internal_ref = \&xml_internal_ref;
$table_item = \&xml_table_item;
$table_line = \&xml_table_line;
$float = \&xml_float;
$caption_shortcaption = \&xml_caption_shortcaption;
$caption_shortcaption_command = \&xml_caption_shortcaption_command;
$normal_text = \&xml_normal_text;
$protect_text = \&xml_default_protect_text;
$paragraph_style_command = \&xml_paragraph_style_command;
$raw = \&xml_raw;
$cartouche = \&xml_cartouche;

$print_Top = \&xml_print_Top;
$print_Top_footer = \&xml_print_Top_footer;
$print_page_head = \&xml_print_page_head;
$print_foot_navigation = \&xml_noop;
$toc_body = \&xml_noop;
$about_body = \&xml_noop;
$print_page_foot = \&xml_print_page_foot;
$end_section = \&xml_end_section;
$one_section = \&xml_one_section;

%xml_misc_elements_with_arg_map = (
  'title'     => 'booktitle',
  'subtitle'  => 'booksubtitle'
);

@xml_misc_elements_with_arg = ('author',
  'dircategory', 'settitle');
#my @xml_misc_elements_with_arg = ('author', 'shorttitlepage',
#  'vskip', 'dircategory', 'settitle');

%def_format_xml = (
  'deffn' => [ ['category', 'category'], ['function', 'name'] ],
   'defvr' => [ ['category', 'category'], ['variable', 'name'] ],
   'deftypefn' => [ ['category', 'category'], ['type', 'type'], ['function', 'name'] ], 
   'deftypeop' => [ ['category', 'category'], ['type', 'type'], ['operation', 'name'] ], 
   'deftypevr' => [ ['category', 'category'], ['type', 'type'], ['variable', 'name'] ], 
   'defcv' => [ ['category' , 'category'], ['class', 'class'], ['classvar', 'name'] ], 
   'deftypecv' => [ ['category', 'category'], ['type', 'type'], ['classvar', 'name'] ], 
   'defop' => [ ['category', 'category'], ['class', 'class'], ['operation', 'name'] ], 
   'deftp' => [ ['category', 'category'], ['datatype', 'name'] ] 
);


}

sub xml_macron($$)
{
    my $accent = shift;
    my $args = shift;
    return $args->[0] . "&macr;";
}

sub xml_email($$)
{
    my $command = shift;
    my $args = shift;
    my $mail = shift @$args;
    my $text = shift @$args;
    $mail = main::normalise_space($mail);
    my $result = "<email><emailaddress>$mail</emailaddress>";
    if (defined($text) and $text =~ /\S/)
    {
        $result .= "<emailname>".main::normalise_space($text)."</emailname>";
    }
    return $result . '</email>';
}

sub xml_uref($$)
{
    shift;
    my $args = shift;
    my $url = shift @$args;
    my $text = shift @$args;
    my $replacement = shift @$args;
    $url = main::normalise_space($url);
    $replacement = '' if (!defined($replacement));
    $replacement = main::normalise_space($replacement);
    $text = '' if (!defined($text));
    $text = main::normalise_space($text);
    my $result = "<uref><urefurl>$url</urefurl>";
    $result .= "<urefdesc>$text</urefdesc>" if ($text ne '');
    $result .= "<urefreplacement>$replacement</urefreplacement>" if ($replacement ne '');
    return $result.'</uref>';
}


sub xml_titlefont($$)
{
    shift;
    my $args = shift;
    return "<titlefont>$args->[0]</titlefont>";
}

sub xml_math($$)
{
    shift;
    my $args = shift;
    my $text = shift @$args;
    return "<math>$text</math>";
}


sub xml_menu_description($$$)
{
    my $text = shift;
    my $state = shift;
    my $element_text = shift;
    return "<menucomment>$text</menucomment>\n</menuentry>";
}

sub xml_menu_link($$$$$$$$$$)
{
    my $entry = shift;
    my $state = shift;
    my $href = shift;
    my $menunode = shift;
    my $menutitle = shift;
    my $ending = shift;
    my $has_title = shift;
    my $command_stack = shift;
    my $in_preformatted = shift;
    my $menunode_normalized = shift;

    return "<menuentry>\n<menunode>$menunode_normalized</menunode>\n<menutitle>$menutitle</menutitle>\n";
}

sub xml_print_page_head($)
{
    my $fh = shift;
    my $setfilename = '';
    $setfilename = "<setfilename>$Texi2HTML::THISDOC{file_base_name}.$EXTENSION</setfilename>" 
        unless (defined($Texi2HTML::THISDOC{'setfilename'}) and $Texi2HTML::THISDOC{'setfilename'} ne '');
    my $language = get_conf('documentlanguage');
    my $doctype = get_conf('doctype');
    print $fh <<EOT;
<?xml version="1.0"?>
$doctype
<texinfo xml:lang="$language">
$setfilename
EOT
}

sub xml_print_page_foot($)
{
    my $fh = shift;
    print $fh "". xml_close_section();
    print $fh <<EOT;
</texinfo>
EOT
}

sub xml_one_section($$)
{
    my $fh = shift;
    my $element = shift;
    main::print_lines($fh);
    #print $fh "". xml_footing($element);
    &$print_foot_navigation($fh);
    &$print_page_foot($fh);
}

sub xml_heading($$$$$)
{
    my $element = shift;
    my $command = shift;
    my $texi_line = shift;
    my $line = shift;
    my $in_preformatted = shift;

#print STDERR "'$command' $line";
    if (defined($command) and $command =~ /heading/)
    {
        my $text = '';
        if (defined($line))
        {
            $text = $line;
            # this isn't done in main program in that case...
            chomp ($text);
            $text =~ s/^\s*//;
        }
        return "<${command}>$text</${command}>\n";
    }
    elsif (defined($command) and $command eq 'node')
    {
#print STDERR "node $command $node_element->{'texi'}\n";
        my $result = '';
        $result .= xml_close_section();
        $result .= "<node>\n";
        $result .= "<nodename>$element->{'text'}</nodename>\n";
        foreach my $direction('nodenext', 'nodeprev', 'nodeup')
        {
            if ($element->{$direction})
            {
                $result .= "<${direction}>$element->{$direction}->{'text'}</${direction}>\n";
            }
        }
        $result .= "</node>\n";
        return $result;
        
    }
    else
    {
        my $result = '';
        $result .= xml_close_section();
        $result .= "<".xml_element_tag($element).">\n<title>$element->{'text'}</title>\n";
        $xml_current_section = $element;
        return $result;
    }
}

sub xml_element_tag($)
{
    my $element = shift;
    my $class = $element->{'tag_level'};
    return $class;
}

sub xml_close_section()
{
    my $element = $xml_current_section;

    if (!defined($element))
    {
        return '';
    }
    my $result = '';

    $xml_current_section = undef;

    # there is a special case for a @chapter that is a child of @top
    # but should not be considered as is, since it is also toplevel.
    # @part, however may have other toplevel elements as children.
    return '' if ($element->{'child'} and (!$element->{'child'}->{'toplevel'} or $element->{'tag'} ne 'top'));
    $result .= '</'.xml_element_tag($element).">\n";

    my $current = $element;
    # the second condition is such that top is closed only if it has
    # sub-elements below chapter.
    # the third condition is such that elements with a next element are
    # only closed for the last element, except when the next element is 
    # toplevel and below top, such that @top is closed before the first 
    # @chapter if there are @section or the like below @top
    while ($current->{'sectionup'} and !($current->{'sectionup'}->{'tag'} eq 'top' and $current->{'toplevel'}) and (!$current->{'childnext'} or ($current->{'childnext'}->{'toplevel'} and $current->{'sectionup'}->{'tag'} eq 'top')))
    {
        $current = $current->{'sectionup'};
        $result .= '</'.xml_element_tag($current).">\n";
    }
    return $result;

    ## there is a special case for a @chapter that is a child of @top
    ## but should not be considered as is, since it is also toplevel.
    #return '' if ($element->{'child'} and !$element->{'child'}->{'toplevel'});
    #$result .= '</'.xml_element_tag($element).">\n";

    #return $result if ($element->{'sectionnext'} or $element->{'level'} <= 1);
    #my $current = $element;
    #while ($current->{'level'} != 1 and $current->{'sectionup'} and !$current->{'sectionnext'})
    #{
    #    $current = $current->{'sectionup'};
    #    $result .= '</'.xml_element_tag($current).">\n";
    #}
    #return $result;
}

sub xml_end_section($$$)
{
    my $fh = shift;
    my $end_foot_navigation = shift;
    my $element = shift;
}

sub xml_print_Top($$$)
{
    my $fh = shift;
    my $has_top_heading = shift;
    my $element = shift;
    main::print_lines($fh, $Texi2HTML::THIS_SECTION);
}

sub xml_print_Top_footer($$)
{
    my $fh = shift;
    my $end_page = shift;
    my $element = shift;
}

# FIXME warning:
#
# @samp{first para
# 
# second para}.
#
# maybe should lead to:
# <para><samp>first para  second para</samp>.</para>
#
# But it leads to
# <para><samp>first para 
# </samp></para>
# <para><samp>second para</samp>.
# </para>
sub xml_paragraph($$$$$$$$$$$$)
{
    my $text = shift;
    my $align = shift;
    my $indent = shift;
    my $paragraph_command = shift;
    my $paragraph_command_formatted = shift;
    my $paragraph_number = shift;
    my $format = shift;
    my $item_nr = shift;
    my $enumerate_style = shift;
    my $number = shift;
    my $command_stack_at_end = shift;
    my $command_stack_at_begin = shift;

    # no para in multitables, caption and shortcaptions.
    my $top_stack = '';
    $top_stack = $command_stack_at_begin->[-1] if (scalar (@$command_stack_at_begin));
    return $text if ($top_stack eq 'multitable' or $top_stack eq 'shortcaption' or $top_stack eq 'caption' or $top_stack eq 'documentdescription');

    if ($text =~ /\S/)
    {
       return "<para>$text</para>";
    }
    return $text;
}

sub xml_preformatted($$$$$$$$$$$$)
{
    my $text = shift;
    my $pre_style = shift;
    my $class = shift;
    my $leading_command = shift;
    my $leading_command_formatted = shift;
    my $preformatted_number = shift;
    my $format = shift;
    my $item_nr = shift;
    my $enumerate_style = shift;
    my $number = shift;
    my $command_stack_at_end = shift;
    my $command_stack_at_begin = shift;

    return $text;
}

sub xml_misc_commands($$$$$)
{
   my $macro = shift;
   my $line = shift;
   my $args = shift;
   my $stack = shift;
   my $state = shift;

#print STDERR "$macro $line";
#print STDERR "ARGS @$args\n" if defined ($args);
    return ($macro, $line, undef) unless($xml_misc_command_output{$macro});

    my $value_name = '';
    my $value = '';
    if ($macro eq 'set' or $macro eq 'clear')
    {
        my $value_line = $line;
        if ($value_line =~ s/^\s+([\w\-]+)//)
        {
            $value_name = $1;
            if ($macro eq 'set')
            {
                $value = $value_line;
                chomp ($value);
                $value =~ s/^\s*//;
            }
        }
    }
    my $result_text = "<${macro}></${macro}>";
    if ($macro eq 'set' or $macro eq 'clear')
    {
        $result_text = "<${macro}value name=\"$value_name\">$value</${macro}value>\n";
    }
    if ($macro eq 'c' or $macro eq 'comment' and scalar(@$args))
    {
        my $comment_line = $args->[0];
        chomp ($comment_line);
        # makeinfo remove all the leading spaces
        $comment_line =~ s/^\s//;
        $result_text = &$comment ($comment_line);
    }
    if ($macro eq 'frenchspacing')
    {
       my $value = $args->[0];
       $value =~ s/\s*//g;
       $result_text = "<${macro} var=\"$value\"></${macro}>";
    }
    if (grep {$macro eq $_} @xml_misc_elements_with_arg)
    {
       my $arg = $args->[0];
       $arg =~ s/^\s*//;
       chomp($arg);
       $result_text = "<${macro}>".main::substitute_line($arg, "\@$macro")."</${macro}>\n";
    }
    if (exists($xml_misc_elements_with_arg_map{$macro}))
    {
       my $arg = $args->[0];
       $arg =~ s/^\s*//;
       chomp($arg);
       $result_text = "<$xml_misc_elements_with_arg_map{$macro}>".main::substitute_line($arg, "\@$macro")."</$xml_misc_elements_with_arg_map{$macro}>\n";
    }
    if ($macro eq 'setfilename')
    {
       my $arg = $args->[0];
       #$arg =~ s/^\s*//;
       #$arg =~ s/\s*$//;
       #$arg = main::substitute_line($arg, "\@$macro");
       if ($arg =~ /\S/)
       {
           $arg = get_conf('setfilename');
           $arg =~ s/\.[^\.]*$//;
           $result_text = "<${macro}>${arg}.xml</${macro}>\n";
       }
    }
    return ($macro, $line, $result_text);
}


sub xml_anchor_label($$)
{
    my $id = shift;
    my $anchor_text = shift;
    return '<anchor name="'. &$protect_text($anchor_text) . '"></anchor>';
}

sub xml_index_entry_command($$$$$)
{               
   my $command = shift;
   my $index_name = shift;
   my $label = shift;
   my $entry_texi = shift;
   my $entry_formatted = shift;

   return $label if (defined($label) and $label ne '');
   return xml_index_entry_label('','','',$main::index_prefix_to_name{$index_name}, '', '', $entry_formatted, {});
}

sub xml_index_entry_label($$$$$$$$$)
{   
    my $identifier = shift;
    my $preformatted = shift;
    my $formatted_entry = shift;
    my $index_name = shift;
    my $index_command = shift;
    my $texi_entry = shift;
    my $formatted_entry_reference = shift;
    my $in_region_not_in_output = shift;
    my $index_entry_ref = shift;
    

    return "<indexterm index=\"${index_name}\">${formatted_entry_reference}</indexterm>";
}

sub xml_listoffloats($$$)
{
    my $style_texi = shift;
    my $style = shift;
    my $float_entries = shift;
    # FIXME style, style_texi? Protected?
    return "<listoffloats type=\"$style\"></listoffloats>";
}

sub xml_acronym_like($$$$$$)
{
    my $command = shift;
    my $acronym_texi = shift;
    my $acronym_text = shift;
    my $with_explanation = shift;
    my $explanation_lines = shift;
    my $explanation_text = shift;
    my $explanation_simply_formatted = shift;

    $command = 'abbrev' if ($command eq 'abbr');
    my $opening = "<${command}><${command}word>$acronym_text</${command}word>";
    if ($with_explanation)
    {
        $opening .= "<${command}desc>$explanation_text</${command}desc>";
    }
    return $opening . "</${command}>";
}

sub xml_foot_line_and_ref($$$$$$$)
{
    my $number_in_doc = shift;
    my $number_in_page = shift;
    my $footnote_id = shift;
    my $place_id = shift;
    my $document_file = shift;
    my $footnote_file = shift;
    my $lines = shift;
    my $state = shift;

    my $result = '<footnote>';
    foreach my $line (@$lines)
    {
       $result .= $line;
    }
    return ([], $result . '</footnote>');
}

sub xml_image($$$$$$$$$$$$$)
{
    my $file = shift;
    my $base = shift;
    my $preformatted = shift;
    my $file_name = shift;
    my $alt = shift;
    my $width = shift;
    my $height = shift;
    my $raw_alt = shift;
    my $extension = shift;
    my $working_dir = shift;
    my $file_path = shift;
    my $in_paragraph = shift;
    my $file_locations = shift;

    $alt = '' if (!defined($alt));
    # dirty hack to avoid " that can be here because of a @verb 
    $alt =~ s/"/&quot;/g;

    $width = '' if (!defined($width));
    $height = '' if (!defined($height));

    my $tag = 'inlineimage';
    $tag = 'image' if ($preformatted or !$in_paragraph);

    return "<$tag width=\"$width\" height=\"$height\" name=\"". &$protect_text($base)."\" extension=\"$extension\"><alttext>$alt</alttext></$tag>";
}

sub xml_sp($$)
{
   my $number = shift;
   my $preformatted = shift;
   return "<sp lines=\"$number\"></sp>\n";
}

sub xml_quotation($$$$$)
{
    my $command = shift;
    my $text = shift;
    my $argument_text = shift;
    my $argument_text_texi = shift;
    my $authors = shift;
    return "<$command>\n" . $text . "</$command>\n";
}

sub xml_format_list_item_texi($$$$)
{
    my $format = shift;
    my $line = shift;
    my $prepended = shift;
    my $command = shift;

    my $result_line = undef;

    if (defined($command) and $command ne '' and !exists $special_list_commands{$format}->{$command} and $format ne 'itemize')
    {
        #@*table
        $line =~ s/^\s*//;
        $line =~ s/\s*$//;
        if (exists ($style_map{$command}))
        {
           $result_line = "\@$command\{$line\}\n";
        }
        elsif (exists ($things_map{$command}))
        {           
           $result_line = "\@$command\{\} $line\n";
        }           
        else        
        {           
           $result_line = "\@$command $line\n";
        }
    }

    return ($result_line, 0);
}

sub xml_list_item($$$$$$$$$)
{
    my $text = shift;
    my $format = shift;
    my $command = shift;
    my $formatted_command = shift;
    my $item_nr = shift;
    my $enumerate_style = shift;
    my $number = shift;
    my $prepended = shift;
    my $prepended_formatted = shift;

    return '<item>' . $text . "</item>\n";
}

sub xml_init_variables()
{
   @xml_multitable_stack = ();
   @xml_table_stack = ();
   $xml_current_section = undef;
   $Texi2HTML::THISDOC{'SPLIT'} = 0 if ($OUTPUT_FORMAT eq 'xml');
}

# row in multitable
sub xml_row($$;$$)
{
    my $text = shift;
    my $macro = shift;
    my $columnfractions = shift;
    my $prototype_row = shift;
    my $prototype_lengths = shift;
    my $column_number = shift;

    my $result = '';
    if ($macro eq 'headitem')
    {
         if ($xml_multitable_stack[-1] != 0)
         {
             $result .= "<thead>";
             $result = "</tbody>" . $result if ($xml_multitable_stack[-1] == 1);
             $xml_multitable_stack[-1] = 0;
         }
    }
    elsif ($xml_multitable_stack[-1] != 1)
    {
         $result .= "<tbody>";
         $result = "</thead>" . $result if ($xml_multitable_stack[-1] == 0);
         $xml_multitable_stack[-1] = 1;
    }
    $result .= "<row>$text</row>";
    
    return $result;
}

# cell in multitable
sub xml_cell($$;$$)
{
    my $text = shift;
    my $row_macro = shift;
    my $columnfractions = shift;
    my $prototype_row = shift;
    my $prototype_lengths = shift;
    my $column_number = shift;

    return "<entry>" . $text . '</entry>';
}

sub xml_table_list($$$$$$$$$)
{
    my $format_command = shift;
    my $text = shift;
    my $command = shift;
    my $formatted_command = shift;
# enumerate
    my $item_nr = shift;
    my $enumerate_style = shift;
# itemize
    my $prepended = shift;
    my $prepended_formatted = shift;
# multitable
    my $columnfractions = shift;
    my $prototype_row = shift;
    my $prototype_lengths = shift;
    my $number = shift;
    
    my $result = "<$format_command>";
    if ($format_command eq 'itemize')
    {
        my $itemfunction;
        $prepended_formatted =~ s/^\s*// if (defined($prepended_formatted));
        if (defined($formatted_command) and $formatted_command ne '')
        {
            $itemfunction = $formatted_command;
            $itemfunction .= " $prepended_formatted" if (defined($prepended_formatted) and $prepended_formatted ne '');
        }
        elsif (defined($prepended_formatted))
        {
            $itemfunction = $prepended_formatted;
        }
        $itemfunction = "&bullet;" if (!defined($itemfunction) or 
            $itemfunction eq '');
        $result .=  "<itemfunction>$itemfunction</itemfunction>";
    }
    elsif ($format_command eq 'enumerate')
    {
        $result = "<$format_command first=\"$enumerate_style\">";
    }
    elsif ($format_command eq 'multitable')
    {
       my $fractions;
       my $multiply = 1;
       if (defined($columnfractions) and (ref($columnfractions) eq 'ARRAY')
           and scalar(@$columnfractions))
       {
           $fractions = [ @$columnfractions ];
           $multiply = 100;
       }
       elsif (defined($prototype_lengths) and (ref($prototype_lengths) eq 'ARRAY')
           and scalar(@$prototype_lengths))
       {
           $fractions = [ @$prototype_lengths ];
       }
       
       if (defined ($fractions))
       {
           foreach my $fraction (@$fractions)
           {
               $result .= "<columnfraction>".($fraction*$multiply)."</columnfraction>\n";
           }
       }
       $text .= "</tbody>" if ($xml_multitable_stack[-1] == 1);
       $text .= "</thead>" if ($xml_multitable_stack[-1] == 0);
       pop @xml_multitable_stack;
    }
    elsif ($format_command =~ /^(v|f)?table$/)
    {
       $result = '<table>';
       $text .= '</tableitem>' if ($xml_table_stack[-1] == 1);
       pop @xml_table_stack;
       return $result . "$text</table>\n";
    }
    return $result . "$text</$format_command>\n";
}

sub xml_begin_format_texi($$$)
{
    my $command = shift;
    my $line = shift;
    my $state = shift;

    push (@xml_multitable_stack, -1) if ($command eq 'multitable');
    push (@xml_table_stack, 0) if ($command =~ /^(v|f)?table/);
    return $line;
}

sub xml_def_line($$$$$$$$$$$$$$$)
{
   my $category_prepared = shift;
   my $name = shift;
   my $type = shift;
   my $arguments = shift;
   my $index_label = shift;
   my $arguments_array = shift;
   my $arguments_type_array = shift;
   my $unformatted_arguments_array = shift;
   my $command = shift;
   my $class_name = shift;
   my $category = shift;
   my $class = shift;
   my $style = shift;
   my $original_command = shift;

   my $result = "<definitionterm><indexterm index=\""
    .$main::index_prefix_to_name{$style}."\">$class_name</indexterm>";

   my %arguments = ( 'prepared_category' => $category_prepared,
         'category' => $category,
         'name' => $name,
         'type' => $type,
         'class' => $class
    );
   foreach my $type (keys(%arguments))
   {
       $arguments{$type} = '' if (!defined($arguments{$type}));
   }

   foreach my $mandatory_arg (@{$def_format_xml{$command}})
   {
       my $elem = $mandatory_arg->[0];
       $result .= "<def$elem>$arguments{$mandatory_arg->[1]}</def$elem>";
   }

   my $params = '';
   my @types = @$arguments_type_array;
   foreach my $arg (@$arguments_array)
   {
       my $type = shift @types;
       if (grep {$_ eq $type} ('param', 'paramtype', 'delimiter'))
       {
            $result .= "<def$type>$arg</def$type>";
       }
   }

   $result .= "</definitionterm>\n";
   return $result;
}

# FIXME 
# @deffn 
# @c comment
# @end deffn
# leads to the creation of a <definitionitem> with a comment within, 
# while there should be no definitionitem 
sub xml_def_item($$)
{
    my $text = shift;
    my $only_inter_item_commands = shift;

    if ($text =~ /\S/)
    {
       return '<definitionitem>' . $text . '</definitionitem>' unless $only_inter_item_commands;
       return $text;
    }
    return '';
}

sub xml_def($)
{
   my $text = shift;
   return '<definition>'.$text.'</definition>';
}

sub xml_index_summary($$)
{
    my $alpha = shift;
    my $nonalpha = shift;
    return '';
}

sub xml_printindex($$)
{
    my $name = shift;
    my $printindex = shift;
    return "<printindex>$name</printindex>\n";
}

sub xml_any_ref($$)
{
    my $type = shift;
    my $args = shift;
    my $result = '';
    if ($type eq 'pxref')
    {
        $result = gdt('see ',{'duplicate'=>1});
    }
    elsif ($type eq 'xref' or $type eq 'inforef')
    {
        $result = gdt('See ',{'duplicate'=>1});
    }
    if ($type eq 'inforef')
    {
        $result .= "<inforef><inforefnodename>$args->[0]</inforefnodename>";
        $result .= "<inforefrefname>$args->[1]</inforefrefname>" if ($args->[1] ne '');
        $result .= "<inforefinfoname>$args->[2]</inforefinfoname></inforef>"
    }
    else
    {
        $result .= "<xref><xrefnodename>$args->[0]</xrefnodename>";
        $result .= "<xrefinfoname>$args->[1]</xrefinfoname>" if ($args->[1] ne '');
        $result .= "<xrefprinteddesc>$args->[2]</xrefprinteddesc>" if ($args->[2] ne '');
        $result .= "<xrefinfofile>$args->[3]</xrefinfofile>" if ($args->[3] ne '');
        $result .= "<xrefprintedname>$args->[4]</xrefprintedname>" if ($args->[4] ne '');
        $result .= '</xref>';
    }
    return $result;
}

sub xml_external_ref($$$$$$$$$)
{
    my $type = shift;
    my $section = shift;
    my $book = shift;
    my $file = shift;
    my $href = shift;
    my $cross_ref = shift;
    my $args_texi = shift;
    my $formatted_args = shift;
    my $node = shift;
    
    return xml_any_ref ($type, $formatted_args);
}

sub xml_internal_ref($$$$$)
{
    my $type = shift;
    my $href = shift;
    my $short_name = shift;
    my $name = shift;
    my $is_section = shift;
    my $args_texi = shift;
    my $formatted_args = shift;

    return xml_any_ref ($type, $formatted_args);
}

sub xml_table_item($$$$$$$)
{
    my $text = shift;
    my $index_label = shift;
    my $format = shift;
    my $command = shift;
#    my $formatted_command = shift;
    my $style_stack = shift;
#    my $text_formatted = shift;
#    my $text_formatted_leading_spaces = shift;
#    my $text_formatted_trailing_spaces = shift;
    my $item_cmd = shift;
    my $formatted_index_entry = shift;


#    $formatted_command = '' if (!defined($formatted_command));
#
#    if (defined($text_formatted))
#    {
#        $text_item = $text_formatted_leading_spaces . $text_formatted .$text_formatted_trailing_spaces;
#    }
#    else
#    {
#        $text_item = $text;
#    }

    my $result = '';
    if ($item_cmd eq 'item')
    {
        $result .= '</tableitem>' if ($xml_table_stack[-1] == 1);
        $xml_table_stack[-1] = 1;
        $result .= '<tableitem>';
    }
    $result .= '<tableterm>';
    #print STDERR "$text | $format | $command | $formatted_command | $text_formatted | $item_cmd \n";
    my $indexterm = '';
#print STDERR "FFFFFFFFFFFFFFFFf   `$index_label' `$text'\n";
    if ($format =~ /^(v|f)/)
    {
#        my $index_prefix = $1;
#        $indexterm = $text;
#        $indexterm =~ s/^\s*//;
#        $result .= "<indexterm index=\"$main::index_prefix_to_name{$index_prefix}\">$formatted_index_entry</indexterm>";
        $result .= "$index_label";
    }
    $result .= $text ."</tableterm>\n";
    return $result;
}

sub xml_table_line($)
{
    my $text = shift;
    my $only_inter_item_commands = shift;
    my $before_items = shift;

    if ($text =~ /\S/)
    {
        return "<item>$text</item>" unless $only_inter_item_commands;
        return $text;
    }
    else
    {
        return '';
    }
}

sub xml_caption_shortcaption($)
{
    my $float = shift;
    my $caption_lines;
    my $shortcaption_lines;
    if (defined($float->{'caption_texi'}))
    {
        @$caption_lines = @{$float->{'caption_texi'}};
    }
    if (defined($float->{'shortcaption_texi'}))
    {
        @$shortcaption_lines = @{$float->{'shortcaption_texi'}};
    }
    return ($caption_lines, $shortcaption_lines);
}

sub xml_caption_shortcaption_command($$$)
{
   my $command = shift;
   my $text = shift;
   my $texi_lines = shift;
   my $float_element = shift;

   if ($text =~ /\S/)
   {
      return "<$command>$text</$command>";
   }
   return '';
}

sub xml_float($$$$$)
{
    my $text = shift;
    my $float = shift;
    my $caption = shift;
    my $shortcaption = shift;

    # FIXME don't use the texi, but a normalized node name
    my $label_texi = $float->{'texi'};
    $label_texi = '' if (!defined($label_texi));
    my $result = "<float name=\"$label_texi\">\n";
    my $style = $float->{'style'};
    $style = '' if (!defined($style));
    $result .= "<floattype>$style</floattype>\n";
    $result .= "<floatpos></floatpos>\n";
    $result .= $text;
    return $result."</float>\n";
}

sub xml_normal_text($$$$$$$;$)
{
   my $text = shift;
   my $in_raw_text = shift;
   my $in_preformatted = shift;
   my $in_code = shift;
   my $in_math = shift;
   my $in_simple = shift;
#print STDERR "Bug: in_raw_text in_simple $text\n" if ($in_raw_text and $in_simple);
   my $style_stack = shift;
   my $state = shift;

   $text = &$protect_text($text) unless($in_raw_text);

   if (! $in_code and !$in_preformatted and !$in_raw_text)
   {
       $text =~ s/---/\&mdash\;/g;
       $text =~ s/--/\&ndash\;/g;
       $text =~ s/``/\&ldquo\;/g;
       $text =~ s/''/\&rdquo\;/g;
   }
   return $text;
}

sub xml_paragraph_style_command($$)
{
    my $format = shift;
    my $text = shift;
    return "<$format>$text</$format>" if ($format eq 'center');
    return $text;
}

sub xml_raw($$)
{
    my $style = shift;
    my $text = shift;

    if ($style eq 'verbatim' or $style eq 'verbatiminclude')
    {
        return '<verbatim xml:space="preserve">' . &$protect_text($text) . '</verbatim>';
    }
    return '' unless (grep {$style eq $_} @EXPAND);
    if ($style eq 'xml')
    {
        chomp ($text);
        return $text;
    }
    else
    {
        main::msg_warn ("Raw style $style not handled", $Texi2HTML::THISDOC{'line_nr'});
        return &$protect_text($text);
    }
}

sub xml_cartouche($$)
{
    my $text = shift;

    return "<cartouche>$text</cartouche>";
}

sub xml_noop
{
    return '';
}

1;

require "$T2H_HOME/formats/xml.init"
    if ($0 =~ /\.pl$/ &&
        -e "$T2H_HOME/formats/xml.init" && -r "$T2H_HOME/formats/xml.init");

# @INIT_PLAINTEXT@
#+##############################################################################
#
# plaintext.init: convert to plaintext
#
#    Copyright (C) 2009  Patrice Dumas <pertusus@free.fr>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
#    02110-1301  USA
#
#-##############################################################################

use strict;

sub plaintext_default_load(;$)
{
my $from_command_line = shift;
info_default_load();

$SHOW_MENU = 0;
$OUT = '-' unless(defined($OUT) and $OUT !~ m:/$:);
$HEADERS = 0;
@T2H_FORMAT_EXPAND = ('plaintext');

$print_page_head   = \&plaintext_default_print_page_head;
$print_page_foot   = \&plaintest_default_print_page_foot;
$element_heading   = \&plaintext_default_element_heading;
$image             = \&plaintext_default_image;
$print_index       = \&plaintext_default_print_index;

}

sub plaintext_default_print_page_head($)
{
   my $fh = shift;
}

sub plaintest_default_print_page_foot($)
{
   my $fh = shift;
}

sub plaintext_default_element_heading($$$$$$$$$$$$)
{
    my $info_result = &Texi2HTML::Config::info_default_element_heading(@_);
    my $element = shift;
    my $command = shift;
    my $texi_line = shift;
    my $line = shift;
    my $in_preformatted = shift;
    my $one_section = shift;
    my $element_heading = shift;
    my $first_in_page = shift;
    my $is_top = shift;
    my $previous_is_top = shift;
    my $command_line = shift;
    my $element_id = shift;
    my $new_element = shift;

    return $info_result if (!$element->{'node'});
    return '';    
}

sub plaintext_default_image($$$$$$$$$$$$$$$$$)
{
    my $file = shift;
    my $base = shift;
    my $preformatted = shift;
    my $file_name = shift;
    my $alt = shift;
    my $width = shift;
    my $height = shift;
    my $raw_alt = shift;
    my $extension = shift;
    my $working_dir = shift;
    my $file_path = shift;
    my $in_paragraph = shift;
    my $file_locations = shift;
    my $base_simple_format = shift;
    my $extension_simple_format = shift;
    my $file_name_simple_format = shift;
    my $line_nr = shift;

    my $txt_path;
    my $found_file;

    my @extensions = @IMAGE_EXTENSIONS;
    if (defined($extension) and ($extension ne ''))
    {
        unshift @extensions, ".$extension";
        unshift @extensions, "$extension";
    }
    else
    {
        $extension = undef;
    }
    my $file_found_index = undef;
    my $file_index = 0;

    foreach my $file_location (@$file_locations)
    {
        my ($file_located, $path, $file_simple_format) = @$file_location;
        my $extension = shift @extensions;
        if (defined($path))
        {
           if ($extension eq 'txt' and !defined($txt_path))
           {
              $txt_path = $path;
           }
           elsif (!defined($found_file))
           {
              $found_file = [$file_located, $extension, $file_simple_format];
              $file_found_index = $file_index;
           }
        }
        $file_index++;
    }

    my $text = '';
    if (defined($txt_path))
    {
       if (open(TXT, "<$txt_path"))
       {
          if (defined($Texi2HTML::THISDOC{'IN_ENCODING'}) and $USE_UNICODE)
          {
              binmode(TXT, ":encoding($Texi2HTML::THISDOC{'IN_ENCODING'})");
          }
          $text='[' if ($in_paragraph or $preformatted);
          while (my $img_txt = <TXT>)
          {
              $text .= $img_txt;
          }
          $text .= ']' if ($in_paragraph or $preformatted);
          close(TXT);
       }
       else
       {
          main::line_warn (sprintf(__("\@image file `%s' unreadable: %s"), $txt_path, $!), $line_nr);
       }
    }
    elsif (!defined($found_file))
    {
        main::line_warn (sprintf(__("Cannot find \@image file `%s.txt'"), $base), $line_nr);
    }
    return $text;
}

sub plaintext_default_print_index($$)
{
    my $text = shift;
    my $name = shift;
    return '';
}

1;

require "$T2H_HOME/formats/plaintext.init"
    if ($0 =~ /\.pl$/ &&
        -e "$T2H_HOME/formats/plaintext.init" && -r "$T2H_HOME/formats/plaintext.init");

my $translation_file = 'translations.pl'; # file containing all the translations
my $T2H_OBSOLETE_STRINGS;

# leave this within comments, and keep the require statement
# This way, you can directly run texi2html.pl, 
# if $T2H_HOME/translations.pl exists.
#
# @T2H_TRANSLATIONS_FILE@
# Automatically generated file. Edit the .po file instead.
$LANGUAGES->{'nl'} = {
                       '  The buttons in the navigation panels have the following meaning:' => '',
                       '  where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '',
                       ' Up ' => '',
                       '(outside of any element)' => '',
                       '(outside of any node)' => '',
                       '@b{{quotation_arg}:} ' => '',
                       '@center --- @emph{{author}}
' => '',
                       '@cite{{book}}' => '',
                       '@{No value for `{value}\'@}' => '',
                       'About' => '',
                       'About (help)' => '',
                       'About This Document' => 'No translation available!',
                       'April' => 'April',
                       'August' => 'Augustus',
                       'Back' => '',
                       'Back section in previous file' => '',
                       'Beginning of this chapter or previous chapter' => '',
                       'Button' => '',
                       'Contents' => '',
                       'Cover (top) of document' => '',
                       'Current' => '',
                       'Current Position' => '',
                       'Current section' => '',
                       'December' => 'December',
                       'FastBack' => '',
                       'FastForward' => '',
                       'February' => 'Februari',
                       'First' => '',
                       'First section in reading order' => '',
                       'Following' => '',
                       'Following node' => '',
                       'Footnotes' => 'No translation available!',
                       'Forward' => '',
                       'Forward section in next file' => '',
                       'From 1.2.3 go to' => '',
                       'Go to' => '',
                       'Index' => 'Index',
                       'Index Entry' => '',
                       'January' => 'Januari',
                       'July' => 'Juli',
                       'Jump to' => '',
                       'June' => 'Juni',
                       'Last' => '',
                       'Last section in reading order' => '',
                       'March' => 'Maart',
                       'May' => 'Mei',
                       'Menu:' => '',
                       'Name' => '',
                       'Next' => '',
                       'Next chapter' => '',
                       'Next file' => '',
                       'Next node' => '',
                       'Next section in reading order' => '',
                       'Next section on same level' => '',
                       'NextFile' => '',
                       'Node following in node reading order' => '',
                       'Node up' => '',
                       'NodeNext' => '',
                       'NodePrev' => '',
                       'NodeUp' => '',
                       'November' => 'November',
                       'October' => 'Oktober',
                       'Overview' => '',
                       'Prev' => '',
                       'PrevFile' => '',
                       'Previous' => '',
                       'Previous file' => '',
                       'Previous node' => '',
                       'Previous section in reading order' => '',
                       'Previous section on same level' => '',
                       'Section' => '',
                       'Section One' => '',
                       'See ' => '',
                       'See @cite{{book}}' => '',
                       'See `{section}\'' => '',
                       'See `{section}\' in @cite{{book}}' => '',
                       'See section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'See section {reference_name}' => '',
                       'See {reference_name}' => '',
                       'See {reference}' => '',
                       'See {reference} in @cite{{book}}' => '',
                       'See {ref}' => '',
                       'See {title_ref}' => '',
                       'September' => 'September',
                       'Short Table of Contents' => 'Korte inhoudsopgave',
                       'Short table of contents' => '',
                       'Subsection One-Four' => '',
                       'Subsection One-One' => '',
                       'Subsection One-Three' => '',
                       'Subsection One-Two' => '',
                       'Subsubsection One-Two-Four' => '',
                       'Subsubsection One-Two-One' => '',
                       'Subsubsection One-Two-Three' => '',
                       'Subsubsection One-Two-Two' => '',
                       'Table of Contents' => 'Inhoudsopgave',
                       'Table of contents' => '',
                       'The node you are looking for is at {href}.' => '',
                       'This' => '',
                       'This document was generated on @i{{date}} using @uref{{program_homepage}, @i{{program}}}.' => '',
                       'This document was generated using @uref{{program_homepage}, @emph{{program}}}.' => '',
                       'Top' => '',
                       'Untitled Document' => '',
                       'Up' => '',
                       'Up node' => '',
                       'Up section' => '',
                       '`{section}\'' => '',
                       '`{section}\' in @cite{{book}}' => '',
                       'current' => '',
                       'on @emph{{date}}' => '',
                       'section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'see ' => '',
                       'see @cite{{book}}' => '',
                       'see `{section}\'' => '',
                       'see `{section}\' in @cite{{book}}' => '',
                       'see section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'see section {reference_name}' => '',
                       'see {reference_name}' => '',
                       'see {reference}' => '',
                       'see {reference} in @cite{{book}}' => '',
                       'see {ref}' => '',
                       'see {title_ref}' => '',
                       '{acronym_like} ({explanation})' => '',
                       '{month} {day}, {year}' => '',
                       '{name} of {class}' => '',
                       '{name} on {class}' => '',
                       '{reference_name}' => '',
                       '{reference}' => '',
                       '{reference} in @cite{{book}}' => '',
                       '{ref}' => '',
                       '{style} {number}' => '',
                       '{style}: {caption_first_line}' => '',
                       '{style}: {shortcaption_first_line}' => '',
                       '{title_ref}' => ''
                     };
# Automatically generated file. Edit the .po file instead.
$LANGUAGES->{'ja'} = {
                       '  The buttons in the navigation panels have the following meaning:' => 'ナビゲーションパネル中のボタンには以下の意味があります。',
                       '  where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '@strong{例}では、以下に示す構造を持つ文書の@strong{1.2.3項}を現在位置に仮定しています。',
                       ' Up ' => '上',
                       '(outside of any element)' => '',
                       '(outside of any node)' => '',
                       '@b{{quotation_arg}:} ' => '',
                       '@center --- @emph{{author}}
' => '',
                       '@cite{{book}}' => '',
                       '@{No value for `{value}\'@}' => '',
                       'About' => '',
                       'About (help)' => '',
                       'About This Document' => 'この文書について',
                       'April' => '4月',
                       'August' => '8月',
                       'Back' => '',
                       'Back section in previous file' => '',
                       'Beginning of this chapter or previous chapter' => '',
                       'Button' => 'ボタン',
                       'Contents' => '目次',
                       'Cover (top) of document' => '',
                       'Current' => '',
                       'Current Position' => '現在位置',
                       'Current section' => '',
                       'December' => '12月',
                       'FastBack' => '',
                       'FastForward' => '',
                       'February' => '2月',
                       'First' => '',
                       'First section in reading order' => '',
                       'Following' => '',
                       'Following node' => '',
                       'Footnotes' => '脚注',
                       'Forward' => '',
                       'Forward section in next file' => '',
                       'From 1.2.3 go to' => '1.2.3項からの移動先',
                       'Go to' => '移動先',
                       'Index' => '見出し',
                       'Index Entry' => '見出し一覧',
                       'January' => '1月',
                       'July' => '7月',
                       'Jump to' => '移動',
                       'June' => '6月',
                       'Last' => '',
                       'Last section in reading order' => '',
                       'March' => '3月',
                       'May' => '5月',
                       'Menu:' => 'メニュー',
                       'Name' => '名称',
                       'Next' => '次',
                       'Next chapter' => '',
                       'Next file' => '',
                       'Next node' => '',
                       'Next section in reading order' => '',
                       'Next section on same level' => '',
                       'NextFile' => '',
                       'Node following in node reading order' => '',
                       'Node up' => '',
                       'NodeNext' => '',
                       'NodePrev' => '',
                       'NodeUp' => '',
                       'November' => '11月',
                       'October' => '10月',
                       'Overview' => '概要',
                       'Prev' => '前',
                       'PrevFile' => '',
                       'Previous' => '',
                       'Previous file' => '',
                       'Previous node' => '',
                       'Previous section in reading order' => '',
                       'Previous section on same level' => '',
                       'Section' => '項',
                       'Section One' => '第1項',
                       'See ' => '',
                       'See @cite{{book}}' => '',
                       'See `{section}\'' => '項',
                       'See `{section}\' in @cite{{book}}' => '@cite{{book}}の `{section}\' ',
                       'See section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'See section {reference_name}' => '',
                       'See {reference_name}' => '',
                       'See {reference}' => '',
                       'See {reference} in @cite{{book}}' => '{node_file_href} @cite{{book}}参照',
                       'See {ref}' => '',
                       'See {title_ref}' => '',
                       'September' => '9月',
                       'Short Table of Contents' => '簡略化した目次',
                       'Short table of contents' => '',
                       'Subsection One-Four' => '第1.4項',
                       'Subsection One-One' => '第1.1項',
                       'Subsection One-Three' => '第1.3項',
                       'Subsection One-Two' => '第1.2項',
                       'Subsubsection One-Two-Four' => '第1.2.4項',
                       'Subsubsection One-Two-One' => '第1.2.1項',
                       'Subsubsection One-Two-Three' => '第1.2.3項',
                       'Subsubsection One-Two-Two' => '第1.2.2項',
                       'Table of Contents' => '目次',
                       'Table of contents' => '',
                       'The node you are looking for is at {href}.' => '',
                       'This' => '',
                       'This document was generated on @i{{date}} using @uref{{program_homepage}, @i{{program}}}.' => 'この文書は@emph{{date}}に@uref{{program_homepage}, @emph{{program}}}を用いて生成されました。',
                       'This document was generated using @uref{{program_homepage}, @emph{{program}}}.' => 'この文書は@uref{{program_homepage}, @emph{{program}}}を用いて生成されました。',
                       'Top' => '冒頭',
                       'Untitled Document' => '無題の文書',
                       'Up' => '',
                       'Up node' => '',
                       'Up section' => '',
                       '`{section}\'' => '項',
                       '`{section}\' in @cite{{book}}' => '@cite{{book}}の `{section}\' ',
                       'current' => '現在位置',
                       'on @emph{{date}}' => '@emph{{date}}',
                       'section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'see ' => '',
                       'see @cite{{book}}' => '',
                       'see `{section}\'' => '',
                       'see `{section}\' in @cite{{book}}' => '@cite{{book}}の `{section}\' ',
                       'see section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'see section {reference_name}' => '',
                       'see {reference_name}' => '',
                       'see {reference}' => '{node_file_href}参照',
                       'see {reference} in @cite{{book}}' => '{node_file_href} @cite{{book}}参照',
                       'see {ref}' => '',
                       'see {title_ref}' => '',
                       '{acronym_like} ({explanation})' => '',
                       '{month} {day}, {year}' => '',
                       '{name} of {class}' => '',
                       '{name} on {class}' => '',
                       '{reference_name}' => '',
                       '{reference}' => '',
                       '{reference} in @cite{{book}}' => '{node_file_href} @cite{{book}}参照',
                       '{ref}' => '',
                       '{style} {number}' => '',
                       '{style}: {caption_first_line}' => '',
                       '{style}: {shortcaption_first_line}' => '',
                       '{title_ref}' => ''
                     };
# Automatically generated file. Edit the .po file instead.
$LANGUAGES->{'fr'} = {
                       '  The buttons in the navigation panels have the following meaning:' => '  Les boutons de navigation ont la signification suivante :',
                       '  where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '  Dans cet exemple on est @`a @strong{ Sous sous section un-deux-trois } dans un document dont la structure est :',
                       ' Up ' => 'Plus haut',
                       '(outside of any element)' => '',
                       '(outside of any node)' => '',
                       '@b{{quotation_arg}:} ' => '',
                       '@center --- @emph{{author}}
' => '',
                       '@cite{{book}}' => '',
                       '@{No value for `{value}\'@}' => '',
                       'About' => 'A propos',
                       'About (help)' => 'A propos (page d\'aide)',
                       'About This Document' => 'A propos de ce document',
                       'April' => 'avril',
                       'August' => 'ao@^ut',
                       'Back' => 'Retour',
                       'Back section in previous file' => '',
                       'Beginning of this chapter or previous chapter' => 'D@\'ebut de ce chapitre ou chapitre pr@\'ec@\'edent',
                       'Button' => 'Bouton',
                       'Contents' => 'Table des mati@`eres',
                       'Cover (top) of document' => 'Couverture (top) du document',
                       'Current' => '',
                       'Current Position' => 'Position',
                       'Current section' => 'Section actuelle',
                       'December' => 'd@\'ecembre',
                       'FastBack' => 'RetourRapide',
                       'FastForward' => 'AvanceRapide',
                       'February' => 'f@\'evrier',
                       'First' => 'Premier',
                       'First section in reading order' => 'Premi@`e section dans l\'ordre de lecture',
                       'Following' => 'Suivant',
                       'Following node' => 'N@oe{}ud suivant',
                       'Footnotes' => 'Notes de bas de page',
                       'Forward' => 'Avant',
                       'Forward section in next file' => '',
                       'From 1.2.3 go to' => 'Depuis 1.2.3 aller @`a',
                       'Go to' => 'Aller @`a',
                       'Index' => 'Index',
                       'Index Entry' => 'Entr@\'ee d\'index',
                       'January' => 'janvier',
                       'July' => 'juillet',
                       'Jump to' => 'Aller @`a',
                       'June' => 'juin',
                       'Last' => 'Dernier',
                       'Last section in reading order' => 'Derni@`ere section dans l\'ordre de lecture',
                       'March' => 'mars',
                       'May' => 'mai',
                       'Menu:' => 'Menu@ :',
                       'Name' => 'Nom',
                       'Next' => 'Suivant',
                       'Next chapter' => 'Chapitre suivant',
                       'Next file' => 'Fichier suivant',
                       'Next node' => 'N@oe{}ud suivant',
                       'Next section in reading order' => 'Section suivante dans l\'ordre de lecture',
                       'Next section on same level' => 'Section suivante au m@^eme niveau',
                       'NextFile' => 'FichierSuivant',
                       'Node following in node reading order' => 'N@oe{}ud suivant dans l\'ordre de lecture',
                       'Node up' => 'N@oe{}ud au dessus',
                       'NodeNext' => 'N@oe{}udSuivant',
                       'NodePrev' => 'N@oe{}udPr@\'ec@\'edent',
                       'NodeUp' => 'N@oe{}udMonter',
                       'November' => 'novembre',
                       'October' => 'octobre',
                       'Overview' => 'Vue d\'ensemble',
                       'Prev' => 'Pr@\'ec@\'edent',
                       'PrevFile' => '',
                       'Previous' => '',
                       'Previous file' => 'Fichier pr@\'ec@\'edent',
                       'Previous node' => 'N@oe{}ud pr@\'ec@\'edent',
                       'Previous section in reading order' => 'Section pr@\'ec@\'edente dans l\'ordre de lecture',
                       'Previous section on same level' => 'Section pr@\'ec@\'edente au m@^eme niveau',
                       'Section' => '',
                       'Section One' => 'Section un',
                       'See ' => '',
                       'See @cite{{book}}' => 'Voir @cite{{book}}',
                       'See `{section}\'' => 'Section sup@\'erieure',
                       'See `{section}\' in @cite{{book}}' => 'Voir la section `{section}\' dans @cite{{book}}',
                       'See section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'See section {reference_name}' => 'Voir la section {reference_name}',
                       'See {node_file_href}' => 'Voir {node_file_href}',
                       'See {node_file_href} section `{section}\' in @cite{{book}}' => 'Voir {node_file_href} section `{section}\' dans @cite{{book}}',
                       'See {reference_name}' => 'Voir {reference_name}',
                       'See {reference}' => 'Voir {reference_name}',
                       'See {reference} in @cite{{book}}' => 'Voir {node_file_href} @cite{{book}}',
                       'See {ref}' => '',
                       'See {title_ref}' => '',
                       'September' => 'septembre',
                       'Short Table of Contents' => 'R@\'esum@\'e du contenu',
                       'Short table of contents' => 'R@\'esum@\'e du contenu',
                       'Subsection One-Four' => 'Sous section un-quatre',
                       'Subsection One-One' => 'Sous section un-un',
                       'Subsection One-Three' => 'Sous section un-trois',
                       'Subsection One-Two' => 'Sous section un-deux',
                       'Subsubsection One-Two-Four' => 'Sous sous section un-deux-quatre',
                       'Subsubsection One-Two-One' => 'Sous sous section un-deux-un',
                       'Subsubsection One-Two-Three' => 'Sous sous section un-deux-trois',
                       'Subsubsection One-Two-Two' => 'Sous sous section un-deux-deux',
                       'Table of Contents' => 'Table des mati@`eres',
                       'Table of contents' => 'Table des mati@`eres',
                       'The node you are looking for is at {href}.' => 'Le n@oe{}ud que vous recherchez est ici@ : {href}.',
                       'This' => 'Ici',
                       'This document was generated on @i{{date}} using @uref{{program_homepage}, @i{{program}}}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e le @emph{{date}} en utilisant @uref{{program_homepage}, @emph{{program}}}',
                       'This document was generated using @uref{{program_homepage}, @emph{{program}}}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e en utilisant @uref{{program_homepage}, @emph{{program}}}.',
                       'Top' => 'Racine',
                       'Untitled Document' => 'Document sans titre',
                       'Up' => 'Monter',
                       'Up node' => 'N@oe{}ud au dessus',
                       'Up section' => 'Section sup@\'erieure',
                       '`{section}\'' => 'Section sup@\'erieure',
                       '`{section}\' in @cite{{book}}' => 'section `{section}\' dans @cite{{book}}',
                       'current' => 'courante',
                       'on @emph{{date}}' => 'le @emph{{date}}',
                       'section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'see ' => '',
                       'see @cite{{book}}' => 'voir @cite{{book}}',
                       'see `{section}\'' => 'Section sup@\'erieure',
                       'see `{section}\' in @cite{{book}}' => 'section `{section}\' dans @cite{{book}}',
                       'see section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'see section `{section}\' in @cite{{book}}' => 'voir la section `{section}\' dans @cite{{book}}',
                       'see section {reference_name}' => 'voir la section {reference_name}',
                       'see {node_file_href}' => 'voir {node_file_href}',
                       'see {node_file_href} section `{section}\' in @cite{{book}}' => 'voir {node_file_href} section `{section}\' dans @cite{{book}}',
                       'see {reference_name}' => 'voir {reference_name}',
                       'see {reference}' => 'voir {reference_name}',
                       'see {reference} in @cite{{book}}' => 'voir {node_file_href} @cite{{book}}',
                       'see {ref}' => '',
                       'see {title_ref}' => '',
                       '{acronym_like} ({explanation})' => '',
                       '{month} {day}, {year}' => 'le {day} {month} {year}',
                       '{name} of {class}' => '{name} de {class}',
                       '{name} on {class}' => '{name} de {class}',
                       '{node_file_href} section `{section}\' in @cite{{book}}' => '{node_file_href} section `{section}\' dans @cite{{book}}',
                       '{reference_name}' => '',
                       '{reference}' => 'voir {reference_name}',
                       '{reference} in @cite{{book}}' => 'voir @cite{{book}}',
                       '{ref}' => '',
                       '{style} {number}' => '',
                       '{style}: {caption_first_line}' => '',
                       '{style}: {shortcaption_first_line}' => '',
                       '{title_ref}' => ''
                     };
# Automatically generated file. Edit the .po file instead.
$LANGUAGES->{'de'} = {
                       '  The buttons in the navigation panels have the following meaning:' => ' Die Links in der Navigationsleiste haben die folgende Bedeutung: ',
                       '  where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => ' wobei das @strong{ Beispiel } annimmt, dass die aktuelle Position bei @strong{ Unterabschnitt 1-2-3 } in einem Dokument mit folgender Struktur liegt:',
                       ' Up ' => ' Nach oben ',
                       '(outside of any element)' => '',
                       '(outside of any node)' => '',
                       '@b{{quotation_arg}:} ' => '@b{{quotation_arg}:} ',
                       '@center --- @emph{{author}}
' => '',
                       '@cite{{book}}' => '@cite{{book}}',
                       '@{No value for `{value}\'@}' => '',
                       'About' => '@"Uber',
                       'About (help)' => '@"Uber (Hilfe)',
                       'About This Document' => '@"Uber dieses Dokument',
                       'April' => 'April',
                       'August' => 'August',
                       'Back' => 'Zur@"uck',
                       'Back section in previous file' => '',
                       'Beginning of this chapter or previous chapter' => 'Anfang dieses oder des letzten Kapitels',
                       'Button' => '',
                       'Contents' => 'Inhalt',
                       'Cover (top) of document' => 'Titelseite des Dokuments',
                       'Current' => '',
                       'Current Position' => 'Aktuelle Position',
                       'Current section' => 'Aktueller Abschnitt',
                       'December' => 'Dezember',
                       'FastBack' => '',
                       'FastForward' => '',
                       'February' => 'Februar',
                       'First' => '',
                       'First section in reading order' => 'Erster Abschnitt in Lesereihenfolge',
                       'Following' => '',
                       'Following node' => 'N@"achster Knoten',
                       'Footnotes' => 'Fu@ss{}noten',
                       'Forward' => 'Nach vorne',
                       'Forward section in next file' => '',
                       'From 1.2.3 go to' => 'Von 1.2.3 gehe zu',
                       'Go to' => 'Gehe zu',
                       'Index' => 'Index',
                       'Index Entry' => 'Indexeintrag',
                       'January' => 'Januar',
                       'July' => 'Juli',
                       'Jump to' => 'Springe zu',
                       'June' => 'Juni',
                       'Last' => '',
                       'Last section in reading order' => 'Letzter Abschnitt in Lesereihenfolge',
                       'March' => 'M@"arz',
                       'May' => 'Mai',
                       'Menu:' => 'Auswahl:',
                       'Name' => 'Name',
                       'Next' => '',
                       'Next chapter' => 'N@"achstes Kapitel',
                       'Next file' => '',
                       'Next node' => 'N@"achster Knoten',
                       'Next section in reading order' => 'N@"achster Abschnitt in Lesereihenfolge',
                       'Next section on same level' => 'N@"achster Abschitt derselben Ebene',
                       'NextFile' => '',
                       'Node following in node reading order' => 'N@"achster Abschnitt in Lesereihenfolge',
                       'Node up' => 'Knoten nach oben',
                       'NodeNext' => '',
                       'NodePrev' => '',
                       'NodeUp' => '',
                       'November' => 'November',
                       'October' => 'Oktober',
                       'Overview' => '@"Ubersicht',
                       'Prev' => '',
                       'PrevFile' => '',
                       'Previous' => '',
                       'Previous file' => '',
                       'Previous node' => 'Voriger Knoten',
                       'Previous section in reading order' => 'Voriger Abschnitt in Lesereihenfolge',
                       'Previous section on same level' => 'Voriger Abschnitt derselben Ebene',
                       'Section' => 'Abschnitt',
                       'Section One' => 'Abschnitt 1',
                       'See ' => '',
                       'See @cite{{book}}' => '',
                       'See `{section}\'' => 'Abschnitt nach oben',
                       'See `{section}\' in @cite{{book}}' => 'Siehe Abschnitt `{section}\' in @cite{{book}}',
                       'See section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'See section {reference_name}' => '',
                       'See {node_file_href}' => 'Siehe {node_file_href}',
                       'See {node_file_href} section `{section}\' in @cite{{book}}' => 'Siehe {node_file_href} in Abschnitt `{section}\' in @cite{{book}}',
                       'See {reference_name}' => '',
                       'See {reference}' => 'siehe {reference_name}',
                       'See {reference} in @cite{{book}}' => 'Siehe {node_file_href} @cite{{book}}',
                       'See {ref}' => '',
                       'See {title_ref}' => '',
                       'September' => 'September',
                       'Short Table of Contents' => 'Kurzes Inhaltsverzeichnis',
                       'Short table of contents' => 'Kurzes Inhaltsverzeichnis',
                       'Subsection One-Four' => 'Unterabschnitt 1-4',
                       'Subsection One-One' => 'Unterabschnitt 1-1',
                       'Subsection One-Three' => 'Unterabschnitt 1-3',
                       'Subsection One-Two' => 'Unterabschnitt 1-2',
                       'Subsubsection One-Two-Four' => 'Unterabschnitt 1-2-4',
                       'Subsubsection One-Two-One' => 'Unterabschnitt 1-2-1',
                       'Subsubsection One-Two-Three' => 'Unterabschnitt 1-2-3',
                       'Subsubsection One-Two-Two' => 'Unterabschnitt 1-2-2',
                       'Table of Contents' => 'Inhaltsverzeichnis',
                       'Table of contents' => 'Inhaltsverzeichnis',
                       'The node you are looking for is at {href}.' => 'Der Knoten, den Sie sehen, befindet sich bei {href}',
                       'This' => '',
                       'This document was generated on @i{{date}} using @uref{{program_homepage}, @i{{program}}}.' => 'Dieses Dokument wurde erzeugt am @i{{date}} durch @uref{{program_homepage}, @i{{program}}}.',
                       'This document was generated using @uref{{program_homepage}, @emph{{program}}}.' => 'Dieses Dokument wurde erzeugt durch @uref{{program_homepage}, @emph{{program}}}.',
                       'Top' => 'Anfang',
                       'Untitled Document' => 'Unbenanntes Dokumen',
                       'Up' => 'Nach oben',
                       'Up node' => 'Knoten nach oben',
                       'Up section' => 'Abschnitt nach oben',
                       '`{section}\'' => 'Abschnitt nach oben',
                       '`{section}\' in @cite{{book}}' => 'Abschnitt `{section}\' in @cite{{book}}',
                       'current' => '',
                       'on @emph{{date}}' => 'am @emph{{date}}',
                       'section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'see ' => '',
                       'see @cite{{book}}' => 'siehe @cite{{book}}',
                       'see `{section}\'' => 'Abschnitt nach oben',
                       'see `{section}\' in @cite{{book}}' => 'Abschnitt `{section}\' in @cite{{book}}',
                       'see section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'see section `{section}\' in @cite{{book}}' => 'siehe Abschnitt `{section}\' in @cite{{book}}',
                       'see section {reference_name}' => 'siehe Abschnitt {reference_name}',
                       'see {node_file_href}' => 'siehe {node_file_href}',
                       'see {node_file_href} section `{section}\' in @cite{{book}}' => 'siehe {node_file_href} im Abschnitt `{section}\' in @cite{{book}}',
                       'see {reference_name}' => 'siehe {reference_name}',
                       'see {reference}' => 'siehe {reference_name}',
                       'see {reference} in @cite{{book}}' => 'siehe {node_file_href} @cite{{book}}',
                       'see {ref}' => '',
                       'see {title_ref}' => '',
                       '{acronym_like} ({explanation})' => '{acronym_like} ({explanation})',
                       '{month} {day}, {year}' => '{day}. {month} {year}',
                       '{name} of {class}' => '',
                       '{name} on {class}' => '',
                       '{node_file_href} section `{section}\' in @cite{{book}}' => '{node_file_href} in Abschnitt `{section}\' in @cite{{book}}',
                       '{reference_name}' => '{reference_name}',
                       '{reference}' => '{reference_name}',
                       '{reference} in @cite{{book}}' => 'siehe @cite{{book}}',
                       '{ref}' => '',
                       '{style} {number}' => '{style} {number}',
                       '{style}: {caption_first_line}' => '{style}: {caption_first_line}',
                       '{style}: {shortcaption_first_line}' => '{style}: {shortcaption_first_line}',
                       '{title_ref}' => ''
                     };
# Automatically generated file. Edit the .po file instead.
$LANGUAGES->{'pt'} = {
                       '  The buttons in the navigation panels have the following meaning:' => '  Os bot@~oes nos pain@\'eis de navega@,{c}@~ao possuem os seguintes significados:',
                       '  where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '  onde o @strong{ Exemplo } assume que a posi@,{c}@~ao atual localiza-se em @strong{ Subsub@,{c}@~ao Um-Dois-Tr@^es } de um documento com a seguinte estrutura:',
                       ' Up ' => ' Acima ',
                       '(outside of any element)' => '',
                       '(outside of any node)' => '',
                       '@b{{quotation_arg}:} ' => '',
                       '@center --- @emph{{author}}
' => '',
                       '@cite{{book}}' => '',
                       '@{No value for `{value}\'@}' => '',
                       'About' => 'Sobre',
                       'About (help)' => 'Sobre (ajuda)',
                       'About This Document' => 'Sobre Esse Documento',
                       'April' => 'Abril',
                       'August' => 'Agosto',
                       'Back' => 'Volta',
                       'Back section in previous file' => '',
                       'Beginning of this chapter or previous chapter' => 'Come@,{c}o desse cap@\'itulo ou cap@\'itulo anterior',
                       'Button' => 'Bot@~ao',
                       'Contents' => 'Conte@\'udo',
                       'Cover (top) of document' => 'In@\'icio (topo) do documento',
                       'Current' => '',
                       'Current Position' => 'Posi@,{c}@~ao Atual',
                       'Current section' => 'Se@,{c}@~ao atual',
                       'December' => 'Dezembro',
                       'FastBack' => 'Voltar R@\'apido',
                       'FastForward' => 'Avan@,{c}ar R@\'apido',
                       'February' => 'Fevereiro',
                       'First' => 'Primeiro',
                       'First section in reading order' => 'Primeira se@,{c}@~ao na ordem de leitura',
                       'Following' => 'Seguinte',
                       'Following node' => 'Nodo seguinte',
                       'Footnotes' => 'Notas de Rodap@\'e',
                       'Forward' => 'Avan@,{c}ar',
                       'Forward section in next file' => '',
                       'From 1.2.3 go to' => 'De 1.2.3 v@\'a para',
                       'Go to' => 'V@\'a para',
                       'Index' => '@\'Indice',
                       'Index Entry' => 'Entrada de @\'Indice',
                       'January' => 'Janeiro',
                       'July' => 'Julho',
                       'Jump to' => 'Pular para',
                       'June' => 'Junho',
                       'Last' => '@\'Ultimo',
                       'Last section in reading order' => '@\'Ultima se@,{c}@~ao na ordem de leitura',
                       'March' => 'Mar@,{c}o',
                       'May' => 'Maio',
                       'Menu:' => '',
                       'Name' => 'Nome',
                       'Next' => 'Pr@\'oximo',
                       'Next chapter' => 'Pr@\'oximo cap@\'itulo',
                       'Next file' => '',
                       'Next node' => 'Pr@\'oximo nodo',
                       'Next section in reading order' => 'Pr@\'oxima se@,{c}@~ao na ordem de leitura',
                       'Next section on same level' => 'Pr@\'oxima se@,{c}@~ao no mesmo n@\'ivel',
                       'NextFile' => '',
                       'Node following in node reading order' => 'Nodo seguinte na ordem de leitura de nodos',
                       'Node up' => 'Nodo acima',
                       'NodeNext' => 'Pr@\'oximo Nodo',
                       'NodePrev' => 'Nodo Anterior',
                       'NodeUp' => 'Nodo Acima',
                       'November' => 'Novembro',
                       'October' => 'Outubro',
                       'Overview' => 'Vis@~ao geral',
                       'Prev' => 'Pr@\'evio',
                       'PrevFile' => '',
                       'Previous' => '',
                       'Previous file' => '',
                       'Previous node' => 'Nodo anterior',
                       'Previous section in reading order' => 'Se@,{c}@~ao anterior na ordem de leitura',
                       'Previous section on same level' => 'Se@,{c}@~ao anterior no mesmo n@\'ivel',
                       'Section' => 'Se@,{c}@~ao',
                       'Section One' => 'Se@,{c}@~ao Um',
                       'See ' => '',
                       'See @cite{{book}}' => 'Veja @cite{{book}}',
                       'See `{section}\'' => 'Se@,{c}@~ao acima',
                       'See `{section}\' in @cite{{book}}' => 'Veja se@,{c}@~ao `{section}\' em @cite{{book}}',
                       'See section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'See section {reference_name}' => 'Veja se@,{c}@~ao {reference_name}',
                       'See {node_file_href}' => 'Veja {node_file_href}',
                       'See {node_file_href} section `{section}\' in @cite{{book}}' => 'Veja {node_file_href} se@,{c}@~ao `{section}\' em @cite{{book}}',
                       'See {reference_name}' => 'Veja {reference_name}',
                       'See {reference}' => 'Veja {reference_name}',
                       'See {reference} in @cite{{book}}' => 'Veja {node_file_href} @cite{{book}}',
                       'See {ref}' => '',
                       'See {title_ref}' => '',
                       'September' => 'Setembro',
                       'Short Table of Contents' => 'Breve Sum@\'ario',
                       'Short table of contents' => 'Breve sum@\'ario',
                       'Subsection One-Four' => 'Subse@,{c}@~ao Um-Quatro',
                       'Subsection One-One' => 'Subse@,{c}@~ao Um-Um',
                       'Subsection One-Three' => 'Subse@,{c}@~ao Um-Tr@^es',
                       'Subsection One-Two' => 'Subse@,{c}@~ao Um-Dois',
                       'Subsubsection One-Two-Four' => 'Subse@,{c}@~ao Um-Dois-Quatro',
                       'Subsubsection One-Two-One' => 'Subse@,{c}@~ao Um-Dois-Um',
                       'Subsubsection One-Two-Three' => 'Subse@,{c}@~ao Um-Dois-Tr@^es',
                       'Subsubsection One-Two-Two' => 'Subse@,{c}@~ao Um-Dois-Dois',
                       'Table of Contents' => 'Sum@\'ario',
                       'Table of contents' => 'Sum@\'ario',
                       'The node you are looking for is at {href}.' => 'O nodo que vo@^e est@\'a olhando est@\'a em {href}.',
                       'This' => 'Esse',
                       'This document was generated on @i{{date}} using @uref{{program_homepage}, @i{{program}}}.' => 'Esse documento foi gerado em @i{{date}} usando @uref{{program_homepage}, @i{{program}}}.',
                       'This document was generated using @uref{{program_homepage}, @emph{{program}}}.' => 'Esse documento foi gerado usando @uref{{program_homepage}, @emph{{program}}}.',
                       'Top' => 'Topo',
                       'Untitled Document' => 'Documento Sem Nome',
                       'Up' => 'Acima',
                       'Up node' => 'Nodo acima',
                       'Up section' => 'Se@,{c}@~ao acima',
                       '`{section}\'' => 'Se@,{c}@~ao acima',
                       '`{section}\' in @cite{{book}}' => 'se@,{c}@~ao `{section}\' em @cite{{book}}',
                       'current' => 'atual',
                       'on @emph{{date}}' => 'em @emph{{date}}',
                       'section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'see ' => '',
                       'see @cite{{book}}' => 'veja @cite{{book}}',
                       'see `{section}\'' => 'Se@,{c}@~ao acima',
                       'see `{section}\' in @cite{{book}}' => 'se@,{c}@~ao `{section}\' em @cite{{book}}',
                       'see section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'see section `{section}\' in @cite{{book}}' => 'veja se@,{c}@~ao `{section}\' em @cite{{book}}',
                       'see section {reference_name}' => 'veja se@,{c}@~ao {reference_name}',
                       'see {node_file_href}' => 'veja {node_file_href}',
                       'see {node_file_href} section `{section}\' in @cite{{book}}' => 'veja {node_file_href} se@,{c}@~ao `{section}\' em @cite{{book}}',
                       'see {reference_name}' => 'veja {reference_name}',
                       'see {reference}' => 'veja {reference_name}',
                       'see {reference} in @cite{{book}}' => 'veja {node_file_href} @cite{{book}}',
                       'see {ref}' => '',
                       'see {title_ref}' => '',
                       '{acronym_like} ({explanation})' => '',
                       '{month} {day}, {year}' => '{day} de {month} de {year}',
                       '{name} of {class}' => '{name} da {class}',
                       '{name} on {class}' => '{name} na {class}',
                       '{node_file_href} section `{section}\' in @cite{{book}}' => '{node_file_href} se@,{c}@~ao `{section}\' em @cite{{book}}',
                       '{reference_name}' => '',
                       '{reference}' => 'veja {reference_name}',
                       '{reference} in @cite{{book}}' => 'veja @cite{{book}}',
                       '{ref}' => '',
                       '{style} {number}' => '',
                       '{style}: {caption_first_line}' => '',
                       '{style}: {shortcaption_first_line}' => '',
                       '{title_ref}' => ''
                     };
# Automatically generated file. Edit the .po file instead.
$LANGUAGES->{'hu'} = {
                       '  The buttons in the navigation panels have the following meaning:' => '  A navigációs panelen levő gombok jelentése a következő:',
                       '  where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '  @strong{ Példánkban } az aktuális pozíció az @strong{ 1.2.3 alalszakasz } egy olyan dokumentumban, melynek szerkezete a következő:',
                       ' Up ' => 'Fel',
                       '(outside of any element)' => '(bármelyik elemen kívül)',
                       '(outside of any node)' => '(bármelyik csomóponton kívül)',
                       '@b{{quotation_arg}:} ' => '@b{{quotation_arg}:} ',
                       '@center --- @emph{{author}}
' => '',
                       '@cite{{book}}' => '@cite{{book}}',
                       '@{No value for `{value}\'@}' => '@{Nincs értéke ennek: `{value}\'@}',
                       'About' => 'Súgó',
                       'About (help)' => 'Segítség a navigációhoz',
                       'About This Document' => 'A navigációs panel használata',
                       'April' => 'április',
                       'August' => 'augusztus',
                       'Back' => 'Vissza',
                       'Back section in previous file' => 'Előző fájl hátsó szakasza',
                       'Beginning of this chapter or previous chapter' => 'Fejezet eleje vagy előző fejezet',
                       'Button' => 'Gomb',
                       'Contents' => 'Tartalom',
                       'Cover (top) of document' => 'Dokumentum címoldala',
                       'Current' => 'Aktuális',
                       'Current Position' => 'Aktuális pozíció',
                       'Current section' => 'Aktuális szakasz',
                       'December' => 'december',
                       'FastBack' => 'Visszaugrás',
                       'FastForward' => 'Előreugrás',
                       'February' => 'február',
                       'First' => 'Első',
                       'First section in reading order' => 'Első szakasz az olvasási sorrendben',
                       'Following' => 'Következő',
                       'Following node' => 'Következő csomópont',
                       'Footnotes' => 'Lábjegyzet',
                       'Forward' => 'Előre',
                       'Forward section in next file' => 'Következő fájl elülső szakasza',
                       'From 1.2.3 go to' => '1.2.3-ból ide jutunk',
                       'Go to' => 'Cél',
                       'Index' => 'Tárgymutató',
                       'Index Entry' => 'Tárgymutató-bejegyzés',
                       'January' => 'január',
                       'July' => 'július',
                       'Jump to' => 'Ugorj ide',
                       'June' => 'június',
                       'Last' => 'Utolsó',
                       'Last section in reading order' => 'Utolsó szakasz az olvasási sorrendben',
                       'March' => 'március',
                       'May' => 'május',
                       'Menu:' => 'Menü:',
                       'Name' => 'Név',
                       'Next' => 'Következő',
                       'Next chapter' => 'Következő fejezet',
                       'Next file' => 'Következő fájl',
                       'Next node' => 'Következő csomópont',
                       'Next section in reading order' => 'Következő szakasz az olvasási sorrendben',
                       'Next section on same level' => 'Következő szakasz ugyanazon a szinten',
                       'NextFile' => 'KövetkezőFájl',
                       'Node following in node reading order' => 'Következő csomópont az olvasási sorrendben',
                       'Node up' => 'Szülő csomópont',
                       'NodeNext' => 'KövetkezőCsomópont',
                       'NodePrev' => 'ElőzőCsomópont',
                       'NodeUp' => 'SzülőCsomópont',
                       'November' => 'november',
                       'October' => 'október',
                       'Overview' => 'Áttekintés',
                       'Prev' => 'Előző',
                       'PrevFile' => 'ElőzőFájl',
                       'Previous' => 'Előző',
                       'Previous file' => 'Előző fájl',
                       'Previous node' => 'Előző csomópont',
                       'Previous section in reading order' => 'Előző szakasz az olvasási sorrendben',
                       'Previous section on same level' => 'Előző szakasz ugyanazon a szinten',
                       'Section' => 'Szakasz',
                       'Section One' => 'szakasz',
                       'See ' => 'Ld. ',
                       'See @cite{{book}}' => 'Ld. @cite{{book}}',
                       'See `{section}\'' => 'Szülő szakasz',
                       'See `{section}\' in @cite{{book}}' => 'Ld. ezt a szakaszt: `{section}\' itt: @cite{{book}}',
                       'See section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => 'Ld. ezt a szakaszt: `@asis{}`{section_name}\'@asis{}\' itt: @cite{{book}}',
                       'See section {reference_name}' => 'Ld. ezt a szakaszt: {reference_name}',
                       'See {node_file_href}' => 'Ld. {node_file_href}',
                       'See {node_file_href} section `{section}\' in @cite{{book}}' => 'Ld. {node_file_href} ezt a szakaszt: `{section}\' itt: @cite{{book}}',
                       'See {reference_name}' => 'Ld. {reference_name}',
                       'See {reference}' => 'Ld. {reference_name}',
                       'See {reference} in @cite{{book}}' => 'See {node_file_href} @cite{{book}}',
                       'See {ref}' => 'Ld. {ref}',
                       'See {title_ref}' => 'Ld. {title_ref}',
                       'September' => 'szeptember',
                       'Short Table of Contents' => 'Rövid tartalomjegyzék',
                       'Short table of contents' => 'Rövid tartalomjegyzék',
                       'Subsection One-Four' => 'alszakasz',
                       'Subsection One-One' => 'alszakasz',
                       'Subsection One-Three' => 'alszakasz',
                       'Subsection One-Two' => 'alszakasz',
                       'Subsubsection One-Two-Four' => 'alalszakasz',
                       'Subsubsection One-Two-One' => 'alalszakasz',
                       'Subsubsection One-Two-Three' => 'alalszakasz',
                       'Subsubsection One-Two-Two' => 'alalszakasz',
                       'Table of Contents' => 'Tartalomjegyzék',
                       'Table of contents' => 'Tartalomjegyzék',
                       'The node you are looking for is at {href}.' => 'A keresett csomópont itt található: {href}.',
                       'This' => 'Ez a(z)',
                       'This document was generated on @i{{date}} using @uref{{program_homepage}, @i{{program}}}.' => 'Ezt a dokumentumot @i{{date}} napon generálta a(z) @uref{{program_homepage}, @i{{program}}}.',
                       'This document was generated using @uref{{program_homepage}, @emph{{program}}}.' => 'Ezt a dokumentumot a(z) @uref{{program_homepage}, @emph{{program}}} generálta.',
                       'Top' => 'Címoldal',
                       'Untitled Document' => 'Névtelen dokumentum',
                       'Up' => 'Fel',
                       'Up node' => 'Szülő csomópont',
                       'Up section' => 'Szülő szakasz',
                       '`{section}\'' => 'Szülő szakasz',
                       '`{section}\' in @cite{{book}}' => 'szakasz: `{section}\' itt: @cite{{book}}',
                       'current' => 'aktuális',
                       'on @emph{{date}}' => 'ekkor: @emph{{date}}',
                       'section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => 'szakasz: `@asis{}`{section_name}\'@asis{}\' itt: @cite{{book}}',
                       'see ' => 'ld. ',
                       'see @cite{{book}}' => 'ld. @cite{{book}}',
                       'see `{section}\'' => 'Szülő szakasz',
                       'see `{section}\' in @cite{{book}}' => 'szakasz: `{section}\' itt: @cite{{book}}',
                       'see section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => 'ld. ezt a szakaszt: `@asis{}`{section_name}\'@asis{}\' itt: @cite{{book}}',
                       'see section `{section}\' in @cite{{book}}' => 'ld. ezt a szakaszt: `{section}\' itt: @cite{{book}}',
                       'see section {reference_name}' => 'ld. ezt a szakaszt: {reference_name}',
                       'see {node_file_href}' => 'ld. {node_file_href}',
                       'see {node_file_href} section `{section}\' in @cite{{book}}' => 'ld. {node_file_href} ezt a szakaszt: `{section}\' itt: @cite{{book}}',
                       'see {reference_name}' => 'ld. {reference_name}',
                       'see {reference}' => 'ld. {reference_name}',
                       'see {reference} in @cite{{book}}' => 'ld. {node_file_href} @cite{{book}}',
                       'see {ref}' => 'ld. {ref}',
                       'see {title_ref}' => 'ld. {title_ref}',
                       '{acronym_like} ({explanation})' => '{acronym_like} ({explanation})',
                       '{month} {day}, {year}' => '',
                       '{name} of {class}' => '{name} típusa: {class}',
                       '{name} on {class}' => '{name} ezen: {class}',
                       '{node_file_href}' => '{node_file_href}',
                       '{node_file_href} section `{section}\' in @cite{{book}}' => '{node_file_href} szakasz: `{section}\' itt: @cite{{book}}',
                       '{reference_name}' => '{reference_name}',
                       '{reference}' => '{reference_name}',
                       '{reference} in @cite{{book}}' => '{node_file_href} @cite{{book}}',
                       '{ref}' => '{ref}',
                       '{style} {number}' => '{style} {number}',
                       '{style}: {caption_first_line}' => '{style}: {caption_first_line}',
                       '{style}: {shortcaption_first_line}' => '{style}: {shortcaption_first_line}',
                       '{title_ref}' => '{title_ref}'
                     };
# Automatically generated file. Edit the .po file instead.
$LANGUAGES->{'pt_BR'} = {
                          '  The buttons in the navigation panels have the following meaning:' => '  Os bot@~oes nos pain@\'eis de navega@,{c}@~ao possuem os seguintes significados:',
                          '  where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '  onde o @strong{ Exemplo } assume que a posi@,{c}@~ao atual localiza-se em @strong{ Subsub@,{c}@~ao Um-Dois-Tr@^es } de um documento com a seguinte estrutura:',
                          ' Up ' => ' Acima ',
                          '(outside of any element)' => '',
                          '(outside of any node)' => '',
                          '@b{{quotation_arg}:} ' => '',
                          '@center --- @emph{{author}}
' => '',
                          '@cite{{book}}' => '',
                          '@{No value for `{value}\'@}' => '',
                          'About' => 'Sobre',
                          'About (help)' => 'Sobre (ajuda)',
                          'About This Document' => 'Sobre Esse Documento',
                          'April' => 'Abril',
                          'August' => 'Agosto',
                          'Back' => 'Volta',
                          'Back section in previous file' => '',
                          'Beginning of this chapter or previous chapter' => 'Come@,{c}o desse cap@\'itulo ou cap@\'itulo anterior',
                          'Button' => 'Bot@~ao',
                          'Contents' => 'Conte@\'udo',
                          'Cover (top) of document' => 'In@\'icio (topo) do documento',
                          'Current' => '',
                          'Current Position' => 'Posi@,{c}@~ao Atual',
                          'Current section' => 'Se@,{c}@~ao atual',
                          'December' => 'Dezembro',
                          'FastBack' => 'Voltar R@\'apido',
                          'FastForward' => 'Avan@,{c}ar R@\'apido',
                          'February' => 'Fevereiro',
                          'First' => 'Primeiro',
                          'First section in reading order' => 'Primeira se@,{c}@~ao na ordem de leitura',
                          'Following' => 'Seguinte',
                          'Following node' => 'Nodo seguinte',
                          'Footnotes' => 'Notas de Rodap@\'e',
                          'Forward' => 'Avan@,{c}ar',
                          'Forward section in next file' => '',
                          'From 1.2.3 go to' => 'De 1.2.3 v@\'a para',
                          'Go to' => 'V@\'a para',
                          'Index' => '@\'Indice',
                          'Index Entry' => 'Entrada de @\'Indice',
                          'January' => 'Janeiro',
                          'July' => 'Julho',
                          'Jump to' => 'Pular para',
                          'June' => 'Junho',
                          'Last' => '@\'Ultimo',
                          'Last section in reading order' => '@\'Ultima se@,{c}@~ao na ordem de leitura',
                          'March' => 'Mar@,{c}o',
                          'May' => 'Maio',
                          'Menu:' => '',
                          'Name' => 'Nome',
                          'Next' => 'Pr@\'oximo',
                          'Next chapter' => 'Pr@\'oximo cap@\'itulo',
                          'Next file' => '',
                          'Next node' => 'Pr@\'oximo nodo',
                          'Next section in reading order' => 'Pr@\'oxima se@,{c}@~ao na ordem de leitura',
                          'Next section on same level' => 'Pr@\'oxima se@,{c}@~ao no mesmo n@\'ivel',
                          'NextFile' => '',
                          'Node following in node reading order' => 'Nodo seguinte na ordem de leitura de nodos',
                          'Node up' => 'Nodo acima',
                          'NodeNext' => 'Pr@\'oximo Nodo',
                          'NodePrev' => 'Nodo Anterior',
                          'NodeUp' => 'Nodo Acima',
                          'November' => 'Novembro',
                          'October' => 'Outubro',
                          'Overview' => 'Vis@~ao geral',
                          'Prev' => 'Pr@\'evio',
                          'PrevFile' => '',
                          'Previous' => '',
                          'Previous file' => '',
                          'Previous node' => 'Nodo anterior',
                          'Previous section in reading order' => 'Se@,{c}@~ao anterior na ordem de leitura',
                          'Previous section on same level' => 'Se@,{c}@~ao anterior no mesmo n@\'ivel',
                          'Section' => 'Se@,{c}@~ao',
                          'Section One' => 'Se@,{c}@~ao Um',
                          'See ' => '',
                          'See @cite{{book}}' => 'Veja @cite{{book}}',
                          'See `{section}\'' => 'Se@,{c}@~ao acima',
                          'See `{section}\' in @cite{{book}}' => 'Veja se@,{c}@~ao `{section}\' em @cite{{book}}',
                          'See section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                          'See section {reference_name}' => 'Veja se@,{c}@~ao {reference_name}',
                          'See {node_file_href}' => 'Veja {node_file_href}',
                          'See {node_file_href} section `{section}\' in @cite{{book}}' => 'Veja {node_file_href} se@,{c}@~ao `{section}\' em @cite{{book}}',
                          'See {reference_name}' => 'Veja {reference_name}',
                          'See {reference}' => 'Veja {reference_name}',
                          'See {reference} in @cite{{book}}' => 'Veja {node_file_href} @cite{{book}}',
                          'See {ref}' => '',
                          'See {title_ref}' => '',
                          'September' => 'Setembro',
                          'Short Table of Contents' => 'Breve Sum@\'ario',
                          'Short table of contents' => 'Breve sum@\'ario',
                          'Subsection One-Four' => 'Subse@,{c}@~ao Um-Quatro',
                          'Subsection One-One' => 'Subse@,{c}@~ao Um-Um',
                          'Subsection One-Three' => 'Subse@,{c}@~ao Um-Tr@^es',
                          'Subsection One-Two' => 'Subse@,{c}@~ao Um-Dois',
                          'Subsubsection One-Two-Four' => 'Subse@,{c}@~ao Um-Dois-Quatro',
                          'Subsubsection One-Two-One' => 'Subse@,{c}@~ao Um-Dois-Um',
                          'Subsubsection One-Two-Three' => 'Subse@,{c}@~ao Um-Dois-Tr@^es',
                          'Subsubsection One-Two-Two' => 'Subse@,{c}@~ao Um-Dois-Dois',
                          'Table of Contents' => 'Sum@\'ario',
                          'Table of contents' => 'Sum@\'ario',
                          'The node you are looking for is at {href}.' => 'O nodo que vo@^e est@\'a olhando est@\'a em {href}.',
                          'This' => 'Esse',
                          'This document was generated on @i{{date}} using @uref{{program_homepage}, @i{{program}}}.' => 'Esse documento foi gerado em @i{{date}} usando @uref{{program_homepage}, @i{{program}}}.',
                          'This document was generated using @uref{{program_homepage}, @emph{{program}}}.' => 'Esse documento foi gerado usando @uref{{program_homepage}, @emph{{program}}}.',
                          'Top' => 'Topo',
                          'Untitled Document' => 'Documento Sem Nome',
                          'Up' => 'Acima',
                          'Up node' => 'Nodo acima',
                          'Up section' => 'Se@,{c}@~ao acima',
                          '`{section}\'' => 'Se@,{c}@~ao acima',
                          '`{section}\' in @cite{{book}}' => 'se@,{c}@~ao `{section}\' em @cite{{book}}',
                          'current' => 'atual',
                          'on @emph{{date}}' => 'em @emph{{date}}',
                          'section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                          'see ' => '',
                          'see @cite{{book}}' => 'veja @cite{{book}}',
                          'see `{section}\'' => 'Se@,{c}@~ao acima',
                          'see `{section}\' in @cite{{book}}' => 'se@,{c}@~ao `{section}\' em @cite{{book}}',
                          'see section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                          'see section `{section}\' in @cite{{book}}' => 'veja se@,{c}@~ao `{section}\' em @cite{{book}}',
                          'see section {reference_name}' => 'veja se@,{c}@~ao {reference_name}',
                          'see {node_file_href}' => 'veja {node_file_href}',
                          'see {node_file_href} section `{section}\' in @cite{{book}}' => 'veja {node_file_href} se@,{c}@~ao `{section}\' em @cite{{book}}',
                          'see {reference_name}' => 'veja {reference_name}',
                          'see {reference}' => 'veja {reference_name}',
                          'see {reference} in @cite{{book}}' => 'veja {node_file_href} @cite{{book}}',
                          'see {ref}' => '',
                          'see {title_ref}' => '',
                          '{acronym_like} ({explanation})' => '',
                          '{month} {day}, {year}' => '{day} de {month} de {year}',
                          '{name} of {class}' => '{name} da {class}',
                          '{name} on {class}' => '{name} na {class}',
                          '{node_file_href} section `{section}\' in @cite{{book}}' => '{node_file_href} se@,{c}@~ao `{section}\' em @cite{{book}}',
                          '{reference_name}' => '',
                          '{reference}' => 'veja {reference_name}',
                          '{reference} in @cite{{book}}' => 'veja @cite{{book}}',
                          '{ref}' => '',
                          '{style} {number}' => '',
                          '{style}: {caption_first_line}' => '',
                          '{style}: {shortcaption_first_line}' => '',
                          '{title_ref}' => ''
                        };
# Automatically generated file. Edit the .po file instead.
$LANGUAGES->{'es'} = {
                       '  The buttons in the navigation panels have the following meaning:' => '  Los botones de los paneles de navegaci@\'on tienen el significado siguiente:',
                       '  where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '  donde el @strong{ Ejemplo } supone que la posici@\'on actual est@\'a en la @strong{ Sub-subsecci@\'on uno-dos-tres } de un documento de la estructura siguiente:',
                       ' Up ' => ' Subir ',
                       '(outside of any element)' => '',
                       '(outside of any node)' => '',
                       '@b{{quotation_arg}:} ' => '',
                       '@center --- @emph{{author}}
' => '',
                       '@cite{{book}}' => '',
                       '@{No value for `{value}\'@}' => '',
                       'About' => 'Acerca de',
                       'About (help)' => 'Acerca de (p@\'agina de ayuda)',
                       'About This Document' => 'Acerca de este documento',
                       'April' => 'abril',
                       'August' => 'agosto',
                       'Back' => 'Atr@\'as',
                       'Back section in previous file' => 'Retroceder secci@\'on en el archivo anterior',
                       'Beginning of this chapter or previous chapter' => 'Inicio de este cap@\'itulo o cap@\'itulo anterior',
                       'Button' => 'Bot@\'on',
                       'Contents' => '@\'Indice general',
                       'Cover (top) of document' => 'Portada del documento',
                       'Current' => '',
                       'Current Position' => 'Posici@\'on actual',
                       'Current section' => 'Secci@\'on actual',
                       'December' => 'diciembre',
                       'FastBack' => 'Retroceso r@\'apido',
                       'FastForward' => 'Avance r@\'apido',
                       'February' => 'febrero',
                       'First' => 'Primero',
                       'First section in reading order' => 'Primera secci@\'on en orden de lectura',
                       'Following' => 'Siguiente',
                       'Following node' => 'Nodo siguiente',
                       'Footnotes' => 'Notas al pie',
                       'Forward' => 'Adelante',
                       'Forward section in next file' => 'Avanzar secci@\'on en el pr@\'oximo archivo',
                       'From 1.2.3 go to' => 'Desde 1.2.3 ir a',
                       'Go to' => 'Ir a',
                       'Index' => '@\'Indice',
                       'Index Entry' => 'Entrada de @\'indice',
                       'January' => 'enero',
                       'July' => 'julio',
                       'Jump to' => 'Saltar a',
                       'June' => 'junio',
                       'Last' => '@\'Ultimo',
                       'Last section in reading order' => '@\'Ultima secci@\'on en orden de lectura',
                       'March' => 'marzo',
                       'May' => 'mayo',
                       'Menu:' => 'Men@\'u:',
                       'Name' => 'Nombre',
                       'Next' => 'Siguiente',
                       'Next chapter' => 'Cap@\'itulo siguiente',
                       'Next file' => 'Archivo siguiente',
                       'Next node' => 'Nodo siguiente',
                       'Next section in reading order' => 'Secci@\'on siguiente en orden de lectura',
                       'Next section on same level' => 'Secci@\'on siguiente en el mismo nivel',
                       'NextFile' => 'ArchivoSiguiente',
                       'Node following in node reading order' => 'Nodo siguiente en orden de lectura de nodos',
                       'Node up' => 'Subir nodo',
                       'NodeNext' => 'NodoSiguiente',
                       'NodePrev' => 'NodoAnterior',
                       'NodeUp' => 'SubirNodo',
                       'November' => 'noviembre',
                       'October' => 'octubre',
                       'Overview' => 'Panor@\'amica',
                       'Prev' => 'Ant',
                       'PrevFile' => 'ArchivoAnt',
                       'Previous' => '',
                       'Previous file' => 'Archivo anterior',
                       'Previous node' => 'Nodo anterior',
                       'Previous section in reading order' => 'Secci@\'on anterior en orden de lectura',
                       'Previous section on same level' => 'Secci@\'on anterior en el mismo nivel',
                       'Section' => 'Secci@\'on',
                       'Section One' => 'Secci@\'on Uno',
                       'See ' => '',
                       'See @cite{{book}}' => 'V@\'ease @cite{{book}}',
                       'See `{section}\'' => 'Subir secci@\'on',
                       'See `{section}\' in @cite{{book}}' => 'V@\'ease la secci@\'on `{section}\' en @cite{{book}}',
                       'See section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'See section {reference_name}' => 'V@\'ease la secci@\'on  {reference_name}',
                       'See {node_file_href}' => 'V@\'ease {node_file_href}',
                       'See {node_file_href} section `{section}\' in @cite{{book}}' => 'V@\'ease {node_file_href} secci@\'on `{section}\' en @cite{{book}}',
                       'See {reference_name}' => 'V@\'ease {reference_name}',
                       'See {reference}' => 'V@\'ease {reference_name}',
                       'See {reference} in @cite{{book}}' => 'V@\'ease {node_file_href} @cite{{book}}',
                       'See {ref}' => '',
                       'See {title_ref}' => '',
                       'September' => 'septiembre',
                       'Short Table of Contents' => 'Resumen del Contenido',
                       'Short table of contents' => 'Resumen del contenido',
                       'Subsection One-Four' => 'Subsecci@\'on uno-cuatro',
                       'Subsection One-One' => 'Subsecci@\'on uno-uno',
                       'Subsection One-Three' => 'Subsecci@\'on uno-tres',
                       'Subsection One-Two' => 'Subsecci@\'on uno-dos',
                       'Subsubsection One-Two-Four' => 'Sub-subsecci@\'on uno-dos-cuatro',
                       'Subsubsection One-Two-One' => 'Sub-subsecci@\'on uno-dos-uno',
                       'Subsubsection One-Two-Three' => 'Sub-subsecci@\'on uno-dos-tres',
                       'Subsubsection One-Two-Two' => 'Sub-subsecci@\'on uno-dos-dos',
                       'Table of Contents' => '@\'{@dotless{I}}ndice General',
                       'Table of contents' => '@\'{@dotless{I}}ndice general',
                       'The node you are looking for is at {href}.' => 'El nodo que busca se encuentra en {href}.',
                       'This' => 'Este',
                       'This document was generated on @i{{date}} using @uref{{program_homepage}, @i{{program}}}.' => 'Este documento se gener@\'o el @i{{date}} utilizando @uref{{program_homepage}, @i{{program}}}.',
                       'This document was generated using @uref{{program_homepage}, @emph{{program}}}.' => 'Este documento se gener@\'o utilizando @uref{{program_homepage}, @emph{{program}}}.',
                       'Top' => 'Arriba',
                       'Untitled Document' => 'Documento sin t@\'itulo',
                       'Up' => 'Subir',
                       'Up node' => 'Subir nodo',
                       'Up section' => 'Subir secci@\'on',
                       '`{section}\'' => 'Subir secci@\'on',
                       '`{section}\' in @cite{{book}}' => 'secci@\'on `{section}\' en @cite{{book}}',
                       'current' => 'actual',
                       'on @emph{{date}}' => 'el @emph{{date}}',
                       'section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'see ' => '',
                       'see @cite{{book}}' => 'v@\'ease @cite{{book}}',
                       'see `{section}\'' => 'Subir secci@\'on',
                       'see `{section}\' in @cite{{book}}' => 'secci@\'on `{section}\' en @cite{{book}}',
                       'see section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'see section `{section}\' in @cite{{book}}' => 'v@\'ease la secci@\'on `{section}\' en @cite{{book}}',
                       'see section {reference_name}' => 'v@\'ease la secci@\'on {reference_name}',
                       'see {node_file_href}' => 'v@\'ease {node_file_href}',
                       'see {node_file_href} section `{section}\' in @cite{{book}}' => 'v@\'ease {node_file_href} secci@\'on `{section}\' en @cite{{book}}',
                       'see {reference_name}' => 'v@\'ease {reference_name}',
                       'see {reference}' => 'v@\'ease {reference_name}',
                       'see {reference} in @cite{{book}}' => 'v@\'ease {node_file_href} @cite{{book}}',
                       'see {ref}' => '',
                       'see {title_ref}' => '',
                       '{acronym_like} ({explanation})' => '',
                       '{month} {day}, {year}' => 'el {day} {month} {year}',
                       '{name} of {class}' => '{name} de {class}',
                       '{name} on {class}' => '{name} en {class}',
                       '{node_file_href} section `{section}\' in @cite{{book}}' => '{node_file_href} secci@\'on `{section}\' en @cite{{book}}',
                       '{reference_name}' => '',
                       '{reference}' => 'v@\'ease {reference_name}',
                       '{reference} in @cite{{book}}' => 'v@\'ease @cite{{book}}',
                       '{ref}' => '',
                       '{style} {number}' => '',
                       '{style}: {caption_first_line}' => '',
                       '{style}: {shortcaption_first_line}' => '',
                       '{title_ref}' => ''
                     };
# Automatically generated file. Edit the .po file instead.
$LANGUAGES->{'it'} = {
                       '  The buttons in the navigation panels have the following meaning:' => '  I bottoni nei pannelli di navigazione hanno il seguente significato:',
                       '  where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '  dove @strong{ Esempio } assume che l\'attuale posizione è alla @strong{ Sottosottosezione Uno-Due-Tre } di un documento che ha la seguente struttura:',
                       ' Up ' => ' Su ',
                       '(outside of any element)' => '(fuori da qualsiasi elemento)',
                       '(outside of any node)' => '(fuori da qualsiasi nodo)',
                       '@b{{quotation_arg}:} ' => '@b{{quotation_arg}:} ',
                       '@center --- @emph{{author}}
' => '',
                       '@cite{{book}}' => '@cite{{book}}',
                       '@{No value for `{value}\'@}' => '@{Nessun valore per `{value}\'@}',
                       'About' => 'Informazioni',
                       'About (help)' => 'Informazioni (aiuto)',
                       'About This Document' => 'Informazioni su questo documento',
                       'April' => 'Aprile',
                       'August' => 'Agosto',
                       'Back' => 'Indietro',
                       'Back section in previous file' => '',
                       'Beginning of this chapter or previous chapter' => 'Inizio di questo capitolo o capitolo precedente',
                       'Button' => 'Bottone',
                       'Contents' => 'Contenuti',
                       'Cover (top) of document' => 'Copertina (inizio) del documento',
                       'Current' => 'Attuale',
                       'Current Position' => 'Posizione Attuale',
                       'Current section' => 'Sezione attuale',
                       'December' => 'Dicembre',
                       'FastBack' => 'Indietro veloce',
                       'FastForward' => 'Avanti veloce',
                       'February' => 'Febbraio',
                       'First' => 'Primo',
                       'First section in reading order' => 'Prima sezione in ordine di lettura',
                       'Following' => 'Seguente',
                       'Following node' => 'Nodo seguente',
                       'Footnotes' => 'Note a piè di pagina',
                       'Forward' => 'Avanti',
                       'Forward section in next file' => 'Sezione successiva nel prossimo file',
                       'From 1.2.3 go to' => 'Da 1.2.3 vai a',
                       'Go to' => 'Vai a',
                       'Index' => 'Indice',
                       'Index Entry' => 'Voce dell\'indice',
                       'January' => 'Gennaio',
                       'July' => 'Luglio',
                       'Jump to' => 'Salta a',
                       'June' => 'Giugno',
                       'Last' => 'Ultimo',
                       'Last section in reading order' => 'Ultima sezione in ordine di lettura',
                       'March' => 'Marzo',
                       'May' => 'Maggio',
                       'Menu:' => 'Menu',
                       'Name' => 'Nome',
                       'Next' => 'Successivo',
                       'Next chapter' => 'Capitolo successivo',
                       'Next file' => 'File successivo',
                       'Next node' => 'Nodo successivo',
                       'Next section in reading order' => 'Sezione successiva in ordine di lettura',
                       'Next section on same level' => 'Sezione successiva sullo stesso livello',
                       'NextFile' => 'File successivo',
                       'Node following in node reading order' => 'Nodo seguente in ordine di lettura',
                       'Node up' => 'Nodo superiore',
                       'NodeNext' => 'Nodo successivo',
                       'NodePrev' => 'Nodo precedente',
                       'NodeUp' => 'Nodo superiore',
                       'November' => 'Novembre',
                       'October' => 'Ottobre',
                       'Overview' => 'Panoramica',
                       'Prev' => 'Prec.',
                       'PrevFile' => 'File precedente',
                       'Previous' => 'Precedente',
                       'Previous file' => 'File precedente',
                       'Previous node' => 'Nodo precedente',
                       'Previous section in reading order' => 'Sezione precedente in ordine di lettura',
                       'Previous section on same level' => 'Sezione precedente sullo stesso livello',
                       'Section' => 'Sezione',
                       'Section One' => 'Sezione uno',
                       'See ' => 'Vedi',
                       'See @cite{{book}}' => 'Vedi @cite{{book}}',
                       'See `{section}\'' => 'Sezione superiore',
                       'See `{section}\' in @cite{{book}}' => 'Vedi la sezione `{section}\' in @cite{{book}}',
                       'See section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => 'Vedi la sezione `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}',
                       'See section {reference_name}' => 'Vedi la sezione {reference_name}',
                       'See {node_file_href}' => 'Vedi {node_file_href}',
                       'See {node_file_href} section `{section}\' in @cite{{book}}' => 'Vedi {node_file_href} nella sezione `{section}\' in @cite{{book}}',
                       'See {reference_name}' => 'Vedi {reference_name}',
                       'See {reference}' => 'Vedi {reference_name}',
                       'See {reference} in @cite{{book}}' => 'Vedi {node_file_href} @cite{{book}}',
                       'See {ref}' => 'Vedi {ref}',
                       'See {title_ref}' => 'Vedi {title_ref}',
                       'September' => 'Settembre',
                       'Short Table of Contents' => 'Indice breve',
                       'Short table of contents' => 'Indice breve',
                       'Subsection One-Four' => 'Sottosezione Uno-Quattro',
                       'Subsection One-One' => 'Sottosezione Uno-Uno',
                       'Subsection One-Three' => 'Sottosezione Uno-Tre',
                       'Subsection One-Two' => 'Sottosezione Uno-Due',
                       'Subsubsection One-Two-Four' => 'Sottosottosezione Uno-Due-Quattro',
                       'Subsubsection One-Two-One' => 'Sottosottosezione Uno-Due-Uno',
                       'Subsubsection One-Two-Three' => 'Sottosottosezione Uno-Due-Tre',
                       'Subsubsection One-Two-Two' => 'Sottosottosezione Uno-Due-Due',
                       'Table of Contents' => 'Indice',
                       'Table of contents' => 'Indice',
                       'The node you are looking for is at {href}.' => 'Il nodo che stai cercando è {href}',
                       'This' => 'Questo',
                       'This document was generated on @i{{date}} using @uref{{program_homepage}, @i{{program}}}.' => 'Questo documento è stato generato il @i{{date}} con @uref{{program_homepage}, @i{{program}}}.',
                       'This document was generated using @uref{{program_homepage}, @emph{{program}}}.' => 'Questo documento è stato generato con @uref{{program_homepage}, @emph{{program}}}.',
                       'Top' => 'Inizio',
                       'Untitled Document' => 'Documento senza titolo',
                       'Up' => 'Su',
                       'Up node' => 'Nodo superiore',
                       'Up section' => 'Sezione superiore',
                       '`{section}\'' => 'Sezione superiore',
                       '`{section}\' in @cite{{book}}' => 'sezione `{section}\' in @cite{{book}}',
                       'current' => 'attuale',
                       'on @emph{{date}}' => 'il @emph{{date}}',
                       'section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => 'sezione `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}',
                       'see ' => 'vedi ',
                       'see @cite{{book}}' => 'vedi @cite{{book}}',
                       'see `{section}\'' => 'Sezione superiore',
                       'see `{section}\' in @cite{{book}}' => 'sezione `{section}\' in @cite{{book}}',
                       'see section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => 'vedi la sezione `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}',
                       'see section `{section}\' in @cite{{book}}' => 'vedi la sezione `{section}\' in @cite{{book}}',
                       'see section {reference_name}' => 'vedi la sezione {reference_name}',
                       'see {node_file_href}' => 'vedi {node_file_href}',
                       'see {node_file_href} section `{section}\' in @cite{{book}}' => 'vedi {node_file_href} nella sezione `{section}\' in @cite{{book}}',
                       'see {reference_name}' => 'vedi {reference_name}',
                       'see {reference}' => 'vedi {reference_name}',
                       'see {reference} in @cite{{book}}' => 'vedi {node_file_href} @cite{{book}}',
                       'see {ref}' => 'vedi {ref}',
                       'see {title_ref}' => 'vedi {title_ref}',
                       '{acronym_like} ({explanation})' => '{acronym_like} ({explanation})',
                       '{month} {day}, {year}' => '',
                       '{name} of {class}' => '{name} di {class}',
                       '{name} on {class}' => '{name} in {class}',
                       '{node_file_href}' => '{node_file_href}',
                       '{node_file_href} section `{section}\' in @cite{{book}}' => '{node_file_href} nella sezione `{section}\' in @cite{{book}}',
                       '{reference_name}' => '{reference_name}',
                       '{reference}' => '{reference_name}',
                       '{reference} in @cite{{book}}' => '{node_file_href} @cite{{book}}',
                       '{ref}' => '{ref}',
                       '{style} {number}' => '{style} {number}',
                       '{style}: {caption_first_line}' => '{style}: {caption_first_line}',
                       '{style}: {shortcaption_first_line}' => '{style}: {shortcaption_first_line}',
                       '{title_ref}' => '{title_ref}'
                     };
# Automatically generated file. Edit the .po file instead.
$LANGUAGES->{'no'} = {
                       '  The buttons in the navigation panels have the following meaning:' => '',
                       '  where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '',
                       ' Up ' => '',
                       '(outside of any element)' => '',
                       '(outside of any node)' => '',
                       '@b{{quotation_arg}:} ' => '',
                       '@center --- @emph{{author}}
' => '',
                       '@cite{{book}}' => '',
                       '@{No value for `{value}\'@}' => '',
                       'About' => '',
                       'About (help)' => '',
                       'About This Document' => 'No translation available!',
                       'April' => 'april',
                       'August' => 'august',
                       'Back' => '',
                       'Back section in previous file' => '',
                       'Beginning of this chapter or previous chapter' => '',
                       'Button' => '',
                       'Contents' => '',
                       'Cover (top) of document' => '',
                       'Current' => '',
                       'Current Position' => '',
                       'Current section' => '',
                       'December' => 'desember',
                       'FastBack' => '',
                       'FastForward' => '',
                       'February' => 'februar',
                       'First' => '',
                       'First section in reading order' => '',
                       'Following' => '',
                       'Following node' => '',
                       'Footnotes' => 'No translation available!',
                       'Forward' => '',
                       'Forward section in next file' => '',
                       'From 1.2.3 go to' => '',
                       'Go to' => '',
                       'Index' => 'Indeks',
                       'Index Entry' => '',
                       'January' => 'januar',
                       'July' => 'juli',
                       'Jump to' => '',
                       'June' => 'juni',
                       'Last' => '',
                       'Last section in reading order' => '',
                       'March' => 'mars',
                       'May' => 'mai',
                       'Menu:' => '',
                       'Name' => '',
                       'Next' => '',
                       'Next chapter' => '',
                       'Next file' => '',
                       'Next node' => '',
                       'Next section in reading order' => '',
                       'Next section on same level' => '',
                       'NextFile' => '',
                       'Node following in node reading order' => '',
                       'Node up' => '',
                       'NodeNext' => '',
                       'NodePrev' => '',
                       'NodeUp' => '',
                       'November' => 'november',
                       'October' => 'oktober',
                       'Overview' => '',
                       'Prev' => '',
                       'PrevFile' => '',
                       'Previous' => '',
                       'Previous file' => '',
                       'Previous node' => '',
                       'Previous section in reading order' => '',
                       'Previous section on same level' => '',
                       'Section' => '',
                       'Section One' => '',
                       'See ' => '',
                       'See @cite{{book}}' => '',
                       'See `{section}\'' => '',
                       'See `{section}\' in @cite{{book}}' => '',
                       'See section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'See section {reference_name}' => '',
                       'See {reference_name}' => '',
                       'See {reference}' => '',
                       'See {reference} in @cite{{book}}' => '',
                       'See {ref}' => '',
                       'See {title_ref}' => '',
                       'September' => 'september',
                       'Short Table of Contents' => 'Kort innholdsfortegnelse',
                       'Short table of contents' => '',
                       'Subsection One-Four' => '',
                       'Subsection One-One' => '',
                       'Subsection One-Three' => '',
                       'Subsection One-Two' => '',
                       'Subsubsection One-Two-Four' => '',
                       'Subsubsection One-Two-One' => '',
                       'Subsubsection One-Two-Three' => '',
                       'Subsubsection One-Two-Two' => '',
                       'Table of Contents' => 'Innholdsfortegnelse',
                       'Table of contents' => '',
                       'The node you are looking for is at {href}.' => '',
                       'This' => '',
                       'This document was generated on @i{{date}} using @uref{{program_homepage}, @i{{program}}}.' => '',
                       'This document was generated using @uref{{program_homepage}, @emph{{program}}}.' => '',
                       'Top' => '',
                       'Untitled Document' => '',
                       'Up' => '',
                       'Up node' => '',
                       'Up section' => '',
                       '`{section}\'' => '',
                       '`{section}\' in @cite{{book}}' => '',
                       'current' => '',
                       'on @emph{{date}}' => '',
                       'section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'see ' => '',
                       'see @cite{{book}}' => '',
                       'see `{section}\'' => '',
                       'see `{section}\' in @cite{{book}}' => '',
                       'see section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'see section {reference_name}' => '',
                       'see {reference_name}' => '',
                       'see {reference}' => '',
                       'see {reference} in @cite{{book}}' => '',
                       'see {ref}' => '',
                       'see {title_ref}' => '',
                       '{acronym_like} ({explanation})' => '',
                       '{month} {day}, {year}' => '',
                       '{name} of {class}' => '',
                       '{name} on {class}' => '',
                       '{reference_name}' => '',
                       '{reference}' => '',
                       '{reference} in @cite{{book}}' => '',
                       '{ref}' => '',
                       '{style} {number}' => '',
                       '{style}: {caption_first_line}' => '',
                       '{style}: {shortcaption_first_line}' => '',
                       '{title_ref}' => ''
                     };
# Automatically generated file. Edit the .po file instead.
$LANGUAGES->{'en'} = {
                       '  The buttons in the navigation panels have the following meaning:' => '',
                       '  where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '',
                       ' Up ' => '',
                       '(outside of any element)' => '',
                       '(outside of any node)' => '',
                       '@b{{quotation_arg}:} ' => '',
                       '@center --- @emph{{author}}
' => '',
                       '@cite{{book}}' => '',
                       '@{No value for `{value}\'@}' => '',
                       'About' => '',
                       'About (help)' => '',
                       'About This Document' => '',
                       'April' => '',
                       'August' => '',
                       'Back' => '',
                       'Back section in previous file' => '',
                       'Beginning of this chapter or previous chapter' => '',
                       'Button' => '',
                       'Contents' => '',
                       'Cover (top) of document' => '',
                       'Current' => '',
                       'Current Position' => '',
                       'Current section' => '',
                       'December' => '',
                       'FastBack' => '',
                       'FastForward' => '',
                       'February' => '',
                       'First' => '',
                       'First section in reading order' => '',
                       'Following' => '',
                       'Following node' => '',
                       'Footnotes' => '',
                       'Forward' => '',
                       'Forward section in next file' => '',
                       'From 1.2.3 go to' => '',
                       'Go to' => '',
                       'Index' => '',
                       'Index Entry' => '',
                       'January' => '',
                       'July' => '',
                       'Jump to' => '',
                       'June' => '',
                       'Last' => '',
                       'Last section in reading order' => '',
                       'March' => '',
                       'May' => '',
                       'Menu:' => '',
                       'Name' => '',
                       'Next' => '',
                       'Next chapter' => '',
                       'Next file' => '',
                       'Next node' => '',
                       'Next section in reading order' => '',
                       'Next section on same level' => '',
                       'NextFile' => '',
                       'Node following in node reading order' => '',
                       'Node up' => '',
                       'NodeNext' => '',
                       'NodePrev' => '',
                       'NodeUp' => '',
                       'November' => '',
                       'October' => '',
                       'Overview' => '',
                       'Prev' => '',
                       'PrevFile' => '',
                       'Previous' => '',
                       'Previous file' => '',
                       'Previous node' => '',
                       'Previous section in reading order' => '',
                       'Previous section on same level' => '',
                       'Section' => '',
                       'Section One' => '',
                       'See ' => '',
                       'See @cite{{book}}' => '',
                       'See `{section}\'' => '',
                       'See `{section}\' in @cite{{book}}' => '',
                       'See section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'See section {reference_name}' => '',
                       'See {reference_name}' => '',
                       'See {reference}' => '',
                       'See {reference} in @cite{{book}}' => '',
                       'See {ref}' => '',
                       'See {title_ref}' => '',
                       'September' => '',
                       'Short Table of Contents' => '',
                       'Short table of contents' => '',
                       'Subsection One-Four' => '',
                       'Subsection One-One' => '',
                       'Subsection One-Three' => '',
                       'Subsection One-Two' => '',
                       'Subsubsection One-Two-Four' => '',
                       'Subsubsection One-Two-One' => '',
                       'Subsubsection One-Two-Three' => '',
                       'Subsubsection One-Two-Two' => '',
                       'Table of Contents' => '',
                       'Table of contents' => '',
                       'The node you are looking for is at {href}.' => '',
                       'This' => '',
                       'This document was generated on @i{{date}} using @uref{{program_homepage}, @i{{program}}}.' => '',
                       'This document was generated using @uref{{program_homepage}, @emph{{program}}}.' => '',
                       'Top' => '',
                       'Untitled Document' => '',
                       'Up' => '',
                       'Up node' => '',
                       'Up section' => '',
                       '`{section}\'' => '',
                       '`{section}\' in @cite{{book}}' => '',
                       'current' => '',
                       'on @emph{{date}}' => '',
                       'section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'see ' => '',
                       'see @cite{{book}}' => '',
                       'see `{section}\'' => '',
                       'see `{section}\' in @cite{{book}}' => '',
                       'see section `@asis{}`{section_name}\'@asis{}\' in @cite{{book}}' => '',
                       'see section {reference_name}' => '',
                       'see {reference_name}' => '',
                       'see {reference}' => '',
                       'see {reference} in @cite{{book}}' => '',
                       'see {ref}' => '',
                       'see {title_ref}' => '',
                       '{acronym_like} ({explanation})' => '',
                       '{month} {day}, {year}' => '',
                       '{name} of {class}' => '',
                       '{name} on {class}' => '',
                       '{reference_name}' => '',
                       '{reference}' => '',
                       '{reference} in @cite{{book}}' => '',
                       '{ref}' => '',
                       '{style} {number}' => '',
                       '{style}: {caption_first_line}' => '',
                       '{style}: {shortcaption_first_line}' => '',
                       '{title_ref}' => ''
                     };

require "$T2H_HOME/$translation_file"
    if ($0 =~ /\.pl$/ &&
        -e "$T2H_HOME/$translation_file" && -r "$T2H_HOME/$translation_file");


# these are unlikely to be used by users, as they are essentially
# used to follow the html external refs specification in texinfo
sub t2h_cross_manual_normal_text($$$$$$$;$)
{
    my $text = shift;
    my $in_raw_text = shift;
    my $in_preformatted = shift;
    my $in_code =shift;
    my $in_math = shift;
    my $in_simple =shift;
    my $style_stack = shift;
    my $state = shift;

    $text = uc($text) if (in_small_caps($style_stack));
    return $text if ($USE_UNICODE);
    return t2h_no_unicode_cross_manual_normal_text($text, 0);
}

sub t2h_cross_manual_normal_text_transliterate($$$$$$$;$)
{
    my $text = shift;
    my $in_raw_text = shift;
    my $in_preformatted = shift;
    my $in_code =shift;
    my $in_math = shift;
    my $in_simple =shift;
    my $style_stack = shift;
    my $state = shift;

    $text = uc($text) if (in_small_caps($style_stack));
    return $text if ($USE_UNICODE);
    return t2h_no_unicode_cross_manual_normal_text($text, 1);
}

sub t2h_no_unicode_cross_manual_normal_text($$)
{
    # if there is no unicode support, we do all the transformations here
    my $text = shift;
    my $transliterate = shift;
    my $result = '';
    
    my $encoding = get_conf('DOCUMENT_ENCODING');
    if (defined($encoding) and exists($t2h_encoding_aliases{$encoding}))
    {
        $encoding = $t2h_encoding_aliases{$encoding};
    }
    
    while ($text ne '')
    {
        if ($text =~ s/^([A-Za-z0-9]+)//o)
        {
             $result .= $1;
        }
        elsif ($text =~ s/^ //o)
        {
             $result .= '-';
        }
        elsif ($text =~ s/^(.)//o)
        {
             if (exists($ascii_character_map{$1}))
             {
                 $result .= '_' . lc($ascii_character_map{$1});
             }
             else
             { 
                  my $character = $1;
                  my $charcode = uc(sprintf("%02x",ord($1)));
                  my $done = 0;
                  if (defined($encoding) and exists($eight_bit_to_unicode{$encoding})
                      and exists($eight_bit_to_unicode{$encoding}->{$charcode}))
                  {
                      $done = 1;
                      my $unicode_point =  $eight_bit_to_unicode{$encoding}->{$charcode};
                      if (!$transliterate)
                      {
                           $result .= '_' . lc($unicode_point);
                      }
                      elsif (exists($transliterate_map{$unicode_point}))
                      {
                           $result .= $transliterate_map{$unicode_point};
                      }
                      elsif (exists($unicode_diacritical{$unicode_point}))
                      {
                           $result .= '';
                      }
                      else
                      {
                          $done = 0;
                      }
                  }

                  if (!$done)
                  { # wild guess that work for latin1, and thus, should fail
                      $result .= '_' . '00' . lc($charcode);
                  }
             }
        }
        else
        {
             msg_debug("Bug: unknown character in cross ref (likely in infinite loop)");
             msg_debug("Text: !!$text!!");
             sleep 1;
        }
    }
   
    return $result;
}

sub t2h_nounicode_cross_manual_accent($$$)
{
    my $accent = shift;
    my $args = shift;
    my $style_stack = shift;
                                                                                
    my $text = $args->[0];

    if ($accent eq 'dotless')
    { 
        if (($text eq 'i') and (!defined($style_stack->[-1]) or (!defined($unicode_accents{$style_stack->[-1]})) or ($style_stack->[-1] eq 'tieaccent')))
        {
             return "_0131";
        }
        #return "\x{}" if ($text eq 'j'); # not found !
        return $text;
    }
    return '_' . lc($unicode_accents{$accent}->{$text})
        if (defined($unicode_accents{$accent}->{$text}));
    return ($text . '_' . lc($unicode_diacritical{$accent})) 
        if (defined($unicode_diacritical{$accent}));
    return ascii_accents($text, $accent);
}

sub t2h_transliterate_cross_manual_accent($$)
{
    my $accent = shift;
    my $args = shift;
                                                                                
    my $text = $args->[0];

    if (exists($unicode_accents{$accent}->{$text}) and
        exists ($transliterate_map{$unicode_accents{$accent}->{$text}}))
    {
         return $transliterate_map{$unicode_accents{$accent}->{$text}};
    }
    return $text;
}


} # end package Texi2HTML::Config

# set the defaults based on real command name
set_config_init_dirs_output($real_command_name);

use vars qw(
%value
%alias
);

# variables which might be redefined by the user but aren't likely to be  
# they seem to be in the main namespace
use vars qw(
%index_names
%index_prefix_to_name
%predefined_index
%valid_index
%reference_sec2level
%code_style_map
%forbidden_index_name
);

# Some global variables are set in the script, and used in the subroutines
# they are in the Texi2HTML namespace, thus prefixed with Texi2HTML::.
# see texi2html.init for details.

#+++############################################################################
#                                                                              #
# Pasted content of File $(srcdir)/MySimple.pm: Command-line processing        #
#                                                                              #
#---############################################################################

# leave this within comments, and keep the require statement
# This way, you can directly run texi2html.pl, if $T2H_HOME/MySimple.pm
# exists.

# @MYSIMPLE@
package Getopt::MySimple;

# Name:
#	Getopt::MySimple.
#
# Documentation:
#	POD-style (incomplete) documentation is in file MySimple.pod
#
# Tabs:
#	4 spaces || die.
#
# Author:
#	Ron Savage	rpsavage@ozemail.com.au.
#	1.00	19-Aug-97	Initial version.
#	1.10	13-Oct-97	Add arrays of switches (eg '=s@').
#	1.20	 3-Dec-97	Add 'Help' on a per-switch basis.
#	1.30	11-Dec-97	Change 'Help' to 'verbose'. Make all hash keys lowercase.
#	1.40	10-Nov-98	Change width of help report. Restructure tests.
#               1-Jul-00        Modifications for Texi2html

# --------------------------------------------------------------------------
# Locally modified by obachman (Display type instead of env, order by cmp)
# $Id: MySimple.pm,v 1.8 2009/08/23 21:50:15 pertusus Exp $

# use strict;
# no strict 'refs';

use vars qw(@EXPORT @EXPORT_OK @ISA);
use vars qw($fieldWidth $opt $VERSION);

use Exporter();
use Getopt::Long;

@ISA		= qw(Exporter);
@EXPORT		= qw();
@EXPORT_OK	= qw($opt);	# An alias for $self -> {'opt'}.

# --------------------------------------------------------------------------

$fieldWidth	= 20;
$VERSION	= '1.41';

# --------------------------------------------------------------------------

sub byOrder
{
	my($self) = @_;
	
	return uc($a) cmp (uc($b));
}

# --------------------------------------------------------------------------

sub dumpOptions
{
	my($self) = @_;

	print 'Option', ' ' x ($fieldWidth - length('Option') ), "Value\n";

	for (sort byOrder keys(%{$self -> {'opt'} }) )
	{
	  print "-$_", ' ' x ($fieldWidth - (1 + length) ), "${$self->{'opt'} }{$_}\n";
	}

	print "\n";

}	# End of dumpOptions.

# --------------------------------------------------------------------------
# Return:
#	0 -> Error.
#	1 -> Ok.

sub getOptions
{
	push(@_, 0) if ($#_ == 2);	# Default for $ignoreCase is 0.
	push(@_, 1) if ($#_ == 3);	# Default for $helpThenExit is 1.

	my($self, $default, $helpText, $versionText, 
	   $helpThenExit, $versionThenExit, $ignoreCase) = @_;
	
	$helpThenExit = 1 unless (defined($helpThenExit));
	$versionThenExit = 1 unless (defined($versionThenExit));
	$ignoreCase = 0 unless (defined($ignoreCase));

	$self -> {'default'}		= $default;
	$self -> {'helpText'}		= $helpText;
	$self -> {'versionText'}        = $versionText;
	$Getopt::Long::ignorecase	= $ignoreCase;

	unless (defined($self -> {'default'}{'help'}))
	{
	  $self -> {'default'}{'help'} = 
	  { 
	   type => ':i', 
	   default => '',
	   linkage => sub {$self->helpOptions($_[1]); sleep 5;exit (0) if $helpThenExit;},
	   verbose => "print help and exit"
	  };
	}

	unless (defined($self -> {'default'}{'version'}))
	{
	  $self -> {'default'}{'version'} = 
	  { 
	   type => '', 
	   default => '',
	   linkage => sub {print $self->{'versionText'};  exit (0) if $versionThenExit;},
	   verbose => "print version and exit"
	  };
	}

	for (keys(%{$self -> {'default'} }) )
	{
	  next unless (ref(${$self -> {'default'} }{$_}) eq 'HASH');
	  my $type = ${$self -> {'default'} }{$_}{'type'};
	  push(@{$self -> {'type'} }, "$_$type");
	  my $key = $_;
	  # get rid of aliases, if any
	  $key =~ s/\|.*//;
	  $self->{'opt'}->{$key} =  ${$self -> {'default'} }{$_}{'linkage'}
            if ${$self -> {'default'} }{$_}{'linkage'};
	}

	my($result) = &GetOptions($self -> {'opt'}, @{$self -> {'type'} });

        return $result unless $result;

	for (keys(%{$self -> {'default'} }) )
	{
 	   if (! defined(${$self -> {'opt'} }{$_})) #{
            {
 	     ${$self -> {'opt'} }{$_} = ${$self -> {'default'} }{$_}{'default'};
            }
	}

	$result;
}	# End of getOptions.

# --------------------------------------------------------------------------

sub helpOptions
{
	my($self) = shift;
	my($noHelp) = shift;
	$noHelp = 0 unless $noHelp;
	my($optwidth, $typewidth, $defaultwidth, $maxlinewidth, $valind, $valwidth) 
	  = (10, 5, 9, 78, 4, 11);

	print "$self->{'helpText'}" if ($self -> {'helpText'});

	print ' Option', ' ' x ($optwidth - length('Option') -1 ),
		'Type', ' ' x ($typewidth - length('Type') + 1),
		'Default', ' ' x ($defaultwidth - length('Default') ),
	        "Description\n";

	for (sort byOrder keys(%{$self -> {'default'} }) )
	{
	  my($line, $help, $option, $val);
	  $option = $_;
	  next if (ref(${$self -> {'default'} }{$_}) ne 'HASH' or (${$self->{'default'} }{$_}{'noHelp'} && ${$self->{'default'} }{$_}{'noHelp'} > $noHelp));
          #$line = " -$_" . ' ' x ($optwidth - (2 + length) ) .
          #      	"${$self->{'default'} }{$_}{'type'} ".
          #      	' ' x ($typewidth - (1+length(${$self -> {'default'} }{$_}{'type'}) ));
		$line = " --$_" . "${$self->{'default'} }{$_}{'type'}".
			' ' x ($typewidth - (1+length(${$self -> {'default'} }{$_}{'type'}) ));

                 $val = ${$self->{'default'} }{$_}{'linkage'};
                if ($val)
                {
                  if ((ref($val) eq 'SCALAR') and (defined($$val)))
		  {
		    $val = $$val; 
		  }
		  else
		  {
		    $val = '';
		  }
                }
		elsif (defined(${$self->{'default'} }{$_}{'default'}))
		{
		  $val = ${$self->{'default'} }{$_}{'default'};
		}
		else
		{
		  $val = '';
		}
	        $line .= "$val  ";
		$line .= ' ' x ($optwidth + $typewidth + $defaultwidth + 1 - length($line));
		
		if (defined(${$self -> {'default'} }{$_}{'verbose'}) &&
		  ${$self -> {'default'} }{$_}{'verbose'} ne '')
	      {
		$help = "${$self->{'default'} }{$_}{'verbose'}";
	      }
	      else
	      {
		$help = ' ';
	      }
	      if ((length("$line") + length($help)) < $maxlinewidth)
	      {
		print $line , $help, "\n";
	      }
	      else
	      {
		print $line, "\n", ' ' x $valind, $help, "\n";
	      }
	      for $val (sort byOrder keys(%{${$self->{'default'}}{$option}{'values'}}))
	      {
	        print ' ' x ($valind + 2);
                print $val, '  ', ' ' x ($valwidth - length($val) - 2);
	        print ${$self->{'default'}}{$option}{'values'}{$val}, "\n";
	      }
	}

	print <<EOT;
Note: 'Options' may be abbreviated. -- prefix may be replaced by a single -.
'Type' specifications mean:
 <none>| !    no argument: variable is set to 1 on -foo (or, to 0 on -nofoo)
    =s | :s   mandatory (or, optional)  string argument
    =i | :i   mandatory (or, optional)  integer argument
EOT
}	# End of helpOptions.

#-------------------------------------------------------------------

sub new
{
	my($class)				= @_;
	my($self)				= {};
	$self -> {'default'}	= {};
	$self -> {'helpText'}	= '';
	$self -> {'opt'}		= {};
	$opt					= $self -> {'opt'};	 # An alias for $self -> {'opt'}.
	$self -> {'type'}		= ();

	return bless $self, $class;

}	# End of new.

# --------------------------------------------------------------------------

1;

# End MySimple.pm

require "$T2H_HOME/MySimple.pm"
    if ($0 =~ /\.pl$/ &&
        -e "$T2H_HOME/MySimple.pm" && -r "$T2H_HOME/MySimple.pm");

#+++########################################################################
#                                                                          #
# Pasted content of File $(srcdir)/T2h_i18n.pm: Internationalisation       #
#                                                                          #
#---########################################################################

# leave this within comments, and keep the require statement
# This way, you can directly run texi2html.pl, if $T2H_HOME/T2h_i18n.pm
# exists.

{
# @T2H_I18N@
#+##############################################################################
#
# T2h_i18n.pm: Internationalization for texi2html
#
#    Copyright (C) 1999-2005  Patrice Dumas <pertusus@free.fr>,
#                             Derek Price <derek@ximbiot.com>,
#                             Adrian Aichner <adrian@xemacs.org>,
#                           & others.
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
#
#-##############################################################################

# This requires perl version 5 or higher
require 5.0;

package Texi2HTML::I18n;

use strict;

use vars qw(
@ISA
@EXPORT
);

use Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(pretty_date);

my $language;
my $i18n_dir = 'i18n'; # name of the directory containing the per language files
#my $translation_file = 'translations.pl'; # file containing all the translations
#my @known_languages = ('de', 'nl', 'es', 'no', 'pt', 'fr'); # The supported
                                               # languages

########################################################################
# Language dependencies:
# To add a new language extend the WORDS hash and create $T2H_<...>_WORDS hash
# To redefine one word, simply do:
# $T2h_i18n::T2H_LANGUAGES->{<language>}->{<word>} = 'whatever' in your personal init file.
#

# Those hashes are obsolete but retained here for reference

my $T2H_WORDS_EN =
{
 # titles  of pages
 #'Table of Contents'       => 'Table of Contents',
 #'Short Table of Contents'  => 'Short Table of Contents',
 #'Index'     => 'Index',
 #'About This Document'     => 'About This Document',
 #'Footnotes' => 'Footnotes',
 #'See'             => 'See',
 #'see'             => 'see',
 #'section'         => 'section',
 'About This Document'       => '',
 'Table of Contents'         => '',
 'Short Table of Contents',  => '',
 'Index'                     => '',
 'Footnotes'                 => '',
 'See'                       => '',
 'see'                       => '',
 'section'                   => '',
 'Top'                       => '',
 'Untitled Document'         => '',
 # If necessary, we could extend this as follows:
 #  # text for buttons
 #  'Top_Button' => 'Top',
 #  'ToC_Button' => 'Contents',
 #  'Overview_Button' => 'Overview',
 #  'Index_button' => 'Index',
 #  'Back_Button' => 'Back',
 #  'FastBack_Button' => 'FastBack',
 #  'Prev_Button' => 'Prev',
 #  'Up_Button' => 'Up',
 #  'Next_Button' => 'Next',
 #  'Forward_Button' =>'Forward',
 #  'FastWorward_Button' => 'FastForward',
 #  'First_Button' => 'First',
 #  'Last_Button' => 'Last',
 #  'About_Button' => 'About'
 'January' => '', 
 'February' => '',
 'March' => '', 
 'April' => '',
 'May' => '',
 'June' => '',
 'July' => '',
 'August' => '',
 'September' => '',
 'October' => '',
 'November' => '',
 'December' => '', 
 'T2H_today' => '%s, %d %d',
};

my $T2H_WORDS_DE =
{
 'Table of Contents'       => 'Inhaltsverzeichniss',
 'Short Table of Contents'  => 'Kurzes Inhaltsverzeichniss',
 'Index'     => 'Index',
 'About This Document'     => '&Uuml;ber dieses Dokument',
 'Footnotes' => 'Fu&szlig;noten',
 'See'             => 'Siehe',
 'see'             => 'siehe',
 'section'         => 'Abschnitt',
 'January' => 'Januar', 
 'February' => 'Februar',
 'March' => 'M&auml;rz', 
 'April' => 'April',
 'May' => 'Mai',
 'June' => 'Juni',
 'July' => 'Juli',
 'August' => 'August',
 'September' => 'September',
 'October' => 'Oktober',
 'November' => 'November',
 'December' => 'Dezember', 
};

my $T2H_WORDS_NL =
{
 'Table of Contents'       => 'Inhoudsopgave',
 'Short Table of Contents'  => 'Korte inhoudsopgave',
 'Index'     => 'Index',      #Not sure ;-)
 'About This Document'     => 'No translation available!', #No translation available!
 'Footnotes' => 'No translation available!', #No translation available!
 'See'             => 'Zie',
 'see'             => 'zie',
 'section'         => 'sectie',
 'January' => 'Januari', 
 'February' => 'Februari',
 'March' => 'Maart', 
 'April' => 'April',
 'May' => 'Mei',
 'June' => 'Juni',
 'July' => 'Juli',
 'August' => 'Augustus',
 'September' => 'September',
 'October' => 'Oktober',
 'November' => 'November',
 'December' => 'December', 
};

my $T2H_WORDS_ES =
{
 'Table of Contents'       => '&iacute;ndice General',
 'Short Table of Contents'  => 'Resumen del Contenido',
 'Index'     => 'Index',      #Not sure ;-)
 'About This Document'     => 'No translation available!', #No translation available!
 'Footnotes' => 'Fu&szlig;noten',
 'See'             => 'V&eacute;ase',
 'see'             => 'v&eacute;ase',
 'section'         => 'secci&oacute;n',
 'January' => 'enero', 
 'February' => 'febrero',
 'March' => 'marzo', 
 'April' => 'abril',
 'May' => 'mayo',
 'June' => 'junio',
 'July' => 'julio',
 'August' => 'agosto',
 'September' => 'septiembre',
 'October' => 'octubre',
 'November' => 'noviembre',
 'December' => 'diciembre', 
};

my $T2H_WORDS_NO =
{
 'Table of Contents'       => 'Innholdsfortegnelse',
 'Short Table of Contents'  => 'Kort innholdsfortegnelse',
 'Index'     => 'Indeks',     #Not sure ;-)
 'About This Document'     => 'No translation available!', #No translation available!
 'Footnotes' => 'No translation available!',
 'See'             => 'Se',
 'see'             => 'se',
 'section'         => 'avsnitt',
 'January' => 'januar', 
 'February' => 'februar',
 'March' => 'mars', 
 'April' => 'april',
 'May' => 'mai',
 'June' => 'juni',
 'July' => 'juli',
 'August' => 'august',
 'September' => 'september',
 'October' => 'oktober',
 'November' => 'november',
 'December' => 'desember', 
};

my $T2H_WORDS_PT =
{
 'Table of Contents'       => 'Sum&aacute;rio',
 'Short Table of Contents'  => 'Breve Sum&aacute;rio',
 'Index'     => '&Iacute;ndice', #Not sure ;-)
 'About This Document'     => 'No translation available!', #No translation available!
 'Footnotes' => 'No translation available!',
 'See'             => 'Veja',
 'see'             => 'veja',
 'section'         => 'Se&ccedil;&atilde;o',
 'January' => 'Janeiro', 
 'February' => 'Fevereiro',
 'March' => 'Mar&ccedil;o', 
 'April' => 'Abril',
 'May' => 'Maio',
 'June' => 'Junho',
 'July' => 'Julho',
 'August' => 'Agosto',
 'September' => 'Setembro',
 'October' => 'Outubro',
 'November' => 'Novembro',
 'December' => 'Dezembro', 
};

my $T2H_WORDS_FR =
{
 'Table of Contents'       => 'Table des mati&egrave;res',
 'Short Table of Contents'  => 'R&eacute;sum&eacute;e du contenu',
 'Index'     => 'Index',
 'About This Document'     => 'A propos de ce document',
 'Footnotes' => 'Notes de bas de page',
 'See'             => 'Voir',
 'see'             => 'voir',
 'section'         => 'section',
 'January' => 'Janvier', 
 'February' => 'F&eacute;vrier',
 'March' => 'Mars', 
 'April' => 'Avril',
 'May' => 'Mai',
 'June' => 'Juin',
 'July' => 'Juillet',
 'August' => 'Ao&ucirc;t',
 'September' => 'Septembre',
 'October' => 'Octobre',
 'November' => 'Novembre',
 'December' => 'D&eacute;cembre', 
 'T2H_today' => 'le %2$d %1$s %3$d'
};

#$T2H_LANGUAGES =
#{
# 'en' => $T2H_WORDS_EN,
# 'de' => $T2H_WORDS_DE,
# 'nl' => $T2H_WORDS_NL,
# 'es' => $T2H_WORDS_ES,
# 'no' => $T2H_WORDS_NO,
# 'pt' => $T2H_WORDS_PT,
# 'fr' => $T2H_WORDS_FR,
#};

sub set_language($)
{
    my $lang = shift;
    if (defined($lang) && exists($Texi2HTML::Config::LANGUAGES->{$lang}) && defined($Texi2HTML::Config::LANGUAGES->{$lang}))
    {
         $language = $lang;
         return 1;
    }
    else
    {
         return 0;
    }
}

sub get_language()
{
    return $language;
}

my @MONTH_NAMES =
    (
     'January', 'February', 'March', 'April', 'May',
     'June', 'July', 'August', 'September', 'October',
     'November', 'December'
    );

# This is not used as code, but used to mark months as strings to be
# translated
if (0)
{
    my @mark_month_for_translation = (
     gdt('January'), 
     gdt('February'), 
     gdt('March'), 
     gdt('April'), 
     gdt('May'),
     gdt('June'), 
     gdt('July'), 
     gdt('August'), 
     gdt('September'), 
     gdt('October'),
     gdt('November'), 
     gdt('December')
    );
}

my $I = \&get_string;

sub pretty_date($) 
{
    my $lang = shift;
    my($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);

    ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
    $year += ($year < 70) ? 2000 : 1900;
    return main::gdt('{month} {day}, {year}', { 'month' => main::gdt($MONTH_NAMES[$mon]),
          'day' => $mday, 'year' => $year });
}

my $error_no_en = 0;

my %missing_strings;

# arguments should already be converted
sub get_string($;$$)
{
    my $string = shift;
    my $arguments = shift;
    $arguments = undef if (!ref($arguments));
    my $state = shift;
    # if duplicate is passed, it means that we are in the text and so should
    # use the main state
    if (defined($state) and $state->{'duplicate'} and defined($Texi2HTML::THISDOC{'state'}))
    {
        $state = main::duplicate_formatting_state($Texi2HTML::THISDOC{'state'});
    }

    my $translated_string;
    my $T2H_LANGUAGES = $Texi2HTML::Config::LANGUAGES;
    if (! exists($T2H_LANGUAGES->{'en'}))
    {
        unless($error_no_en)
        {
            print STDERR "i18n: no LANGUAGES->{'en'} hash\n";
            $error_no_en = 1;
        }
    }
    else
    {
        unless (exists ($T2H_LANGUAGES->{'en'}->{$string}))
        {
            unless (exists($missing_strings{$string}))
            {
                #print STDERR "i18n: missing string $string\n";
                $missing_strings{$string} = 1;
            }
        }
        if (defined ($T2H_LANGUAGES->{$language}->{$string}) and
           ($T2H_LANGUAGES->{$language}->{$string} ne ''))
        {
            $translated_string = $T2H_LANGUAGES->{$language}->{$string};
        }
        elsif (defined ($T2H_LANGUAGES->{'en'}->{$string}) and
            ($T2H_LANGUAGES->{'en'}->{$string} ne ''))
        {
            $translated_string = $T2H_LANGUAGES->{'en'}->{$string};
        }
        else
        {
            $translated_string = $string;
        }
    }
    return main::substitute_line($translated_string, "translation",  $state) unless (defined($arguments) or !keys(%$arguments));
    
    # taken from libintl perl, copyright Guido. sub __expand
    my %args = %$arguments;
    my $re = join '|', map { quotemeta $_ } keys %args;

    if ($state->{'keep_texi'})
    {
        $translated_string =~ s/\{($re)\}/defined $args{$1} ? $args{$1} : "{$1}"/ge;
        return $translated_string;
    }

    # if there are arguments, we must protect the {arg} constructs before
    # doing substitute_line. So there is a first pass here to change {arg} 
    # to %@internal_translation_open_brace{}arg@internal_translation_close_brace{}
    $translated_string =~ s/\{($re)\}/\@internal_translation_open_brace\{\}$1\@internal_translation_close_brace\{\}/g;
    foreach my $map (\%Texi2HTML::Config::things_map, \%Texi2HTML::Config::pre_map,  \%Texi2HTML::Config::texi_map, \%Texi2HTML::Config::simple_format_texi_map)
    {
         $map->{'internal_translation_open_brace'} = '{';
         $map->{'internal_translation_close_brace'} = '}';
    }
    $translated_string = main::substitute_line($translated_string, "translation", $state);
    $translated_string =~ s/\{($re)\}/defined $args{$1} ? $args{$1} : "{$1}"/ge;
    foreach my $map (\%Texi2HTML::Config::things_map, \%Texi2HTML::Config::pre_map,  \%Texi2HTML::Config::texi_map, \%Texi2HTML::Config::simple_format_texi_map)
    {
         delete $map->{'internal_translation_open_brace'};
         delete $map->{'internal_translation_close_brace'};
    }
    return $translated_string;

}

1;
require "$T2H_HOME/T2h_i18n.pm"
    if ($0 =~ /\.pl$/ &&
        -e "$T2H_HOME/T2h_i18n.pm" && -r "$T2H_HOME/T2h_i18n.pm");
}


#########################################################################
#
# latex2html code
#
#---######################################################################

{
# leave this within comments, and keep the require statement
# This way, you can directly run texi2html.pl, if $ENV{T2H_HOME}/T2h_l2h.pm
# exists.

# @T2H_L2H@
#+##############################################################################
#
# T2h_l2h.pm: interface to LaTeX2HTML
#
#    Copyright (C) 1999-2005  Patrice Dumas <pertusus@free.fr>,
#                             Derek Price <derek@ximbiot.com>,
#                             Adrian Aichner <adrian@xemacs.org>,
#                           & others.
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
#    02110-1301  USA
#
#-##############################################################################

require 5.0;
use strict;

package Texi2HTML::LaTeX2HTML;
use Cwd;


# latex2html conversions consist of three stages:
# 1) to latex: Put "latex" code into a latex file 
#                    (init, to_latex, finish_to_latex)
# 2) to html: Use latex2html to generate corresponding html code and images
#                    (to_html)
# 3) from html: Extract generated code and images from latex2html run
#                    (init_from_html, do_tex)

# init l2h defaults for files and names

# global variable used for caching
# FIXME there is no reason for this variable to be global
use vars qw(
            %l2h_cache
           );

my ($l2h_name, $l2h_latex_file, $l2h_cache_file, $l2h_html_file, $l2h_prefix);

# holds the status of latex2html operations. If 0 it means that there was 
# an error
my $status = 0;

my $debug;
my $verbose;
my $docu_rdir;
my $docu_name;

# init_from_html
my $extract_error_count;
my $invalid_counter_count;

# change_image_file_names
my %l2h_img;            # associate src file to destination file
                        # such that files are not copied twice
my $image_count;

# do_tex
my $html_output_count = 0;   # html text outputed in html result file

##########################
#
# First stage: Generation of Latex file
# Initialize with: init
# Add content with: to_latex ($text) --> HTML placeholder comment
# Finish with: finish_to_latex
#

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

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

my %l2h_to_latex = ();         # associate a latex text with the index in the
                               # html result array.
my @l2h_to_latex = ();         # array used to associate the index with 
                               # the original latex text.
my $latex_count = 0;           # number of latex texts really stored
my $latex_converted_count = 0; # number of latex texts passed through latex2html
my $to_latex_count = 0;        # total number of latex texts processed
my $cached_count = 0;          # number of cached latex texts
%l2h_cache = ();               # the cache hash. Associate latex text with 
                               # html from the previous run
my @l2h_from_html;             # array of resulting html

my %global_count = ();         # associate a command name and the 
                               # corresponding counter to the index in the
                               # html result array

# set $status to 1, if l2h could be initalized properly, to 0 otherwise
sub init()
{

   %l2h_to_latex = ();         # associate a latex text with the index in the
                               # html result array.
   @l2h_to_latex = ();         # array used to associate the index with 
                               # the original latex text.
   $latex_count = 0;           # number of latex texts really stored
   $latex_converted_count = 0; # number of latex texts passed through latex2html
   $to_latex_count = 0;        # total number of latex texts processed
   $cached_count = 0;          # number of cached latex texts
   %l2h_cache = ();            # the cache hash. Associate latex text with 
                               # html from the previous run
   @l2h_from_html = ();        # array of resulting html

   %global_count = ();         # associate a command name and the 
                               # corresponding counter to the index in the
                               # html result array
   $extract_error_count = 0;
   $invalid_counter_count = 0;
   %l2h_img = ();       # associate src file to destination file
                        # such that files are not copied twice
   $image_count = 1;

   $html_output_count = 0;   # html text outputed in html result file
   $status = 0;
   return if ($Texi2HTML::Config::null_device_file{$Texi2HTML::THISDOC{'filename'}->{'top'}});

    $docu_name = $Texi2HTML::THISDOC{'file_base_name'};
    $docu_rdir = $Texi2HTML::THISDOC{'destination_directory'};
    $docu_rdir = '' if (!defined($docu_rdir));
    $l2h_name =  "${docu_name}_l2h";
    $l2h_latex_file = "$docu_rdir${l2h_name}.tex";
    $l2h_cache_file = "${docu_rdir}${docu_name}-l2h_cache.pm";
    # 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}_";
    $debug = $Texi2HTML::THISDOC{'debug_l2h'};
    $verbose = $Texi2HTML::Config::VERBOSE;

    unless ($Texi2HTML::Config::L2H_SKIP)
    {
        unless (open(L2H_LATEX, ">$l2h_latex_file"))
        {
            main::document_error ("l2h: Can't open latex file '$l2h_latex_file' for writing: $!");
            $status = 0;
            return;
        }
        warn "# l2h: use ${l2h_latex_file} as latex file\n" if ($verbose);
        print L2H_LATEX $l2h_latex_preamble;
    }
    # open the database that holds cached text
    init_cache() if (!defined($Texi2HTML::Config::L2H_SKIP) or $Texi2HTML::Config::L2H_SKIP);
    $status = 1;
}


# print text (2nd arg) into latex file (if not already there nor in cache)
# which can be later on replaced by the latex2html generated text.
# 
sub to_latex($$$)
{
    my $command = shift;
    my $text = shift;
    my $counter = shift;
    return unless ($status);
    if ($command eq 'tex')
    {
        $text .= ' ';
    }
    elsif ($command eq 'math') 
    {
        $text = "\$".$text."\$";
    }
    $to_latex_count++;
    $text =~ s/(\s*)$//;
    # try whether we have text already on things to do
    my $count = $l2h_to_latex{$text};
    unless ($count)
    {
        $latex_count++;
        $count = $latex_count;
        # try whether we can get it from cache
        my $cached_text = from_cache($text);
        if (defined($cached_text))
        {
             $cached_count++;
             # put the cached result in the html result array
             $l2h_from_html[$count] = $cached_text;
        }
        else
        {
             $latex_converted_count++;
             unless ($Texi2HTML::Config::L2H_SKIP)
             {
                 print L2H_LATEX "\\begin{rawhtml}\n\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\n";
                 print L2H_LATEX "\\end{rawhtml}\n";
            }
        }
        $l2h_to_latex[$count] = $text;
        $l2h_to_latex{$text} = $count;
    }
    $global_count{"${command}_$counter"} = $count; 
    return 1;
}

# print closing into latex file and close it
sub finish_to_latex()
{
    my $reused = $to_latex_count - $latex_converted_count - $cached_count;
    unless ($Texi2HTML::Config::L2H_SKIP)
    {
        print L2H_LATEX $l2h_latex_closing;
        close (L2H_LATEX);
    }
    warn "# l2h: finished to latex ($cached_count cached, $reused reused, $latex_converted_count to process)\n" if ($verbose);
    unless ($latex_count)
    {
        # no @tex nor @math
        finish();
        return 0;
    }
    return 1;
}

###################################
# Second stage: Use latex2html to generate corresponding html code and images
#
# to_html([$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 to_html()
{
    my ($call, $dotbug);
    # when there are no tex constructs to convert (happens in case everything
    # comes from the cache), there is no latex2html run
    if ($Texi2HTML::Config::L2H_SKIP or ($latex_converted_count == 0))
    {
        warn "# l2h: skipping latex2html run\n" if ($verbose);
        return 1;
    }
    # Check for dot in directory where dvips will work
    if ($Texi2HTML::Config::L2H_TMP)
    {
        if ($Texi2HTML::Config::L2H_TMP =~ /\./)
        {
            main::document_warn ("l2h: l2h_tmp dir contains a dot.");
            $dotbug = 1;
        }
    }
    else
    {
        if (cwd() =~ /\./)
        {
            main::document_warn ("l2h: current dir contains a dot.");
            $dotbug = 1;
        }
    }
    # fix it, if necessary and hope that it works
    #$Texi2HTML::Config::L2H_TMP = "/tmp" if ($dotbug);
    return 0 if ($dotbug);

    $call = $Texi2HTML::Config::L2H_L2H;
    # use init file, if specified
    my $init_file = main::locate_init_file($Texi2HTML::Config::L2H_FILE);
    $call = $call . " -init_file " . $init_file if ($init_file);
    # set output dir
    $call .=  (($docu_rdir ne '') ? " -dir $docu_rdir" : " -no_subdir");
    # use l2h_tmp, if specified
    $call .= " -tmp $Texi2HTML::Config::L2H_TMP" 
         if (defined($Texi2HTML::Config::L2H_TMP) and $Texi2HTML::Config::L2H_TMP ne '');
    # use a given html version if specified
    $call .= " -html_version $Texi2HTML::Config::L2H_HTML_VERSION" 
      if (defined($Texi2HTML::Config::L2H_HTML_VERSION) and $Texi2HTML::Config::L2H_HTML_VERSION ne '');
    # options we want to be sure of
    $call .= " -address 0 -info 0 -split 0 -no_navigation -no_auto_link";
    $call .= " -prefix $l2h_prefix $l2h_latex_file";

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

##########################
# Third stage: Extract generated contents from latex2html run
# Initialize with: init_from_html
#   open $l2h_html_file for reading
#   reads in contents into array indexed by numbers
#   return 1,  on success -- 0, otherwise
# Finish with: finish
#   closes $l2h_html_dir/$l2h_name.".$docu_ext"


# the images generated by latex2html have names like ${docu_name}_l2h_img?.png
# they are copied to ${docu_name}_?.png, and html is changed accordingly.

# FIXME is it really necessary to bother doing that? Looks like an unneeded
# complication to me (pertusus, 2009), and it could go bad if there is some
# SRC="(.*?)" in the text (though the regexp could be made more specific).

# %l2h_img;            # associate src file to destination file
                        # such that files are not copied twice
sub change_image_file_names($)
{
    my $content = shift;
    my @images = ($content =~ /SRC="(.*?)"/g);
    my ($src, $dest);

    for $src (@images)
    {
        $dest = $l2h_img{$src};
        unless ($dest)
        {
            my $ext = '';
            if ($src =~ /.*\.(.*)$/ and (!defined($Texi2HTML::THISDOC{'extension'}) or $1 ne $Texi2HTML::THISDOC{'extension'}))
            {
                $ext = ".$1";
            }
            else
            { # A warning when the image extension is the same than the 
              # document extension. copying the file could result in 
              # overwriting an output file (almost surely if the default 
              # texi2html file names are used).
                main::document_warn ("L2h image $src has invalid extension");
                next;
            }
            while (-e "$docu_rdir${docu_name}_${image_count}$ext")
            {
                $image_count++;
            }
            $dest = "${docu_name}_${image_count}$ext";
            if ($debug)
            {
               # not portable, but only used with debug.
               system("cp -f $docu_rdir$src $docu_rdir$dest");
            }
            else
            {
               # FIXME error condition not checked.
               rename ("$docu_rdir$src", "$docu_rdir$dest");
            }
            $l2h_img{$src} = $dest;
            #unlink "$docu_rdir$src" unless ($debug);
        }
        $content =~ s/SRC="$src"/SRC="$dest"/g;
    }
    return $content;
}

sub init_from_html()
{
    # when there are no tex constructs to convert (happens in case everything
    # comes from the cache), the html file that was generated by previous
    # latex2html runs isn't reused.
    if ($latex_converted_count == 0)
    {
        return 1;
    }

    if (! open(L2H_HTML, "<$l2h_html_file"))
    {
        main::document_warn ("l2h: Can't open $l2h_html_file for reading");
        return 0;
    }
    warn "# l2h: use $l2h_html_file as html file\n" if ($verbose);

    my $html_converted_count = 0;   # number of html resulting texts 
                                    # retrieved in the file

    my ($count, $h_line);
    while ($h_line = <L2H_HTML>)
    {
        if ($h_line =~ /!-- l2h_begin $l2h_name ([0-9]+) --/)
        {
            $count = $1;
            my $h_content = '';
            my $h_end_found = 0;
            while ($h_line = <L2H_HTML>)
            {
                if ($h_line =~ /!-- l2h_end $l2h_name $count --/)
                {
                    $h_end_found = 1;
                    chomp $h_content;
                    chomp $h_content;
                    $html_converted_count++;
                    # transform image file names and copy image files
                    $h_content = change_image_file_names($h_content);
                    # store result in the html result array
                    $l2h_from_html[$count] = $h_content;
                    # also add the result in cache hash
                    $l2h_cache{$l2h_to_latex[$count]} = $h_content;
                    last;
                }
                $h_content = $h_content.$h_line;
            }
            unless ($h_end_found)
            { # couldn't found the closing comment. Certainly  a bug.
                main::msg_debug ("l2h: l2h_end $l2h_name $count not found");
                close(L2H_HTML);
                return 0;
            }
        }
    }

    # Not the same number of converted elements and retrieved elements
    if ($latex_converted_count != $html_converted_count)
    {
        main::msg_debug ("l2h: waiting for $latex_converted_count elements found $html_converted_count");
    }

    warn "# l2h: Got $html_converted_count of $latex_count html contents\n"
        if ($verbose);

    close(L2H_HTML);
    return 1;
}

# $html_output_count = 0;   # html text outputed in html result file

# called each time a construct handled by latex2html is encountered, should
# output the corresponding html
sub do_tex($$$$)
{
    my $style = shift;
    my $counter = shift;
    my $state = shift;
    return unless ($status);
    my $count = $global_count{"${style}_$counter"}; 
    ################################## begin debug section (incorrect counts)
    if (!defined($count))
    {
         # counter is undefined
         $invalid_counter_count++;
         main::msg_debug ("l2h: undefined count for ${style}_$counter");
         return ("<!-- l2h: ". __LINE__ . " undef count for ${style}_$counter -->")
                if ($debug);
         return '';
    }
    elsif(($count <= 0) or ($count > $latex_count))
    {
        # counter out of range
        $invalid_counter_count++;
        main::msg_debug ("l2h: Request of $count content which is out of valide range [0,$latex_count)");
         return ("<!-- l2h: ". __LINE__ . " out of range count $count -->") 
                if ($debug);
         return '';
    }
    ################################## end debug section (incorrect counts)

    # this seems to be a valid counter
    my $result = '';
    $result = "<!-- l2h_begin $l2h_name $count -->" if ($debug);
    if (defined($l2h_from_html[$count]))
    {
         $html_output_count++;
         # maybe we could also have something if simple_format
         # with Texi2HTML::Config::protect_text in case there
         # was some @math on a line passed through simple_format.
         # This would certainly be illegal texinfo, however.
         if ($state->{'remove_texi'})
         {# don't protect anything
             $result .= $l2h_to_latex[$count];
         }
         else
         { 
             $result .= $l2h_from_html[$count];
         }
    } 
    else
    {
    # if the result is not in @l2h_from_html, there is an error somewhere.
        $extract_error_count++;
        main::msg_debug ("l2h: can't extract content $count from html");
        # try simple (ordinary) substitution (without l2h)
        $result .= "<!-- l2h: ". __LINE__ . " use texi2html -->" if ($debug);
        $result .= main::substitute_text({}, undef, 'error in l2h', $l2h_to_latex[$count]);
    }
    $result .= "<!-- l2h_end $l2h_name $count -->" if ($debug);
    return $result;
}

# store results in the cache and remove temporary files.
sub finish()
{
    return unless($status);
    if ($verbose)
    {
        if ($extract_error_count + $invalid_counter_count)
        {
            warn "# l2h: finished from html ($extract_error_count extract and $invalid_counter_count invalid counter errors)\n";
        }
        else
        {
            warn "# l2h: finished from html (no error)\n";
        }
        if ($html_output_count != $latex_converted_count)
        { # this may happen if @-commands are collected at some places
          # but @-command at those places are not expanded later. For 
          # example @math on @multitable lines.
             warn "# l2h: $html_output_count html outputed for $latex_converted_count converted\n";
        }
    }
    store_cache();
    if ($Texi2HTML::Config::L2H_CLEAN)
    {
        local ($_);
        warn "# l2h: removing temporary files generated by l2h extension\n"
            if $verbose;
        while (<"$docu_rdir$l2h_name"*>)
        {
# FIXME error condition not checked
            unlink $_;
        }
    }
    warn "# l2h: Finished\n" if $verbose;
    return 1;
}

# the driver of end of first pass and second pass
#
sub latex2html()
{
    return unless($status);
    return unless ($status = finish_to_latex());
    return unless ($status = to_html());
}


##############################
# stuff for l2h caching
#
# FIXME it is clear that l2h stuff takes very long compared with texi2html
# which is already quite long. However this also adds some complexity 

# 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 init_cache
{
    if (-r "$l2h_cache_file")
    {
        my $rdo = do "$l2h_cache_file";
        main::document_error ("l2h: could not load $docu_rdir$l2h_cache_file: $@")
            unless ($rdo);
    }
}

# store all the text obtained through latex2html
sub store_cache
{
    return unless $latex_count;
    my ($key, $value);
    unless (open(FH, ">$l2h_cache_file"))
    { 
        main::document_error ("l2h: could not open $docu_rdir$l2h_cache_file for writing: $!");
        return;
    }
    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/\|/\\\|/go;
        $value =~ s/\\\\\|/\\\|/go;
        $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 from_cache($)
{
    my $text = shift;
    my $cached = $l2h_cache{$text};
    if (defined($cached))
    {
        while ($cached =~ m/SRC="(.*?)"/g)
        {
            unless (-e "$docu_rdir$1")
            {
                return undef;
            }
        }
        return $cached;
    }
    return undef;
}

1;

require "$T2H_HOME/T2h_l2h.pm"
    if ($0 =~ /\.pl$/ &&
        -e "$T2H_HOME/T2h_l2h.pm" && -r "$T2H_HOME/T2h_l2h.pm");

}

{
package Texi2HTML::LaTeX2HTML::Config;

# latex2html variables
# These variables are not used. They are here for information only, and
# an example of config file for latex2html file is included.
my $ADDRESS;
my $ANTI_ALIAS;
my $ANTI_ALIAS_TEXT;
my $ASCII_MODE;
my $AUTO_LINK;
my $AUTO_PREFIX;
my $CHILDLINE;
my $DEBUG;
my $DESTDIR;
my $DVIPS = 'dvips';
my $ERROR;
my $EXTERNAL_FILE;
my $EXTERNAL_IMAGES;
my $EXTERNAL_UP_LINK;
my $EXTERNAL_UP_TITLE;
my $FIGURE_SCALE_FACTOR;
my $HTML_VERSION;
my $IMAGES_ONLY;
my $INFO;
my $LINE_WIDTH;
my $LOCAL_ICONS;
my $LONG_TITLES;
my $MATH_SCALE_FACTOR;
my $MAX_LINK_DEPTH;
my $MAX_SPLIT_DEPTH;
my $NETSCAPE_HTML;
my $NOLATEX;
my $NO_FOOTNODE;
my $NO_IMAGES;
my $NO_NAVIGATION;
my $NO_SIMPLE_MATH;
my $NO_SUBDIR;
my $PAPERSIZE;
my $PREFIX;
my $PS_IMAGES;
my $REUSE;
my $SCALABLE_FONTS;
my $SHORTEXTN;
my $SHORT_INDEX;
my $SHOW_SECTION_NUMBERS;
my $SPLIT;
my $TEXDEFS;
my $TITLE;
my $TITLES_LANGUAGE;
my $TMP;
my $VERBOSE;
my $WORDS_IN_NAVIGATION_PANEL_TITLES;
my $WORDS_IN_PAGE;

# @T2H_L2H_INIT@

######################################################################
# from here on, its l2h init stuff
#

## initialization for latex2html as for Singular manual generation
## obachman 3/99

#
# Options controlling Titles, File-Names, Tracing and Sectioning
#
$TITLE = '';

$SHORTEXTN = 0;

$LONG_TITLES = 0;

#$DESTDIR = '';                  

$NO_SUBDIR = 1;                

#$PREFIX = '';                 

$AUTO_PREFIX = 0;            

$AUTO_LINK = 0;

$SPLIT = 0;

$MAX_LINK_DEPTH = 0;

#$TMP = '';                     

$DEBUG = 0;

$VERBOSE = 1;

#
# Options controlling Extensions and Special Features
#
#$HTML_VERSION = "3.2";         # set by command line

$TEXDEFS = 1;                   # we absolutely need that

$EXTERNAL_FILE = '';

$SCALABLE_FONTS = 1;

$NO_SIMPLE_MATH = 1;

$LOCAL_ICONS = 1;

$SHORT_INDEX = 0;

$NO_FOOTNODE = 1;

$ADDRESS = '';

$INFO = '';

#
# Switches controlling Image Generation
#
$ASCII_MODE = 0;

$NOLATEX = 0;

$EXTERNAL_IMAGES = 0;

$PS_IMAGES = 0;

$NO_IMAGES = 0;

$IMAGES_ONLY = 0;

$REUSE = 2;

$ANTI_ALIAS = 1;

$ANTI_ALIAS_TEXT = 1;

#
#Switches controlling Navigation Panels
#
$NO_NAVIGATION = 1;
$ADDRESS = '';
$INFO = 0;                      # 0 = do not make a "About this document..." section

#
#Switches for Linking to other documents
#
# currently -- we don't care

$MAX_SPLIT_DEPTH = 0;           # Stop making separate files at this depth

$MAX_LINK_DEPTH = 0;            # Stop showing child nodes at this depth

$NOLATEX = 0;                   # 1 = do not pass unknown environments to Latex

$EXTERNAL_IMAGES = 0;           # 1 = leave the images outside the document

$ASCII_MODE = 0;                # 1 = do not use any icons or internal images

# 1 =  use links to external postscript images rather than inlined bitmap
# images.
$PS_IMAGES = 0;
$SHOW_SECTION_NUMBERS = 0;

### Other global variables ###############################################

# put dvips stderr on stdout since latex2html is alread very verbose
$DVIPS = "$DVIPS ".' 2>&1';

$CHILDLINE = "";

# This is the line width measured in pixels and it is used to right justify
# equations and equation arrays;
$LINE_WIDTH = 500;

# Used in conjunction with AUTO_NAVIGATION
$WORDS_IN_PAGE = 300;

# The value of this variable determines how many words to use in each
# title that is added to the navigation panel (see below)
#
$WORDS_IN_NAVIGATION_PANEL_TITLES = 0;

# This number will determine the size of the equations, special characters,
# and anything which will be converted into an inlined image
# *except* "image generating environments" such as "figure", "table"
# or "minipage".
# Effective values are those greater than 0.
# Sensible values are between 0.1 - 4.
$MATH_SCALE_FACTOR = 1.5;

# This number will determine the size of
# image generating environments such as "figure", "table" or "minipage".
# Effective values are those greater than 0.
# Sensible values are between 0.1 - 4.
$FIGURE_SCALE_FACTOR = 1.6;


#  If both of the following two variables are set then the "Up" button
#  of the navigation panel in the first node/page of a converted document
#  will point to $EXTERNAL_UP_LINK. $EXTERNAL_UP_TITLE should be set
#  to some text which describes this external link.
$EXTERNAL_UP_LINK = "";
$EXTERNAL_UP_TITLE = "";

# If this is set then the resulting HTML will look marginally better if viewed
# with Netscape.
$NETSCAPE_HTML = 1;

# Valid paper sizes are "letter", "legal", "a4","a3","a2" and "a0"
# Paper sizes has no effect other than in the time it takes to create inlined
# images and in whether large images can be created at all ie
#  - larger paper sizes *MAY* help with large image problems
#  - smaller paper sizes are quicker to handle
$PAPERSIZE = "a4";

# Replace "english" with another language in order to tell LaTeX2HTML that you
# want some generated section titles (eg "Table of Contents" or "References")
# to appear in a different language. Currently only "english" and "french"
# is supported but it is very easy to add your own. See the example in the
# file "latex2html.config"
$TITLES_LANGUAGE = "english";

1;                              # This must be the last non-comment line

# End File l2h.init
######################################################################

}

package main;

if (!defined(Texi2HTML::Config::get_conf('use_nls')))
{
   my $use_nls = ('yes' eq 'yes' or $0 =~ /\.pl$/);
   Texi2HTML::Config::set_conf('use_nls', $use_nls);
}

# prepare the gettext-like framework. To be noted that Locales::TextDomain
# canot be used, since it cannot be used dynamically through a reuires.
# Fortunately, Locales::TextDomain is a thin layer above Locales::Messages.

my $strings_textdomain = 'texi2html' . '_document';
$strings_textdomain = 'texi2html_document' if ($strings_textdomain eq '@'.'PACKAGE@' . '_document');
my $messages_textdomain = 'texi2html';
$messages_textdomain = 'texi2html' if ($messages_textdomain eq '@'.'PACKAGE@');

#my $messages_textdomain = 'texinfo';

if (Texi2HTML::Config::get_conf('use_nls'))
{
    if ($0 =~ /\.pl$/)
    { # use in-source libintl when testing
        unshift @INC, "$T2H_HOME/lib/libintl-perl/lib";
    }
    elsif ($ENV{T2H_SOURCE_LIBINTL})
    {
        unshift @INC, $ENV{T2H_SOURCE_LIBINTL};
    }
    elsif ('no' ne 'yes')
    {
        unshift @INC, "$pkgdatadir/lib/libintl-perl/lib";
    }
    else
    {
        eval {
            require Locale::Messages;
        };
        if ($@)
        {
            unshift @INC, "$pkgdatadir/lib/libintl-perl/lib";
        }
    }
    # gettext-like translations
    #require Locale::TextDomain;
    require Locale::Messages;
    # we want a reliable way to switch locale, so we don't use the system 
    # gettext.
    Locale::Messages->select_package ('gettext_pp');
    if ($0 =~ /\.pl$/)
    {
         # in case of out of source build, the locales directory should 
         # be two levels below. $T2H_HOME is in srcdir.
         foreach my $locales_dir ("$T2H_HOME/locales", "../../locales")
         {
             if (-d $locales_dir)
             {
                  Locale::Messages::bindtextdomain ($strings_textdomain, $locales_dir);
                  last;
             }
        }
    }
    else
    { # match where gettext installs
        Locale::Messages::bindtextdomain ($strings_textdomain, "$datadir/locale");
    }
    # simply bind error messages to the installation directory.
    # Messages should be untranslated for tests.
    Locale::Messages::bindtextdomain ($messages_textdomain, "$datadir/locale");
}
else
{
    unshift @INC, "$pkgdatadir/lib/libintl-perl/lib";
    require Locale::Messages;
}

sub __($)
{
    my $msgid = shift;
    return Locale::Messages::dgettext($messages_textdomain, $msgid);
}

sub __p($$)
{
    my $context = shift;
    my $msgid = shift;
    return Locale::Messages::dpgettext($messages_textdomain, $context, $msgid);
}

sub N__($)
{
    return $_[0];
}

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

my $I = \&Texi2HTML::I18n::get_string;

########################################################################
#
# Global variable initialization
#
########################################################################
#
# pre-defined indices
#

%index_prefix_to_name = ();

%index_names =
(
 'cp' => { 'prefixes' => {'cp' => 0,'c' => 0}},
 'fn' => { 'prefixes' => {'fn' => 1, 'f' => 1}},
 'vr' => { 'prefixes' => {'vr' => 1, 'v' => 1}},
 'ky' => { 'prefixes' => {'ky' => 1, 'k' => 1}},
 'pg' => { 'prefixes' => {'pg' => 1, 'p' => 1}},
 'tp' => { 'prefixes' => {'tp' => 1, 't' => 1}}
);

foreach my $name(keys(%index_names))
{
    foreach my $prefix (keys %{$index_names{$name}->{'prefixes'}})
    {
        $forbidden_index_name{$prefix} = 1;
        $index_prefix_to_name{$prefix} = $name;
    }
}

foreach my $other_forbidden_index_name ('info','ps','pdf','htm',
   'log','aux','dvi','texi','txi','texinfo','tex','bib')
{
    $forbidden_index_name{$other_forbidden_index_name} = 1;
}

# commands with ---, -- '' and `` preserved
# usefull with the old interface

%code_style_map = (
           'code'    => 1,
           'command' => 1,
           'env'     => 1,
           'file'    => 1,
           'kbd'     => 1,
           'option'  => 1,
           'samp'    => 1,
           'verb'    => 1,
);

my @element_directions = ('Up', 'Forward', 'Back', 'Next', 'Prev', 
'SectionNext', 'SectionPrev', 'SectionUp', 'FastForward', 'FastBack', 
'This', 'NodeUp', 'NodePrev', 'NodeNext', 'Following', 'NextFile', 'PrevFile',
'ToplevelNext', 'ToplevelPrev');
$::simple_map_ref = \%Texi2HTML::Config::simple_map;
$::simple_map_math_ref = \%Texi2HTML::Config::simple_map_math;
#$::simple_map_pre_ref = \%Texi2HTML::Config::simple_map_pre;
$::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi;
$::style_map_ref = \%Texi2HTML::Config::style_map;
$::style_map_pre_ref = \%Texi2HTML::Config::style_map_pre;
$::style_map_math_ref = \%Texi2HTML::Config::style_map_math;
$::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi;
$::things_map_ref = \%Texi2HTML::Config::things_map;
$::pre_map_ref = \%Texi2HTML::Config::pre_map;
$::texi_map_ref = \%Texi2HTML::Config::texi_map;

#print STDERR "MAPS: $::simple_map_ref $::simple_map_pre_ref $::simple_map_texi_ref $::style_map_ref $::style_map_pre_ref $::style_map_texi_ref $::things_map_ref $::pre_map_ref $::texi_map_ref\n";

# delete from hash if we are using the new interface
foreach my $code (keys(%code_style_map))
{
    delete ($code_style_map{$code}) 
       if (ref($::style_map_ref->{$code}) eq 'HASH');
}

# no paragraph in these commands
my %no_paragraph_macro = (
           'xref'         => 1,
           'ref'          => 1,
           'pxref'        => 1,
           'inforef'      => 1,
           'anchor'       => 1,
);


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

# the reverse mapping. There is an entry for each sectioning command.
# The value is a ref on an array containing at each index the corresponding
# sectioning command name.
my %level2sec;
{
    my $sections = [ ];
    my $appendices = [ ];
    my $unnumbered = [ ];
    my $headings = [ ];
    foreach my $command (keys (%reference_sec2level))
    {
        if ($command =~ /^appendix/)
        {
            $level2sec{$command} = $appendices;
        }
        elsif ($command =~ /^unnumbered/ or $command eq 'top')
        {
            $level2sec{$command} = $unnumbered;
        }
        elsif ($command =~ /section$/ or $command eq 'chapter')
        {
            $level2sec{$command} = $sections;
        }
        else
        {
            $level2sec{$command} = $headings;
        }
        $level2sec{$command}->[$reference_sec2level{$command}] = $command;
    }
}

# out of the main hierarchy
$reference_sec2level{'part'} = 0;
# this are synonyms
$reference_sec2level{'appendixsection'} = 2;
# sec2level{'majorheading'} is also 1 and not 0
$reference_sec2level{'majorheading'} = 1;
$reference_sec2level{'chapheading'} = 1;
$reference_sec2level{'centerchap'} = 1;

sub stop_paragraph_command($)
{
   my $command = shift;
   return 1 if ($Texi2HTML::Config::stop_paragraph_command{$command} or defined($reference_sec2level{$command}));
}

sub set_no_line_macro($$)
{
   my $macro = shift;
   my $value = shift;
   $Texi2HTML::Config::no_paragraph_commands{$macro} = $value 
      unless defined($Texi2HTML::Config::no_paragraph_commands{$macro});
}

# those macros aren't considered as beginning a paragraph
foreach my $no_line_macro ('alias', 'macro', 'unmacro', 'rmacro',
 'titlefont', 'include', 'copying', 'end copying', 'tab', 'item',
 'itemx', '*', 'float', 'end float', 'caption', 'shortcaption', 'cindex',
 'image')
{
    set_no_line_macro($no_line_macro, 1);
}

foreach my $key (keys(%Texi2HTML::Config::misc_command), keys(%reference_sec2level))
{
    set_no_line_macro($key, 1);
}

# a hash associating a format @thing / @end thing with the type of the format
# 'complex_format' 'simple_format' 'deff' 'list' 'menu' 'paragraph_format'
my %format_type = (); 

foreach my $simple_format (keys(%Texi2HTML::Config::format_map))
{
   $format_type{$simple_format} = 'simple_format';
}
foreach my $paragraph_style (keys(%Texi2HTML::Config::paragraph_style))
{
   $format_type{$paragraph_style} = 'paragraph_format';
}
# FIXME $complex_format_map obsoleted in nov 2009
foreach my $complex_format (keys(%$Texi2HTML::Config::complex_format_map),
    keys(%Texi2HTML::Config::complex_format_map))
{
   $format_type{$complex_format} = 'complex_format';
}
foreach my $table (('table', 'ftable', 'vtable'))
{
   $format_type{$table} = 'table';
}
$format_type{'multitable'} = 'multitable';
foreach my $def_format (keys(%Texi2HTML::Config::def_map))
{
   $format_type{$def_format} = 'deff';
}
$format_type{'itemize'} = 'list';
$format_type{'enumerate'} = 'list';

$format_type{'menu'} = 'menu';
$format_type{'detailmenu'} = 'menu';
$format_type{'direntry'} = 'menu';

$format_type{'cartouche'} = 'cartouche';

$format_type{'float'} = 'float';

$format_type{'quotation'} = 'quotation';
$format_type{'smallquotation'} = 'quotation';

$format_type{'group'} = 'group';

my @special_regions = ('titlepage', 'copying', 'documentdescription');
foreach my $region (@special_regions)
{
   $format_type{$region} = 'region';
}

foreach my $key (keys(%format_type))
{
   set_no_line_macro($key, 1);
   set_no_line_macro("end $key", 1);
}

foreach my $macro (keys(%Texi2HTML::Config::format_in_paragraph))
{
   set_no_line_macro($macro, 1);
   set_no_line_macro("end $macro", 1);
}

# fake format at the bottom of the stack
$format_type{'noformat'} = '';

# fake formats are formats used internally within other formats
# we associate them with a real format, for the error messages
my %fake_format = (
     'line' => 'table',
     'term' => 'table',
     'item' => 'list or table',
     'row' => 'multitable row',
     'cell' => 'multitable cell',
     'deff_item' => 'definition command',
     'menu_comment' => 'menu',
     'menu_description' => 'menu',
  );

foreach my $key (keys(%fake_format))
{
    $format_type{$key} = 'fake';
}

# raw formats which are expanded especially
my @raw_regions = ('html', 'tex', 'xml', 'docbook');
foreach my $format (keys(%Texi2HTML::Config::texi_formats_map))
{
    push @raw_regions, $format if ($Texi2HTML::Config::texi_formats_map{$format} eq 'raw');
}

# The css formats are associated with complex format commands, and associated
# with the 'pre_style' key
# FIXME $complex_format_map obsoleted in nov 2009
foreach my $complex_format (keys(%$Texi2HTML::Config::complex_format_map))
{
    next if (defined($Texi2HTML::Config::complex_format_map->{$complex_format}->{'pre_style'}));
    $Texi2HTML::Config::complex_format_map->{$complex_format}->{'pre_style'} = '';
    $Texi2HTML::Config::complex_format_map->{$complex_format}->{'pre_style'} = $Texi2HTML::Config::css_map{"pre.$complex_format"} if (exists($Texi2HTML::Config::css_map{"pre.$complex_format"}));
}

# The css formats are associated with complex format commands, and associated
# with the 'pre_style' key
foreach my $complex_format (keys(%Texi2HTML::Config::complex_format_map))
{
    next if (defined($Texi2HTML::Config::complex_format_map{$complex_format}->{'pre_style'}));
    $Texi2HTML::Config::complex_format_map{$complex_format}->{'pre_style'} = '';
    $Texi2HTML::Config::complex_format_map{$complex_format}->{'pre_style'} = $Texi2HTML::Config::css_map{"pre.$complex_format"} if (exists($Texi2HTML::Config::css_map{"pre.$complex_format"}));
}



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

# shorthand for Texi2HTML::Config::VERBOSE
my $T2H_VERBOSE;
my $T2H_DEBUG;

sub line_warn($$);
sub document_warn($);
sub file_line_warn($$;$);
sub cmdline_warn ($);

my $T2H_FAILURE_TEXT = sprintf(__("Try `%s --help' for more information.\n"), $real_command_name);

#print STDERR "" . gdt('test i18n: \' , \a \\ %% %{unknown}a %known % %{known}  \\', { 'known' => 'a known string', 'no' => 'nope'}); exit 0;

# file:        file name to locate. It can be a file path.
# all_files:   if true collect all the files with that name, otherwise stop
#              at first match.
# directories: a reference on a array containing a list of directories to
#              search the file in. default is 
#              @Texi2HTML::Config::CONF_DIRS, @program_config_dirs.
sub locate_init_file($;$$)
{
    my $file = shift;
    my $all_files = shift;
    my $directories = shift;

    if (!defined($directories))
    {
       if ($all_files)
       {
           $directories = [ @program_config_dirs ];
       }
       else
       {
           $directories = [ @Texi2HTML::Config::CONF_DIRS, @program_init_dirs ];
       }
    }

    if ($file =~ /^\//)
    {
         return $file if (-e $file and -r $file);
    }
    else
    {
         my @files;
         foreach my $dir (@$directories)
         {
              next unless (-d "$dir");
              if ($all_files)
              {
                  push (@files, "$dir/$file") if (-e "$dir/$file" and -r "$dir/$file");
              }
              else
              {
                  return "$dir/$file" if (-e "$dir/$file" and -r "$dir/$file");
              }
         }
         return @files if ($all_files);
    }
    return undef;
}

# called on -init-file
sub load_init_file
{
    # First argument is option
    shift;
    # second argument is value of options
    my $init_file = shift;
    my $file;
    if ($file = locate_init_file($init_file))
    {
        print STDERR "# reading initialization file from $file\n"
            if ($T2H_VERBOSE);
        # require the file in the Texi2HTML::Config namespace
        return (Texi2HTML::Config::load($file));
    }
    else
    {
        document_error ("Can't read init file $init_file");
        return 0;
    }
}

sub set_date($)
{
    my $language = shift;
    if (!$Texi2HTML::Config::TEST)
    {
        print STDERR "# Setting date in $language\n" if ($T2H_DEBUG);
        $Texi2HTML::THISDOC{'today'} = Texi2HTML::I18n::pretty_date($language);  # like "20 September 1993";
    }
    else
    {
        $Texi2HTML::THISDOC{'today'} = 'a sunny day';
    }
    $Texi2HTML::THISDOC{'today'} = $Texi2HTML::Config::DATE 
        if (defined($Texi2HTML::Config::DATE));
    $::things_map_ref->{'today'} = $Texi2HTML::THISDOC{'today'};
    $::pre_map_ref->{'today'} = $Texi2HTML::THISDOC{'today'};
    $::texi_map_ref->{'today'} = $Texi2HTML::THISDOC{'today'};
}

sub warn_unknown_language($;$)
{
    my $lang = shift;
    my $line_nr = shift;

    my $lang_code = $lang;
    my $region_code;

    if ($lang =~ /^([a-z]+)_([A-Z]+)/)
    {
        $lang_code = $1;
        $region_code = $2;
    }

    if (! $Texi2HTML::Config::language_codes{$lang_code})
    {
        msg_warn(sprintf(__("%s is not a valid language code"), $lang_code), $line_nr);
    }
    if (defined($region_code) and ! $Texi2HTML::Config::region_codes{$region_code})
    {
        msg_warn(sprintf(__("%s is not a valid region code"), $region_code), $line_nr);
    }
}

# Called on --document-language, at the beginning of each pass and
# when a @documentlanguage appears
sub set_document_language ($$;$)
{
    my $lang = shift;
    my $silent = shift;
    my $line_nr = shift;

    my @langs = ($lang);

#    my $lang_code = $lang;
#    my $region_code;

    my $main_lang;

    if ($lang =~ /^([a-z]+)_([A-Z]+)/)
    {
        $main_lang = $1;
#        $region_code = $2;
#        $lang_code = $main_lang;
        push @langs, $main_lang;
    }

#    if (!$silent)
#    {         
#        if (! $Texi2HTML::Config::language_codes{$lang_code})
#        { # i18n
#            msg_warn("$lang_code is not a valid language code.", $line_nr);
#        }
#        if (defined($region_code) and ! $Texi2HTML::Config::region_codes{$region_code})
#        { # i18n
#            msg_warn("$region_code is not a valid region code.", $line_nr);
#        }
#    }
    # Always succeed if using a gettext-like environment
    if (!$Texi2HTML::Config::I18N_PERL_HASH)
    {
        set_date($lang);
        return 1;
    }

    my @files = locate_init_file("$i18n_dir/$lang.thl", 1);
    if (! scalar(@files) and defined($main_lang))
    {
        @files = locate_init_file("$i18n_dir/$main_lang.thl", 1);
    }

    foreach  my $file (@files)
    {
        Texi2HTML::Config::load($file);
    }
    foreach my $language (@langs)
    {
        if (Texi2HTML::I18n::set_language($language))
        {
            print STDERR "# using '$language' as document language\n" if ($T2H_VERBOSE);
            # since it may be different from get_conf('documentlanguage'),
            # we record it.
            # Currently this is not used anywhere, not sure what the value
            # really corresponds with.
            $Texi2HTML::THISDOC{'current_language'} = $language;
            set_date($language);
            return 1;
        }
    }
    return 0;
}


# manage footnote style
sub set_footnote_style($$;$)
{
    my $value = shift;
    my $from_command_line = shift;
    my $line_nr = shift;
    my $command = 'footnotestyle';
    if ($value eq 'end' or $value eq 'separate')
    {
         Texi2HTML::Config::set_conf($command, $value, !$from_command_line);
    }
    elsif ($from_command_line)
    {
         die sprintf(__("%s: --footnote-style arg must be `separate' or `end', not `%s'.\n"), $real_command_name, $value);
         # the T2H_FAILURE_TEXT is output by getOption, seems to catch die
    }
    else
    {
         line_error (sprintf(__("\@%s arg must be `separate' or `end', not `%s'"), $command, $value), $line_nr);
    }
}


# find the encoding alias.
# with encoding support (USE_UNICODE), may return undef if no alias was found
sub encoding_alias($;$$)
{
    my $encoding = shift;
    my $line_nr = shift;
    my $context_string = shift;
    return undef if (!defined($encoding) or $encoding eq '');
    if ($Texi2HTML::Config::USE_UNICODE)
    {
         my $result_encoding = Encode::resolve_alias($encoding);
         if (! $result_encoding)
         {
              msg_warn(sprintf(__("unrecognized encoding name `%s'"), $encoding), $line_nr, $context_string);
              return undef;
         }
         if (defined($Texi2HTML::Config::t2h_encoding_aliases{$result_encoding}))
         {
             $result_encoding = $Texi2HTML::Config::t2h_encoding_aliases{$result_encoding};
         }
         print STDERR "# Using encoding $result_encoding\n" if ($T2H_VERBOSE);
         return $result_encoding; 
    }
    else
    {
         if (exists($Texi2HTML::Config::t2h_encoding_aliases{$encoding}))
         {
             $encoding = $Texi2HTML::Config::t2h_encoding_aliases{$encoding};
             document_warn (__("Document encoding is utf8, but there is no unicode support")) if ($encoding eq 'utf-8');
             return $encoding;
         }
         msg_warn(sprintf(__("Encoding %s certainly poorly supported"), $encoding), $line_nr);
         return $encoding;
    }
}

# libintl converts between encodings but doesn't decode them into the
# perl internal format.
sub encode_i18n_string($$)
{
   my $string = shift;
   my $encoding = shift;
   if ($encoding ne 'us-ascii' and $Texi2HTML::Config::USE_UNICODE
        and Encode::resolve_alias($encoding))
   {
      return Encode::decode($encoding, $string);
   }
   return $string;
}

sub gdt($;$$)
{
    my $message = shift;
    my $context = shift;
    my $state = shift;

    # FIXME this should be done only once, for @documentencoding
    my $encoding = lc(Texi2HTML::Config::get_conf('DOCUMENT_ENCODING'));
    if (defined($encoding) and $encoding ne '' and exists($Texi2HTML::Config::t2h_encoding_aliases{$encoding}))
    {
       $encoding = $Texi2HTML::Config::t2h_encoding_aliases{$encoding};
    }
    $encoding = 'us-ascii' if (!defined($encoding) or $encoding eq '');

    return &$I($message, $context, $state) if ($Texi2HTML::Config::I18N_PERL_HASH);
    # if set, use substitute_text instead of substitute_line
    my $allow_paragraph = $state->{'allow_paragraph'};
    # if duplicate is passed, it means that we are in the text and so should
    # use the main state
    if (defined($state) and $state->{'duplicate'} and defined($Texi2HTML::THISDOC{'state'}))
    {
        $state = main::duplicate_formatting_state($Texi2HTML::THISDOC{'state'});
    }

    my $result;
    # taken from libintl perl, copyright Guido. sub __expand. Overall not
    # enough code taken form Guido right now to be copyrightable.
    my $re = join '|', map { quotemeta $_ } keys %$context if (defined($context) and ref($context));

    if (Texi2HTML::Config::get_conf('use_nls'))
    {
       my $saved_LANGUAGE = $ENV{'LANGUAGE'};

       Locale::Messages::textdomain($strings_textdomain);

   
       Locale::Messages::bind_textdomain_codeset($strings_textdomain, $encoding) if ($encoding ne 'us-ascii');
       Locale::Messages::bind_textdomain_filter($strings_textdomain, \&encode_i18n_string, $encoding);

       my $lang = Texi2HTML::Config::get_conf('documentlanguage');
       my @langs = ($lang);
       if ($lang =~ /^([a-z]+)_([A-Z]+)/)
       {
           my $main_lang = $1;
           my $region_code = $2;
           push @langs, $main_lang;
       }
   
       my $locales = '';
       foreach my $language (@langs)
       {
           $locales .= "$language.$encoding:";
           #$locales .= "$language:";
           # always try us-ascii, the charset should always be a subset of
           # all charset, and should resort to @-commands if needed for non
           # ascii characters
           if ($encoding ne 'us-ascii')
           {
               $locales .= "$language.us-ascii:";
           }
       }
       $locales =~ s/:$//;
       #print STDERR "$locales\n";
       Locale::Messages::nl_putenv("LANGUAGE=$locales");
   
       if (!defined($context) or ref($context))
       {
            $result = Locale::Messages::gettext($message);
       }
       else
       {
            $result = Locale::Messages::pgettext($context, $message);
       }
       Locale::Messages::textdomain($messages_textdomain);
       # old perl complains 'Use of uninitialized value in scalar assignment'
       if (!defined($saved_LANGUAGE))
       {
          delete ($ENV{'LANGUAGE'});
       }
       else
       {
          $ENV{'LANGUAGE'} = $saved_LANGUAGE;
       }
    }

    # now perform the argument substitutions
    if ($state->{'keep_texi'})
    {
         # next line taken from libintl perl, copyright Guido. sub __expand
         $result =~ s/\{($re)\}/defined $context->{$1} ? $context->{$1} : "{$1}"/ge if (defined($re));
         return $result;
    }
    if (defined($re))
    {
         # next line taken from libintl perl, copyright Guido. sub __expand
         $result =~ s/\{($re)\}/\@internal_translation_open_brace\{\}$1\@internal_translation_close_brace\{\}/g;
         foreach my $map (\%Texi2HTML::Config::things_map, \%Texi2HTML::Config::pre_map,  \%Texi2HTML::Config::texi_map, \%Texi2HTML::Config::simple_format_texi_map)
         {
             $map->{'internal_translation_open_brace'} = '{';
             $map->{'internal_translation_close_brace'} = '}';
         }
    }
    if ($allow_paragraph)
    {
        delete $state->{'allow_paragraph'};
        $result = substitute_text ($state, undef, __("translation"), ($result));
    }
    else
    {
        $result = substitute_line ($result, __("translation"), $state);
    }
    if (defined($re))
    {
         $result =~ s/\{($re)\}/defined $context->{$1} ? $context->{$1} : "{$1}"/ge;
         foreach my $map (\%Texi2HTML::Config::things_map, \%Texi2HTML::Config::pre_map,  \%Texi2HTML::Config::texi_map, \%Texi2HTML::Config::simple_format_texi_map)
         {
               delete $map->{'internal_translation_open_brace'};
               delete $map->{'internal_translation_close_brace'};
         }
    }
    return $result;
}

my %nodes;             # nodes hash. The key is the texi node name
my %cross_reference_nodes;  # normalized node names arrays

#
# %value hold texinfo variables, see also -D, -U, @set and @clear.
# we predefine html (the output format) and texi2html (the translator)
# it is initialized with %value_initial at the beginning of the 
# document parsing and filled and emptied as @set and @clear are 
# encountered
my %value_initial = 
      (
          'html' => 1,
          'texi2html' => $THISVERSION,
      );

#
# _foo: internal variables to track @foo
#
foreach my $key ('_author', '_title', '_subtitle', '_shorttitlepage',
	 '_settitle', '_titlefont')
{
    $value_initial{$key} = '';            # prevent -w warnings
}


sub unicode_to_protected($)
{
    my $text = shift;
    my $result = '';
    while ($text ne '')
    {
        if ($text =~ s/^([A-Za-z0-9]+)//o)
        {
             $result .= $1;
        }
        elsif ($text =~ s/^ //o)
        {
             $result .= '-';
        }
        elsif ($text =~ s/^(.)//o)
        {
             my $char = $1;
             if (exists($Texi2HTML::Config::ascii_character_map{$char}))
             {
                 $result .= '_' . lc($Texi2HTML::Config::ascii_character_map{$char});
             }
             else
             {
                 if (ord($char) <= hex(0xFFFF)) 
                 {
                     $result .= '_' . lc(sprintf("%04x",ord($char)));
                 }
                 else
                 {
                     $result .= '__' . lc(sprintf("%06x",ord($char)));
                 }
             }
        }
        else
        {
             print STDERR "Bug: unknown character in a cross ref (likely in infinite loop)\n";
             print STDERR "Text: !!$text!!\n";
             sleep 1;
        }
    }
    return $result;
}

sub unicode_to_transliterate($)
{
    my $text = shift;
    if (chomp($text))
    {
       print STDERR "Strange: end of line to transliterate: $text\n";
    }
    my $result = '';
    while ($text ne '')
    {
        if ($text =~ s/^([A-Za-z0-9 ]+)//o)
        {
             $result .= $1;
        }
        elsif ($text =~ s/^(.)//o)
        {
             my $char = $1;
             if (exists($Texi2HTML::Config::ascii_character_map{$char}))
             {
                 $result .= $char;
             }
             elsif (ord($char) <= hex(0xFFFF) and exists($Texi2HTML::Config::transliterate_map{uc(sprintf("%04x",ord($char)))}))
             {
                 $result .= $Texi2HTML::Config::transliterate_map{uc(sprintf("%04x",ord($char)))};
             }
             elsif (ord($char) <= hex(0xFFFF) and exists($Texi2HTML::Config::unicode_diacritical{uc(sprintf("%04x",ord($char)))}))
             {
                 $result .= '';
             }
             # in this case, we want to avoid calling unidecode, as we are sure
             # that there is no useful transliteration of the unicode character
             # instead we want to keep it as is.
             # This is the case, for example, for @exclamdown, is corresponds
             # with x00a1, but unidecode transliterates it to a !, we want
             # to avoid that and keep x00a1.
             elsif (ord($char) <= hex(0xFFFF) and exists($Texi2HTML::Config::no_transliterate_map{uc(sprintf("%04x",ord($char)))}))
             {
                 $result .= $char;
             }
             else
             {
                 if ($Texi2HTML::Config::USE_UNIDECODE)
                 {
                      $result .= unidecode($char);
                 }
                 else
                 {
                      $result .= $char;
                 }
             }
        }
        else
        {
             print STDERR "Bug: unknown character in cross ref transliteration (likely in infinite loop)\n";
             print STDERR "Text: !!$text!!\n";
             sleep 1;
        }
    }
    return $result;
}

# used both for command line and @-command argument checking
sub set_paragraphindent($$;$$)
{
   my $value = shift;
   my $from_command_line = shift;
   my $line_nr = shift;
   my $pass = shift;
   my $command = 'paragraphindent';

   if ($value =~ /^([0-9]+)$/ or $value eq 'none' or $value eq 'asis')
   {
       Texi2HTML::Config::set_conf($command, $value, !$from_command_line);
   }
   elsif ($from_command_line)
   {
       die sprintf(__("%s: --paragraph-indent arg must be numeric/`none'/`asis', not `%s'.\n"), $real_command_name, $value);
   }
   elsif ($pass == 1)
   {
       line_error (sprintf(__("\@paragraphindent arg must be numeric/`none'/`asis', not `%s'"), $value), $line_nr);
   }
}

# T2H_OPTIONS is a hash whose keys are the (long) names of valid
# command-line options and whose values are a hash with the following keys:
# type    ==> one of !|=i|:i|=s|:s (see Getopt::Long for more info)
# linkage ==> ref to scalar, array, or subroutine (see Getopt::Long for more info)
# verbose ==> short description of option (displayed by -h)
# noHelp  ==> if 1 -> for "not so important options": only print description on -h 1
#                2 -> for obsolete options: only print description on -h 2
my $T2H_OPTIONS;
$T2H_OPTIONS -> {'debug'} =
{
 type => '=i',
 linkage => \$Texi2HTML::Config::DEBUG,
 verbose => 'output HTML with debuging information',
};

$T2H_OPTIONS -> {'doctype'} =
{
 type => '=s',
 linkage => sub {Texi2HTML::Config::set_conf('doctype', $_[1]);},
 verbose => 'document type which is output in header of HTML files',
 noHelp => 1
};

$T2H_OPTIONS -> {'frameset-doctype'} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::FRAMESET_DOCTYPE,
 verbose => 'document type for HTML frameset documents',
 noHelp => 1
};

$T2H_OPTIONS -> {'test'} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::TEST,
 verbose => 'use predefined information to avoid differences with reference files',
 noHelp => 1
};

$T2H_OPTIONS -> {'dump-texi'} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::DUMP_TEXI,
 verbose => 'dump the output of first pass into a file with extension passfirst and exit',
 noHelp => 1
};

$T2H_OPTIONS -> {'macro-expand|E'} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::MACRO_EXPAND,
 verbose => 'output macro expanded source in <file>',
};

$T2H_OPTIONS -> {'ifhtml'} =
{
 type => '!',
 linkage => sub { Texi2HTML::Config::set_expansion('html', $_[1]); },
 verbose => "expand ifhtml and html sections",
};

$T2H_OPTIONS -> {'ifinfo'} =
{
 type => '!',
 linkage => sub { Texi2HTML::Config::set_expansion('info', $_[1]); },
 verbose => "expand ifinfo",
};

$T2H_OPTIONS -> {'ifxml'} =
{
 type => '!',
 linkage => sub { Texi2HTML::Config::set_expansion('xml', $_[1]); },
 verbose => "expand ifxml and xml sections",
};

$T2H_OPTIONS -> {'ifdocbook'} =
{
 type => '!',
 linkage => sub { Texi2HTML::Config::set_expansion('docbook', $_[1]); },
 verbose => "expand ifdocbook and docbook sections",
};

$T2H_OPTIONS -> {'iftex'} =
{
 type => '!',
 linkage => sub { Texi2HTML::Config::set_expansion('tex', $_[1]); },
 verbose => "expand iftex and tex sections",
};

$T2H_OPTIONS -> {'ifplaintext'} =
{
 type => '!',
 linkage => sub { Texi2HTML::Config::set_expansion('plaintext', $_[1]); },
 verbose => "expand ifplaintext sections",
};

$T2H_OPTIONS -> {'iso'} =
{
 type => 'iso',
 linkage => sub {Texi2HTML::Config::t2h_default_set_iso_symbols ($_[1]);},
 verbose => 'if set, entities are used for special symbols (like copyright, etc...) and quotes',
 noHelp => 1,
};

$T2H_OPTIONS -> {'I'} =
{
 type => '=s',
 linkage => \@Texi2HTML::Config::INCLUDE_DIRS,
 verbose => 'append $s to the @include search path',
};

$T2H_OPTIONS -> {'conf-dir'} =
{
 type => '=s',
 linkage => \@Texi2HTML::Config::CONF_DIRS,
 verbose => 'append $s to the init file directories',
};

$T2H_OPTIONS -> {'P'} =
{
 type => '=s',
 linkage => sub {unshift (@Texi2HTML::Config::PREPEND_DIRS, $_[1]);},
 verbose => 'prepend $s to the @include search path',
};

$T2H_OPTIONS -> {'top-file'} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::TOP_FILE,
 verbose => 'use $s as top file, instead of <docname>.html',
};

$T2H_OPTIONS -> {'toc-file'} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::TOC_FILE,
 verbose => 'use $s as ToC file, instead of <docname>_toc.html',
};

$T2H_OPTIONS -> {'frames'} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::FRAMES,
 verbose => 'output files which use HTML 4.0 frames (experimental)',
 noHelp => 1,
};

$T2H_OPTIONS -> {'menu'} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::SHOW_MENU,
 verbose => 'output Texinfo menus',
};

$T2H_OPTIONS -> {'number-sections'} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::NUMBER_SECTIONS,
 verbose => 'output chapter and sectioning numbers.',
};

$T2H_OPTIONS -> {'number-footnotes'} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::NUMBER_FOOTNOTES,
 verbose => 'output footnote numbers.',
};

$T2H_OPTIONS -> {'use-nodes'} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::USE_NODES,
 verbose => 'use nodes for sectioning',
};

$T2H_OPTIONS -> {'node-files'} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::NODE_FILES,
 verbose => 'produce one file per node for cross references'
};

$T2H_OPTIONS -> {'footnote-style|s'} =
{
 type => '=s',
 linkage => sub {set_footnote_style ($_[1], 1);},
 verbose => 'output footnotes separate|end',
};

$T2H_OPTIONS -> {'toc-links'} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::TOC_LINKS,
 verbose => 'create links from headings to toc entries'
};

$T2H_OPTIONS -> {'split'} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::SPLIT,
 verbose => 'split document on section|chapter|node else no splitting',
};

$T2H_OPTIONS -> {'no-split'} =
{
 type => '!',
 linkage => sub {$Texi2HTML::Config::SPLIT = ''; $Texi2HTML::Config::SPLIT_SIZE = undef;},
 verbose => 'no splitting of document',
 noHelp => 1,
};

$T2H_OPTIONS -> {'headers'} =
{
 type => '!',
 linkage => sub {
    Texi2HTML::Config::set_conf('headers', $_[1]);
    Texi2HTML::Config::t2h_default_load_format('plaintext', 1)
        if (!$_[1] and defined($Texi2HTML::Config::OUTPUT_FORMAT) and $Texi2HTML::Config::OUTPUT_FORMAT eq 'info');
 },
 verbose => 'output navigation headers for each section',
};

$T2H_OPTIONS -> {'subdir'} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::SUBDIR,
 verbose => 'put files in directory $s, not $cwd',
 noHelp => 1,
};

$T2H_OPTIONS -> {'short-ext'} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::SHORTEXTN,
 verbose => 'use "htm" extension for output HTML files',
};

$T2H_OPTIONS -> {'prefix'} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::PREFIX,
 verbose => 'use as prefix for output files, instead of <docname>',
};

$T2H_OPTIONS -> {'output|out|o'} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::OUT,
 verbose => 'output goes to $s (directory if split)',
};

$T2H_OPTIONS -> {'no-validate|no-pointer-validate'} = 
{
 type => '',
 linkage => sub {Texi2HTML::Config::set_conf('novalidate',$_[1])},
 verbose => 'suppress node cross-reference validation',
};

$T2H_OPTIONS -> {'no-warn'} =
{
 type => '',
 linkage => \$Texi2HTML::Config::NO_WARN,
 verbose => 'suppress warnings (but not errors).'
};

$T2H_OPTIONS -> {'short-ref'} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::SHORT_REF,
 verbose => 'if set, references are without section numbers',
};

$T2H_OPTIONS -> {'idx-sum'} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::IDX_SUMMARY,
 verbose => 'if set, also output index summary',
 noHelp  => 1,
};

$T2H_OPTIONS -> {'def-table'} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::DEF_TABLE,
 verbose => 'if set, \@def.. are converted using tables.',
 noHelp  => 1,
};

$T2H_OPTIONS -> {'verbose'} = 0;
$T2H_OPTIONS -> {'verbose|v'} =
{
 type => '!',
 linkage=> \$Texi2HTML::Config::VERBOSE,
 verbose => 'print progress info to stdout',
};

$T2H_OPTIONS -> {'document-language'} =
{
 type => '=s',
 linkage => sub {
        warn_unknown_language ($_[1]);
        Texi2HTML::Config::set_conf('documentlanguage', $_[1])
    },
 verbose => 'use $s as document language',
};

$T2H_OPTIONS -> {'ignore-preamble-text'} =
{
  type => '!',
  linkage => \$Texi2HTML::Config::IGNORE_PREAMBLE_TEXT,
  verbose => 'if set, ignore the text before @node and sectioning commands',
  noHelp => 1,
};

$T2H_OPTIONS -> {'html-xref-prefix'} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::EXTERNAL_DIR,
 verbose => '$s is the base dir for external manual references',
 noHelp => 1,
};

$T2H_OPTIONS -> {'l2h'} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::L2H,
 verbose => 'if set, uses latex2html for @math and @tex',
};

$T2H_OPTIONS -> {'l2h-l2h'} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::L2H_L2H,
 verbose => 'program to use for latex2html translation',
 noHelp => 1,
};

$T2H_OPTIONS -> {'l2h-skip'} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::L2H_SKIP,
 verbose => 'if set, tries to reuse previously latex2html output',
 noHelp => 1,
};

$T2H_OPTIONS -> {'l2h-tmp'} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::L2H_TMP,
 verbose => 'if set, uses $s as temporary latex2html directory',
 noHelp => 1,
};

$T2H_OPTIONS -> {'l2h-file'} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::L2H_FILE,
 verbose => 'if set, uses $s as latex2html init file',
 noHelp => 1,
};


$T2H_OPTIONS -> {'l2h-clean'} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::L2H_CLEAN,
 verbose => 'if set, do not keep intermediate latex2html files for later reuse',
 noHelp => 1,
};

$T2H_OPTIONS -> {'D'} =
{
 type => '=s',
 linkage => sub {$value_initial{$_[1]} = 1;},
 verbose => 'equivalent to Texinfo "@set $s 1"',
 noHelp => 1,
};

$T2H_OPTIONS -> {'U'} =
{
 type => '=s',
 linkage => sub {delete $value_initial{$_[1]};},
 verbose => 'equivalent to Texinfo "@clear $s"',
 noHelp => 1,
};

$T2H_OPTIONS -> {'init-file'} =
{
 type => '=s',
 linkage => \&load_init_file,
 verbose => 'load init file $s'
};

$T2H_OPTIONS -> {'css-include'} =
{
 type => '=s',
 linkage => \@Texi2HTML::Config::CSS_FILES,
 verbose => 'use css file $s'
};

$T2H_OPTIONS -> {'css-ref'} =
{
 type => '=s',
 linkage => \@Texi2HTML::Config::CSS_REFS,
 verbose => 'generate reference to the CSS URL $s'
};

$T2H_OPTIONS -> {'transliterate-file-names'} =
{
 type => '!',
 linkage=> \$Texi2HTML::Config::TRANSLITERATE_FILE_NAMES,
 verbose => 'produce file names in ASCII transliteration',
};

$T2H_OPTIONS -> {'error-limit|e'} =
{
 type => '=i',
 linkage => \$Texi2HTML::Config::ERROR_LIMIT,
 verbose => 'quit after NUM errors (default 1000).',
};

$T2H_OPTIONS -> {'split-size'} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::SPLIT_SIZE,
 verbose => 'split Info files at size s (default 300000).',
};

$T2H_OPTIONS -> {'paragraph-indent|p'} =
{
 type => '=s',
 linkage => sub {set_paragraphindent($_[1], 1);},
 'verbose' => "indent Info paragraphs by VAL spaces (default 3).
                              If VAL is `none', do not indent; if VAL is
                                `asis', preserve existing indentation.",
};

$T2H_OPTIONS -> {'fill-column|f'} =
{
 type => '=i',
 linkage => sub {Texi2HTML::Config::set_conf('fillcolumn',$_[1]);},
 'verbose' => "break Info lines at NUM characters (default 72).",
};

$T2H_OPTIONS -> {'enable-encoding'} =
{
 type => '',
 linkage => \$Texi2HTML::Config::ENABLE_ENCODING,
 verbose => 'override --disable-encoding (default in Info).',
};

$T2H_OPTIONS -> {'disable-encoding'} =
{
 type => '',
 linkage => sub {$Texi2HTML::Config::ENABLE_ENCODING = 0},
 verbose => 'do not output accented and special characters
                                in Info output based on @documentencoding.',
};

$T2H_OPTIONS -> {'internal-links'} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::INTERNAL_LINKS,
 verbose => 'produce list of internal links in FILE.'
};

$T2H_OPTIONS -> {'force|F'} = 
{ type => '!',
 linkage => \$Texi2HTML::Config::FORCE,
 verbose => 'preserve output even if errors.'
};

$T2H_OPTIONS -> {'monolithic'} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::MONOLITHIC,
 verbose => 'output only one file including ToC, About...',
 noHelp => 1
};

$T2H_OPTIONS -> {'commands-in-node-names'} =
{
 type => '!',
 verbose => 'Always set',
 noHelp => 1
};

$T2H_OPTIONS -> {'output-indent'} = 
{
 type => '=i',
 verbose => 'This option used to indent XML, it is ignored'
};

$T2H_OPTIONS -> {'program'} =
{
 type => '=s',
 linkage => sub {set_config_init_dirs_output($_[1]);},
 'verbose' => 'Call as $s, setting corresponding defaults'
};

#$T2H_OPTIONS -> {'command'} =
#{
# type => '=s',
# linkage => \@Texi2HTML::Config::COMMANDS,
# verbose => 'insert CMD in copy of input file'
#};


foreach my $output_format (keys(%Texi2HTML::Config::output_format_names))
{
  next if (defined($Texi2HTML::Config::DEFAULT_OUTPUT_FORMAT) and $output_format eq $Texi2HTML::Config::DEFAULT_OUTPUT_FORMAT);
  $T2H_OPTIONS -> {$output_format} =
  {
    type => '',
    linkage => sub {Texi2HTML::Config::t2h_default_load_format($_[0], 1);},
    verbose => "output $Texi2HTML::Config::output_format_names{$output_format} rather than $Texi2HTML::Config::output_format_names{$Texi2HTML::Config::DEFAULT_OUTPUT_FORMAT}.",
  }
}

$T2H_OPTIONS -> {$Texi2HTML::Config::DEFAULT_OUTPUT_FORMAT} =
{
  type => '',
  linkage => sub {Texi2HTML::Config::t2h_default_load_format($_[0], 1);},
  verbose => "output default format.",
  noHelp => 2
};

##
## obsolete cmd line options
##
my $T2H_OBSOLETE_OPTIONS;

# actually a noop, since it is not used anywhere
$T2H_OBSOLETE_OPTIONS -> {'invisible'} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::INVISIBLE_MARK,
 verbose => 'use text in invisble anchor',
 noHelp  => 2,
};

$T2H_OBSOLETE_OPTIONS -> {'expand'} =
{
 type => '=s',
 linkage => sub {Texi2HTML::Config::set_expansion($_[1], 1);},
 verbose => 'Expand <s> section of texinfo source',
 noHelp => 1,
};

$T2H_OBSOLETE_OPTIONS -> {'no-expand'} =
{
 type => '=s',
 linkage => sub {Texi2HTML::Config::set_expansion ($_[1], 0);},
 verbose => 'Don\'t expand the given section of texinfo source',
};

$T2H_OBSOLETE_OPTIONS -> {'noexpand'} = 
{
 type => '=s',
 linkage => $T2H_OBSOLETE_OPTIONS->{'no-expand'}->{'linkage'},
 verbose => $T2H_OBSOLETE_OPTIONS->{'no-expand'}->{'verbose'},
 noHelp  => 1,
};

$T2H_OBSOLETE_OPTIONS -> {'out-file'} =
{
 type => '=s',
 linkage => sub {$Texi2HTML::Config::OUT = $_[1]; $Texi2HTML::Config::SPLIT = '';},
 verbose => 'if set, all HTML output goes into file $s, obsoleted by "-output" with different semantics',
 noHelp => 2
};

$T2H_OBSOLETE_OPTIONS -> {'lang'} =
{
 type => '=s',
 linkage => sub {Texi2HTML::Config::set_conf('documentlanguage', $_[1])},
 verbose => 'obsolete, use "--document-language" instead',
 noHelp => 2
};

$T2H_OBSOLETE_OPTIONS -> {'separated-footnotes'} =
{
 type => '!',
 linkage => sub {my $style = 'separate'; $style = 'end' if !$_[1]; set_footnote_style ($style, 1);},
 verbose => 'obsolete, use "--footnote-style" instead',
 noHelp => 2
};

$T2H_OBSOLETE_OPTIONS -> {'Verbose'} =
{
 type => '!',
 linkage=> \$Texi2HTML::Config::VERBOSE,
 verbose => 'obsolete, use "--verbose" instead',
 noHelp => 2
};


$T2H_OBSOLETE_OPTIONS -> {init_file} =
{
 type => '=s',
 linkage => \&load_init_file,
 verbose => 'obsolete, use "-init-file" instead',
 noHelp => 2
};

$T2H_OBSOLETE_OPTIONS -> {l2h_clean} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::L2H_CLEAN,
 verbose => 'obsolete, use "-l2h-clean" instead',
 noHelp => 2,
};

$T2H_OBSOLETE_OPTIONS -> {l2h_l2h} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::L2H_L2H,
 verbose => 'obsolete, use "-l2h-l2h" instead',
 noHelp => 2
};

$T2H_OBSOLETE_OPTIONS -> {l2h_skip} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::L2H_SKIP,
 verbose => 'obsolete, use "-l2h-skip" instead',
 noHelp => 2
};

$T2H_OBSOLETE_OPTIONS -> {l2h_tmp} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::L2H_TMP,
 verbose => 'obsolete, use "-l2h-tmp" instead',
 noHelp => 2
};

$T2H_OBSOLETE_OPTIONS -> {out_file} =
{
 type => '=s',
 linkage => sub {$Texi2HTML::Config::OUT = $_[1]; $Texi2HTML::Config::SPLIT = '';},
 verbose => 'obsolete, use "-out-file" instead',
 noHelp => 2
};

$T2H_OBSOLETE_OPTIONS -> {short_ref} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::SHORT_REF,
 verbose => 'obsolete, use "-short-ref" instead',
 noHelp => 2
};

$T2H_OBSOLETE_OPTIONS -> {idx_sum} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::IDX_SUMMARY,
 verbose => 'obsolete, use "-idx-sum" instead',
 noHelp  => 2
};

$T2H_OBSOLETE_OPTIONS -> {def_table} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::DEF_TABLE,
 verbose => 'obsolete, use "-def-table" instead',
 noHelp  => 2
};

$T2H_OBSOLETE_OPTIONS -> {short_ext} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::SHORTEXTN,
 verbose => 'obsolete, use "-short-ext" instead',
 noHelp  => 2
};

$T2H_OBSOLETE_OPTIONS -> {sec_nav} =
{
 type => '!',
 linkage => sub {Texi2HTML::Config::set_conf('headers', $_[1]);},
 verbose => 'obsolete, use "-headers" instead',
 noHelp  => 2
};

$T2H_OBSOLETE_OPTIONS -> {'sec-nav'} =
{
 type => '!',
 linkage => sub {Texi2HTML::Config::set_conf('headers', $_[1]);},
 verbose => 'obsolete, use "--header" instead',
 noHelp  => 2
};

$T2H_OBSOLETE_OPTIONS -> {top_file} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::TOP_FILE,
 verbose => 'obsolete, use "-top-file" instead',
 noHelp  => 2
};

$T2H_OBSOLETE_OPTIONS -> {toc_file} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::TOC_FILE,
 verbose => 'obsolete, use "-toc-file" instead',
 noHelp  => 2
};

$T2H_OBSOLETE_OPTIONS -> {glossary} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::USE_GLOSSARY,
 verbose => "this does nothing",
 noHelp  => 2,
};

$T2H_OBSOLETE_OPTIONS -> {check} =
{
 type => '!',
 linkage => sub {exit 0;},
 verbose => "exit without doing anything",
 noHelp  => 2,
};

$T2H_OBSOLETE_OPTIONS -> {dump_texi} =
{
 type => '!',
 linkage => \$Texi2HTML::Config::DUMP_TEXI,
 verbose => 'obsolete, use "-dump-texi" instead',
 noHelp => 1
};

$T2H_OBSOLETE_OPTIONS -> {frameset_doctype} =
{
 type => '=s',
 linkage => \$Texi2HTML::Config::FRAMESET_DOCTYPE,
 verbose => 'obsolete, use "-frameset-doctype" instead',
 noHelp => 2
};

$T2H_OBSOLETE_OPTIONS -> {'no-section_navigation'} =
{
 type => '!',
 linkage => sub {Texi2HTML::Config::set_conf('headers', 0);},
 verbose => 'obsolete, use -nosec_nav',
 noHelp => 2,
};
my $use_acc; # not used
$T2H_OBSOLETE_OPTIONS -> {use_acc} =
{
 type => '!',
 linkage => \$use_acc,
 verbose => 'obsolete, set to true unconditionnaly',
 noHelp => 2
};
$T2H_OBSOLETE_OPTIONS -> {expandinfo} =
{
 type => '!',
 linkage => sub {push @Texi2HTML::Config::EXPAND, 'info';},
 verbose => 'obsolete, use "--ifinfo" instead',
 noHelp => 2,
};
$T2H_OBSOLETE_OPTIONS -> {expandtex} =
{
 type => '!',
 linkage => sub {push @Texi2HTML::Config::EXPAND, 'tex';},
 verbose => 'obsolete, use "--iftex" instead',
 noHelp => 2,
};
$T2H_OBSOLETE_OPTIONS -> {split_node} =
{
 type => '!',
 linkage => sub{$Texi2HTML::Config::SPLIT = 'section';},
 verbose => 'obsolete, use "-split section" instead',
 noHelp => 2,
};
$T2H_OBSOLETE_OPTIONS -> {split_chapter} =
{
 type => '!',
 linkage => sub{$Texi2HTML::Config::SPLIT = 'chapter';},
 verbose => 'obsolete, use "-split chapter" instead',
 noHelp => 2,
};
$T2H_OBSOLETE_OPTIONS -> {no_verbose} =
{
 type => '!',
 linkage => sub {$Texi2HTML::Config::VERBOSE = 0;},
 verbose => 'obsolete, use -noverbose instead',
 noHelp => 2,
};
$T2H_OBSOLETE_OPTIONS -> {output_file} =
{
 type => '=s',
 linkage => sub {$Texi2HTML::Config::OUT = $_[1]; $Texi2HTML::Config::SPLIT = '';},
 verbose => 'obsolete, use --out-file instead',
 noHelp => 2
};

$T2H_OBSOLETE_OPTIONS -> {section_navigation} =
{
 type => '!',
 linkage => sub {Texi2HTML::Config::set_conf('headers', $_[1]);},
 verbose => 'obsolete, use --sec-nav instead',
 noHelp => 2,
};

# read initialzation from $sysconfdir/texi2htmlrc or $HOME/.texi2htmlrc
# (this is obsolete). Obsoleted in 1.68 (March 20 2004).
my @rc_files = ();
push @rc_files, "$sysconfdir/texi2htmlrc" if defined($sysconfdir);
push @rc_files, "$ENV{'HOME'}/.texi2htmlrc" if (defined($ENV{'HOME'}));
foreach my $i (@rc_files)
{
    if (-e $i and -r $i)
    {
        print STDERR "# reading initialization file from $i\n"
	    if ($T2H_VERBOSE);
        print STDERR "Reading config from $i is obsolete, use texi2html/$conf_file_name instead\n";
        Texi2HTML::Config::load($i);
    }
}

# read initialization files
foreach my $file (locate_init_file($conf_file_name, 1))
{
    print STDERR "# reading initialization file from $file\n" if ($T2H_VERBOSE);
    Texi2HTML::Config::load($file);
}


#+++############################################################################
#                                                                              #
# parse command-line options
#                                                                              #
#---############################################################################

# options known by makeinfo (+version, help and if*)
my @makeinfo_options = ('error-limit', 'document-language',
'force', 'help', 'no-validate', 'no-warn', 'verbose', 'docbook', 'html', 
'xml', 'plaintext', 'macro-expand', 'headers', 'no-split', 
'number-sections', 'output', 'disable-encoding', 'enable-encoding', 
'fill-column', 'footnote-style', 'paragraph-indent', 'split-size', 
'css-include', 'css-ref', 'internal-links', 'transliterate-file-names', 
'output-indent', 'number-footnotes', 'D', 'I', 'P', 'U');

# always used, even though they are not in makeinfo in C.
# dump-texi', 'debug', 'test' are for debugging.
# split is in makeinfo in C, as --no-split.
# 'conf-dir', 'init-file' options have to be taken into account for proper
# functionning.
my @basic_options = ('dump-texi', 'debug', 'test', 'conf-dir', 'init-file',
'split', 'program');

#      --command=CMD           insert CMD in copy of input file
my $makeinfo_help =
sprintf(__("Usage: %s [OPTION]... TEXINFO-FILE...\n"), $real_command_name) 
."\n".
__("Translate Texinfo source documentation to various other formats, by default
Info files suitable for reading online with Emacs or standalone GNU Info.\n") 
."\n";
$makeinfo_help .= sprintf(__("General options:
      --error-limit=NUM       quit after NUM errors (default %d).
      --document-language=STR locale to use in translating Texinfo keywords
                                for the output document (default C).
      --force                 preserve output even if errors.
      --help                  display this help and exit.
      --no-validate           suppress node cross-reference validation.
      --no-warn               suppress warnings (but not errors).
  -v, --verbose               explain what is being done.
      --version               display version information and exit.\n"), $Texi2HTML::Config::ERROR_LIMIT)
."\n";
$makeinfo_help .= __("Output format selection (default is to produce Info):
      --docbook               output Docbook XML rather than Info.
      --html                  output HTML rather than Info.
      --xml                   output Texinfo XML rather than Info.
      --plaintext             output plain text rather than Info.\n")
."\n";
$makeinfo_help .= __("General output options:
  -E, --macro-expand=FILE     output macro-expanded source to FILE,
                                ignoring any \@setfilename.
      --no-headers            suppress node separators, Node: lines, and menus
                                from Info output (thus producing plain text)
                                or from HTML (thus producing shorter output);
                                also, write to standard output by default.
      --no-split              suppress the splitting of Info or HTML output,
                                generate only one output file.
      --number-sections       output chapter and sectioning numbers.
  -o, --output=FILE           output to FILE (or directory if split HTML).\n")
."\n";
$makeinfo_help .= sprintf(__("Options for Info and plain text:
      --disable-encoding      do not output accented and special characters
                                in Info output based on \@documentencoding.
      --enable-encoding       override --disable-encoding (default).
      --fill-column=NUM       break Info lines at NUM characters (default %d).
      --footnote-style=STYLE  output footnotes in Info according to STYLE:
                                `separate' to put them in their own node;
                                `end' to put them at the end of the node, in
                                which they are defined (this is the default).
      --paragraph-indent=VAL  indent Info paragraphs by VAL spaces (default %d).
                                If VAL is `none', do not indent; if VAL is
                                `asis', preserve existing indentation.
      --split-size=NUM        split Info files at size NUM (default %d).\n"),
  $Texi2HTML::Config::FILLCOLUMN, $Texi2HTML::Config::PARAGRAPHINDENT, $Texi2HTML::Config::SPLIT_SIZE)
."\n";
$makeinfo_help .= __("Options for HTML:
      --css-include=FILE      include FILE in HTML <style> output;
                                read stdin if FILE is -.
      --css-ref=URL           generate reference to a CSS file.
      --internal-links=FILE   produce list of internal links in FILE.
      --transliterate-file-names
                              produce file names in ASCII transliteration.\n")
."\n";
# This is ignored, so remove it from help
#Options for XML and Docbook:
#      --output-indent=VAL     indent XML elements by VAL spaces (default 2).
#                                If VAL is 0, ignorable whitespace is dropped.
#
$makeinfo_help .= __("Input file options:
      --commands-in-node-names  allow \@ commands in node names.
  -D VAR                        define the variable VAR, as with \@set.
  -I DIR                        append DIR to the \@include search path.
  -P DIR                        prepend DIR to the \@include search path.
  -U VAR                        undefine the variable VAR, as with \@clear.\n")
."\n";
$makeinfo_help .= __("Conditional processing in input:
  --ifdocbook       process \@ifdocbook and \@docbook even if
                      not generating Docbook.
  --ifhtml          process \@ifhtml and \@html even if not generating HTML.
  --ifinfo          process \@ifinfo even if not generating Info.
  --ifplaintext     process \@ifplaintext even if not generating plain text.
  --iftex           process \@iftex and \@tex; implies --no-split.
  --ifxml           process \@ifxml and \@xml.
  --no-ifdocbook    do not process \@ifdocbook and \@docbook text.
  --no-ifhtml       do not process \@ifhtml and \@html text.
  --no-ifinfo       do not process \@ifinfo text.
  --no-ifplaintext  do not process \@ifplaintext text.
  --no-iftex        do not process \@iftex and \@tex text.
  --no-ifxml        do not process \@ifxml and \@xml text.

  Also, for the --no-ifFORMAT options, do process \@ifnotFORMAT text.\n")
."\n";
$makeinfo_help .= __("  The defaults for the \@if... conditionals depend on the output format:
  if generating HTML, --ifhtml is on and the others are off;
  if generating Info, --ifinfo is on and the others are off;
  if generating plain text, --ifplaintext is on and the others are off;
  if generating XML, --ifxml is on and the others are off.\n")
."\n";
$makeinfo_help .= __("Examples:
  makeinfo foo.texi                      write Info to foo's \@setfilename
  makeinfo --html foo.texi               write HTML to \@setfilename
  makeinfo --xml foo.texi                write Texinfo XML to \@setfilename
  makeinfo --docbook foo.texi            write DocBook XML to \@setfilename
  makeinfo --no-headers foo.texi         write plain text to standard output

  makeinfo --html --no-headers foo.texi  write html without node lines, menus
  makeinfo --number-sections foo.texi    write Info with numbered sections
  makeinfo --no-split foo.texi           write one Info file however big\n")
."\n";
$makeinfo_help .= __("Email bug reports to bug-texinfo\@gnu.org,
general questions and discussion to help-texinfo\@gnu.org.
Texinfo home page: http://www.gnu.org/software/texinfo/") ."\n";

# parsing like texi2html:


my $T2H_USAGE_TEXT = <<EOT;
Usage: texi2html  [OPTIONS] TEXINFO-FILE
Translates Texinfo source documentation to HTML.
EOT


my $options = new Getopt::MySimple;

$T2H_OPTIONS -> {'help'} = 0;
$T2H_OPTIONS -> {'help|h'} = 
{ 
 type => ':i', 
 default => '',
 linkage => sub {$options->helpOptions($_[1]); 
    print "\nSend bugs and suggestions to <texi2html-bug\@nongnu.org>\n";
    exit (0);},
 verbose => "print help and exit"
};

# this avoids getOptions defining twice 'help' and 'version'.
$T2H_OBSOLETE_OPTIONS->{'help'} = 0;
$T2H_OBSOLETE_OPTIONS->{'version'} = 0;
$T2H_OBSOLETE_OPTIONS->{'verbose'} = 0;


if ($real_command_name eq 'texi2html')
{
  # some older version of GetOpt::Long don't have
  # Getopt::Long::Configure("pass_through")
  eval {Getopt::Long::Configure("pass_through");};
  my $Configure_failed = $@ && <<EOT;
**WARNING: Parsing of obsolete command-line options could have failed.
           Consider to use only documented command-line options (run
           'texi2html --help 2' for a complete list) or upgrade to perl
           version 5.005 or higher.
EOT
  if (! $options->getOptions($T2H_OPTIONS, $T2H_USAGE_TEXT, "$THISVERSION\n"))
  {
     print STDERR "$Configure_failed" if $Configure_failed;
     die $T2H_FAILURE_TEXT;
  }
  if (@ARGV > 1)
  {
     eval {Getopt::Long::Configure("no_pass_through");};
     if (! $options->getOptions($T2H_OBSOLETE_OPTIONS, $T2H_USAGE_TEXT, "$THISVERSION\n"))
     {
        print STDERR "$Configure_failed" if $Configure_failed;
        die $T2H_FAILURE_TEXT;
      }
  }
}
else
{
   # changes how command lines are parsed, for example -init file.init 
   # doesn't work anymore.
   Getopt::Long::Configure("gnu_getopt");
   my $opts;
   my @types;
   foreach my $key (keys(%$T2H_OPTIONS))
   {
      next unless ($T2H_OPTIONS->{$key});
      my $primary = $key;
      $primary =~ s/\|.*//;
      next if ($primary eq 'version' or $primary eq 'help');
      next if ($real_command_name eq 'makeinfo' and ! grep {$primary eq $_} (@makeinfo_options, @basic_options) and $primary !~ /^if/);
      $opts->{$primary} = $T2H_OPTIONS->{$key}->{'linkage'} if defined($T2H_OPTIONS->{$key}->{'linkage'});
      push @types, "$key$T2H_OPTIONS->{$key}->{'type'}";
   }
   $opts->{'version'} = sub {
      print "$real_command_name (GNU texinfo) $THISVERSION\n\n";

      printf __("Copyright (C) %s Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.\n"), '2008';
      exit 0;
   };
   $opts->{'help'} = sub {
      print "$makeinfo_help";
      exit 0;
   };
   push @types, ('version|V', 'help|h');
   #foreach my $key (sort(keys(%$opts)))
   #{
   #   #print STDERR "$key, $opts->{$key}\n";
   #   print "$key\n";
   #}
   #print STDERR "@types\n";
   my $result_options = Getopt::Long::GetOptions ($opts, @types);
}

if (! $Texi2HTML::THISDOC{'format_from_command_line'} and defined($ENV{'TEXINFO_OUTPUT_FORMAT'}) and $ENV{'TEXINFO_OUTPUT_FORMAT'} ne '')
{
  if (! Texi2HTML::Config::t2h_default_load_format($ENV{'TEXINFO_OUTPUT_FORMAT'}, 0))
  {  
      warn sprintf(__("%s: Ignoring unrecognized TEXINFO_OUTPUT_FORMAT value `%s'.\n"), $real_command_name, $ENV{'TEXINFO_OUTPUT_FORMAT'});
  }
}

# $T2H_DEBUG and $T2H_VERBOSE are shorthands
$T2H_DEBUG = $Texi2HTML::Config::DEBUG;
$T2H_VERBOSE = $Texi2HTML::Config::VERBOSE;

#
# read texi2html extensions (if any)
# It is obsolete (obsoleted by -init-file). we keep it for backward
# compatibility.
my $extensions = 'texi2html.ext';  # extensions in working directory
if (-f $extensions)
{
    print STDERR "# reading extensions from $extensions\n" if $T2H_VERBOSE;
    require($extensions);
}
my $progdir;
($progdir = $0) =~ s/[^\/]+$//;
if ($progdir && ($progdir ne './'))
{
    $extensions = "${progdir}texi2html.ext"; # extensions in texi2html directory
    if (-f $extensions)
    {
	print STDERR "# reading extensions from $extensions\n" if $T2H_VERBOSE;
	require($extensions);
    }
}


#+++############################################################################
#                                                                              #
# evaluation of cmd line options
#                                                                              #
#---############################################################################

# set the default 'args' entry to normal for each style hash (and each command
# within)
my $name_index = -1;
my @hash_names = ('style_map', 'style_map_pre', 'style_map_texi', 'simple_format_style_map_texi');
foreach my $hash (\%Texi2HTML::Config::style_map, \%Texi2HTML::Config::style_map_pre, \%Texi2HTML::Config::style_map_texi, \%Texi2HTML::Config::simple_format_style_map_texi)
{
    $name_index++;
    my $name = $hash_names[$name_index]; # name associated with hash ref
    foreach my $style (keys(%{$hash}))
    {
        next unless (ref($hash->{$style}) eq 'HASH');
        $hash->{$style}->{'args'} = ['normal'] if (!exists($hash->{$style}->{'args'}));
        die "Bug: args not defined, but existing, for $style in $name" if (!defined($hash->{$style}->{'args'}));
#print STDERR "DEFAULT($name, $hash) add normal as arg for $style ($hash->{$style}), $hash->{$style}->{'args'}\n";
    }
}

# setup hashes used for html manual cross references in texinfo
my %cross_ref_texi_map = %Texi2HTML::Config::default_texi_map;
my %cross_transliterate_texi_map = %cross_ref_texi_map;

my %cross_ref_simple_map_texi = %Texi2HTML::Config::default_simple_map;
$cross_ref_simple_map_texi{"*"} = ' ';

my %cross_ref_style_map_texi = ();
my %cross_transliterate_style_map_texi = ();
Texi2HTML::Config::t2h_default_copy_style_map(\%Texi2HTML::Config::default_style_map_texi, \%cross_ref_style_map_texi);
Texi2HTML::Config::t2h_default_copy_style_map(\%Texi2HTML::Config::default_style_map_texi, \%cross_transliterate_style_map_texi);



# Fill in the %style_type hash, a hash associating style @-comand with 
# the type, 'accent', real 'style', 'simple_style', or 'special'.
# 'simple_style' styles don't extend accross lines.
my %style_type = (); 
my @simple_styles = ('ctrl', 'w', 'url','uref','indicateurl','email',
    'titlefont');
foreach my $style (keys(%Texi2HTML::Config::style_map))
{
    if (exists $Texi2HTML::Config::command_type{$style})
    {
        $style_type{$style} = $Texi2HTML::Config::command_type{$style};
        next;
    }
    if (ref($Texi2HTML::Config::style_map{$style} eq 'HASH'))
    {
        $style_type{$style} = $Texi2HTML::Config::style_map{$style}->{'type'}
          if (exists($Texi2HTML::Config::style_map{$style}->{'type'}));
    }
    else
    {
        $style_type{$style} = 'simple_style' if (grep {$_ eq $style} @simple_styles);
    }
    $style_type{$style} = 'style' unless (defined($style_type{$style}));
}

foreach my $accent (keys(%Texi2HTML::Config::unicode_accents), 'tieaccent', 'dotless')
{
    if (exists $Texi2HTML::Config::command_type{$accent})
    {
        $style_type{$accent} = $Texi2HTML::Config::command_type{$accent};
        next;
    }
    $style_type{$accent} = 'accent';
}




foreach my $special ('footnote', 'ref', 'xref', 'pxref', 'inforef', 'anchor', 'image', 'hyphenation')
{
    if (exists $Texi2HTML::Config::command_type{$special})
    {
        $style_type{$special} = $Texi2HTML::Config::command_type{$special};
        next;
    }
    $style_type{$special} = 'special';
}

# retro compatibility for $Texi2HTML::Config::EXPAND
push (@Texi2HTML::Config::EXPAND, $Texi2HTML::Config::EXPAND) if ($Texi2HTML::Config::EXPAND);

push (@Texi2HTML::Config::EXPAND, @Texi2HTML::Config::T2H_FORMAT_EXPAND);

# correct %Texi2HTML::Config::texi_formats_map based on command line and init
# variables
$Texi2HTML::Config::texi_formats_map{'menu'} = 'normal' if ($Texi2HTML::Config::SHOW_MENU);

foreach my $expanded (@Texi2HTML::Config::EXPAND)
{
    $Texi2HTML::Config::texi_formats_map{"if$expanded"} = 1 if (exists($Texi2HTML::Config::texi_formats_map{"if$expanded"}));
    next unless (exists($Texi2HTML::Config::texi_formats_map{$expanded}));
    if (grep {$_ eq $expanded} @raw_regions)
    {
         $Texi2HTML::Config::texi_formats_map{$expanded} = 'raw'; 
    }
    else
    {
         $Texi2HTML::Config::texi_formats_map{$expanded} = 'normal'; 
    }
}

# don't set set_no_line_macro for raw EXPAND formats 
foreach my $key (keys(%Texi2HTML::Config::texi_formats_map))
{
    unless ($Texi2HTML::Config::texi_formats_map{$key} eq 'raw')
    {
        set_no_line_macro($key, 1);
        set_no_line_macro("end $key", 1);
    }
}

# the remaining (not in @EXPAND) raw formats are set as 'raw' such that 
# they are propagated to formatting functions, but
# they don't start paragraphs or preformatted.
foreach my $raw (@raw_regions)
{
    if (!defined($Texi2HTML::Config::texi_formats_map{$raw}))
    {
        $Texi2HTML::Config::texi_formats_map{$raw} = 'raw'; 
        $Texi2HTML::Config::format_in_paragraph{$raw} = 1;
        set_no_line_macro($raw, 1);
        set_no_line_macro("end $raw", 1);
    }
}

# handle ifnot regions
foreach my $region (keys (%Texi2HTML::Config::texi_formats_map))
{
    next if ($region =~ /^ifnot/);
    if ($Texi2HTML::Config::texi_formats_map{$region} and $region =~ /^if(\w+)$/)
    {
        $Texi2HTML::Config::texi_formats_map{"ifnot$1"} = 0;
    }
}

if ($T2H_VERBOSE)
{
    print STDERR "# Expanded: ";
    foreach my $text_macro (keys(%Texi2HTML::Config::texi_formats_map))
    {
        print STDERR "$text_macro " if ($Texi2HTML::Config::texi_formats_map{$text_macro});
    }
    print STDERR "\n";
}

# This is kept in that file although it is html formatting as it seems to 
# be rather obsolete
$Texi2HTML::Config::INVISIBLE_MARK = '<img src="invisible.xbm" alt="">' if $Texi2HTML::Config::INVISIBLE_MARK eq 'xbm';

$T2H_DEBUG |= $DEBUG_TEXI if ($Texi2HTML::Config::DUMP_TEXI);

# no user provided USE_UNICODE, use configure provided
if (!defined($Texi2HTML::Config::USE_UNICODE))
{
    $Texi2HTML::Config::USE_UNICODE = 'unknown';
}

# no user provided nor configured, run time test
if ($Texi2HTML::Config::USE_UNICODE eq 'unknown' or $Texi2HTML::Config::USE_UNICODE eq '@' .'USE_UNICODE@')
{
    eval {
        require Encode;
        require Unicode::Normalize; 
        Encode->import('encode');
    };
    if ($@)
    {
        $Texi2HTML::Config::USE_UNICODE = 0 
    }
    else
    {
        $Texi2HTML::Config::USE_UNICODE = 1;
    }
}

if ($Texi2HTML::Config::USE_UNICODE)
{
    require Encode;
    require Unicode::Normalize;
    Encode->import('encode');

    # use EastAsianWidth if USE_UNICODE is set
    if ($0 =~ /\.pl$/)
    { # use in-source EastAsianWidth when testing
        unshift @INC, "$T2H_HOME/lib/Unicode-EastAsianWidth/lib";
    }
    elsif ($ENV{T2H_SOURCE_EASTASIANWIDTH})
    {
        unshift @INC, $ENV{T2H_SOURCE_EASTASIANWIDTH};
    }
    elsif ('no' ne 'yes')
    {
        unshift @INC, "$pkgdatadir/lib/Unicode-EastAsianWidth/lib";
    }
    else
    {
        eval {
            require Unicode::EastAsianWidth;
        };
        if ($@)
        {
            unshift @INC, "$pkgdatadir/lib/Unicode-EastAsianWidth/lib";
        }
    }
    # unicode east asian character width tables.
    require Unicode::EastAsianWidth;
}

# no user provided USE_UNIDECODE, use configure provided
if (!defined($Texi2HTML::Config::USE_UNIDECODE))
{
    $Texi2HTML::Config::USE_UNIDECODE = 'unknown';
}

# no user provided nor configured, run time test
if ($Texi2HTML::Config::USE_UNIDECODE eq 'unknown' or $Texi2HTML::Config::USE_UNIDECODE eq '@' .'USE_UNIDECODE@')
{
    $Texi2HTML::Config::USE_UNIDECODE = 1;
    eval {
        require Text::Unidecode;
        Text::Unidecode->import('unidecode');
    };
    $Texi2HTML::Config::USE_UNIDECODE = 0 if ($@);
}

if ($Texi2HTML::Config::USE_UNIDECODE)
{
    require Text::Unidecode;
    Text::Unidecode->import('unidecode');
}

print STDERR "# USE_UNICODE $Texi2HTML::Config::USE_UNICODE, USE_UNIDECODE $Texi2HTML::Config::USE_UNIDECODE \n" 
  if ($T2H_VERBOSE);

# Construct hashes used for cross references generation
# Do it now as the user may have changed $USE_UNICODE

foreach my $key (keys(%Texi2HTML::Config::unicode_map))
{
    if ($Texi2HTML::Config::unicode_map{$key} ne '')
    {
        if ($Texi2HTML::Config::USE_UNICODE)
        {
             my $char_nr = hex($Texi2HTML::Config::unicode_map{$key});
             #$cross_ref_texi_map{$key} = chr(hex($Texi2HTML::Config::unicode_map{$key}));
             #$cross_ref_texi_map{$key} = pack("U0U*",hex($Texi2HTML::Config::unicode_map{$key}));
             if ($char_nr > 126 and $char_nr < 255)
             {
                 $cross_ref_texi_map{$key} = Encode::decode("iso-8859-1", chr($char_nr));
             }
             else
             {
                 $cross_ref_texi_map{$key} = chr($char_nr);
             }
             # cross_transliterate_texi_map is only used if 
             # USE_UNIDECODE is unset and TRANSLITERATE_FILE_NAMES is set
             if (exists ($Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}}))
             {
                $cross_transliterate_texi_map{$key} = $Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}};
             }
             else
             {
                 $cross_transliterate_texi_map{$key} = $cross_ref_texi_map{$key};
             }
        }
        else
        {
            $cross_ref_texi_map{$key} = '_' . lc($Texi2HTML::Config::unicode_map{$key});
             # cross_transliterate_texi_map is used if TRANSLITERATE_FILE_NAMES is set
             if (exists ($Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}}))
             {
                 $cross_transliterate_texi_map{$key} = $Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}};
             }
             else
             {
                  $cross_transliterate_texi_map{$key} = '_' . lc($Texi2HTML::Config::unicode_map{$key});
             }
        }
    }
}
#if ($Texi2HTML::Config::USE_UNICODE and $Texi2HTML::Config::TRANSLITERATE_FILE_NAMES
if ($Texi2HTML::Config::TRANSLITERATE_FILE_NAMES and (
    ($Texi2HTML::Config::USE_UNICODE and ! $Texi2HTML::Config::USE_UNIDECODE)
    or !$Texi2HTML::Config::USE_UNICODE))
{
    foreach my $key (keys (%Texi2HTML::Config::transliterate_accent_map))
    {
        $Texi2HTML::Config::transliterate_map{$key} = $Texi2HTML::Config::transliterate_accent_map{$key};
    }
}

foreach my $key (keys(%cross_ref_style_map_texi))
{
    if ($style_type{$key} eq 'accent' 
        and (ref($cross_ref_style_map_texi{$key}) eq 'HASH'))
    {
        if ($Texi2HTML::Config::USE_UNICODE)
        {
             $cross_ref_style_map_texi{$key}->{'function'} = \&Texi2HTML::Config::t2h_utf8_accent;
        }
        else
        {
             $cross_ref_style_map_texi{$key}->{'function'} = \&Texi2HTML::Config::t2h_nounicode_cross_manual_accent;
        }
        # this is only used if TRANSLITERATE_FILE_NAMES is set and USE_UNICODE
        # or USE_UNIDECODE is not set
        $cross_transliterate_style_map_texi{$key}->{'function'} = \&Texi2HTML::Config::t2h_transliterate_cross_manual_accent;
    }
}

if ($Texi2HTML::Config::L2H and defined($Texi2HTML::Config::OUTPUT_FORMAT) and $Texi2HTML::Config::OUTPUT_FORMAT eq 'html')
{
   push @Texi2HTML::Config::command_handler_init, \&Texi2HTML::LaTeX2HTML::init;
   push @Texi2HTML::Config::command_handler_process, \&Texi2HTML::LaTeX2HTML::latex2html;
   # do it here once to have something ready for special regions
   push @Texi2HTML::Config::command_handler_process, \&Texi2HTML::LaTeX2HTML::init_from_html;
   # do it here once more in case the file was modified (see mediawiki.init)
   push @Texi2HTML::Config::command_handler_output, \&Texi2HTML::LaTeX2HTML::init_from_html;
   push @Texi2HTML::Config::command_handler_finish, \&Texi2HTML::LaTeX2HTML::finish;
   $Texi2HTML::Config::command_handler{'math'} = 
     { 'init' => \&Texi2HTML::LaTeX2HTML::to_latex, 
       'expand' => \&Texi2HTML::LaTeX2HTML::do_tex
     };
   $Texi2HTML::Config::command_handler{'tex'} = 
     { 'init' => \&Texi2HTML::LaTeX2HTML::to_latex, 
       'expand' => \&Texi2HTML::LaTeX2HTML::do_tex
     };
}

if ($Texi2HTML::Config::ENABLE_ENCODING)
{
   if ($Texi2HTML::Config::USE_UNICODE)
   {
      Texi2HTML::Config::t2h_enable_encoding_load();
   }
   else
   { # FIXME: only warn if ENABLE_ENCODING is set on the command line
      #warn "** --enable-encoding requires utf-8 support\n";
   }
}

# for all files. This won't be overriden by @documentencoding, this is not
# what is done in general.
Texi2HTML::Config::set_conf('IN_ENCODING', $Texi2HTML::Config::IN_ENCODING);
Texi2HTML::Config::set_conf('DOCUMENT_ENCODING', $Texi2HTML::Config::DOCUMENT_ENCODING);

# Backward compatibility for deprecated $Texi2HTML::Config::ENCODING
$Texi2HTML::Config::ENCODING_NAME = $Texi2HTML::Config::ENCODING 
  if (!defined($Texi2HTML::Config::ENCODING_NAME) and defined($Texi2HTML::Config::ENCODING));

# APA: There's got to be a better way:
if ($Texi2HTML::Config::TEST)
{
    # to generate files similar to reference ones to be able to check for
    # real changes we use these dummy values if -test is given
    $THISPROG = 'texi2html';
    setlocale( LC_ALL, "C" );
} 

$Texi2HTML::GLOBAL{'debug_l2h'} = 1 if ($T2H_DEBUG & $DEBUG_L2H);

# parse texinfo cnf file for external manual specifications. This was
# discussed on texinfo list but not in makeinfo for now. 
my @texinfo_htmlxref_files = locate_init_file ($texinfo_htmlxref, 1, \@texinfo_config_dirs);

foreach my $file (@texinfo_htmlxref_files)
{
    print STDERR "html refs config file: $file\n" if ($T2H_DEBUG);    
    unless (open (HTMLXREF, $file))
    {
         document_warn("Cannot open html refs config file ${file}: $!");
         next;
    }
    my $line_nr = 0;
    my %variables;
    while (my $hline = <HTMLXREF>)
    {
        my $line = $hline;
        $line_nr++;
        next if $hline =~ /^\s*#/;
        #$hline =~ s/[#]\s.*//;
        $hline =~ s/^\s*//;
        next if $hline =~ /^\s*$/;
        chomp ($hline);
        if ($hline =~ s/^(\w+)\s*=\s*//)
        {
           # handle variables
           my $var = $1;
           my $re = join '|', map { quotemeta $_ } keys %variables;
           $hline =~ s/\$\{($re)\}/defined $variables{$1} ? $variables{$1} : "\${$1}"/ge;
           $variables{$var} = $hline;
           next;
        }
        my @htmlxref = split /\s+/, $hline;
        my $manual = shift @htmlxref;
        my $split_or_mono = shift @htmlxref;
#print STDERR "$split_or_mono $Texi2HTML::Config::htmlxref_entries{$split_or_mono} $line_nr\n";
        if (!defined($split_or_mono))
        {
            file_line_warn(__("Missing type"), $file, $line_nr);
            next;
        }
        elsif (!defined($Texi2HTML::Config::htmlxref_entries{$split_or_mono}))
        {
            file_line_warn(sprintf(__("Unrecognized type: %s"), $split_or_mono), $file, $line_nr);
            next;
        }
        my $href = shift @htmlxref;
        next if (exists($Texi2HTML::GLOBAL{'htmlxref'}->{$manual}->{$split_or_mono}) and exists($Texi2HTML::GLOBAL{'htmlxref'}->{$manual}->{$split_or_mono}->{'href'}));
        
        if (defined($href))
        {
            my $re = join '|', map { quotemeta $_ } keys %variables;
            $href =~ s/\$\{($re)\}/defined $variables{$1} ? $variables{$1} : "\${$1}"/ge;
            $href =~ s/\/*$// if ($split_or_mono ne 'mono');
            $Texi2HTML::GLOBAL{'htmlxref'}->{$manual}->{$split_or_mono}->{'href'} = $href;
        }
        else
        {
            $Texi2HTML::GLOBAL{'htmlxref'}->{$manual}->{$split_or_mono} = {};
        }
    }
    close (HTMLXREF);
}

if ($T2H_DEBUG)
{
    foreach my $manual (keys(%{$Texi2HTML::GLOBAL{'htmlxref'}}))
    {
         foreach my $split (keys(%Texi2HTML::Config::htmlxref_entries))
         {
              my $href = 'NO';
              next unless (exists($Texi2HTML::GLOBAL{'htmlxref'}->{$manual}->{$split}));
              $href = $Texi2HTML::GLOBAL{'htmlxref'}->{$manual}->{$split}->{'href'} if
                  exists($Texi2HTML::GLOBAL{'htmlxref'}->{$manual}->{$split}->{'href'});
              print STDERR "$manual: $split, href: $href\n";
         }
    }
}

# resulting files splitting
if ($Texi2HTML::Config::SPLIT =~ /section/i)
{
    $Texi2HTML::Config::SPLIT = 'section';
}
elsif ($Texi2HTML::Config::SPLIT =~ /node/i)
{
    $Texi2HTML::Config::SPLIT = 'node';
}
elsif ($Texi2HTML::Config::SPLIT =~ /chapter/i)
{
    $Texi2HTML::Config::SPLIT = 'chapter';
}
else
{
    $Texi2HTML::Config::SPLIT = '';
}

$Texi2HTML::Config::SPLIT_INDEX = 0 unless $Texi2HTML::Config::SPLIT;
$Texi2HTML::Config::NODE_FILENAMES = 1 if ((!defined($Texi2HTML::Config::NODE_FILENAMES) and $Texi2HTML::Config::SPLIT eq 'node') or $Texi2HTML::Config::NODE_FILES);

# Something like backward compatibility. This would make sense to keep 
# it ad-infinitum since the meaning of --out and --subdir are different.
if ($Texi2HTML::Config::SPLIT and defined($Texi2HTML::Config::SUBDIR)
    and ($Texi2HTML::Config::SUBDIR ne '') and 
   (!defined($Texi2HTML::Config::OUT) or ($Texi2HTML::Config::OUT eq '')))
{
    $Texi2HTML::Config::OUT = $Texi2HTML::Config::SUBDIR;
}

die "output to STDOUT and split or frames incompatible\n" 
    if (($Texi2HTML::Config::SPLIT or $Texi2HTML::Config::FRAMES) and defined($Texi2HTML::Config::OUT) and $Texi2HTML::Config::OUT eq '-');

if ($Texi2HTML::Config::SPLIT and defined($Texi2HTML::Config::OUT) and ($Texi2HTML::Config::OUT eq '.'))
{# This is to avoid trouble with latex2html
    $Texi2HTML::Config::OUT = '';
}

@Texi2HTML::Config::INCLUDE_DIRS = split(/$quoted_path_separator/,join($path_separator,@Texi2HTML::Config::INCLUDE_DIRS));
@Texi2HTML::Config::PREPEND_DIRS = split(/$quoted_path_separator/,join($path_separator,@Texi2HTML::Config::PREPEND_DIRS));

my @include_dirs_orig = @Texi2HTML::Config::INCLUDE_DIRS;

@Texi2HTML::Config::CONF_DIRS = split(/$quoted_path_separator/,join($path_separator,@Texi2HTML::Config::CONF_DIRS));
# extension
$Texi2HTML::GLOBAL{'extension'} = $Texi2HTML::Config::EXTENSION;
if ($Texi2HTML::Config::SHORTEXTN)
{
   $Texi2HTML::GLOBAL{'extension'} = "htm";
}

my $global_pass; # track the phases of processing for debugging output purposes

#
# file name business
#

my @created_directories = ();

my $docu_dir;            # directory of the document
my $docu_name;           # basename of the document
my $docu_rdir;           # directory for the output
my $docu_toc;            # document's table of contents
my $docu_stoc;           # document's short toc
my $docu_foot;           # document's footnotes
my $docu_about;          # about this document
my $docu_top;            # document top
my $docu_doc;            # document (or document top of split)
my $docu_frame;          # main frame file
my $docu_toc_frame;      # toc frame file
my $path_to_working_dir; # relative path leading to the working 
                         # directory from the document directory
my $docu_doc_file; 
my $docu_toc_file;
my $docu_stoc_file;
my $docu_foot_file;
my $docu_about_file;
my $docu_top_file;
my $docu_frame_file;
my $docu_toc_frame_file;

sub set_docu_names($$)
{
   my $docu_base_name = shift;
   my $file_nr = shift;
   if ($docu_base_name =~ /(.*\/)/)
   {
      $docu_dir = $1;
      chop($docu_dir);
      $docu_name = $docu_base_name;
      $docu_name =~ s/.*\///;
   }
   else
   {
      $docu_dir = '.';
      $docu_name = $docu_base_name;
   }

   @Texi2HTML::Config::INCLUDE_DIRS = @include_dirs_orig;
   my @prependended_include_directories = ('.');
   push @prependended_include_directories, $Texi2HTML::THISDOC{'input_directory'} if ($Texi2HTML::THISDOC{'input_directory'} ne '.');
   # as Karl said, adding the destination directory is confusing.
   #push @prependended_include_directories, $docu_dir if ($docu_dir ne '.' and $docu_dir ne $Texi2HTML::THISDOC{'input_directory'});
   unshift(@Texi2HTML::Config::INCLUDE_DIRS, @prependended_include_directories);
   unshift(@Texi2HTML::Config::INCLUDE_DIRS, @Texi2HTML::Config::PREPEND_DIRS);
# AAAA
   if ($Texi2HTML::Config::PREFIX and ($file_nr == 0))
   {
      $docu_name = $Texi2HTML::Config::PREFIX;
   }
   elsif ($docu_name eq '-')
   {
      $docu_name = $Texi2HTML::Config::STDIN_DOCU_NAME;
   }

# subdir
   $docu_rdir = '';
   my $null_output;
   if (defined($Texi2HTML::Config::OUT) and ($file_nr == 0) and $Texi2HTML::Config::null_device_file{$Texi2HTML::Config::OUT})
   { # this overrides the setting for this file.
      $Texi2HTML::THISDOC{'SPLIT'} = '';
      $Texi2HTML::THISDOC{'SPLIT_SIZE'} = undef;
      $null_output = 1;
      $path_to_working_dir = $docu_rdir;
   }
   if (!$null_output)
   {
      if (Texi2HTML::Config::get_conf('SPLIT'))
      {
         if (defined($Texi2HTML::Config::OUT) and ($file_nr == 0))
         {
            $docu_rdir = $Texi2HTML::Config::OUT;
         }
         else
         {
            $docu_rdir = $docu_name;
         }
         if ($docu_rdir ne '')
         {
            $docu_rdir =~ s|/*$||;
            $docu_rdir .= '/'; 
         }
      }
      else
      {
         my $out_file;
# AAAA
      # even if the out file is not set by OUT, in case it is not the first
      # file, the out directory is still used. This is only used to determine
      # the directory, the out file itself is set below
         if (defined($Texi2HTML::Config::OUT) and $Texi2HTML::Config::OUT ne '')
         {
            $out_file = $Texi2HTML::Config::OUT;
         }
         else
         {
            $out_file = $docu_name;
         }

         if ($out_file =~ m|(.*)/|)
         {# there is a leading directories
            $docu_rdir = "$1/";
         }
      }
   
      if ($docu_rdir ne '')
      {
         unless (-d $docu_rdir)
         {
            if ( mkdir($docu_rdir, oct(755)))
            {
               print STDERR "# created directory $docu_rdir\n" if ($T2H_VERBOSE);
               push @created_directories, $docu_rdir;
            }
            else
            {
               document_error (sprintf(__("Can't create directory `%s': %s"), $docu_rdir, $!), 1);
            }
        }
        print STDERR "# putting result files into directory $docu_rdir\n" if ($T2H_VERBOSE);
      }
      else
      {
         print STDERR "# putting result files into current directory \n" if ($T2H_VERBOSE);
      }
      # We don't use "./" as $docu_rdir when $docu_rdir is the current directory
      # because it is problematic for latex2html. To test writability with -w, 
      # however we need a real directory.
      my $result_rdir = $docu_rdir;
      $result_rdir = "." if ($docu_rdir eq '');
      unless (-w $result_rdir)
      {
         $docu_rdir = 'current directory' if ($docu_rdir eq '');
         document_error ("$docu_rdir not writable", 1);
      }
   
      # relative path leading to the working directory from the document directory
      $path_to_working_dir = $docu_rdir;
      if ($docu_rdir ne '')
      {
         my $cwd = cwd;
         my $docu_path = $docu_rdir;
         $docu_path = $cwd . '/' . $docu_path unless ($docu_path =~ /^\//);
         my @result = ();
         # this code simplify the paths. The cwd is absolute, while in the 
         # document path there may be some .., a .. is removed with the 
         # previous path element, such that something like
         # /cwd/directory/../somewhere/
         # leads to
         # /cwd/somewhere/
         # with directory/.. removed
         foreach my $element (split /\//, File::Spec->canonpath($docu_path))
         {
            if ($element eq '')
            {
               push @result, '';
            }
            elsif ($element eq '..')
            {
               if (@result and ($result[-1] eq ''))
               {
                  print STDERR "Too much .. in absolute file name\n";
               }
               elsif (@result and ($result[-1] ne '..'))
               {
                  pop @result;
               }
               else
               {
                  push @result, $element;
               }
            }
            else
            {
               push @result, $element;
            }
         }
         $path_to_working_dir = File::Spec->abs2rel($cwd, join ('/', @result));
         # this should not be needed given what canonpath does
         $path_to_working_dir =~ s:/*$::;
         $path_to_working_dir .= '/' unless($path_to_working_dir eq '');
      }
   }
   
   my $docu_ext = $Texi2HTML::THISDOC{'extension'};
   # out_dir is undocummented, should never be used, use destination_directory
   $Texi2HTML::THISDOC{'out_dir'} = $docu_rdir;

   $Texi2HTML::THISDOC{'destination_directory'} = $docu_rdir;
   $Texi2HTML::THISDOC{'file_base_name'} = $docu_name;

   $docu_doc = $docu_name . (defined($docu_ext) ? ".$docu_ext" : ""); # document's contents
   if (Texi2HTML::Config::get_conf('SPLIT') and $Texi2HTML::Config::NODE_FILENAMES)
   {
      if (defined($Texi2HTML::Config::TOP_NODE_FILE))
      {
         $docu_doc = $Texi2HTML::Config::TOP_NODE_FILE;
         if (defined($Texi2HTML::Config::NODE_FILE_EXTENSION) and $Texi2HTML::Config::NODE_FILE_EXTENSION ne '')
         {
            $docu_doc .= ".$Texi2HTML::Config::NODE_FILE_EXTENSION";
         }
      }
   }
   if (Texi2HTML::Config::get_conf('SPLIT'))
   {
# AAAA
      if (defined($Texi2HTML::Config::TOP_FILE) and ($Texi2HTML::Config::TOP_FILE ne '') and ($file_nr == 0))
      {
         $docu_top = $Texi2HTML::Config::TOP_FILE;
      }
   }
   else
   {
# AAAA
      if (defined($Texi2HTML::Config::OUT) and ($file_nr == 0))
      {
         my $out_file = $Texi2HTML::Config::OUT;
         if ($out_file eq '-')
         {
            $Texi2HTML::THISDOC{'SPLIT'} = '';
            $Texi2HTML::THISDOC{'SPLIT_SIZE'} = undef;
         }
         $out_file =~ s|.*/|| unless ($null_output);
         $docu_doc = $out_file if ($out_file !~ /^\s*$/);
      }
   }

   if (defined $Texi2HTML::Config::element_file_name)
   {
      my $docu_doc_set = &$Texi2HTML::Config::element_file_name
        (undef, 'doc', $docu_name);
      $docu_doc = $docu_doc_set if (defined($docu_doc_set));
   } 
   $docu_top = $docu_doc if (!defined($docu_top));

   if (Texi2HTML::Config::get_conf('SPLIT') or !$Texi2HTML::Config::MONOLITHIC)
   {
      if (defined $Texi2HTML::Config::element_file_name)
      {
         $docu_toc = &$Texi2HTML::Config::element_file_name
            (undef, 'toc', $docu_name);
         $docu_stoc = &$Texi2HTML::Config::element_file_name
            (undef, 'stoc', $docu_name);
         $docu_foot = &$Texi2HTML::Config::element_file_name
            (undef, 'foot', $docu_name);
         $docu_about = &$Texi2HTML::Config::element_file_name
            (undef, 'about', $docu_name);
	# $docu_top may be overwritten later.
      }
      if (!defined($docu_toc))
      {
         my $default_toc = "${docu_name}_toc";
         $default_toc .= ".$docu_ext" if (defined($docu_ext));
# AAAA
      if (defined($Texi2HTML::Config::TOC_FILE) and ($Texi2HTML::Config::TOC_FILE ne '') and ($file_nr == 0))
         {
            $docu_toc = $Texi2HTML::Config::TOC_FILE;
         }
         else
         {
            $docu_toc = $default_toc;
         }
      }
      if (!defined($docu_stoc))
      {
         $docu_stoc  = "${docu_name}_ovr";
         $docu_stoc .= ".$docu_ext" if (defined($docu_ext));
      }
      if (!defined($docu_foot))
      {
         $docu_foot  = "${docu_name}_fot";
         $docu_foot .= ".$docu_ext" if (defined($docu_ext));
      }
      if (!defined($docu_about))
      {
         $docu_about = "${docu_name}_abt";
         $docu_about .= ".$docu_ext" if (defined($docu_ext));
      }
   }
   else
   {
      $docu_toc = $docu_foot = $docu_stoc = $docu_about = $docu_doc;
   }

   # Note that file extension has already been added here.
   if ($Texi2HTML::Config::FRAMES)
   {
      if (defined $Texi2HTML::Config::element_file_name)
      {
         $docu_frame = &$Texi2HTML::Config::element_file_name
            (undef, 'frame', $docu_name);
         $docu_toc_frame = &$Texi2HTML::Config::element_file_name
           (undef, 'toc_frame', $docu_name);
      }
   }

   if (!defined($docu_frame))
   {
      $docu_frame = "${docu_name}_frame";
      $docu_frame .= ".$docu_ext" if (defined($docu_ext));
   }
   if (!defined($docu_toc_frame))
   {
      $docu_toc_frame  = "${docu_name}_toc_frame";
      $docu_toc_frame .= ".$docu_ext" if (defined($docu_ext));
   }

   if ($T2H_VERBOSE)
   {
      print STDERR "# Files and directories:\n";
      print STDERR "# rdir($docu_rdir) path_to_working_dir($path_to_working_dir)\n";
      print STDERR "# doc($docu_doc) top($docu_top) toc($docu_toc) stoc($docu_stoc)\n";
      print STDERR "# foot($docu_foot) about($docu_about) frame($docu_toc) toc_frame($docu_toc_frame)\n";
   }

   $docu_doc_file = "$docu_rdir$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";
   $docu_frame_file = "$docu_rdir$docu_frame";
   $docu_toc_frame_file = "$docu_rdir$docu_toc_frame";

# For use in init files
   $Texi2HTML::THISDOC{'filename'}->{'top'} = $docu_top;
   $Texi2HTML::THISDOC{'filename'}->{'foot'} = $docu_foot;
   $Texi2HTML::THISDOC{'filename'}->{'stoc'} = $docu_stoc;
   $Texi2HTML::THISDOC{'filename'}->{'about'} = $docu_about;
   $Texi2HTML::THISDOC{'filename'}->{'toc'} = $docu_toc;
   $Texi2HTML::THISDOC{'filename'}->{'toc_frame'} = $docu_toc_frame;
   $Texi2HTML::THISDOC{'filename'}->{'frame'} = $docu_frame;
}

sub var_to_str($)
{
    return 'UNDEF' if (!defined($_[0]));
    return $_[0];
}

#
# Common initializations
#

sub texinfo_initialization($)
{
    my $pass = shift;

    # set the translations now. This means at the beginning of each pass.
    # Do it silently, except during the last pass.
    my $lang = Texi2HTML::Config::get_conf('documentlanguage');
    my $silent_lang = 1 if ($pass != 2);
    if (!set_document_language($lang, $silent_lang))
    {
       document_warn ("Translations for '$lang' not found. Using 'en'.") unless ($silent_lang);
       set_document_language('en', $silent_lang);
    }
    # All the initialization used the informations still there at the 
    # end of the previous pass.
    # Now we reset everything, such that things are used when they happen.
    # also reset the @set/@clear values.
    %value = %value_initial;
    foreach my $init_mac ('everyheading', 'everyfooting', 'evenheading', 
        'evenfooting', 'oddheading', 'oddfooting', 'headings', 
        'allowcodebreaks', 'frenchspacing', 'exampleindent', 
        'firstparagraphindent', 'paragraphindent', 'clickstyle', 
        'novalidate', 'documentlanguage')
    {
        Texi2HTML::Config::set_conf($init_mac, undef, 1);
    }
}

#+++###########################################################################
#                                                                             #
# Pass texi: read source, handle variable, ignored text,                      #
#                                                                             #
#---###########################################################################

#my @lines = ();             # whole document
#my @lines_numbers = ();     # line number, originating file associated with 
                            # whole document 
my $macros = undef;         # macros. reference on a hash
my %info_enclose = ();      # macros defined with definfoenclose
my @floats = ();            # floats list
my %floats = ();            # floats by style

sub initialise_state_texi($)
{
    my $state = shift;
    $state->{'texi'} = 1;           # for substitute_text and close_stack: 
                                    # 1 if pass_texi/scan_texi is to be used
    $state->{'macro_inside'} = 0 unless(defined($state->{'macro_inside'}));
    $state->{'ifvalue_inside'} = 0 unless(defined($state->{'ifvalue_inside'}));
    $state->{'arg_expansion'} = 0 unless(defined($state->{'arg_expansion'}));
    $state->{'files_stack'} = [] unless(defined($state->{'files_stack'}));
}


sub pass_texi($)
{
    my $input_file_name = shift;
    #my $texi_line_number = { 'file_name' => '', 'line_nr' => 0, 'macro' => '' };

    my @lines = ();             # whole document
    my @lines_numbers = ();     # line number, originating file associated with 
                                # whole document 
    my @first_lines = ();
    my $first_lines = 1;        # is it the first lines
    my $state = {};
                                # holds the informations about the context
                                # to pass it down to the functions
    my @command_line_lines = @Texi2HTML::Config::COMMANDS;
    initialise_state_texi($state);
    my $texi_line_number;
    ($texi_line_number, $state->{'input_spool'}) = 
          open_file($input_file_name, '', $state->{'files_stack'});
    my @stack;
    my $text;
    my $cline;
 INPUT_LINE: while (1)
    {
        ($cline, $state->{'input_spool'}) = next_line($texi_line_number, $state->{'files_stack'});
        last if (!defined($cline));
        #
        # remove the lines preceding \input or an @-command
        # 
        if ($first_lines)
        {
            if ($cline =~ /^\\input/)
            {
                push @first_lines, $cline;
                $first_lines = 0;
                next;
            }
            if ($cline =~ /^\s*\@/)
            {
                $first_lines = 0;
            }
            else
            {
                push @first_lines, $cline;
                next;
            }
        }
	#print STDERR "PASS_TEXI($texi_line_number->{'line_nr'})$cline";
        my $chomped_line = $cline;
        if (scan_texi ($cline, \$text, \@stack, $state, $texi_line_number) and chomp($chomped_line))
        {
        #print STDERR "==> new page (line_nr $texi_line_number->{'line_nr'},$texi_line_number->{'file_name'},$texi_line_number->{'macro'})\n";
            push (@lines_numbers, { 'file_name' => $texi_line_number->{'file_name'},
                  'line_nr' => $texi_line_number->{'line_nr'},
                  'macro' => $texi_line_number->{'macro'} });
        }
        #dump_stack (\$text, \@stack, $state);
        if ($state->{'bye'})
        {
            #dump_stack(\$text, \@stack, $state);
            # close stack after bye
            #print STDERR "close stack after bye\n";
            close_stack_texi(\$text, \@stack, $state, $texi_line_number);
            #dump_stack(\$text, \@stack, $state);
        }
        next if (@stack);
        $cline = $text;
        $text = '';
        if (!defined($cline))
        {
            msg_debug ("\$cline undefined after scan_texi", $texi_line_number);
            next unless ($state->{'bye'});
        }
        push @lines, split_lines($cline);
        last if ($state->{'bye'});
    }
    # close stack at the end of pass texi
    #print STDERR "close stack at the end of pass texi\n";
    close_stack_texi(\$text, \@stack, $state, $texi_line_number);
    push @lines, split_lines($text);
    print STDERR "# end of pass texi\n" if $T2H_VERBOSE;
    return (\@lines, \@first_lines, \@lines_numbers);
}

#+++###########################################################################
#                                                                             #
# Pass structure: parse document structure                                    #
#                                                                             #
#---###########################################################################

sub initialise_state_structure($)
{
    my $state = shift;
    $state->{'structure'} = 1;      # for substitute_text and close_stack: 
                                    # 1 if pass_structure/scan_structure is 
                                    # to be used
    $state->{'menu'} = 0;           # number of opened menus
    $state->{'detailmenu'} = 0;     # number of opened detailed menus      
    $state->{'direntry'} = 0;     # number of opened direntry  
    $state->{'sectionning_base'} = 0;         # current base sectioning level
    $state->{'table_stack'} = [ "no table" ]; # a stack of opened tables/lists
    # seems to be only debug
    if (exists($state->{'region_lines'}) and !defined($state->{'region_lines'}))
    {
        delete ($state->{'region_lines'});
        print STDERR "Bug: state->{'region_lines'} exists but undef.\n";
    }
}
# This is a virtual element for things appearing before @node and 
# sectioning commands
my $element_before_anything;

#
# initial counters. Global variables for pass_structure.
#
my $document_idx_num;
my $document_sec_num;
my $document_head_num;
my $document_anchor_num;

# section to level hash taking into account raise and lower sections.
# Reset at document beginning
my %sec2level;
# initial state for the special regions.
my %region_initial_state;
my %region_lines;
my %region_line_nrs;

# This is a place for index entries, anchors and so on appearing in 
# copying or documentdescription
my $no_element_associated_place;


my @nodes_list;             # nodes in document reading order
                            # each member is a reference on a hash
my @sections_list;          # sections in reading order
                            # each member is a reference on a hash
my @all_elements;           # sectioning elements (nodes and sections)
                            # in reading order. Each member is a reference
                            # on a hash which also appears in %nodes,
                            # @sections_list @nodes_list, @elements_list
my @elements_list;          # all the resulting elements in document order
my %sections;               # sections hash. The key is the section number
my %headings;               # headings hash. The key is the heading number
my $section_top;            # @top section
my $element_top;            # Top element
my $node_top;               # Top node
my $node_first;             # First node
my $element_index;          # element with first index
my $element_chapter_index;  # chapter with first index
my $element_first;          # first element
my $element_last;           # last element
my %special_commands;       # hash for the commands specially handled 
                            # by the user 

# element for content and shortcontent if on a separate page
my %content_element;
my %reference_content_element =
   (
     'contents' => { 'id' => $Texi2HTML::Config::misc_pages_targets{'Contents'},
         'target' => $Texi2HTML::Config::misc_pages_targets{'Contents'},
         'contents' => 1, 'texi' => '_contents' },
     'shortcontents' => { 
        'id' => $Texi2HTML::Config::misc_pages_targets{'Overview'}, 
        'target' => $Texi2HTML::Config::misc_pages_targets{'Overview'}, 
        'shortcontents' => 1, 'texi' => '_shortcontents' },
   );

# holds content elements located with @*contents commands
my %all_content_elements;

# common code for headings and sections
sub new_section_heading($$$$)
{
    my $command = shift;
    my $name = shift;
    my $state = shift;
    my $line_nr = shift;
    
    $name = trim_comment_spaces ($name, "\@$command", $line_nr);
    $name = normalise_texi_space($name);
    $name = '' if (!defined($name));
    # no increase if in @copying and the like. Also no increase if it is top
    # since top has number 0.
    my $docid;
    my $num;

    my $section_ref = { 'texi' => $name,
       'level' => $sec2level{$command},
       'tag' => $command,
    };
    return $section_ref;
}

sub scan_line_separators($$$;$)
{
    my $line = shift;
    my $separators = shift;
    my $context = shift;
    my $line_nr = shift;

    my @command_stack;
    my $result = '';
    while (1)
    {
        # macro_regexp
        if ($line =~ s/^([^{}\@$separators]*)\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/\\])// or $line =~ s/^([^{}\@$separators]*)\@([a-zA-Z][\w-]*)//)
        {
            $result .= $1;
            my $command = $2;
            $command = $alias{$command} if (exists($alias{$command}));
            if (defined($Texi2HTML::Config::misc_command{$command}))
            {
               if ($command ne 'c' and $command ne 'comment')
               { # misc commands other than comments are kept as-is, only 
                 # comments are removed.
                   my ($text, $args);
                   ($line, $text, $args) = &$Texi2HTML::Config::preserve_misc_command($line, $command);
                   $result .= "\@$command".$text;
                   next;
               }
               else
               {
                   $line =~ s/.*//;
                   return ($result, $line, undef);
               }
            }
            $result .= "\@$command";
            if ($line =~ s/^{//)
            {
                push @command_stack, $command;
                $result .= '{';
            }
            if ($command eq 'verb')
            {
               if ($line =~ s/^(.)//)
               {
                  my $char = $1;
                  my $verb_char = quotemeta($char);
                  if ($line =~ s/^(.*?${verb_char}\})//)
                  {
                     $result .= $char.$1;
                  }
                  else
                  {
                     $line =~ s/^(.*)//;
                     $result .= $char . $1;
                     return ($result, $line, undef);
                  }
               }
               else
               {
                  return ($result, $line, undef);
               }
               pop @command_stack;
            }
        }
        elsif ($line =~ s/^([^\{\}$separators]*)([{}])//)
        {
            $result .= $1 . $2;
            my $brace = $2;
            if (@command_stack and $brace eq '}')
            {
                pop @command_stack;
            }
        }
        elsif ($separators ne '' and $line =~ s/^([^${separators}]*)([$separators])//)
        {
            $result .= $1;
            my $separator = $2;
            if (@command_stack)
            { 
                $result .= $separator;
            }
            else
            {
                return ($result, $line, $separator);
            }
        }
        else 
        {
            $result .= $line;
            $line = '';
            return ($result, $line, undef);
        }
    }
}

sub trim_comment_spaces($$;$)
{
    my $line = shift;
    my $context = shift;
    my $line_nr = shift;

    if(!defined($line))
    {
        msg_debug("trim_comment_spaces: $context: line undef", $line_nr);
        return undef; 
    }
    my ($arg, $remaining, $separator) = scan_line_separators ($line, '', $context, $line_nr);
    #msg_debug ("trim_comment_spaces: $context: arg undef. $line", $line_nr) if (!defined($arg));
    #msg_debug ("trim_comment_spaces: $context: $arg !!! $line", $line_nr);
    return $arg if (!defined($arg));
    return  trim_around_spaces($arg);
}

# argument may be the number of arguments when the commas in the last 
# argument has no specific meaning. When it is undef it means that
# all the arguments have to be parsed
sub parse_line_arguments($$$;$)
{
    my $line = shift;
    my $arg_total_nr = shift;
    my $context = shift;
    my $line_nr = shift;

    my @args;
    my $arg_nr = 0;
    my $remaining = $line;

    while (!defined($arg_total_nr) or $arg_nr < $arg_total_nr -1)
    {
        my ($arg, $separator);
        ($arg, $remaining, $separator) = scan_line_separators($remaining, ',', $context, $line_nr);
        push @args, trim_around_spaces($arg) if (defined($arg));
        return @args if (!defined($separator) or !defined($remaining) or !defined($arg));
        $arg_nr++;
    }
    if (defined($arg_total_nr))
    {
        my ($last_arg, $separator);
        ($last_arg, $remaining, $separator) = scan_line_separators($remaining, '', $context, $line_nr);
        push @args, trim_around_spaces($last_arg) if (defined($last_arg));
    }
    return @args;
}

sub pass_structure($$)
{
    my $texi_lines = shift;
    my $lines_numbers = shift;

    my @doc_lines;              # whole document
    my @doc_numbers;            # whole document line numbers and file names

    my $state = {};
                                # holds the informations about the context
                                # to pass it down to the functions
    initialise_state_structure($state);
    $state->{'heading_element'} = $element_before_anything;
    $state->{'current_element'} = $element_before_anything;
    $state->{'place'} = $element_before_anything->{'place'};
    my @stack;
    my $text;
    my $line_nr;

    while (@$texi_lines or $state->{'in_deff_line'})
    {
        my $cline = shift @$texi_lines;
        my $chomped_line = $cline;
        if (@$texi_lines and !chomp($chomped_line))
        {
             $texi_lines->[0] = $cline . $texi_lines->[0];
             next;
        }
        # !defined($cline) may happen if $state->{'in_deff_line'} is true 
        # but there is no more line, in case the last end of line is
        # protected
        $line_nr = shift (@$lines_numbers) unless (!defined($cline));

        if ($state->{'in_deff_line'})
        { # line stored in $state->{'in_deff_line'} was protected by @
          # and can be concatenated with the next line
            if (defined($cline))
            {
                $cline = $state->{'in_deff_line'} . $cline;
            }
            else
            {# end of line protected at the very end of the file
             # in that case there is also no line_nr anymore.
                $cline = $state->{'in_deff_line'};
            }
            delete $state->{'in_deff_line'};
        }

        #print STDERR "PASS_STRUCTURE($line_nr->{'line_nr'}. raw:".var_to_str($state->{'raw'}).", verb:".var_to_str($state->{'verb'})."): $cline";
        if (!$state->{'raw'} and !$state->{'verb'})
        {
            my $tag = '';
            if ($cline =~ /^\s*\@(\w+)\b/)
            {
                $tag = $1;
            }

            #
            # analyze the tag
            #
            if ($tag and $tag eq 'node' or (defined($sec2level{$tag}) and ($tag !~ /heading/)) or ($tag eq 'insertcopying' and $Texi2HTML::Config::INLINE_INSERTCOPYING))
            {
                my @added_lines = ($cline);
                my @added_numbers = ($line_nr);
                if ($tag eq 'node' or defined($sec2level{$tag}))
                {# in pass structure node shouldn't appear in formats
                    close_stack_structure(\$text, \@stack, $state, $line_nr);
                    if (exists($state->{'region_lines'}))
                    {
                        push @{$region_lines{$state->{'region_lines'}->{'format'}}}, split_lines($text);
                        push @doc_lines, split_lines($text) if ($Texi2HTML::Config::region_formats_kept{$state->{'region_lines'}->{'format'}});
                        $state->{'region_lines'}->{'number'} = 0;
                        close_region($state); 
                    }
                    else
                    {
                        push @doc_lines, split_lines($text);
                    }
                    $text = '';
                }
                if ($tag eq 'node')
                {
                    my $node_ref;
                    my $auto_directions;
                    my $node_line = $cline;
                    $node_line =~ s/^\@node\s*//;
                    my @node_res = parse_line_arguments($node_line, undef, '@node', $line_nr);
                    @node_res = normalise_node_array (\@node_res);
                    # even for empty nodes, @nodes_res has one element.
                    #line_error (sprintf(__("Error scanning %s"), $cline), $line_nr) if (@node_res < 1);
                    $auto_directions = 1 if (scalar(@node_res) == 1);
                    if (@node_res > 4)
                    {
                        line_warn(__("Superfluous arguments for node"), $line_nr);
                    }
                    my ($node, $node_next, $node_prev, $node_up) = @node_res;
                    if (defined($node) and ($node ne ''))
                    {
                        if (exists($nodes{$node}) and defined($nodes{$node})
                             and $nodes{$node}->{'seen'})
                        {
                            line_error (sprintf(__("Node `%s' previously defined %s"), $node, format_line_number($nodes{$node}->{'line_nr'})), $line_nr);
                            next;
                        }
                        elsif ($node =~ /^\(.+\)/)
                        {
                            line_error (sprintf(__("Syntax for an external node used for `%s'"), $node), $line_nr);
                            next;
                        }
                        else
                        {
                            if (exists($nodes{$node}) and defined($nodes{$node}))
                            { # node appeared in a menu
                                $node_ref = $nodes{$node};
                            }
                            else
                            {
                                $node_ref = {};
                                $nodes{$node} = $node_ref;
                            }
                            $node_ref->{'node'} = 1;
                            $node_ref->{'tag'} = 'node';
                            $node_ref->{'tag_level'} = 'node';
                            $node_ref->{'texi'} = $node;
                            $node_ref->{'seen'} = 1;
                            $node_ref->{'automatic_directions'} = $auto_directions;
                            $node_ref->{'place'} = [];
                            $node_ref->{'current_place'} = [];
                            $node_ref->{'line_nr'} = $line_nr;
                            merge_element_before_anything($node_ref);
                            $node_ref->{'index_names'} = [];
                            $state->{'place'} = $node_ref->{'current_place'};
                            $state->{'heading_element'} = $node_ref;
                            $state->{'current_element'} = $node_ref;
                            $state->{'node_ref'} = $node_ref;
                            $state->{'menu_in_node'} = 0;
                            # makeinfo treats differently case variants of
                            # top in nodes and anchors and in refs commands and 
                            # refs from nodes. 
                            if ($node =~ /^top$/i)
                            {
                                if (!defined($node_top))
                                {
                                    $node_top = $node_ref;
                                    $node_top->{'texi'} = 'Top';
                                    delete $nodes{$node};
                                    $nodes{$node_top->{'texi'}} = $node_ref;
                                }
                                else
                                { # All the refs are going to point to the first Top
                                    line_warn ("Top node already exists", $line_nr);
                                }
                            }
                            unless (@nodes_list)
                            {
                                $node_first = $node_ref;
                            }
                            push (@nodes_list, $node_ref);
                            push @all_elements, $node_ref;
                        }
                    }
                    else
                    {
                        line_error ("Empty node", $line_nr);
                        next;
                    }

                    if (defined($node_next) and ($node_next ne ''))
                    {
                        $node_ref->{'node_next'} = $node_next;
                    }
                    if (defined($node_prev) and ($node_prev ne ''))
                    {
                        $node_ref->{'node_prev'} = $node_prev;
                    }
                    if (defined($node_up) and ($node_up ne ''))
                    { 
                        $node_ref->{'node_up'} = $node_up;
                    }
                }
                elsif (defined($sec2level{$tag}))
                { # section
                    if ($cline =~ /^\@$tag\s*(.*)$/)
                    {
                        my $name = $1;
                        my $section_ref = new_section_heading($tag, $name, $state, $line_nr);
                        $document_sec_num++ if ($tag ne 'top');
                        
                        $section_ref->{'sec_num'} = $document_sec_num;
                        $section_ref->{'id'} = "SEC$document_sec_num";
                        $section_ref->{'seen'} = 1;
                        $section_ref->{'index_names'} = [];
                        $section_ref->{'current_place'} = [];
                        $section_ref->{'place'} = [];
                        $section_ref->{'section'} = 1;
                        $section_ref->{'line_nr'} = $line_nr;

                        if ($tag eq 'top')
                        {
                            $section_ref->{'number'} = '';
                            $section_ref->{'id'} = "SEC_Top";
                            $section_ref->{'sec_num'} = 0;
                            if (defined($section_top))
                            {
                               line_error ("\@top already exists", $line_nr);
                               $sections{0} = $section_ref;
                            }
                            else
                            {
                               $sections{0.1} = $section_ref;
                            }
                            $section_top = $section_ref;
                        }
                        else
                        {
                            $sections{$section_ref->{'sec_num'}} = $section_ref;
                        }
                        merge_element_before_anything($section_ref);
                        if ($state->{'node_ref'})
                        {
                            $section_ref->{'node_ref'} = $state->{'node_ref'};
                            push @{$state->{'node_ref'}->{'sections'}}, $section_ref;
                        }
                        if ($state->{'node_ref'} and !exists($state->{'node_ref'}->{'with_section'}))
                        {
                            my $node_ref = $state->{'node_ref'};
                            $section_ref->{'with_node'} = $node_ref;
                            $section_ref->{'titlefont'} = $node_ref->{'titlefont'};
                            $node_ref->{'with_section'} = $section_ref;
                        }
                        if (! $name and $section_ref->{'level'})
                        {
                            line_warn (sprintf(__("\@%s requires an argument"), $tag), $line_nr);
                        }
                        push @sections_list, $section_ref;
                        push @all_elements, $section_ref;
                        $state->{'heading_element'} = $section_ref;
                        $state->{'current_element'} = $section_ref;
                        $state->{'place'} = $section_ref->{'current_place'};
                        ################# debug 
                        my $node_ref = "NO NODE";
                        my $node_texi ='';
                        if ($state->{'node_ref'})
                        {
                            $node_ref = $state->{'node_ref'};
                            $node_texi = $state->{'node_ref'}->{'texi'};
                        }
                        print STDERR "# pass_structure node($node_ref)$node_texi, tag \@$tag($section_ref->{'level'}) ref $section_ref, num,id $section_ref->{'sec_num'},$section_ref->{'id'}\n   $name\n"
                           if $T2H_DEBUG & $DEBUG_ELEMENTS;
                        ################# end debug 
                    }
                }
                elsif ($cline =~ /^\@insertcopying\s*/)
                {
                    @added_lines = @{$region_lines{'copying'}};
                    @added_numbers = @{$region_line_nrs{'copying'}};
                    unshift (@$texi_lines, @added_lines);
                    unshift (@$lines_numbers, @added_numbers);
                    next;
                }
                if (exists($state->{'region_lines'}))
                {
                    push @{$region_lines{$state->{'region_lines'}->{'format'}}}, @added_lines;
                    if ($Texi2HTML::Config::region_formats_kept{$state->{'region_lines'}->{'format'}})
                    { # the region is kept in the document in addition with
                      # being put in the appropriate region_lines entry.
                        push @doc_lines, @added_lines;
                        push @doc_numbers, @added_numbers;
                    }
                }
                else
                {
                    push @doc_lines, @added_lines;
                    push @doc_numbers, @added_numbers;
                }
                next;
            }
        }
        if (scan_structure ($cline, \$text, \@stack, $state, $line_nr))
        {
            if (!exists($state->{'region_lines'}) or $Texi2HTML::Config::region_formats_kept{$state->{'region_lines'}->{'format'}})
            {
                 push (@doc_numbers, $line_nr);
            }
            if (exists($state->{'region_lines'}))
            {
                 push @{$region_line_nrs{$state->{'region_lines'}->{'format'}}}, $line_nr unless ($state->{'region_lines'}->{'first_line'});
            }
        }
        next if (scalar(@stack) or $state->{'in_deff_line'});
        $cline = $text;
        $text = '';
        next if (!defined($cline));
        if ($state->{'region_lines'})
        {
            # the first line is like @copying, it is not put in the region
            # lines
            push @{$region_lines{$state->{'region_lines'}->{'format'}}}, split_lines($cline) unless ($state->{'region_lines'}->{'first_line'});
            delete $state->{'region_lines'}->{'first_line'};
            push @doc_lines, split_lines($cline) if ($Texi2HTML::Config::region_formats_kept{$state->{'region_lines'}->{'format'}});
        }
        else
        {
            push @doc_lines, split_lines($cline);
        }
    }
    if (@stack)
    {# close stack at the end of pass structure
        close_stack_structure(\$text, \@stack, $state, $line_nr);
        if ($text)
        {
            if (!exists($state->{'region_lines'}) or $Texi2HTML::Config::region_formats_kept{$state->{'region_lines'}->{'format'}})
            {
                push @doc_lines, split_lines($text);
            }
            if (exists($state->{'region_lines'}))
            {
                push @{$region_lines{$state->{'region_lines'}->{'format'}}}, 
                   split_lines($text);
            }
        }
    }
    #line_warn ("Expected $state->{'region_lines'}->{'number'} \@end $state->{'region_lines'}->{'format'}", $line_nr) if (exists($state->{'region_lines'}));
    line_error (sprintf(__("Expected \@end %s"), $state->{'region_lines'}->{'format'}), $line_nr) if (exists($state->{'region_lines'}));
    print STDERR "# end of pass structure\n" if $T2H_VERBOSE;
    # To remove once they are handled
    #print STDERR "No node nor section, texi2html won't be able to place things rightly\n" if ($element_before_anything->{'place'} and @{$element_before_anything->{'place'}});
    return (\@doc_lines, \@doc_numbers);
}

# split line at end of line and put each resulting line in an array
# FIXME there must be a more perlish way to do it... Not a big deal 
# as long as it work
sub split_lines($)
{
   my $line = shift;
   my @result = ();
   return @result if (!defined($line));
   my $i = 0;
   while ($line ne '')
   {
       $result[$i] = '';
       $line =~ s/^(.*)//;
       $result[$i] .= $1;
       $result[$i] .= "\n" if ($line =~ s/^\n//);
       #print STDERR "$i: $result[$i]";
       $i++;
   }
   return @result;
}

# handle @documentlanguage
sub do_documentlanguage($$$$)
{
    my $command = shift;
    my $line = shift;
    my $silent = shift;
    my $line_nr = shift;
    my $language_change_succes = 0;
    if ($line =~ s/\s+(\w+)\s*//)
    {
        my $lang = $1;
        my $prev_lang = Texi2HTML::Config::get_conf('documentlanguage');
        # This won't be done if the documentlanguage was set on the command line
        if (Texi2HTML::Config::set_conf('documentlanguage', $lang, 1))
        {
            warn_unknown_language ($lang, $line_nr) unless ($silent);
            $language_change_succes = set_document_language($lang, $silent, $line_nr);
            if (!$language_change_succes)
            { # reset previous documentlanguage
                Texi2HTML::Config::set_conf('documentlanguage', $prev_lang, 1);
                line_warn (sprintf(__("Translations for `%s' not found. Reverting to `%s'"),$lang, $prev_lang), $line_nr) unless ($silent);
            }
        }
        # FIXME warn about stuff remaining on the line?
    }
    return $language_change_succes;
}

# actions that should be done in more than one pass. In fact most are not 
# to be done in pass_texi. The $pass argument is the number of the pass, 
# 0 for pass_texi, 1 for pass_structure, 2 for pass_text
sub common_misc_commands($$$$)
{
    my $command = shift;
    my $line = shift;
    my $pass = shift;
    my $line_nr = shift;

    # for error messages
    my $cline = $line;
    chomp($cline);
    $cline =~ s/^\s*//;

    # track variables
    if ($command eq 'set')
    {
        if ($line =~ /^(\s+)($VARRE)(\s+)(.*)$/)
        {
             $value{$2} = $4;
        }
        else
        {
             line_error (sprintf(__("%c%s requires a name"), ord('@'), $command), $line_nr) if (!$pass);
        }
    }
    elsif ($command eq 'clear')
    {
        if ($line =~ /^(\s+)($VARRE)/)
        {
            delete $value{$2};
        }
        else
        {
             line_error (sprintf(__("%c%s requires a name"), ord('@'), $command), $line_nr) if (!$pass);
        }
    }
    elsif ($command eq 'clickstyle')
    {
        if ($line =~ s/^\s+@([^\s\{\}\@]+)({})?\s*//)
        {
            $Texi2HTML::THISDOC{$command} = $1;
            # FIXME warn about what remains on the line?
        }
        else
        {
            line_error (sprintf(__("\@%s should only accept a \@-command as argument, not `%s'"), $command, $cline), $line_nr) if ($pass == 1);
        }
    }
    elsif ($command eq 'novalidate')
    {
        Texi2HTML::Config::set_conf($command, 1, 1);
    }
    if ($pass)
    { # these commands are only taken into account here in pass_structure 1 
      # and pass_text 2
        if ($command eq 'setfilename')
        {
            my $filename = trim_comment_spaces($line, "\@$command");
            $filename = substitute_line($filename, "\@$command",{'code_style' => 1, 'remove_texi' => 1});
            if ($filename ne '')
            {
                Texi2HTML::Config::set_conf($command, $filename, 1);
            }
        }
        elsif ($command eq 'paragraphindent')
        {
            if ($line =~ /\s+([\w\-]+)[^\w\-]/)
            {
               set_paragraphindent ($1, 0, $line_nr, $pass);
            }
            else
            {
               set_paragraphindent ($line, 0, $line_nr, $pass);
            }
        }
        elsif ($command eq 'firstparagraphindent')
        {
            if (($line =~ /^\s+(none)[^\w\-]/) or ($line =~ /^\s+(insert)[^\w\-]/))
            {
                Texi2HTML::Config::set_conf($command, $1, 1);
            }
            else
            {
                line_error (sprintf(__("\@firstparagraphindent arg must be `none' or `insert', not `%s'"), $cline), $line_nr) if ($pass == 1);
            }
        }
        elsif ($command eq 'exampleindent')
        {
            if ($line =~ /^\s+([0-9]+)/)
            {
                $Texi2HTML::THISDOC{$command} = $1;
            }
            elsif ($line =~ /^\s+(asis)[^\w\-]/)
            {
                $Texi2HTML::THISDOC{$command} = $1;
            }
            else
            {
                line_error (sprintf(__("\@exampleindent arg must be numeric/`asis', not `%s'"), $cline), $line_nr) if ($pass == 1);
            }
        }
        elsif ($command eq 'frenchspacing')
        {
            if (($line =~ /^\s+(on)[^\w\-]/) or ($line =~ /^\s+(off)[^\w\-]/))
            {
                Texi2HTML::Config::set_conf($command, $1, 1);
            }
            else
            {
                line_error (sprintf(__("Expected \@%s on or off, not `%s'"), $command, $cline), $line_nr) if ($pass == 1);
            }
        }
        elsif ($command eq 'kbdinputstyle')
        {
            if ($line =~ /\s+([a-z]+)/ and ($1 eq 'code' or $1 eq 'example' or $1 eq 'distinct'))
            {
                Texi2HTML::Config::set_conf($command, $1, 1);
            }
            else
            {
                line_error (sprintf(__("\@kbdinputstyle arg must be `code'/`example'/`distinct', not `%s'"), $cline), $line_nr) if ($pass == 1);
            }
        }
        elsif (grep {$command eq $_} ('everyheading', 'everyfooting',
              'evenheading', 'evenfooting', 'oddheading', 'oddfooting'))
        { # FIXME have a _texi and without texi, and without texi, 
          # and expand rightly @this*? And use @| to separate, and give
          # an array for user consumption? This should be done for each new
          # chapter, section, and page. What is a page is not necessarily 
          # well defined in html, however...
          # @thisfile is the @include file. Should be in $line_nr.

          # Also if that command appears in the texi, the error message is 
          # Unknown command `@evenheading'
          # It could be better.
            my $arg = $line;
            $arg =~ s/^\s+//;
            $Texi2HTML::THISDOC{$command} = $arg;
        }
        elsif ($command eq 'allowcodebreaks')
        {
            if (($line =~ /^\s+(true)[^\w\-]/) or ($line =~ /^\s+(false)[^\w\-]/))
            {
                Texi2HTML::Config::set_conf($command, $1, 1);
            }
            else
            {
                line_error (sprintf(__("\@allowcodebreaks arg must be `true' or `false', not `%s'"), $cline), $line_nr) if ($pass == 1);
            }
        }
        elsif ($command eq 'headings')
        {
            my $valid_arg = 0;
            foreach my $possible_arg (('off','on','single','double',
                          'singleafter','doubleafter'))
            {
                if ($line =~ /^\s+($possible_arg)[^\w\-]/)
                {   
                    $valid_arg = 1;
                    $Texi2HTML::THISDOC{$command} = $possible_arg;
                    last;
                }
            }
            unless ($valid_arg)
            {
                line_error (sprintf(__("Bad argument to \@%s: %s"), $command, $cline), $line_nr) if ($pass == 1);
            }
        }
        elsif ($command eq 'documentlanguage')
        {
            if (do_documentlanguage($command, $line, $pass -1, $line_nr))
            {
                &$Texi2HTML::Config::translate_names();
                set_special_names();
            }
        }
    }
}

sub misc_command_texi($$$$)
{
   my $line = shift;
   my $command = shift;
   my $state = shift;
   my $line_nr = shift;
   my $text;
   my $args;
   my $cline = $line;
    
   if (!$state->{'ignored'} and !$state->{'arg_expansion'})
   {
      if ($command eq 'documentencoding')
      {  # FIXME accept more characters, like @?
         if ($cline =~ s/^(\s+)([\w\-]+)//)
         {
            my $encoding = $2;
            $Texi2HTML::THISDOC{'documentencoding'} = $encoding;
            line_warn(sprintf(__("Encoding %s is not a canonical texinfo encoding"), $encoding), $line_nr)
                if (!$Texi2HTML::Config::canonical_texinfo_encodings{lc($encoding)});
            if (Texi2HTML::Config::set_conf('DOCUMENT_ENCODING', $Texi2HTML::THISDOC{'documentencoding'}, 1))
            {
               my $from_encoding;
               if (!defined($Texi2HTML::Config::IN_ENCODING))
               {
                  $from_encoding = encoding_alias($encoding, $line_nr);
                  Texi2HTML::Config::set_conf('IN_ENCODING', $from_encoding, 1) 
                     if (defined($from_encoding));
               }
               if (defined($from_encoding) and $Texi2HTML::Config::USE_UNICODE)
               {
                  foreach my $file (@{$state->{'files_stack'}})
                  {
                     binmode($file->{'fh'}, ":encoding($from_encoding)");
                  }
               }
            }
            #FIXME error if garbage remains on the line?
         }
         else
         {
            line_error(sprintf(__("\@%s arg must be an encoding"), $command), $line_nr);
         }
      }
      elsif ($command eq 'alias')
      { 
          if ($line =~ /(\s+)([a-zA-Z][\w-]*)(\s*=\s*)([a-zA-Z][\w-]*)(\s*)/)
          {
               $alias{$2} = $4;
          }
          else
          {
               line_error (sprintf(__("Bad argument to \@%s"), $command), $line_nr);
          }
      }
      elsif ($command eq 'definfoenclose')
      {
          if ($cline =~ s/^\s+([a-z][\w\-]*)\s*,\s*([^\s]+)\s*,\s*([^\s]+)//)
          {
             $info_enclose{$1} = [ $2, $3 ];
          }
          else
          {
             line_error (sprintf(__("Bad argument to \@%s"), $command), $line_nr);
          } # FIXME warn about garbage remaining on the line?
      }
      else
      {
          if ($command eq 'setfilename' and $Texi2HTML::Config::USE_SETFILENAME)
          { # a double setfillename is removed before calling misc_command_texi
             my $filename = trim_comment_spaces($line, "\@$command");
             $filename = substitute_line($filename, "\@$command",{'code_style' => 1, 'remove_texi' => 1}, $line_nr);
             if ($filename ne '')
             {
                 Texi2HTML::Config::set_conf($command, $filename, 1);
                 # remove extension
                 $filename =~ s/\.[^\.]*$//;
                 init_with_file_name ($filename) if ($filename ne '');
             }
          }
          # in reality, do only set, clear and clickstyle.
          # though we should never go there for clickstyle... 
          common_misc_commands($command, $line, 0, $line_nr);
      }
   }

   ($line, $text, $args) = &$Texi2HTML::Config::preserve_misc_command($line, $command);
   return ($line, $text);
}

sub new_content_element($)
{
   my $command = shift;
   $command = 'shortcontents' if ($command ne 'contents');
   my $element;
   foreach my $key (keys(%{$reference_content_element{$command}}))
   {
      $element->{$key} = $reference_content_element{$command}->{$key};
   }
   return $element;
}

# handle misc commands and misc command args
sub misc_command_structure($$$$)
{
    my $line = shift;
    my $command = shift;
    my $state = shift;
    my $line_nr = shift;
    my $text;
    my $args;
    # for error messages
    my $cline = $line;
    chomp $cline;
    $cline =~ s/^\s*//;

    if ($command eq 'lowersections')
    {
        my ($sec, $level);
        while (($sec, $level) = each %sec2level)
        {
            $sec2level{$sec} = $level + 1 if ($reference_sec2level{$sec} > 0);
        }
        $state->{'sectionning_base'}--;
    }
    elsif ($command eq 'raisesections')
    {
        my ($sec, $level);
        while (($sec, $level) = each %sec2level)
        {
            $sec2level{$sec} = $level - 1 if ($reference_sec2level{$sec} > 0);
        }
        $state->{'sectionning_base'}++;
    }
    elsif (($command eq 'contents') or ($command eq 'summarycontents') or ($command eq 'shortcontents'))
    {
        if ($command ne 'contents')
        {
            $command = 'shortcontents';
        }
        Texi2HTML::Config::set_conf($command, 1, 1);
        my $new_content_element = new_content_element($command);
        push @{$state->{'place'}}, $new_content_element;
        push @{$all_content_elements{$command}}, $new_content_element;
    }
    elsif ($command eq 'dircategory')
    {
        my $arg = trim_comment_spaces ($line, "\@$command");
        $Texi2HTML::THISDOC{"${command}_texi"} = $arg;
        $Texi2HTML::THISDOC{$command} = substitute_line($arg, "\@$command");
    }
    elsif (grep {$_ eq $command} ('settitle','shorttitlepage','title'))
    {
        my $arg = trim_comment_spaces($line, "\@$command");
        $Texi2HTML::THISDOC{$command . '_texi'} = $arg;
        $Texi2HTML::THISDOC{$command . '_line_nr'} = $line_nr;

        # FIXME backward compatibility. Obsoleted in nov 2009.
        $value{"_$command"} = $arg;
        if ($command eq 'title')
        { # FIXME This was obsoleted in jun 2007
            $Texi2HTML::THISDOC{"${command}s_texi"} = [ $arg ];
        }
    }
    elsif (grep {$_ eq $command} ('author','subtitle'))
    {
        my $arg = trim_comment_spaces($line, "\@$command");
        $Texi2HTML::THISDOC{$command . '_texi'} .= $arg . "\n";
        if ($state->{'region'} and $state->{'region'} eq 'titlepage')
        {
           push @{$Texi2HTML::THISDOC{"${command}s_texi"}}, $arg;
           push @{$Texi2HTML::THISDOC{"${command}s_line_nr"}}, $line_nr;
        }
        #chomp($arg);

        # FIXME backward compatibility. Obsoleted in nov 2009.
        $value{"_$command"} .= $arg . "\n";
    }
    elsif ($command eq 'synindex' || $command eq 'syncodeindex')
    {
        if ($line =~ /^\s+(\w+)\s+(\w+)/)
        {
            my $index_from = $1;
            my $index_to = $2;
            line_error (sprintf(__("Unknown from index `%s' in \@%s"), $index_from, $command), $line_nr)
                unless $index_names{$index_from};
            line_error (sprintf(__("Unknown to index name `%s' in \@%s"), $index_to, $command), $line_nr)
                unless $index_names{$index_to};
            if ($index_names{$index_from} and $index_names{$index_to})
            {
                my $in_code = 0;
                $in_code = 1 if ($command eq 'syncodeindex');
                my $current_to = $index_to;
                while ($current_to ne $index_from and $Texi2HTML::THISDOC{'merged_index'}->{$current_to})
                {
                    $current_to = $Texi2HTML::THISDOC{'merged_index'}->{$current_to};
                }
                if ($current_to ne $index_from)
                {
                    foreach my $prefix (keys(%{$index_names{$index_from}->{'prefixes'}}))
                    {
                        $index_names{$current_to}->{'prefixes'}->{$prefix} = $in_code;
                        $index_prefix_to_name{$prefix} = $current_to;
                    }
                    $Texi2HTML::THISDOC{'merged_index'}->{$index_from} = $current_to;
                }
                push @{$Texi2HTML::THISDOC{$command}}, [$index_from,$index_to]; 
            }
        }
        else
        {
            line_error (sprintf(__("Bad argument to \@%s: %s"), $command, $cline), $line_nr);
        }
    }
    elsif ($command eq 'defindex' || $command eq 'defcodeindex')
    {
        if ($line =~ /^\s+(\w+)\s*$/)
        {
            my $name = $1;
            if ($forbidden_index_name{$name})
            {
                line_error(sprintf(__("Reserved index name %s"),$name), $line_nr);
            }
            else
            {
                my $in_code = 0;
                $in_code = 1 if ($command eq 'defcodeindex');
                # FIXME this leads to spurious error message in hello_nodes
                #if (defined($index_names{$name})) 
                #{
                #    line_error(sprintf(__("Index `%s' already exists"),$name), $line_nr);
                #}
                $index_names{$name}->{'prefixes'}->{$name} = $in_code;
                $index_prefix_to_name{$name} = $name;
                push @{$Texi2HTML::THISDOC{$command}}, $name;
            }
        }
        else
        {
            line_error (sprintf(__("Bad argument to \@%s: %s"), $command, $cline), $line_nr);
        }
    }
    elsif (grep {$_ eq $command} ('everyheadingmarks','everyfootingmarks',
        'evenheadingmarks','oddheadingmarks','evenfootingmarks','oddfootingmarks'))
    {
        if (($line =~ /^\s+(top)[^\w\-]/) or ($line =~ /^\s+(bottom)[^\w\-]/))
        {
            $Texi2HTML::THISDOC{$command} = $1;
        }
        else
        {
            line_error (sprintf(__("\@%s arg must be `top' or `bottom', not `%s'"), $command, $cline), $line_nr);
        }
    }
    elsif ($command eq 'fonttextsize')
    {
        if (($line =~ /^\s+(10)[^\w\-]/) or ($line =~ /^\s+(11)[^\w\-]/))
        {
            $Texi2HTML::THISDOC{$command} = $1;
        }
        else
        {
            line_error (sprintf(__("Only \@%s 10 or 11 is supported, not `%s'"),$command, $cline), $line_nr);
        }
    }
    elsif ($command eq 'pagesizes')
    {
        if ($line =~ /^\s+(.*)\s*$/)
        {
            $Texi2HTML::THISDOC{$command} = $1;
        }
    }
    elsif ($command eq 'footnotestyle')
    {
        if ($line =~ /^\s+([a-z]+)[^\w\-]/)
        {
            set_footnote_style ($1, 0, $line_nr);
        }
        else
        {
            set_footnote_style ($line, 0, $line_nr);
        }
    }
    elsif ($command eq 'setchapternewpage')
    {
        if (($line =~ /^\s+(on)[^\w\-]/) or ($line =~ /^\s+(off)[^\w\-]/)
                or ($line =~ /^\s+(odd)[^\w\-]/))
        {
            $Texi2HTML::THISDOC{$command} = $1;
        }
        else
        {
            line_error (sprintf(__("\@%s arg must be `on', `off' or `odd', not `%s'"), $command, $cline), $line_nr);
        }
    }
    elsif ($command eq 'setcontentsaftertitlepage' or $command eq 'setshortcontentsaftertitlepage')
    {
        Texi2HTML::Config::set_conf($command, 1, 1);
    }
    elsif ($command eq 'need')
    { # only a warning
        unless (($line =~ /^\s+([0-9]+(\.[0-9]*)?)[^\w\-]/) or 
                 ($line =~ /^\s+(\.[0-9]+)[^\w\-]/))
        {
            line_error (sprintf(__("Bad argument to \@%s: %s"), $command, $cline), $line_nr);
        }
    }
    else
    {
        common_misc_commands($command, $line, 1, $line_nr);
    }

    ($text, $line, $args) = &$Texi2HTML::Config::preserve_misc_command($line, $command);
    return ($text, $line);
}

sub set_special_names()
{
    $Texi2HTML::NAME{'About'} = gdt('About This Document');
    $Texi2HTML::NAME{'Contents'} = gdt('Table of Contents');
    $Texi2HTML::NAME{'Overview'} = gdt('Short Table of Contents');
    $Texi2HTML::NAME{'Footnotes'} = gdt('Footnotes');
    $Texi2HTML::NO_TEXI{'About'} = gdt('About This Document', {}, {'remove_texi' => 1} );
    $Texi2HTML::NO_TEXI{'Contents'} = gdt('Table of Contents', {}, {'remove_texi' => 1} );
    $Texi2HTML::NO_TEXI{'Overview'} = gdt('Short Table of Contents', {}, {'remove_texi' => 1} );
    $Texi2HTML::NO_TEXI{'Footnotes'} = gdt('Footnotes', {}, {'remove_texi' => 1} );
    $Texi2HTML::SIMPLE_TEXT{'About'} = gdt('About This Document', {}, {'simple_format' => 1});
    $Texi2HTML::SIMPLE_TEXT{'Contents'} = gdt('Table of Contents',{},  {'simple_format' => 1});
    $Texi2HTML::SIMPLE_TEXT{'Overview'} = gdt('Short Table of Contents', {}, {'simple_format' => 1});
    $Texi2HTML::SIMPLE_TEXT{'Footnotes'} = gdt('Footnotes', {},{'simple_format' => 1});
}

sub enter_author_command($$$$$$)
{
    my $command = shift;
    my $texi = shift;
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $line_nr = shift;
    $texi = trim_comment_spaces($texi, "\@$command");
    if ($command eq 'author')
    {
        my $top_format = top_stack($stack, 2);
        if (defined($top_format) and $format_type{$top_format->{'format'}} eq 'quotation')
        {
            push @{$top_format->{'quote_authors'}}, {'author_texi' => $texi, 'author_text' => $text};
        }
        elsif (!$state->{'region'} or $state->{'region'} ne 'titlepage')
        {
            line_warn (sprintf(__("\@%s not meaningful outside `\@titlepage' and `\@quotation' environments"), $command), $line_nr);
        }
    }
}

# return the line after removing things according to misc_command map.
# if the skipped command has an effect it is done here
# this is used during pass_text
sub misc_command_text($$$$$$)
{
    my $line = shift;
    my $command = shift;
    my $stack = shift;
    my $state = shift;
    my $text = shift;
    my $line_nr = shift;
    my ($skipped, $remaining, $args, $result);

    # The strange condition associated with 'keep_texi' is 
    # there because for an argument appearing on an @itemize 
    # line (we're in 'check_item'), meant to be prepended to an 
    # @item we don't want to keep @c or @comment as otherwise it 
    # eats the @item line. Other commands could do that too but 
    # then the user deserves what he gets.
    if ($state->{'keep_texi'} and 
        (!$state->{'check_item'} or ($command ne 'c' and $command ne 'comment'))) 
    {
        ($remaining, $skipped, $args) = &$Texi2HTML::Config::preserve_misc_command($line, $command);
        add_prev($text, $stack, "\@$command". $skipped);
        return $remaining;
    }

    ($remaining, $skipped, $args) = &$Texi2HTML::Config::preserve_misc_command($line, $command);

    if ($state->{'remove_texi'})
    {
        ($command, $line, $result) = &$Texi2HTML::Config::misc_command_line_texi($command, $line, $args, $stack, $state);
    }
    else
    {
        ($command, $line, $result) = &$Texi2HTML::Config::misc_command_line($command, $line, $args, $stack, $state);
    }

    enter_author_command ($command, $line, $result, $stack, $state, $line_nr);

    # for error messages
    my $cline = $line;
    $cline =~ s/^\s*//;
    chomp $cline;

    # if it is true the command args are kept so the user can modify how
    # they are skipped and handle them as unknown @-commands. Nowadays, it is
    # not that interesting since using misc_command_line above should do
    # about the same more simply.
    my $keep = $Texi2HTML::Config::misc_command{$command}->{'keep'};

    if ($command eq 'sp')
    {
        my $sp_number;
        if ($line =~ /^\s+(\d+)\s/)
        {
            $sp_number = $1;
        }
        elsif ($line =~ /(\s*)$/)
        {
            $sp_number = '';
        }
        else
        {
            line_error (sprintf(__("\@sp requires a positive numeric argument, not `%s'"), $cline), $line_nr);
        }
        $sp_number = 1 if ($sp_number eq '');
        if (!$state->{'remove_texi'})
        {
            add_prev($text, $stack, &$Texi2HTML::Config::sp($sp_number, $state->{'preformatted'}));
        }
    }
    elsif($command eq 'verbatiminclude' and !$keep)
    {
        if ($line =~ /\s+(.+)/)
        {
            my $arg = $1;
            $arg = trim_around_spaces($arg);
            my $file_name = substitute_line($arg, "\@$command", {'code_style' => 1});
            my $file = locate_include_file($file_name);
            if (defined($file))
            {
                if (!open(VERBINCLUDE, $file))
                {
                    line_error (sprintf(__("Cannot read %s: %s"), $file, $!), $line_nr);
                }
                else
                {
                    my $verb_text = '';
                    while (my $verb_line = <VERBINCLUDE>)
                    {
                        $verb_text .= $verb_line;
                    }
                    
                    if ($state->{'remove_texi'})
                    {
                        add_prev ($text, $stack, &$Texi2HTML::Config::raw_no_texi('verbatiminclude', $verb_text));
                    }
                    else
                    { 
                        add_prev($text, $stack, &$Texi2HTML::Config::raw('verbatiminclude', $verb_text, $line_nr));
                    }
                    close VERBINCLUDE;
                }
            }
            else
            {
                line_error (sprintf(__("\@%s: Cannot find %s"), $command, $file_name), $line_nr);
            }
        }
        else
        {
            line_error (sprintf(__("Bad argument to \@%s: %s"), $command, $cline), $line_nr);
        }
    }
    elsif ($command eq 'indent' or $command eq 'noindent')
    {
        $state->{'paragraph_indent'} = $command;
    }
    else
    {
        common_misc_commands($command, $line, 2, $line_nr);
    }

    return ($skipped.$remaining, $result) if ($keep);
    return ($remaining, $result);
}

# merge the things appearing before the first @node or sectioning command
# (held by element_before_anything) with the current element 
# do that only once.
sub merge_element_before_anything($)
{
    my $element = shift;
    if (exists($element_before_anything->{'place'}))
    {
        $element->{'current_place'} = $element_before_anything->{'place'};
        delete $element_before_anything->{'place'};
        foreach my $placed_thing (@{$element->{'current_place'}})
        {
            $placed_thing->{'element'} = $element if (exists($placed_thing->{'element'}));
        }
    }
    # this is certainly redundant with the above condition, but cleaner 
    # that way
    if (exists($element_before_anything->{'titlefont'}))
    {
        $element->{'titlefont'} = $element_before_anything->{'titlefont'};
        delete $element_before_anything->{'titlefont'};
    }
}

# find menu_prev, menu_up... for a node in menu
sub menu_entry_texi($$$)
{
    my $node = shift;
    my $state = shift;
    my $line_nr = shift;
    return if ($state->{'direntry'});
    my $node_menu_ref = {};
    if (exists($nodes{$node}))
    {
        $node_menu_ref = $nodes{$node};
    }
    else
    {
        $nodes{$node} = $node_menu_ref;
        $node_menu_ref->{'texi'} = $node;
        $node_menu_ref->{'external_node'} = 1 if ($node =~ /^\(.+\)/);
    }
    return if ($state->{'detailmenu'});
    if ($state->{'node_ref'})
    {
        if ($node_menu_ref->{'menu_up'} and !$node_menu_ref->{'external_node'})
        {
           # This is not an error. This is used a lot in real life manuals
           #line_warn ("Double entry in menu for `$node' (also below `$node_menu_ref->{'menu_up'}->{'texi'}')", $line_nr);
        }
        $node_menu_ref->{'menu_up'} = $state->{'node_ref'};
        $node_menu_ref->{'menu_up_hash'}->{$state->{'node_ref'}->{'texi'}} = 1;
    }
    if ($state->{'prev_menu_node'})
    {
        $node_menu_ref->{'menu_prev'} = $state->{'prev_menu_node'};
        $state->{'prev_menu_node'}->{'menu_next'} = $node_menu_ref;
    }
    elsif ($state->{'node_ref'} and !$state->{'node_ref'}->{'menu_child'})
    {
        $state->{'node_ref'}->{'menu_child'} = $node_menu_ref;
    }
    $state->{'prev_menu_node'} = $node_menu_ref;
}

my @index_labels;                  # array corresponding with @?index commands
                                   # constructed during pass_structure, used to
                                   # put labels in pass_text
my @unknown_index_index_entries;   # array of index entries not associated 
                                   # with any index

sub sorted_line($)
{
   my $line = shift;
   $::texi_map_ref = \%Texi2HTML::Config::sorting_things_map;
   my $result = remove_texi($line);
   $::texi_map_ref = \%Texi2HTML::Config::texi_map;
   return $result;
}

sub prepare_indices()
{
    #print STDERR "Do splitting of index letters, once.\n";

    foreach my $index_name(keys %{$Texi2HTML::THISDOC{'index_entries_array'}})
    {
        #print STDERR "$Texi2HTML::THISDOC{'index_entries_array'}->{$index_name}) letters\n";
        my %letters_hash;
        foreach my $index_entry (@{$Texi2HTML::THISDOC{'index_entries_array'}->{$index_name}})
        {
          my $key = sorted_line($index_entry->{'texi'});
          $index_entry->{'key'} = $key;
          my $letter = uc(substr($key, 0, 1));
          push @{$letters_hash{$letter}}, $index_entry;
        }

        # use cmp if only letters or only symbols, otherwise symbols before 
        # letters
        foreach my $letter (sort { 
           ((($a =~ /^[[:alpha:]]/ and $b =~ /^[[:alpha:]]/) or 
            ($a !~ /^[[:alpha:]]/ and $b !~ /^[[:alpha:]]/)) && $a cmp $b)
             || ($a =~ /^[[:alpha:]]/ && 1) || -1 } (keys %letters_hash))
        {
          # FIXME sort without uc?
          # This sorts the entries for a given letter
          my @sorted_letter_entries = (sort {uc($a->{'key'}) cmp uc($b->{'key'})} (@{$letters_hash{$letter}}));

          push @{$Texi2HTML::THISDOC{'index_letters_array'}->{$index_name}}, { 'letter' => $letter, 'entries' => \@sorted_letter_entries };
        }
    }

    # generate the keys for index sorting also for the entries not
    # associated with an index. 
    foreach my $index_entry_without_index (@unknown_index_index_entries)
    {
       my $key = sorted_line($index_entry_without_index->{'texi'});
       $index_entry_without_index->{'key'} = $key;
    }
    Texi2HTML::Config::t2h_default_init_split_indices();
}

# This function is used to construct link names from node names as
# specified for texinfo
sub cross_manual_links()
{
    my @all_index_entries;
    foreach my $index_name (sort(keys(%{$Texi2HTML::THISDOC{'index_entries_array'}})))
    {
       push @all_index_entries, @{$Texi2HTML::THISDOC{'index_entries_array'}->{$index_name}};
    }
    print STDERR "# Doing ".scalar(keys(%nodes))." cross manual links ".
      scalar(@all_index_entries). " index entries\n" 
       if ($T2H_DEBUG);
    $::simple_map_texi_ref = \%cross_ref_simple_map_texi;
    $::style_map_texi_ref = \%cross_ref_style_map_texi;
    $::texi_map_ref = \%cross_ref_texi_map;
    my $normal_text_kept = $Texi2HTML::Config::normal_text;
    $Texi2HTML::Config::normal_text = \&Texi2HTML::Config::t2h_cross_manual_normal_text;
    my $style_kept = $Texi2HTML::Config::style;
    $Texi2HTML::Config::style = \&Texi2HTML::Config::T2H_GPL_style;

    foreach my $key (keys(%nodes))
    {
        my $node = $nodes{$key};
        #print STDERR "CROSS_MANUAL:$key,$node\n";
        if (!defined($node->{'texi'}))
        {
            ###################### debug section 
            foreach my $key (keys(%$node))
            {
                #print STDERR "$key:$node->{$key}!!!\n";
            }
            ###################### end debug section 
        }
        else 
        {
            $node->{'cross_manual_target'} = remove_texi($node->{'texi'});
            if ($node->{'cross_manual_target'} !~ /\S/)
            {
                line_error (sprintf(__("Empty node name after expansion `%s'"), $node->{'texi'}), $node->{'line_nr'});
                $node->{'cross_manual_target'} = 't_0';
                $node->{'cross_manual_file'} = 't_0';
            }
            elsif ($Texi2HTML::Config::USE_UNICODE)
            {
                $node->{'cross_manual_target'} = Unicode::Normalize::NFC($node->{'cross_manual_target'});
                if ($Texi2HTML::Config::TRANSLITERATE_FILE_NAMES and $Texi2HTML::Config::USE_UNIDECODE)
                {
                     $node->{'cross_manual_file'} = 
                       unicode_to_protected(unicode_to_transliterate($node->{'cross_manual_target'}));
                }
                $node->{'cross_manual_target'} = 
                    unicode_to_protected($node->{'cross_manual_target'});
            }
#print STDERR "CROSS_MANUAL_TARGET $node->{'cross_manual_target'}\n";
            unless ($node->{'external_node'})
            {
                if (exists($cross_reference_nodes{$node->{'cross_manual_target'}}))
                {
                    my $other_node_array = $cross_reference_nodes{$node->{'cross_manual_target'}};
                    my $node_seen;
                    foreach my $other_node (@{$other_node_array})
                    { # find the first node seen for the error message
                        $node_seen = $other_node;
                        last if ($nodes{$other_node}->{'seen'})
                    }
                    my $other_node_line_nr = $nodes{$node_seen}->{'line_nr'};
                    if (defined($other_node_line_nr))
                    {
                        msg_error ("Node equivalent with `$node->{'texi'}' already used `$node_seen' ".format_line_number($other_node_line_nr), $node->{'line_nr'});
                    }
                    else
                    {
                        msg_error ("Node equivalent with `$node->{'texi'}' already used `$node_seen'", $node->{'line_nr'});
                    }
                    push @{$other_node_array}, $node->{'texi'};
                }
                else 
                {
                    push @{$cross_reference_nodes{$node->{'cross_manual_target'}}}, $node->{'texi'};
                }
            }
        }
    }

    
    if ($Texi2HTML::Config::TRANSLITERATE_FILE_NAMES and 
         (!$Texi2HTML::Config::USE_UNICODE or !$Texi2HTML::Config::USE_UNIDECODE))
    {
        $::style_map_texi_ref = \%cross_transliterate_style_map_texi;
        $::texi_map_ref = \%cross_transliterate_texi_map;
        $Texi2HTML::Config::normal_text = \&Texi2HTML::Config::t2h_cross_manual_normal_text_transliterate if (!$Texi2HTML::Config::USE_UNICODE);

        foreach my $key (keys(%nodes))
        {
            my $node = $nodes{$key};
            #print STDERR "TRANSLITERATE:$key,$node\n";
            if (defined($node->{'texi'}))
            {
                 $node->{'cross_manual_file'} = remove_texi($node->{'texi'});
                 if ($node->{'cross_manual_file'} !~ /\S/)
                 {
                    $node->{'cross_manual_file'} = 't_0';
                 }
                 elsif ($Texi2HTML::Config::USE_UNICODE)
                 {
                    $node->{'cross_manual_file'} = unicode_to_protected(unicode_to_transliterate($node->{'cross_manual_file'}));
                 }
            }
        }

        foreach my $entry (@all_index_entries, values(%sections), values(%headings))
        {
            #print STDERR "TRANSLITERATE($entry) $entry->{'texi'}\n";
            $entry->{'cross'} = remove_texi($entry->{'texi'});
            $entry->{'cross'} = unicode_to_protected(unicode_to_transliterate($entry->{'cross'})) if ($Texi2HTML::Config::USE_UNICODE);
        }
    }
    else
    {
        foreach my $entry (@all_index_entries, values(%sections), values(%headings))
        {
            $entry->{'cross'} = remove_texi($entry->{'texi'});
            if ($Texi2HTML::Config::USE_UNICODE)
            {
                $entry->{'cross'} = Unicode::Normalize::NFC($entry->{'cross'});
                if ($Texi2HTML::Config::TRANSLITERATE_FILE_NAMES and $Texi2HTML::Config::USE_UNIDECODE) # USE_UNIDECODE is redundant
                {
                     $entry->{'cross'} = 
                       unicode_to_protected(unicode_to_transliterate($entry->{'cross'}));
                }
                else
                {
                     $entry->{'cross'} = 
                        unicode_to_protected($entry->{'cross'});
                }
            }
        }
    }

    $Texi2HTML::Config::normal_text = $normal_text_kept;
    $Texi2HTML::Config::style = $style_kept;
    $::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi;
    $::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi;
    $::texi_map_ref = \%Texi2HTML::Config::texi_map;
}

# This function is used to construct a link name from a node name as
# specified for texinfo
sub cross_manual_line($;$)
{
    my $text = shift;
    my $transliterate = shift;
#print STDERR "cross_manual_line $text\n";
#print STDERR "remove_texi text ". remove_texi($text)."\n\n\n";
    if ($text !~ /\S/)
    {
       # special case for empty node/ref
       return ('t_0', 't_0');
    }
    $::simple_map_texi_ref = \%cross_ref_simple_map_texi;
    $::style_map_texi_ref = \%cross_ref_style_map_texi;
    $::texi_map_ref = \%cross_ref_texi_map;
    my $normal_text_kept = $Texi2HTML::Config::normal_text;
    $Texi2HTML::Config::normal_text = \&Texi2HTML::Config::t2h_cross_manual_normal_text;
    my $style_kept = $Texi2HTML::Config::style;
    $Texi2HTML::Config::style = \&Texi2HTML::Config::T2H_GPL_style;
    
    my ($cross_ref_target, $cross_ref_file);
    if ($Texi2HTML::Config::USE_UNICODE)
    {
         $cross_ref_target = Unicode::Normalize::NFC(remove_texi($text));
         if ($transliterate and $Texi2HTML::Config::USE_UNIDECODE)
         {
             $cross_ref_file = 
                unicode_to_protected(unicode_to_transliterate($cross_ref_target));
         }
         $cross_ref_target = unicode_to_protected($cross_ref_target);
    }
    else
    {
         $cross_ref_target = remove_texi($text);
    }
    
    if ($transliterate and 
         (!$Texi2HTML::Config::USE_UNICODE or !$Texi2HTML::Config::USE_UNIDECODE))
    {
         $::style_map_texi_ref = \%cross_transliterate_style_map_texi;
         $::texi_map_ref = \%cross_transliterate_texi_map;
         $Texi2HTML::Config::normal_text = \&Texi2HTML::Config::t2h_cross_manual_normal_text_transliterate if (!$Texi2HTML::Config::USE_UNICODE);
         $cross_ref_file = remove_texi($text);
         $cross_ref_file = unicode_to_protected(unicode_to_transliterate($cross_ref_file))
               if ($Texi2HTML::Config::USE_UNICODE);
    }

    $Texi2HTML::Config::normal_text = $normal_text_kept;
    $Texi2HTML::Config::style = $style_kept;
    $::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi;
    $::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi;
    $::texi_map_ref = \%Texi2HTML::Config::texi_map;
#print STDERR "\n\ncross_ref $cross_ref\n";
    unless ($transliterate)
    {
        return $cross_ref_target;
    }
#    print STDERR "$text|$cross_ref_target|$cross_ref_file\n";
    return ($cross_ref_target, $cross_ref_file);
}

sub equivalent_nodes($)
{
    my $name = shift;
#print STDERR "equivalent_nodes $name\n";
    my $node = normalise_node($name);
    $name = cross_manual_line($node);
#print STDERR "equivalent_nodes `$node' `$name'\n";
    my @equivalent_nodes = ();
    if (exists($cross_reference_nodes{$name}))
    {
        @equivalent_nodes = grep {$_ ne $node} @{$cross_reference_nodes{$name}};
    }
    return @equivalent_nodes;
}

sub do_place_target_file($$$)
{
   my $place = shift;
   my $element = shift;
   my $context = shift;

   $place->{'file'} = $element->{'file'} unless defined($place->{'file'});
   $place->{'target'} = $element->{'target'} unless defined($place->{'target'});
   if (defined($Texi2HTML::Config::placed_target_file_name))
   {
      my ($target, $id, $file) = &$Texi2HTML::Config::placed_target_file_name($place,$element,$place->{'target'}, $place->{'id'}, $place->{'file'},$context);
      $place->{'target'} = $target if (defined($target));
      $place->{'file'} = $file if (defined($file));
      $place->{'id'} = $id if (defined($id));
   }
}

sub do_node_target_file($$)
{
    my $node = shift;
    my $type_of_node = shift;
    my $node_file = &$Texi2HTML::Config::node_file_name($node,$type_of_node);
    $node->{'node_file'} = $node_file if (defined($node_file));
    if (defined($Texi2HTML::Config::node_target_name))
    {
        my ($target,$id) = &$Texi2HTML::Config::node_target_name($node,$node->{'target'},$node->{'id'}, $type_of_node);
        $node->{'target'} = $target if (defined($target));
        $node->{'id'} = $id if (defined($id));
    }
}

sub do_element_targets($;$)
{
   my $element = shift;
   my $use_node_file = shift;
   my $is_top = '';

   $is_top = 'top' if (defined($element_top) and ($element eq $element_top or (defined($element->{'with_node'}) and $element->{'with_node'} eq $element_top)));

   if ($Texi2HTML::Config::SPLIT_INDEX and Texi2HTML::Config::get_conf('SPLIT'))
   {
      Texi2HTML::Config::t2h_default_associate_index_element($element, $is_top, $docu_name, $use_node_file);
   }

   if (defined($Texi2HTML::Config::element_file_name))
   {
      my $previous_file_name = $element->{'file'};
      my $filename = 
          &$Texi2HTML::Config::element_file_name ($element, $is_top, $docu_name);
      if (defined($filename))
      {
         foreach my $place (@{$element->{'place'}})
         {
            $place->{'file'} = $filename if (defined($place->{'file'}) and ($place->{'file'} eq $previous_file_name));
         }
         $element->{'file'} = $filename;
         if ($is_top)
         { # reset these variables, although they aren't used much, they may be
           # used in file name comparisons
            $docu_top = $filename;
            $docu_top_file = "$docu_rdir$docu_top";
         }
      }
   }
   print STDERR "file !defined for element $element->{'texi'}\n" if (!defined($element->{'file'}));
   if (defined($Texi2HTML::Config::element_target_name))
   {
       my ($target,$id) = &$Texi2HTML::Config::element_target_name($element, $element->{'target'}, $element->{'id'});
       $element->{'target'} = $target if (defined($target));
       $element->{'id'} = $id if (defined($id));
   }
   foreach my $place(@{$element->{'place'}})
   {
      do_place_target_file($place, $element, '');
   }
}

sub add_t2h_element($$$)
{
    my $element = shift;
    my $elements_list = shift;
    my $prev_element = shift;

    push @$elements_list, $element;
    $element->{'element_ref'} = $element;
    $element->{'this'} = $element;

    if (defined($prev_element))
    {
        $element->{'back'} = $prev_element;
        $prev_element->{'forward'} = $element;
    }
    push @{$element->{'place'}}, $element;
    push @{$element->{'place'}}, @{$element->{'current_place'}};
    return $element;
}

sub add_t2h_dependent_element ($$)
{
    my $element = shift;
    my $element_ref = shift;
    $element->{'element_ref'} = $element_ref;
    $element_index = $element_ref if ($element_index and ($element_index eq $element));
    push @{$element_ref->{'place'}}, $element;
    push @{$element_ref->{'place'}}, @{$element->{'current_place'}};
}

my %files = ();   # keys are files. This is used to avoid reusing an already
                  # used file name
my @opened_files = (); # all the files opened by the program to remove
                       # them if FORCE is not set and an error occured
my %printed_indices = (); # value is true for an index name not empty and
                          # printed
# This is a virtual element used to have the right hrefs for index entries
# and anchors in footnotes.
my $footnote_element;   

# find next, prev, up, back, forward, fastback, fastforward
# find element id and file
# split index pages
# associate placed items (items which have links to them) with the right 
# file and id
# associate nodes with sections
sub rearrange_elements()
{
    print STDERR "# find sections levels and toplevel\n"
        if ($T2H_DEBUG & $DEBUG_ELEMENTS);
    
    my $toplevel = 4;

    # correct level if raisesections or lowersections overflowed
    # and find toplevel level
    # use %sections and %headings to modify also the headings
    foreach my $section (values(%sections), values(%headings))
    {
        my $level = $section->{'level'};
        if ($level > $MAX_LEVEL)
        {
             $section->{'level'} = $MAX_LEVEL;
        }
        # second condition is for @top and @part
        elsif ($level < $MIN_LEVEL and ($reference_sec2level{$section->{'tag'}} >= $MIN_LEVEL))
        {
             $section->{'level'} = $MIN_LEVEL;
        }
        else
        {
             $section->{'level'} = $level;
        }
        $section->{'toc_level'} = $section->{'level'};
        # This is for top
        $section->{'toc_level'} = $MIN_LEVEL if ($section->{'level'} < $MIN_LEVEL);
        # find the new tag corresponding with the level of the section
        if ($section->{'tag'} !~ /heading/ and ($level ne $reference_sec2level{$section->{'tag'}}))
        {
             $section->{'tag_level'} = $level2sec{$section->{'tag'}}->[$section->{'level'}];
        }
        else
        {
             $section->{'tag_level'} = $section->{'tag'};
        }
        $toplevel = $section->{'level'} if (($section->{'level'} < $toplevel) and ($section->{'level'} > 0 and ($section->{'tag'} !~ /heading/)));
        print STDERR "# section level $level: $section->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
    }
    
    print STDERR "# find sections structure, construct section numbers (toplevel=$toplevel)\n"
        if ($T2H_DEBUG & $DEBUG_ELEMENTS);
    my $in_appendix = 0;
    # these arrays have an element per sectioning level. 
    my @previous_numbers = ();   # holds the number of the previous sections
                                 # at the same and upper levels
    my @previous_sections = ();  # holds the ref of the previous sections
    my $previous_toplevel;
    my @pending_parts;           # parts yet to be associated with the 
                                 # following element
    
    foreach my $section (@sections_list)
    {
        ########################### debug
        print STDERR "BUG: node or section_ref defined for section $section->{'texi'}\n"
            if (exists($section->{'node'}) or exists($section->{'section_ref'}));
        print STDERR "Bug level undef for ($section) $section->{'texi'}\n" if (!defined($section->{'level'}));
        ########################### end debug

        # associate with first node if it is a section appearing before
        # the first node
        $section->{'node_ref'} = $nodes_list[0] if ($nodes_list[0] and !$section->{'node_ref'});

        # a part doesn't really make up an element, it is associated with the
        # next sectioning element instead.
        if ($section->{'tag'} eq 'part')
        {
           push @pending_parts, $section;
        }
        elsif (@pending_parts)
        {
           if ($section->{'tag'} ne 'top')
           {
              foreach my $part (@pending_parts)
              {
                 $part->{'part_section_ref'} = $section;
                 if (!$section->{'with_part'})
                 {
                    $section->{'with_part'} = $part;
                    $part->{'part_with_section'} = $section;
                 }
                 # if a node is associated with the part, reassociate it with 
                 # the chapter
                 if ($part->{'with_node'} and !$section->{'with_node'})
                 {
                    $section->{'with_node'} = $part->{'with_node'};
                    delete $part->{'with_node'};
                    $section->{'with_node'}->{'with_section'} = $section;
                 }
              }
           }
           @pending_parts = ();
        }

        # we track the toplevel next and previous because there is no
        # strict child parent relationship between chapters and top. Indeed
        # a chapter may appear before @top, it may be better to consider them
        # on the same toplevel.
        if ($section->{'level'} <= $toplevel)
        {
            $section->{'toplevel'} = 1;
            if (defined($previous_toplevel))
            {
                $previous_toplevel->{'toplevelnext'} = $section;
                $section->{'toplevelprev'} = $previous_toplevel; 
            }
            # part is not used as previous_toplevel since toplevel directions
            # are used to move between chapters (and top)
            $previous_toplevel = $section if ($section->{'tag'} ne 'part');
            # In fact this is only useful for toplevel elements appearing
            # before @top, the other have their sectionup reset up below
            # based on the sectioning commands hierarchy.
            if (defined($section_top) and $section ne $section_top)
            {
                $section->{'sectionup'} = $section_top;
            }
        }
        # undef things under that section level
        my $section_level = $section->{'level'};
        for (my $level = $section_level + 1; $level < $MAX_LEVEL + 1 ; $level++)
        {
            $previous_numbers[$level] = undef unless ($section->{'tag'} =~ /unnumbered/ or $section->{'tag'} eq 'centerchap');
            $previous_sections[$level] = undef;
        }
        my $number_set;
        # find number at the current level
        if ($section->{'tag'} =~ /appendix/ and !$in_appendix)
        {
            $previous_numbers[$toplevel] = 'A';
            $in_appendix = 1;
            $number_set = 1 if ($section->{'level'} <= $toplevel);
            $section->{'appendix_beginning'} = 1;
        }
        if (!defined($previous_numbers[$section->{'level'}]) and !$number_set)
        {
            if ($section->{'tag'} =~ /unnumbered/ or $section->{'tag'} eq 'centerchap')
            {
                $previous_numbers[$section->{'level'}] = undef;
            }
            else
            {
                $previous_numbers[$section->{'level'}] = 1;
            }
        }
        elsif ($section->{'tag'} !~ /unnumbered/ and $section->{'tag'} ne 'centerchap' and !$number_set)
        {
            $previous_numbers[$section->{'level'}]++;
        }
        # construct the section number
        $section->{'number'} = '';

        unless ($section->{'tag'} =~ /unnumbered/ or $section->{'tag'} eq 'centerchap' or $section->{'tag'} eq 'top' or $section->{'tag'} eq 'part')
        { 
            my $level = $section->{'level'};
            while ($level > $toplevel)
            {
                my $number = $previous_numbers[$level];
                $number = 0 if (!defined($number));
                if ($section->{'number'})
                {
                    $section->{'number'} = "$number.$section->{'number'}";
                }
                else
                {
                    $section->{'number'} = $number;
                }    
                $level--;
            }
            my $toplevel_number = $previous_numbers[$toplevel];
            $toplevel_number = 0 if (!defined($toplevel_number));
            
            if ($section->{'number'})
            { # not toplevel
                $section->{'number'} = "$toplevel_number.$section->{'number'}";
            }
            else
            { # toplevel
                $section->{'number'} = $toplevel_number;
                if ($section->{'tag'} =~ /appendix/)
                {# i18n
                    $section->{'plain_number'} = $section->{'number'};
                    $section->{'number'} = "Appendix $section->{'number'}";
                }
            }
        }
        $section->{'plain_number'} = $section->{'number'} if (!defined($section->{'plain_number'}));
        # find the previous section
        if (defined($previous_sections[$section->{'level'}]))
        {
            my $prev_section = $previous_sections[$section->{'level'}];
            $section->{'sectionprev'} = $prev_section;
            $prev_section->{'sectionnext'} = $section;
        }
        # find the up section
        my $level = $section->{'level'} - 1;
        while (!defined($previous_sections[$level]) and ($level >= 0))
        {
            $level--;
        }
        # The second conditions ensures that a @part is stopped by 
        # the first @appendix command.
        if (defined($previous_sections[$level]) 
           and !($section->{'appendix_beginning'} and $previous_sections[$level]->{'tag'} eq 'part' and $previous_sections[$level]->{'part_section_ref'} ne $section))
        {
            # toplevel elements have already their up set to the top element,
            # it is overwriten here for most cases -- this leads to a different
            # sectionup if there are parts, for instance.
            # as a side note, it is not touched upon if the element appears 
            # before @top.
            $section->{'sectionup'} = $previous_sections[$level];
            # 'child' is the first child. 
            if (!$section->{'sectionup'}->{'child'})
            {
                $section->{'sectionup'}->{'child'} = $section;
            }
            else
            {
                # 'childnext' is the next child of a an element. it may
                # be different from 'sectionnext' when the elemnt are not
                # at the same level, for example
                # @chapter chapter
                # @subsection subsection (certainly wrong)
                # @section section (not next of subsection, but childnext)
                $section->{'sectionup'}->{'section_childs'}->[-1]->{'childnext'} = $section if (defined($section->{'sectionup'}->{'section_childs'}));
            }
            push @{$section->{'sectionup'}->{'section_childs'}}, $section;
        }
        $previous_sections[$section->{'level'}] = $section;
        # This is what is used in the .init file. 
        $section->{'up'} = $section->{'sectionup'};
        # Not used but documented. 
        $section->{'next'} = $section->{'sectionnext'};
        $section->{'prev'} = $section->{'sectionprev'};

        ############################# debug
        my $up = "NO_UP";
        $up = $section->{'sectionup'} if (defined($section->{'sectionup'}));
        print STDERR "# numbering section ($section->{'level'}): $section->{'number'}: (up: $up) $section->{'texi'}\n"
            if ($T2H_DEBUG & $DEBUG_ELEMENTS);
        ############################# end debug
    }

    # at that point there are still some node structures that are not 
    # in %nodes, (the external nodes, and unknown nodes in case 
    # novalidate is true) so we cannot find the id. The consequence is that
    # some node equivalent with another node may not be catched during
    # that pass. We mark the nodes that have directions for unreferenced 
    # nodes and make a second pass for these nodes afterwards.
    my @nodes_with_unknown_directions = ();

    my %node_directions = (
         'node_prev' => 'nodeprev',
         'node_next' => 'nodenext',
         'node_up' => 'nodeup');
    # handle nodes 
    # the node_prev... are texinfo strings, find the associated node references
    print STDERR "# Resolve nodes directions\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
    foreach my $node (@nodes_list)
    {
        foreach my $direction (keys(%node_directions))
        {
            if (defined($node->{$direction}))
            {
                if ($nodes{$node->{$direction}} and $nodes{$node->{$direction}}->{'seen'})
                {
                     $node->{$node_directions{$direction}} = $nodes{$node->{$direction}};
                }
                elsif (($node->{$direction} =~ /^\(.*\)/) or Texi2HTML::Config::get_conf('novalidate'))
                { # ref to an external node
                    if (exists($nodes{$node->{$direction}}))
                    {
                        $node->{$node_directions{$direction}} = $nodes{$node->{$direction}};
                    }
                    else
                    {
                        my $node_ref = { 'texi' => $node->{$direction} };
                        $node_ref->{'external_node'} = 1 if ($node->{$direction} =~ /^\(.*\)/);
                        $nodes{$node->{$direction}} = $node_ref;
                        $node->{$node_directions{$direction}} = $node_ref;
                    }
                }
                else
                {
                     push @nodes_with_unknown_directions, $node;
                }
            }
        }
    }

    # Find cross manual links as explained on the texinfo mailing list
    # The  specification is such that cross manual links formatting should 
    # be insensitive to the manual split
    cross_manual_links();    

    my %direction_texts = (
      'node_prev' => 'Prev',,
      'node_next' => 'Next',
      'node_up' => 'Up'
    );
    # Now it is possible to find the unknown directions that are equivalent
    # (have same node id) than an existing node
    foreach my $node (@nodes_with_unknown_directions)
    {
        foreach my $direction (keys(%node_directions))
        { 
            if (defined($node->{$direction}) and !$node->{$node_directions{$direction}})
            {
                line_error (sprintf(__("%s reference to nonexistent `%s'"),$direction_texts{$direction}, $node->{$direction}), $node->{'line_nr'}); # for `$node->{'texi'}'"
                my @equivalent_nodes = equivalent_nodes($node->{$direction});
                my $node_seen;
                foreach my $equivalent_node (@equivalent_nodes)
                {
                    if ($nodes{$equivalent_node}->{'seen'})
                    {
                        $node_seen = $equivalent_node;
                        last;
                    }
                }
                if (defined($node_seen))
                {
                    document_warn ("---> but equivalent node `$node_seen' found");
                    $node->{$node_directions{$direction}} = $nodes{$node_seen};
                }
            }
        }
    }

    # nodes are attached to the section preceding them if not already 
    # associated with a section.
    # a @part should never have nodes associated, if it is associated
    # with a chapter, instead the chapter pointed on by part_section_ref is
    # used.
    my $current_section = $sections_list[0];
    $current_section = $current_section->{'part_section_ref'} if ($current_section and $current_section->{'part_section_ref'});
    foreach my $element (@all_elements)
    {
        if ($element->{'node'})
        {
            if ($element->{'with_section'})
            { # the node is associated with a section
                $element->{'section_ref'} = $element->{'with_section'};
            }
            elsif (defined($current_section))
            {# node appearing after a section, but not before another section,
             # or appearing before any section
                $element->{'section_ref'} = $current_section;
                push @{$current_section->{'node_childs'}}, $element;
            }
        }
        else
        {
            $current_section = $element;
            $current_section = $element->{'part_section_ref'} if ($element->{'part_section_ref'});
        }
    }

    print STDERR "# Complete nodes next prev and up based on menus and sections\n"
        if ($T2H_DEBUG & $DEBUG_ELEMENTS);
    # set the default id based on the node number 
    my $node_nr = 1;
    # find the node* directions
    # find the directions corresponding with sections
    # and set 'up' for the node
    foreach my $node (@nodes_list)
    {
        # first a warning if the node and the equivalent nodes don't 
        # appear in menus.
        # Don't warn for the top node, and the first node if there is no
        # top node.
        if ((($node_top and $node ne $node_top) or (!$node_top and $node ne $node_first)) and !$node->{'menu_up'} and $Texi2HTML::Config::SHOW_MENU)
        {
            my @equivalent_nodes = equivalent_nodes($node->{'texi'});
            my $found = 0;
            foreach my $equivalent_node (@equivalent_nodes)
            {
                if (($nodes{$equivalent_node} eq $node_first) or $nodes{$equivalent_node}->{'menu_up'})
                {
                   $found = 1;
                   last;
                }
            }
            unless ($found)
            { # makeinfo has also 
              # "`%s' has no Up field (perhaps incorrect sectioning?)"
              # but it is not useful since the up will always be set if 
              # the node appears in a menu so the following error message 
              # is enough
                line_warn (sprintf(__("unreferenced node `%s'"), $node->{'texi'}), $node->{'line_nr'});
            }
        }

        # use values deduced from menus to complete missing up, next, prev
        # or from sectioning commands if automatic sectioning
        if (!$node->{'nodeup'})
        {
            if (defined($node_top) and ($node eq $node_top) and $node->{'automatic_directions'})
            { # Top node has a special up, which is (dir) by default
                my $top_nodeup = $Texi2HTML::Config::TOP_NODE_UP;
                if (exists($nodes{$top_nodeup}))
                {
                    $node->{'nodeup'} = $nodes{$top_nodeup};
                }
                else
                {
                    my $node_ref = { 'texi' => $top_nodeup };
                    $node_ref->{'external_node'} = 1;
                    $nodes{$top_nodeup} = $node_ref;
                    $node->{'nodeup'} = $node_ref;
                }
            }
            elsif ($node->{'automatic_directions'}) 
            {
                if ($node->{'with_section'})
                {
                    # ignore the up if it is a @part. If the sectioning is
                    # correct, the element is toplevel and will be handled 
                    # by the next condition. 
                    if ($node->{'with_section'}->{'sectionup'} and !$node->{'with_section'}->{'sectionup'}->{'part_section_ref'})
                    {
                        $node->{'nodeup'} = get_node($node->{'with_section'}->{'sectionup'});
                    }
                    elsif ($node->{'with_section'}->{'toplevel'} and defined($section_top) and ($node->{'with_section'} ne $section_top))
                    {
                        $node->{'nodeup'} = get_node($section_top);
                    }
                    print STDERR "# Deducing from section node_up $node->{'nodeup'}->{'texi'} for $node->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS and defined($node->{'nodeup'}));
                }
                elsif ($node->{'menu_up'})
                {
                    $node->{'nodeup'} = $node->{'menu_up'};
                    print STDERR "# Deducing from menu node_up $node->{'menu_up'}->{'texi'} for $node->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
                }
            }
        }

        if ($node->{'nodeup'} and !$node->{'nodeup'}->{'external_node'})
        {
            # We detect when the up node has no menu entry for that node, as
            # there may be infinite loops when finding following node (see below)
            unless (defined($node->{'menu_up_hash'}) and ($node->{'menu_up_hash'}->{$node->{'nodeup'}->{'texi'}}))
            {
                line_error(sprintf(__("Node `%s' lacks menu item for `%s' despite being its Up target"), $node->{'nodeup'}->{'texi'}, $node->{'texi'}), $node->{'nodeup'}->{'line_nr'}) if ($Texi2HTML::Config::SHOW_MENU);
                push @{$node->{'up_not_in_menu'}}, $node->{'nodeup'}->{'texi'};
            }
        }
        # check that the up is in one of the menus
        if ($Texi2HTML::Config::SHOW_MENU and $node->{'nodeup'} and $node->{'menu_up'})
        {
            my @equivalent_nodes = equivalent_nodes($node->{'nodeup'}->{'texi'});
            my $found = 0;
            foreach my $equivalent_node ($node->{'nodeup'}->{'texi'}, @equivalent_nodes)
            {
                if ($node->{'menu_up_hash'}->{$equivalent_node})
                {
                   $found = 1;
                   last;
                }
            }
            unless ($found)
            {
                line_warn (sprintf(__("For `%s', up in menu `%s' and up `%s' don't match"), $node->{'texi'}, $node->{'menu_up'}->{'texi'}, $node->{'nodeup'}->{'texi'}), $node->{'line_nr'});
            }

        }

        # Find next node if not already found
        if ($node->{'nodenext'}) 
        {
            # doing the following would be wrong:
            #$node->{'nodenext'}->{'nodeprev'} = $node if (!defined($node->{'nodenext'}->{'nodeprev'}));
        }
        elsif ($node->{'texi'} eq 'Top' and $node->{'automatic_directions'})
        { # special case as said in the texinfo manual
            if ($node->{'menu_child'})
            {
                $node->{'nodenext'} = $node->{'menu_child'};
                $node->{'menu_child'}->{'nodeprev'} = $node;
            }
        }
        elsif ($node->{'automatic_directions'})
        { 
            if (defined($node->{'with_section'}))
            {
                my $next;
                my $warn_for_next_not_in_menu = 1;
                my $section = $node->{'with_section'};
                if ($section->{'sectionnext'})
                {
                    $next = get_node($section->{'sectionnext'});
                }
                # we use toplevelnext, mostly for chapters associated with 
                # @part. But we don't want to have the @top as prev for
                # a @chapter or the like
                elsif ($section->{'toplevelnext'} and $section->{'toplevelnext'} ne $section_top)
                {
                    $next = get_node($section->{'toplevelnext'});
                }
                elsif ($Texi2HTML::Config::USE_UP_FOR_ADJACENT_NODES) 
                { # makeinfo don't do that. So this is conditionnal. 
                  # Also no warning, because it is expected that the 
                  # next found out with the up is not the next in menu.
                    $warn_for_next_not_in_menu = 0;
                    while (defined($section->{'sectionup'}) and !defined($section->{'sectionnext'}))
                    {
                        $section = $section->{'sectionup'};
                    }
                    if (defined($section->{'sectionnext'}))
                    {
                        $next = get_node($section->{'sectionnext'});
                    }
                }
                if (defined($next) and $Texi2HTML::Config::SHOW_MENU and $warn_for_next_not_in_menu)
                {
                    line_warn (sprintf(__("No node following `%s' in menu, but `%s' follows in sectioning"), $node->{'texi'}, $next->{'texi'}), $node->{'line_nr'}) if (!defined($node->{'menu_next'}));
                    line_warn (sprintf(__("Node following `%s' in menu `%s' and in sectioning `%s' differ"), $node->{'texi'}, $node->{'menu_next'}->{'texi'}, $next->{'texi'}), $node->{'line_nr'}) 
                       if (defined($node->{'menu_next'}) and $next ne $node->{'menu_next'});
                }
                $node->{'nodenext'} = $next;
            }
            elsif ($node->{'menu_next'})
            {
                $node->{'nodenext'} = $node->{'menu_next'};
            }
        }

        # Find prev node
        if ($node->{'nodeprev'})
        {
            # doing the following would be wrong:
            #$node->{'nodeprev'}->{'nodenext'} = $node if (!defined($node->{'nodeprev'}->{'nodenext'}));
        }
        elsif ($node->{'automatic_directions'})
        {
            if (defined($node->{'with_section'}))
            {
                my $section = $node->{'with_section'};
                if ($section->{'sectionprev'})
                {
                    $node->{'nodeprev'} = get_node($section->{'sectionprev'});
                }
                # we use toplevelprev, mostly for chapters associated with 
                # @part. But we don't want to have the @top as prev for
                # a @chapter or the like
                elsif ($section->{'toplevelprev'} and $section->{'toplevelprev'} ne $section_top)
                { 
                    $node->{'nodeprev'} = get_node($section->{'toplevelprev'});
                }
                elsif ($Texi2HTML::Config::USE_UP_FOR_ADJACENT_NODES and defined($section->{'sectionup'}))
                { # makeinfo don't do that
                    $node->{'nodeprev'} = get_node($section->{'sectionup'});
                }
            }
            elsif ($node->{'menu_prev'}) 
            {
                $node->{'nodeprev'} = $node->{'menu_prev'};
            }
            # the prev node is the parent node
            elsif ($node->{'menu_up'} and ($node->{'menu_up'}->{'menu_child'} eq $node) and $Texi2HTML::Config::USE_UP_FOR_ADJACENT_NODES)
            {
                $node->{'nodeprev'} = $node->{'menu_up'};
            }
        }
    
        # the following node is the node following in node reading order
        # it is thus first the child, else the next, else the next following
        # the up
        if ($node->{'menu_child'})
        {
            $node->{'following'} = $node->{'menu_child'};
        }
        elsif ($node->{'automatic_directions'} and defined($node->{'with_section'}) and defined($node->{'with_section'}->{'child'}))
        {
            $node->{'following'} = get_node($node->{'with_section'}->{'child'});
        }
        elsif (defined($node->{'nodenext'}))
        {
            $node->{'following'} = $node->{'nodenext'};
        }
	else
        {
            my $up = $node->{'nodeup'};
            # in order to avoid infinite recursion in case the up node is the 
            # node itself we use the up node as following when there isn't 
            # a correct menu structure, here and also below.
            $node->{'following'} = $up if (defined($up) and grep {$_ eq $up->{'texi'}} @{$node->{'up_not_in_menu'}});
            while ((!defined($node->{'following'})) and (defined($up)))
            {
                if (($node_top) and ($up eq $node_top))
                { # if we are at Top, Top is following 
                    $node->{'following'} = $node_top;
                    $up = undef;
                }
                if (defined($up->{'nodenext'}))
                {
                    $node->{'following'} = $up->{'nodenext'};
                }
                elsif (defined($up->{'nodeup'}))
                {
                    if (! grep { $_ eq $up->{'nodeup'}->{'texi'} } @{$node->{'up_not_in_menu'}}) 
                    { 
                        $up = $up->{'nodeup'};
                    }
                    else
                    { # in that case we can go into a infinite loop
                        $node->{'following'} = $up->{'nodeup'};
                    }
                }
                else
                {
                    $up = undef;
                }
            }
        }
        # copy the direction of the associated section.
        if (defined($node->{'with_section'}))
        {
            my $section = $node->{'with_section'};
            foreach my $direction ('sectionnext', 'sectionprev', 'sectionup')
            {
                $node->{$direction} = $section->{$direction}
                  if (defined($section->{$direction}));
            }
        }
        # 'up' is used in .init files. It is almost sectionup, but not
        # exactly, it allows to have something relevant whether elements
        # are nodes or sections -- just like Back and Forward. So it
        # should certainly be kept.
        if (defined($node->{'sectionup'}))
        {
            $node->{'up'} = $node->{'sectionup'};
        }
        elsif (defined($node->{'nodeup'}) and 
             (!$node_top or ($node ne $node_top)))
        {
            $node->{'up'} = $node->{'nodeup'};
        }
        # 'next' not used but documented. 
        if (defined($node->{'sectionnext'}))
        {
            $node->{'next'} = $node->{'sectionnext'};
        }
        if (defined($node->{'sectionprev'}))
        {
            $node->{'prev'} = $node->{'sectionprev'};
        }

        # default id for nodes. Should be overriden later.
        $node->{'id'} = 'NOD' . $node_nr;
        $node_nr++;
    }
    
    # do node directions for sections.
    foreach my $section (@sections_list)
    {
        # If the element is not a node, then all the node directions are copied
        # if there is an associated node
        if (defined($section->{'with_node'}))
        {
            $section->{'nodenext'} = $section->{'with_node'}->{'nodenext'};
            $section->{'nodeprev'} = $section->{'with_node'}->{'nodeprev'};
            $section->{'menu_next'} = $section->{'with_node'}->{'menu_next'};
            $section->{'menu_prev'} = $section->{'with_node'}->{'menu_prev'};
            $section->{'menu_child'} = $section->{'with_node'}->{'menu_child'};
            $section->{'menu_up'} = $section->{'with_node'}->{'menu_up'};
            $section->{'nodeup'} = $section->{'with_node'}->{'nodeup'};
            $section->{'following'} = $section->{'with_node'}->{'following'};
        }
    }

    my $only_nodes = 0;
    my $only_sections = 0;

    # for legibility
    my $use_nodes = $Texi2HTML::Config::USE_NODES;
    my $use_sections = $Texi2HTML::Config::USE_SECTIONS;

    $only_nodes = 1 if (
         (!scalar(@sections_list) and 
            ($use_nodes or (!$use_sections and !defined($use_nodes))))
      or ($use_nodes and !$use_sections)
    );
    $only_sections = 1 if (!$only_nodes and !$use_nodes and ($use_sections or !defined($use_sections)));
    #print STDERR "USE_NODES $use_nodes, USE_SECTIONS $use_sections. only_nodes: $only_nodes, only_sections $only_sections\n";

    my $prev_element;
    print STDERR "# Build the elements list only_nodes: $only_nodes, only_sections $only_sections\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
    foreach my $element (@all_elements)
    {
        if ($element->{'node'})
        {
            if ($element->{'section_ref'} and ($only_sections or (!$only_nodes and $element->{'with_section'})))
            {
                add_t2h_dependent_element ($element, $element->{'section_ref'});
                #$element->{'toc_level'} = $element->{'section_ref'}->{'toc_level'};
            }
            elsif (!$only_sections)
            {
                $prev_element = add_t2h_element($element, \@elements_list, $prev_element);
            }
            else # $only_section and !$section_ref. This should only
                 # happen when there are no sections
            {
                #print STDERR "node $element->{'texi'} not associated with an element\n";
            }
        }
        else
        {
            my $part_element = $element->{'part_section_ref'};
            if (($element->{'node_ref'} or ($part_element and $part_element->{'node_ref'})) and $only_nodes)
            {
                my $element_with_node = $element;
                $element_with_node = $part_element if ($part_element);
                add_t2h_dependent_element ($element, $element_with_node->{'node_ref'});
            }
            elsif (!$only_nodes)
            {
                if ($part_element)
                {
                    add_t2h_dependent_element ($element, $part_element);
                }
                else
                {
                    $prev_element = add_t2h_element($element, \@elements_list, $prev_element);
                }
            }
            else
            { # no node, and $only_nodes
                #print STDERR "$element->{'tag'} $element->{'texi'} not associated with an element\n";
            }
        }
    }

    # find texi2html specific directions and elements that are not texinfo
    # language features.
    #
    # Maybe Config hooks should be used at that point (up to index 
    # preparation)
    #
    # find first, last and top elements 
    if (@elements_list)
    {
        $element_first = $elements_list[0];
        print STDERR "# element first: $element_first->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS); 
        # It is the last element before indices split, which may add new 
        # elements
        $element_last = $elements_list[-1];
    }
    else
    {
        print STDERR "# \@elements_list is empty\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS); 
    }
    print STDERR "# top node: $node_top->{'texi'}\n" if (defined($node_top) and
        ($T2H_DEBUG & $DEBUG_ELEMENTS));

    # Remark: there are many subtle distinctions among the elements that
    # have a flavor of being at top. First there are the texinfo top
    # elements (if present), namely $section_top for the @top element
    # and $node_top for the @node Top element (and both may be associated).

    # Then there is $element_top, set up just below. In addition to 
    # $section_top and $node_top, the section associated with $node_top
    # and the first element may be used. $element_top is used to determine
    # file splitting and file names, since it is always associated with 
    # $docu_top file.

    # The $element_top may have 'top' set, in case it is a node or @top.
    # In that case, special formatting is done, like using print_Top and
    # similar.

    # Similarly with element_top, some other nodes than $node_top may 
    # get associated with the top node filename without being considered
    # as top otherwise (this is done below).

    if (defined($section_top) and $section_top->{'this'})
    {
    # element top is the element with @top.
        $element_top = $section_top;
    }
    elsif (defined($node_top) and $node_top->{'this'})
    {
    # otherwise top node may be the element_top
        $element_top = $node_top;
    }
    elsif (defined($node_top) and defined($node_top->{'with_section'}) and $node_top->{'with_section'}->{'this'})
    {
        # next, the element associated with the @node Top may be
        # the $element_top. In that case $element_top->{'top'} won't be set
        $element_top = $node_top->{'with_section'};
    }
    elsif (defined($element_first))
    {
    # If there is no @top section no top node associated with an element,
    # first element is used
         $element_top = $element_first;
    }

    # Rather arbitrarily, 'top' is set for nodes as top elements 
    # and @top. This triggers specific formatting, like calling
    # print_Top and similar things.
    if (defined($element_top))
    {
        $element_top->{'top'} = 1 if ($element_top->{'node'} or $element_top->{'tag'} eq 'top');
        print STDERR "# element top: $element_top->{'texi'}\n" if ($element_top and
           ($T2H_DEBUG & $DEBUG_ELEMENTS));
    }
    
    print STDERR "# find fastback and fastforward\n" 
       if ($T2H_DEBUG & $DEBUG_ELEMENTS);
    foreach my $element (@elements_list)
    { # nodes are ignored here, although their associated sectioning
      # command may be taken into account.
        my $up = get_top($element);
        next unless (defined($up));
        # take the opportunity to set the first chapter with index 
        $element_chapter_index = $up if ($element_index and ($element_index eq $element));
        # fastforward is the next element on same level than the upper parent
        # element.
        if (exists ($up->{'toplevelnext'}))
        {
            $element->{'fastforward'} = $up->{'toplevelnext'}
        }
        # if the element isn't at the highest level, fastback is the 
        # highest parent element
        if ($up and ($up ne $element))
        {
            $element->{'fastback'} = $up;
        }
        elsif ($element->{'toplevel'})
        {
             # the element is a top level element, we adjust the next
            # toplevel element fastback
            $element->{'fastforward'}->{'fastback'} = $element if ($element->{'fastforward'});
        }
    }

    # set 'reference_element' which is used each time there is a cross ref
    # to that node (xref and menu entry), to do the href, and also the 
    # element heading text.
    # It is the section associated with the node if there are only sections.
    # Since in the default case the target is the node target, even for 
    # sections, this, in fact shouldn't lead to a different target, unless 
    # the node and the section don't have the same file associated, which could 
    # only happen with indices split. The heading text will be different, though.
    # The node name should also always be passed to the formatting functions 
    # such that it is always possible for the formatting to chose the node
    # heading over the element heading selected using 'reference_element'.
    if ($only_sections)
    {
        foreach my $node(@nodes_list)
        {
            if ($node->{'with_section'})
            {
                $node->{'reference_element'} = $node->{'with_section'};
            }
        }
    }
    # the symmetric is not done for sections, since there is no crossref
    # to sections in texinfo (only to anchors and nodes), so that when
    # there is a link to an element (in Toc, for instance),
    # there is no reason to want to have the node (though, once again,
    # the href is almost surely the same than what would be with the node,
    # the heading would be different).

    # end texi2html added directions

    # do human readable id
    print STDERR "# find float id\n" 
       if ($T2H_DEBUG & $DEBUG_ELEMENTS);
    foreach my $float (@floats)
    {
        $float->{'style_id'} = cross_manual_line($float->{'style_texi'});
        my $float_style = { };
        if (exists($floats{$float->{'style_id'}}))
        {
            $float_style = $floats{$float->{'style_id'}};
        }
        else
        {
            $floats{$float->{'style_id'}} = $float_style;
        }
        push @{$float_style->{'floats'}}, $float;
        $float->{'absolute_nr'} = scalar(@{$float_style->{'floats'}});
        my $up = get_top($float->{'element'});
        if (defined($up) and (!defined($float_style->{'current_chapter'}) or ($up->{'texi'} ne $float_style->{'current_chapter'})))
        {
            $float_style->{'current_chapter'} = $up->{'texi'};
            $float_style->{'nr_in_chapter'} = 1;
        }
        else
        {
            $float_style->{'nr_in_chapter'}++;
        }
        if (defined($up) and $up->{'toplevel'} and $up->{'number'} ne '')
        {
            $float->{'chapter_nr'} = $up->{'plain_number'};
            $float->{'nr'} = $float->{'chapter_nr'} . "." . $float_style->{'nr_in_chapter'};
        }
        else
        {
            $float->{'nr'} = $float->{'absolute_nr'};
        }
    }

    print STDERR "# do human-readable index entries id\n" 
       if ($T2H_DEBUG & $DEBUG_ELEMENTS);
    if ($Texi2HTML::Config::NEW_CROSSREF_STYLE)
    {
        foreach my $entry_region (sort(keys(%{$Texi2HTML::THISDOC{'index_entries_region_array'}})))
        {
            foreach my $index_entry (@{$Texi2HTML::THISDOC{'index_entries_region_array'}->{$entry_region}})
            {
                my $region = '';
                $region = "$index_entry->{'region'}-" if (defined($index_entry->{'region'}) and $index_entry->{'region'} ne '');
                my $index_id = "index-" . $region .$index_entry->{'cross'};
                my $index = 1;
                # $index > 0 should prevent integer overflow, hopefully
                while (exists($cross_reference_nodes{$index_id}) and $index > 0)
                {
                    $index_id = "index-" . $region . $index_entry->{'cross'} . "-" .$index;
                    $index++;
                }
                $index_entry->{'id'} = $index_id;
                $index_entry->{'target'} = $index_id;
                my $texi_entry = "index-".$region.$index_entry->{'texi'};
                $texi_entry .= "-".$index if ($index > 1);
                push @{$cross_reference_nodes{$index_id}}, $texi_entry;
            }
        }
    }


    if ($Texi2HTML::Config::NEW_CROSSREF_STYLE)
    { 
        foreach my $key (keys(%nodes))
        {
            my $node = $nodes{$key};
            next if ($node->{'external_node'});
            $node->{'id'} = node_to_id($node->{'cross_manual_target'});
            # FIXME if NEW_CROSSREF_STYLE false is it done for anchors?
            $node->{'target'} = $node->{'id'};
        }
    }

    # use %sections and %headings to modify also the headings
    foreach my $section (values(%sections), values(%headings))
    {
        if ($Texi2HTML::Config::NEW_CROSSREF_STYLE and ($section->{'cross'} =~ /\S/))
        {
            my $section_cross = $section->{'cross'};
            if (defined($section->{'region'}))
            { # for headings appearing in special regions like @copying...
                $section_cross = "${target_prefix}-$section->{'region'}_$section_cross";
            }
            $section->{'cross_manual_target'} = $section_cross;

            my $index = 1;
            # $index > 0 should prevent integer overflow, hopefully
            while (exists($cross_reference_nodes{$section->{'cross_manual_target'}}) and $index > 0)
            {
                $section->{'cross_manual_target'} = $section_cross . "-" .$index;
                $index++;
            }
            my $texi_entry = $section->{'texi'};
            $texi_entry .= "-".$index if ($index > 1);
            push @{$cross_reference_nodes{$section->{'cross_manual_target'}}}, $texi_entry;
            $section->{'id'} = node_to_id($section->{'cross_manual_target'});
        }
    }
    # use the associated @part as target if there is an associated part.
    # do it separately to be sure that all the parts have an id.
    foreach my $section (values(%sections), values(%headings))
    {
        my $target = $section;
        $target = $section->{'with_part'} if ($section->{'with_part'});
        if ($Texi2HTML::Config::USE_NODE_TARGET and $target->{'with_node'})
        {
            $section->{'target'} = $target->{'with_node'}->{'target'};
        }
        else
        {
            $section->{'target'} = $target->{'id'};
        }
    }

    # construct human readable tocid
    foreach my $section (values(%sections))
    {
        if ($Texi2HTML::Config::NEW_CROSSREF_STYLE and ($section->{'cross'} =~ /\S/))
        {
            foreach my $toc_id (['tocid','toc'], ['stocid', 'stoc'])
            {
                my $id_string = $toc_id->[0];
                my $prefix_string = $toc_id->[1];
                my $cross_string = '-' . $section->{'cross_manual_target'};
                $section->{$id_string} = $prefix_string . $cross_string;
                my $index = 1;
                # $index > 0 should prevent integer overflow, hopefully
                while (exists($cross_reference_nodes{$section->{$id_string}}) and $index > 0)
                {
                    $section->{$id_string} = $prefix_string . "-" .$index .$cross_string;
                    $index++;
                }
                my $texi_entry = $prefix_string.'-'.$section->{'texi'};
                $texi_entry = $prefix_string .'-'.$index.'-'.$section->{'texi'}  if ($index > 1);
                push @{$cross_reference_nodes{$section->{$id_string}}}, $texi_entry;
            }
        }
    }
    if (!$Texi2HTML::Config::NEW_CROSSREF_STYLE)
    {
        my $tocnr = 1;
        foreach my $element (@elements_list)
        {
            $element->{'tocid'} = 'TOC' . $tocnr;
            $tocnr++;
        }
    }

    # Set file names
    # Find node file names and file names for nodes considered as elements
    my $node_as_top;
    if ($node_top)
    {
        $node_as_top = $node_top;
    }
    # following possibilities lead to some node being considered
    # as top for the purpose of setting the file node, but not as node_top
    elsif ($element_top->{'with_node'})
    { 
        $node_as_top = $element_top->{'with_node'};
    }
    else
    {
        $node_as_top = $node_first;
    }
    if ($node_as_top)
    {
        do_node_target_file($node_as_top, 'top');
    }
    foreach my $key (keys(%nodes))
    {
        my $node = $nodes{$key};
        next if (defined($node_as_top) and ($node eq $node_as_top));
        do_node_target_file($node,'');
    }
    
    print STDERR "# split(".Texi2HTML::Config::get_conf('SPLIT').") and set files\n" 
       if ($T2H_DEBUG & $DEBUG_ELEMENTS);
    # find document nr and document file for sections and nodes. 
    # Split according to Texi2HTML::Config::SPLIT.
    # find file and id for placed elements (anchors, index entries, headings)
    if (Texi2HTML::Config::get_conf('SPLIT'))
    {
        $Texi2HTML::THISDOC{'split_level'} = $toplevel;
        my $doc_nr = -1;
        if (Texi2HTML::Config::get_conf('SPLIT') eq 'section')
        {
            $Texi2HTML::THISDOC{'split_level'} = 2 if ($toplevel <= 2);
        }
        my $previous_file;
        my $previous_is_top = 0;
        foreach my $element (@elements_list)
        { 
            print STDERR "# Splitting (".Texi2HTML::Config::get_conf('SPLIT').":$Texi2HTML::THISDOC{'split_level'}) $element->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
            my $new_file = 0;
            if (
               (!defined($previous_file)) or 
               (Texi2HTML::Config::get_conf('SPLIT') eq 'node') or
               (
                 defined($element->{'level'}) and ($element->{'level'} <= $Texi2HTML::THISDOC{'split_level'})
               ) or
               (
                 !defined($element->{'level'}) and defined($element->{'with_section'}) and ($element->{'with_section'}->{'level'} <= $Texi2HTML::THISDOC{'split_level'})
               ) or
               ( # top file after another file
                 (defined($previous_file) and ($element eq $element_top)
                  and ($previous_file ne $docu_top))
               ) # element following top element is always considered to be
                 # in a different file.
               or ($previous_is_top)
              )
            {
                $new_file = 1;
                $doc_nr++;
            }
            $previous_is_top = 0 if ($previous_is_top);

            $element->{'doc_nr'} = $doc_nr;
            $element->{'file'} = "${docu_name}_$doc_nr"
                . (defined($Texi2HTML::THISDOC{'extension'}) ? ".$Texi2HTML::THISDOC{'extension'}" : '');
            my $use_node_file = 0;
            if ($element eq $element_top)
            { # the top element
                $element->{'file'} = $docu_top;
                $previous_is_top = 1;
            }
            elsif ($Texi2HTML::Config::NODE_FILENAMES)
            {
                $use_node_file = 1;
                if ($new_file)
                {
                    my $node = get_node($element);
                    if ($node and defined($node->{'node_file'}))
                    {
                        $element->{'file'} = $node->{'node_file'};
                    }
                    elsif ($element->{'cross'} =~ /\S/)
                    { # use the canonicalized/transliterated section file name.
                        $element->{'file'} = $element->{'cross'} 
                         . (defined($Texi2HTML::THISDOC{'extension'}) ? ".$Texi2HTML::THISDOC{'extension'}" : '');
                    }
                    # The remaining case is for sectioning elements with empty
                    # headings and no node associated. They will have a name
                    # with numbers, like "${docu_name}_$doc_nr", they may 
                    # collide with split indices names
                }
                else
                {
                    $element->{'file'} = $previous_file;
                }
            }
            $previous_file = $element->{'file'};
            do_element_targets($element, $use_node_file);
            print STDERR "# [$doc_nr] add_file($use_node_file,$new_file,".var_to_str($previous_file).") $element->{'file'} for $element->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
            add_file($element->{'file'});
        }
    }
    else
    { # not split
        add_file($docu_doc);
        foreach my $element(@elements_list)
        {
            $element->{'file'} = $docu_doc;
            $element->{'doc_nr'} = 0;
            do_element_targets($element);
        }
    }
    # 'pathological' cases. No texinfo sectioning element at all or no 
    # texi2html sectioning elements
    if (!@elements_list)
    {
        if (@all_elements)
        {
            # in fact this happens only if there is no top element, but still
            # sections, so only if USE_SECTIONS = 0 and there is no node.
            #document_warn ("No elements available for splitting") if (Texi2HTML::Config::get_conf('SPLIT'));
            foreach my $element (@all_elements)
            {
                #print STDERR "# no \@elements_list. Processing $element->{'texi'}\n";
                $element->{'file'} = $docu_doc;
                $element->{'doc_nr'} = 0;
                push @{$element->{'place'}}, @{$element->{'current_place'}};
                do_element_targets($element,$Texi2HTML::Config::NODE_FILENAMES);
                print STDERR "# no \@elements_list, setting $element->{'file'} for $element->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
            }
            add_file($docu_doc);
        }
        else
        {
            #document_warn ("No elements at all") if (Texi2HTML::Config::get_conf('SPLIT'));
            $element_before_anything->{'file'} = $docu_doc;
            $element_before_anything->{'doc_nr'} = 0;
            do_element_targets($element_before_anything,$Texi2HTML::Config::NODE_FILENAMES);
            print STDERR "# no element at all, setting $element_before_anything->{'file'} for $element_before_anything->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
        }
    }

    # correct the id and file for the things placed in footnotes
    foreach my $place(@{$footnote_element->{'place'}})
    {
        do_place_target_file ($place, $footnote_element, 'footnotes');
    }
    # if setcontentsaftertitlepage is set, the contents should be associated
    # with the titlepage. That's what is done there.
    push @$no_element_associated_place, $content_element{'contents'} 
      if (Texi2HTML::Config::get_conf('contents') and $Texi2HTML::THISDOC{'setcontentsaftertitlepage'});
    push @$no_element_associated_place, $content_element{'shortcontents'} 
      if (Texi2HTML::Config::get_conf('shortcontents') and $Texi2HTML::THISDOC{'setshortcontentsaftertitlepage'});
    # correct the id and file for the things placed in regions (copying...)
    foreach my $place(@$no_element_associated_place)
    {
#print STDERR "entry $place->{'entry'} texi $place->{'texi'}\n";
        $place->{'element'} = $element_top if (exists($place->{'element'}));
        do_place_target_file ($place, $element_top, 'no_associated_element');
    }
    
    # determine contents element and files
    foreach my $content_type(keys(%content_element))
    {
        # with set*aftertitlepage, there will always be a href to Contents
        # or Overview pointing to the top element, even if there is no 
        # titlepage outputed.
        if (!scalar(@{$all_content_elements{$content_type}}))
        {
            if  ($Texi2HTML::Config::INLINE_CONTENTS)
            {
                print STDERR "# No content $content_type\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
                $content_element{$content_type} = undef;
            }
        }
        elsif ($Texi2HTML::Config::INLINE_CONTENTS and !Texi2HTML::Config::get_conf('set' . $content_type .'aftertitlepage'))
        { # use the last element for references in case there is more than one
            $content_element{$content_type} = $all_content_elements{$content_type}->[-1];
        }
    }
    my ($toc_file, $stoc_file);
    $toc_file = $docu_toc;
    $stoc_file = $docu_stoc;
    if ($Texi2HTML::Config::INLINE_CONTENTS)
    {
        $toc_file = $content_element{'contents'}->{'file'} if (defined($content_element{'contents'}));
        $stoc_file = $content_element{'shortcontents'}->{'file'} if (defined($content_element{'shortcontents'}));
    }
    $Texi2HTML::THISDOC{'toc_file'} = $toc_file; 
    $Texi2HTML::THISDOC{'stoc_file'} = $stoc_file; 
    
    print STDERR "# find NextFile and PrevFile\n" 
       if ($T2H_DEBUG & $DEBUG_ELEMENTS);
    foreach my $element (@elements_list)
    {
        my $current_element = $element;
        my $file = $current_element->{'file'};
        my $previous_file;
        while ($current_element->{'back'})
        {
#print STDERR "Back $current_element->{'texi'}\n";
            $current_element = $current_element->{'back'};
            if ($current_element->{'file'} ne $file)
            {
                $previous_file = $current_element->{'file'};
                last;
            }
        }
        if (defined($previous_file))
        {
            while ($current_element->{'back'})
            {
                if ($current_element->{'back'}->{'file'} ne $previous_file)
                {
                    last;
                }
                $current_element = $current_element->{'back'};
            }
            $element->{'prevfile'} = $current_element;
        }

        $current_element = $element;
        while ($current_element->{'forward'})
        {
#print STDERR "Fwd $current_element->{'texi'}\n";
            $current_element = $current_element->{'forward'};
            if ($current_element->{'file'} ne $file)
            {
                 $element->{'nextfile'} = $current_element;
            }
        }
    }
    # convert directions in direction with first letter in all caps, to be
    # consistent with the convention used in the .init file.
    foreach my $element (@elements_list)
    {
        foreach my $direction (@element_directions)
        {
            my $direction_no_caps = $direction;
            $direction_no_caps =~ tr/A-Z/a-z/;
            $element->{$direction} = $element->{$direction_no_caps};
        }
    }

    ########################### debug prints
    foreach my $file (keys(%files))
    {
        last unless ($T2H_DEBUG & $DEBUG_ELEMENTS);
        print STDERR "$file: counter $files{$file}->{'counter'}\n";
    }
    my $output_elements = \@elements_list;
    if (!scalar(@elements_list) and ($T2H_DEBUG & $DEBUG_ELEMENTS))
    {
        print STDERR "No elements_list, no texi2html elements\n";
        $output_elements = \@all_elements;
    }
    foreach my $element ((@$output_elements, $footnote_element))
    {
        last unless ($T2H_DEBUG & $DEBUG_ELEMENTS);
        my $is_toplevel = 'not toplevel';
        $is_toplevel = 'toplevel' if ($element->{'toplevel'});
        print STDERR "$element ";
        if ($element->{'node'})
        {
            print STDERR "node($element->{'id'}, $is_toplevel, doc_nr $element->{'doc_nr'}($element->{'file'})) $element->{'texi'}:\n";
            print STDERR "  section_ref: $element->{'section_ref'}->{'texi'}\n" if (defined($element->{'section_ref'}));
            print STDERR "  with_section: $element->{'with_section'}->{'texi'}\n" if (defined($element->{'with_section'}));
        }
        elsif ($element->{'footnote'})
        {
            print STDERR "footnotes($element->{'id'}, file $element->{'file'})\n";
        }
        else 
        {
            my $number = "UNNUMBERED";
            $number = $element->{'number'} if ($element->{'number'});
            print STDERR "$number ($element->{'id'}, $is_toplevel, level $element->{'level'}-$element->{'toc_level'}, doc_nr $element->{'doc_nr'}($element->{'file'})) $element->{'texi'}:\n";
            print STDERR "  with_node: $element->{'with_node'}->{'texi'}\n" if (defined($element->{'with_node'}));
            print STDERR "  node_ref: $element->{'node_ref'}->{'texi'}\n" if (defined($element->{'node_ref'}));
        }

        if (!$element->{'footnote'})
        {
            if (!defined($files{$element->{'file'}}))
            {
               die "Bug: files{\$element->{'file'}} undef element $element->{'texi'}, file $element->{'file'}.";
            }
            print STDERR "  file: $element->{'file'} $files{$element->{'file'}}, counter $files{$element->{'file'}}->{'counter'}\n";
        }
        print STDERR "  level: $element->{'level'}\n" if (defined($element->{'level'}));
        print STDERR "  TOP($toplevel) " if ($element->{'top'});
        print STDERR "  u: $element->{'up'}->{'texi'}\n" if (defined($element->{'up'}));
        print STDERR "  ch: $element->{'child'}->{'texi'}\n" if (defined($element->{'child'}));
        print STDERR "  fb: $element->{'fastback'}->{'texi'}\n" if (defined($element->{'fastback'}));
        print STDERR "  b: $element->{'back'}->{'texi'}\n" if (defined($element->{'back'}));
        print STDERR "  p: $element->{'prev'}->{'texi'}\n" if (defined($element->{'prev'}));
        print STDERR "  u: $element->{'sectionup'}->{'texi'}\n" if (defined($element->{'sectionup'}));
        print STDERR "  n: $element->{'sectionnext'}->{'texi'}\n" if (defined($element->{'sectionnext'}));
	print STDERR "  t_n: $element->{'toplevelnext'}->{'texi'}\n" if (defined($element->{'toplevelnext'}));
	print STDERR "  t_p: $element->{'toplevelprev'}->{'texi'}\n" if (defined($element->{'toplevelprev'}));
        print STDERR "  n_u: $element->{'nodeup'}->{'texi'}\n" if (defined($element->{'nodeup'}));
        print STDERR "  f: $element->{'forward'}->{'texi'}\n" if (defined($element->{'forward'}));
        print STDERR "  follow: $element->{'following'}->{'texi'}\n" if (defined($element->{'following'}));
	print STDERR "  m_p: $element->{'menu_prev'}->{'texi'}\n" if (defined($element->{'menu_prev'}));
	print STDERR "  m_n: $element->{'menu_next'}->{'texi'}\n" if (defined($element->{'menu_next'}));
	print STDERR "  m_u: $element->{'menu_up'}->{'texi'}\n" if (defined($element->{'menu_up'}));
	print STDERR "  m_ch: $element->{'menu_child'}->{'texi'}\n" if (defined($element->{'menu_child'}));
        print STDERR "  ff: $element->{'fastforward'}->{'texi'}\n" if (defined($element->{'fastforward'}));
        print STDERR "  n_f: $element->{'nextfile'}->{'texi'}\n" if (defined($element->{'nextfile'}));
        print STDERR "  p_f: $element->{'prevfile'}->{'texi'}\n" if (defined($element->{'prevfile'}));
        my $section_childs = '';
        if (defined($element->{'section_childs'}))
        {
            foreach my $child (@{$element->{'section_childs'}})
            {
                $section_childs .= "$child->{'texi'}|";
            }
        }
        print STDERR "  s_chs: $section_childs\n" if ($section_childs ne '');
        my $node_childs = '';
        if (defined($element->{'node_childs'}))
        {
            foreach my $child (@{$element->{'node_childs'}})
            {
                $node_childs .= "$child->{'texi'}|";
            }
        }
        print STDERR "  n_chs: $node_childs\n" if ($node_childs ne '');

        if (defined($element->{'menu_up_hash'}))
        {
            print STDERR "  parent nodes:\n";
            foreach my $menu_up (keys%{$element->{'menu_up_hash'}})
            {
                print STDERR "   $menu_up ($element->{'menu_up_hash'}->{$menu_up})\n";
            }
        }
        print STDERR "  places: $element->{'place'}\n";
        foreach my $place(@{$element->{'place'}})
        {
            if (!$place->{'entry'} and !$place->{'float'} and !$place->{'texi'} and !$place->{'contents'} and !$place->{'shortcontents'} and (!defined($place->{'command'} or $place->{'command'} ne 'printindex')))
            {
                 print STDERR "BUG: unknown placed stuff ========\n";
                 foreach my $key (keys(%$place))
                 {
                      print STDERR "$key: $place->{$key}\n";
                 }
                 print STDERR "==================================\n";
            }
            elsif ($place->{'entry'})
            {
                print STDERR "    index($place): $place->{'entry'} ($place->{'id'}, $place->{'file'})\n";
            }
            elsif ($place->{'anchor'})
            {
                print STDERR "    anchor: $place->{'texi'} ($place->{'id'}, $place->{'file'})\n";
            }
            elsif ($place->{'float'})
            {
                if (defined($place->{'texi'}))
                {
                    print STDERR "    float($place): $place->{'texi'} ($place->{'id'}, $place->{'file'})\n";
                }
                else
                {
                    print STDERR "    float($place): NO LABEL ($place->{'id'}, $place->{'file'})\n";
                }
            }
            elsif ($place->{'contents'})
            {
                print STDERR "    contents\n";
            }
            elsif ($place->{'shortcontents'})
            {
                print STDERR "    shortcontents\n";
            }
            elsif (defined($place->{'command'}) and $place->{'command'} eq 'printindex')
            {
                print STDERR "    printindex $place->{'name'}\n";
            }
            else
            {
                print STDERR "    heading: $place->{'texi'} ($place->{'id'}, $place->{'file'})\n";
            }
        }
    }
    ########################### end debug prints
}

sub add_file($)
{
    my  $file = shift;
    if ($files{$file})
    {
         $files{$file}->{'counter'}++;
    }
    else
    {
         $files{$file} = { 
           'counter' => 1,
           'relative_foot_num' => 0,
           'foot_lines' => []
         };
    }
}

# find parent element which is a toplevel element
sub get_top($)
{
   my $element = shift;
   if ($element->{'node'})
   {
      if (defined($element->{'section_ref'}))
      {
         $element = $element->{'section_ref'};
      }
      else
      {
         return undef;
      }
   }
   return undef if ($element eq $element_before_anything);
   my $up = $element;
   while (!$up->{'toplevel'} and $up->{'tag'} ne 'top')
   {
       if (!defined($up->{'sectionup'}))
       {
           # If there is no section, it is normal not to have toplevel element,
           # and it is also the case if there is a low level element before
           # a top level element
           return undef;
       }
       $up = $up->{'sectionup'};
   }
   return $up;
}

sub get_node($)
{
    my $element = shift;
    return undef if (!defined($element));
    return $element if ($element->{'node'});
    return $element->{'with_node'} if ($element->{'with_node'});
}

sub do_section_names($$)
{
    my $number = shift;
    my $section = shift;
    my $texi = &$Texi2HTML::Config::heading_texi($section->{'tag'}, $section->{'texi'}, $section->{'number'});
    $section->{'text'} = substitute_line($texi, "\@$section->{'tag'}", undef, $section->{'line_nr'});
    # no need for translation since there is no line number it should never
    # appear in error messages.
    $section->{'text_nonumber'} = substitute_line($section->{'texi'}, "\@$section->{'tag'} no number");
    # backward compatibility
    # Removed from doc in nov 2009
    $section->{'name'} = $section->{'text_nonumber'};
    $section->{'no_texi'} = remove_texi($texi);
    $section->{'simple_format'} = simple_format(undef,undef,"\@$section->{'tag'} simple_format", $texi);
    $section->{'heading_texi'} = $texi;
}

# get the html names from the texi for all elements
sub do_names()
{
   print STDERR "# Doing ". scalar(keys(%nodes)) . " nodes, ".
       scalar(keys(%sections)) . " sections, " .
       scalar(keys(%headings)) . " headings in ". $#elements_list . 
       " elements\n" if ($T2H_DEBUG);
   # for nodes and anchors we haven't any state defined
   # This seems right, however, as we don't want @refs or @footnotes
   # or @anchors within nodes, section commands or anchors.
   $global_pass = '2 node names';
   foreach my $node (keys(%nodes))
   {
       my $texi = &$Texi2HTML::Config::heading_texi($nodes{$node}->{'tag'}, 
          $nodes{$node}->{'texi'}, undef);
       my $command = 'node';
       $command = $nodes{$node}->{'tag'} if ($nodes{$node}->{'tag'});
       $nodes{$node}->{'text'} = substitute_line ($texi, "\@$command", {'code_style' => 1}, $nodes{$node}->{'line_nr'});
       $nodes{$node}->{'text_nonumber'} = $nodes{$node}->{'text'};
       # backward compatibility -> maybe used to have the name without code_style ?
       # Removed from doc in nov 2009
       $nodes{$node}->{'name'} = substitute_line($texi, "\@$command name");
       $nodes{$node}->{'no_texi'} = remove_texi($texi);
       $nodes{$node}->{'simple_format'} = simple_format(undef, undef, "\@$command simple_format", $texi);
       $nodes{$node}->{'heading_texi'} = $texi;
       
       ################# debug
       # if $nodes{$node}->{'external_node'} and $nodes{$node}->{'seen'}
       # this is a bug, since there are checks that the node hasn't an
       # external node syntax.
       msg_debug ("$nodes{$node}->{'texi'} is external and was seen",  $nodes{$node}->{'line_nr'}) if ($nodes{$node}->{'seen'} and $nodes{$node}->{'external_node'});
       ################# end debug
   }
   $global_pass = '2 section names';
   foreach my $number (keys(%sections))
   {
       do_section_names($number, $sections{$number});
   }
   $global_pass = '2 heading names';
   foreach my $number (keys(%headings))
   {
       do_section_names($number, $headings{$number});
   }
   print STDERR "# Names done\n" if ($T2H_DEBUG);
}


#+++############################################################################
#                                                                              #
# Stuff related to Index generation                                            #
#                                                                              #
#---############################################################################

# called during pass_structure
sub enter_index_entry($$$$$)
{
    my $prefix = shift;
    my $line_nr = shift;
    my $entry = shift;
    my $command = shift;
    my $state = shift;

    my $heading_element = $state->{'heading_element'};
    my $current_element = $state->{'current_element'};
    my $place = $state->{'place'};
    my $region = $state->{'region'};

    my $index_name = $index_prefix_to_name{$prefix};
    if (!defined($index_name))
    {
        line_error (sprintf(__("Unknown index `%s'"), $prefix), $line_nr);
    }
    if ($current_element eq $element_before_anything)
    {
        #line_warn ("Index entry before document: \@${prefix}index $entry", $line_nr); 
        line_error (sprintf(__("Entry for index `%s' outside of any node"), $index_name), $line_nr);
    }
    $entry = trim_comment_spaces ($entry, "index entry in \@$command", $line_nr);
    # beware that the texinfo could be non empty, but the no_texi be empty. 
    # So the $no_texi should be used to determine whether the entry is 
    # empty or not.
    my $no_texi = remove_texi($entry);

    my $id;
    # don't add a specific index target if the index entry is in a special
    # region like @copying or the like or the index is not defined
    if (!defined($region))
    {
        $region = 'document';
        # No id if the index is unknown.
        $id = 'IDX' . ++$document_idx_num if (defined($index_name));
    }
    my $target = $id;

    # entry will later be in @code for code-like index entry. texi stays
    # the same.
    my $index_entry = {
           'entry'    => $entry,
           'texi'     => $entry,
           'element'  => $heading_element,
           'real_element'  => $current_element,
           'prefix'   => $prefix,
           'id'       => $id,
           'target'   => $target,
           'command'  => $command,
           'region'   => $state->{'region'},
           'line_nr'  => $line_nr,
           'index_name' => $index_name
    };
    
    my $id_text = $id;
    $id_text = 'NO ID' if (!defined($id));
    print STDERR "# in $region enter \@$command ${prefix}index($no_texi) [$entry] with id $id_text ($index_entry)\n"
        if ($T2H_DEBUG & $DEBUG_INDEX);

    $index_entry->{'entry'} = '@code{'.$index_entry->{'entry'}.'}'
       if (defined($index_name) and 
        defined($index_names{$index_name}->{'prefixes'}) and 
        $index_names{$index_name}->{'prefixes'}->{$prefix} 
        and $no_texi =~ /\S/);

    push @$place, $index_entry;

    #msg_debug("enter_index_entry: region $region, index_entry $index_entry, \@$command, texi `$entry'", $line_nr);

    # don't add the index entry to the list of index entries used for index
    # entry formatting, if the index entry appears in a region like copying 
    # currently this is only used for debugging purposes, since the 
    # index entries lists are broken by region now.
    push @index_labels, $index_entry unless (defined($state->{'region'}));

    # these lists are used to retrieve index entries in pass 3
    push @{$Texi2HTML::THISDOC{'index_entries'}->{$region}->{$entry}->{'entries'}}, $index_entry;
    if (defined($index_name))
    {
        # this is used for @printindex
        push @{$Texi2HTML::THISDOC{'index_entries_array'}->{$index_name}}, $index_entry;
        # this is used for targets
        push @{$Texi2HTML::THISDOC{'index_entries_region_array'}->{$region}}, $index_entry;
    }
    else
    {
        push @unknown_index_index_entries, $index_entry;
    }
}

# these variables are global, so great care should be taken with
# state->{'multiple_state'}, ->{'region'}, ->{'region_pass'} and
# {'outside_document'}.
my $global_head_num = 0;       # heading index. it is global for the main doc, 
                               # and taken from the state if in multiple_pass.
my $global_foot_num = 0;
my $global_relative_foot_num = 0;
my @foot_lines = ();           # footnotes
my $copying_comment = '';      # comment constructed from text between
                               # @copying and @end copying with licence
my %acronyms_like = ();        # acronyms or similar commands associated texts
                               # the key are the commands, the values are
                               # hash references associating shorthands to
                               # texts.

# detailmenu    number of opened detailed menus
sub fill_state($)
{
    my $state = shift;
    foreach my $key ('preformatted', 'code_style', 'math_style', 'keep_texi',
      'keep_nr',  'detailmenu', 'direntry', 'sec_num', 'menu', 'multiple_pass')
    {
        $state->{$key} = 0 unless exists($state->{$key});
    }
       
    $state->{'paragraph_style'} = [ '' ] unless exists($state->{'paragraph_style'}); 
    $state->{'preformatted_stack'} = [ '' ] unless exists($state->{'preformatted_stack'}); 
    $state->{'command_stack'} = [] unless exists($state->{'command_stack'});
    $state->{'quotation_stack'} = [] unless exists($state->{'quotation_stack'});
    # if there is no $state->{'element'} the first element is used
    if ((!$state->{'element'} or $state->{'element'}->{'before_anything'}) and (@elements_list))
    {
        $state->{'element'} = $elements_list[0];
    }
    # this is consistent with what is done in rearrange_elements
    $state->{'element'} = {'file' => $docu_doc, 'texi' => 'VIRTUAL ELEMENT'} if (!$state->{'element'});
}

sub do_element_directions ($)
{
   my $this_element = shift;
   #print STDERR "Doing hrefs for $this_element->{'texi'} First ";
   $Texi2HTML::HREF{'First'} = href($element_first, $this_element->{'file'});
   #print STDERR "Last ";
   $Texi2HTML::HREF{'Last'} = href($element_last, $this_element->{'file'});
   #print STDERR "Index ";
   $Texi2HTML::HREF{'Index'} = href($element_chapter_index, $this_element->{'file'}) if (defined($element_chapter_index));
   #print STDERR "Top ";
   $Texi2HTML::HREF{'Top'} = href($element_top, $this_element->{'file'});
   if ($Texi2HTML::Config::INLINE_CONTENTS)
   {
      $Texi2HTML::HREF{'Contents'} = href($content_element{'contents'}, $this_element->{'file'});
      $Texi2HTML::HREF{'Overview'} = href($content_element{'shortcontents'}, $this_element->{'file'});
   }
   else 
   {
      $Texi2HTML::HREF{'Contents'} = file_target_href($Texi2HTML::THISDOC{'toc_file'}, $this_element->{'file'}, $content_element{'contents'}->{'target'}) if (@{$Texi2HTML::TOC_LINES} and defined($content_element{'contents'}));
      $Texi2HTML::HREF{'Overview'} = file_target_href($Texi2HTML::THISDOC{'stoc_file'}, $this_element->{'file'}, $content_element{'shortcontents'}->{'target'}) if (@{$Texi2HTML::OVERVIEW} and defined($content_element{'shortcontents'}));
   }
   if ($Texi2HTML::THISDOC{'do_about'})
   {
      $Texi2HTML::HREF{'About'} = file_target_href($docu_about, $this_element->{'file'}, $Texi2HTML::Config::misc_pages_targets{'About'});
   }
   $Texi2HTML::HREF{'Footnotes'} = file_target_href($docu_foot, $this_element->{'file'}, $Texi2HTML::Config::misc_pages_targets{'Footnotes'});
   foreach my $direction (@element_directions)
   {
      my $elem = $this_element->{$direction};
      $Texi2HTML::NODE{$direction} = undef;
      $Texi2HTML::HREF{$direction} = undef;
      $Texi2HTML::NAME{$direction} = undef;
      #print STDERR "$direction \n";
      next unless (defined($elem));
      if ($elem->{'node'} or $elem->{'external_node'} or !$elem->{'seen'})
      {
         $Texi2HTML::NODE{$direction} = $elem->{'text'};
      }
      elsif ($elem->{'with_node'})
      {
         $Texi2HTML::NODE{$direction} = $elem->{'with_node'}->{'text'};
      }
      if (!$elem->{'seen'})
      {
         $Texi2HTML::HREF{$direction} = do_external_href($elem->{'texi'});
      }
      else
      {
         $Texi2HTML::HREF{$direction} = href($elem, $this_element->{'file'});
      }
      $Texi2HTML::NAME{$direction} = $elem->{'text'};
      $Texi2HTML::NO_TEXI{$direction} = $elem->{'no_texi'};
      $Texi2HTML::SIMPLE_TEXT{$direction} = $elem->{'simple_format'};
      #print STDERR "$direction ($this_element->{'texi'}): \n  NO_TEXI: $Texi2HTML::NO_TEXI{$direction}\n  NAME $Texi2HTML::NAME{$direction}\n  NODE $Texi2HTML::NODE{$direction}\n  HREF $Texi2HTML::HREF{$direction}\n\n";
   }
   #print STDERR "\nDone hrefs for $this_element->{'texi'}\n";
}

sub open_out_file($)
{
  my $new_file = shift;
  my $do_page_head = 0;
  # if the filehandle is closed, with fileno undef, open_out
  # is called with the second argument true, which leads to opening
  # the file in append mode, to avoid overwriting the previous
  # file.
  if ($files{$new_file}->{'filehandle'} and defined(fileno($files{$new_file}->{'filehandle'})))
  {
    $Texi2HTML::THISDOC{'FH'} = $files{$new_file}->{'filehandle'};
  }
  else
  {
    my $known_file = 0;
    if ($files{$new_file}->{'filehandle'})
    {
       $known_file = 1;
       document_warn ("The file $new_file was already closed and is reopened");
    }
    $Texi2HTML::THISDOC{'FH'} = open_out("$docu_rdir$new_file", $known_file);
#print STDERR "OPEN $docu_rdir$file, $Texi2HTML::THISDOC{'FH'}". scalar($Texi2HTML::THISDOC{'FH'})."\n";
    $files{$new_file}->{'filehandle'} = $Texi2HTML::THISDOC{'FH'};
    $do_page_head = !$known_file;
  }
  return $do_page_head;
}

sub set_line_nr_in_stack($$$)
{
   my $state = shift;
   my $stack = shift;
   my $line_nr = shift;

   if ($state->{'keep_texi'} and defined($line_nr))
   {
        my $stack_index = $#$stack;
        while ($stack_index >= 0 and defined($stack->[$stack_index]->{'keep_line_nr'}))
        {
            push @{$stack->[$stack_index]->{'keep_line_nr'}}, $line_nr;
            $stack_index --;
        }
    }
}

sub unref_file($)
{
    my $file = shift;
    $files{$file}->{'counter'}--;
    print STDERR "# Unref file $file, remaining counter $files{$file}->{'counter'}\n"
                 if ($T2H_DEBUG & $DEBUG_ELEMENTS);

}

sub pass_text($$)
{
    my $doc_lines = shift;
    my $doc_numbers = shift;
    my %state;
    fill_state(\%state);
    my @stack;
    my $text = '';
    my $doc_nr;
    my $in_doc = 0;
    my @text =();
    my $one_section = 1 if (@elements_list <= 1);

    push_state(\%state);

    $global_pass = '3 prepare names';
    set_special_names();
    $footnote_element->{'text'} = $Texi2HTML::NAME{'Footnotes'};
    # We set titlefont only if the titlefont appeared in the top element
    if (defined($element_top->{'titlefont'}))
    {
         $Texi2HTML::THISDOC{'titlefont_texi'} = $element_top->{'titlefont'};
         # backward compatibility nov 2009
         $value{'_titlefont'} = $element_top->{'titlefont'};
    }
    
    # prepare %Texi2HTML::THISDOC
    $Texi2HTML::THISDOC{'command_stack'} = $state{'command_stack'};

    #foreach my $texi_cmd (('shorttitlepage', 'settitle', 'author', 'title',
    #       'subtitle'))
    #{
    #    $Texi2HTML::THISDOC{$texi_cmd . '_texi'} = $value{'_' . $texi_cmd};
    #}
    $Texi2HTML::THISDOC{'top_texi'} = $section_top->{'texi'} if (defined($section_top));

    $Texi2HTML::THISDOC{'fulltitle_texi'} = '';
    foreach my $possible_fulltitle('settitle', 'title', 'shorttitlepage', 'top', 'titlefont')
    {
        if (defined($Texi2HTML::THISDOC{$possible_fulltitle . '_texi'}) and $Texi2HTML::THISDOC{$possible_fulltitle . '_texi'} =~ /\S/)
        {
            $Texi2HTML::THISDOC{'fulltitle_texi'} = $Texi2HTML::THISDOC{$possible_fulltitle . '_texi'};
            last;
        }
    }
    $Texi2HTML::THISDOC{'simpletitle_texi'} = '';
    foreach my $possible_simpletitle('settitle', 'shorttitlepage')
    {
        if (defined($Texi2HTML::THISDOC{$possible_simpletitle . '_texi'}) and $Texi2HTML::THISDOC{$possible_simpletitle . '_texi'} =~ /\S/)
        {
            $Texi2HTML::THISDOC{'simpletitle_texi'} = $Texi2HTML::THISDOC{$possible_simpletitle . '_texi'};
            last;
        }
    }

    foreach my $doc_thing (('shorttitlepage', 'settitle', 'author',
           'titlefont', 'subtitle', 'title', 'fulltitle', 'simpletitle'))
    {
        my $thing_texi = $Texi2HTML::THISDOC{$doc_thing . '_texi'};
        $Texi2HTML::THISDOC{$doc_thing} = substitute_line($thing_texi, "\@$doc_thing", undef, $Texi2HTML::THISDOC{$doc_thing . '_line_nr'});
        $Texi2HTML::THISDOC{$doc_thing . '_no_texi'} =
           remove_texi($thing_texi);
        $Texi2HTML::THISDOC{$doc_thing . '_simple_format'} =
           simple_format(undef, undef, "simple_format \@$doc_thing", $thing_texi);
    }


    # find the triplet (Top name, Top with texi removed, Top simply formatted)
    # the corresponding href is used a lot but these are only used because
    # they are used in LINKS_BUTTONS...

    my $element_top_Top = [undef,undef,undef];
    my $node_top_Top = [undef,undef,undef];
    # Preferred Top name is the element_top name if it is not the @node Top
    # the @node Top may also be used, but before fulltitle is tried
    if (defined($element_top))
    {
        if ($element_top->{'node'} and $element_top->{'texi'} =~ /^Top$/i)
        {
           $node_top_Top = [ $element_top->{'text'}, $element_top->{'no_texi'}, $element_top->{'simple_format'} ];
        }
        else
        {
           $element_top_Top = [ $element_top->{'text'}, $element_top->{'no_texi'}, $element_top->{'simple_format'} ];
        }
    }
    # FIXME remove fulltitle?
    foreach my $possible_top (
       [substitute_line($Texi2HTML::Config::TOP_HEADING, '$TOP_HEADING'), 
        remove_texi($Texi2HTML::Config::TOP_HEADING), 
        simple_format(undef, undef, 'simple_format $TOP_HEADING', $Texi2HTML::Config::TOP_HEADING)],
       $element_top_Top,
       [$Texi2HTML::THISDOC{'fulltitle'}, 
        $Texi2HTML::THISDOC{'fulltitle_no_texi'}, 
        $Texi2HTML::THISDOC{'fulltitle_simple_format'}],
       $node_top_Top
      )
    {
        if (defined($possible_top->[0]) and $possible_top->[0] =~ /\S/)
        {
           ($Texi2HTML::NAME{'Top'}, $Texi2HTML::NO_TEXI{'Top'}, $Texi2HTML::SIMPLE_TEXT{'Top'}) = @$possible_top;
           last;
        }
    }
     
    $Texi2HTML::THISDOC{'program'} = $THISPROG;
    $Texi2HTML::THISDOC{'program_homepage'} = $T2H_HOMEPAGE;
    $Texi2HTML::THISDOC{'program_authors'} = $T2H_AUTHORS;
    foreach my $command (('authors', 'subtitles', 'titles'))
    {
        $Texi2HTML::THISDOC{$command} = [];
        my $i;
        for ($i = 0; $i < $#{$Texi2HTML::THISDOC{$command .'_texi'}} + 1; $i++) 
        {
            my $texi_line = $Texi2HTML::THISDOC{$command .'_texi'}->[$i];
            my $command_line_nr = $Texi2HTML::THISDOC{$command .'_line_nr'}->[$i];
            chomp ($texi_line);
            $Texi2HTML::THISDOC{$command}->[$i] = substitute_line($texi_line, "\@$command", undef, $command_line_nr);
            #print STDERR "$command:$i: $Texi2HTML::THISDOC{$command}->[$i]\n";
        }
    }

    $Texi2HTML::THISDOC{'do_about'} = 1 unless (defined($Texi2HTML::THISDOC{'do_about'}) or $one_section or (not Texi2HTML::Config::get_conf('SPLIT') and not Texi2HTML::Config::get_conf('headers')));
    
    $Texi2HTML::NAME{'First'} = $element_first->{'text'};
    $Texi2HTML::NAME{'Last'} = $element_last->{'text'};
    $Texi2HTML::NAME{'Index'} = $element_chapter_index->{'text'} if (defined($element_chapter_index));
    $Texi2HTML::NAME{'Index'} = $Texi2HTML::Config::INDEX_CHAPTER if ($Texi2HTML::Config::INDEX_CHAPTER ne '');

    $Texi2HTML::NO_TEXI{'First'} = $element_first->{'no_texi'};
    $Texi2HTML::NO_TEXI{'Last'} = $element_last->{'no_texi'};
    $Texi2HTML::NO_TEXI{'Index'} = $element_chapter_index->{'no_texi'} if (defined($element_chapter_index));
    $Texi2HTML::SIMPLE_TEXT{'First'} = $element_first->{'simple_format'};
    $Texi2HTML::SIMPLE_TEXT{'Last'} = $element_last->{'simple_format'};
    $Texi2HTML::SIMPLE_TEXT{'Index'} = $element_chapter_index->{'simple_format'} if (defined($element_chapter_index));

    # We do the regions formatting here, even if they never appear.
    # so we should be very carefull to take into accout 'outside_document' to
    # avoid messing with information that has to be set in the main document.
    # FIXME also the error messages will appear even though the corresponding 
    # texinfo is never used. Since no state is passed to the do_special_region_lines
    # 'outside_document' will be true. Also 'multiple_pass' is equal to -1
    # for this case.
    $global_pass = '3 prepare regions';

    my ($region_text, $region_no_texi, $region_simple_format);
    ($region_text, $region_no_texi, $region_simple_format) = do_special_region_lines('documentdescription');
    &$Texi2HTML::Config::documentdescription($region_lines{'documentdescription'}, $region_text, $region_no_texi, $region_simple_format);
    
    # do copyright notice inserted in comment at the beginning of the files
    ($region_text, $region_no_texi, $region_simple_format) = do_special_region_lines('copying');
    $copying_comment = &$Texi2HTML::Config::copying_comment($region_lines{'copying'}, $region_text, $region_no_texi, $region_simple_format);

    $Texi2HTML::THISDOC{'copying_comment'} = $copying_comment;
    # must be after toc_body, but before titlepage
    foreach my $command ('contents', 'shortcontents')
    {
        next if (!defined($content_element{$command}));
        my $toc_lines = &$Texi2HTML::Config::inline_contents(undef, $command, $content_element{$command}, \@sections_list);
        @{$Texi2HTML::THISDOC{'inline_contents'}->{$command}} = @$toc_lines if (defined($toc_lines));
    }
    
    ($region_text, $region_no_texi, $region_simple_format) = do_special_region_lines('titlepage');

    &$Texi2HTML::Config::titlepage($region_lines{'titlepage'}, $region_text, $region_no_texi, $region_simple_format);

    $global_pass = '3';
    &$Texi2HTML::Config::init_out();

    # FIXME It is not clear whether it should be here or before 
    # command_handler_output calls. After, it means that 
    # command_handler_output may modify the initializations. Before
    # it allows to look at the values from the preceding pass.
    texinfo_initialization(2);

    foreach my $handler(@Texi2HTML::Config::command_handler_output)
    {
        &$handler;
    }

    ############################################################################
    # print frame and frame toc file
    #
    if ( $Texi2HTML::Config::FRAMES )
    {
        my $FH = open_out($docu_frame_file);
        print STDERR "# Creating frame in $docu_frame_file ...\n" if $T2H_VERBOSE;
        &$Texi2HTML::Config::print_frame($FH, $docu_toc_frame_file, $docu_top_file);
        close_out($FH, $docu_frame_file);

        $FH = open_out($docu_toc_frame_file);
        print STDERR "# Creating toc frame in $docu_frame_file ...\n" if $T2H_VERBOSE;
        &$Texi2HTML::Config::print_toc_frame($FH, $Texi2HTML::OVERVIEW);
        close_out($FH, $docu_toc_frame_file);
    }



    ############################################################################
    # Start processing the document
    #

    #my $FH;
    my $line_nr;
    my $current_file;
    my $first_section = 0; # 1 if it is the first section of a page
    my $previous_is_top = 0; # 1 if it is the element following the top element

    my $cline;
    # this is true for the state that goes through the document
    $state{'inside_document'} = 1;
    while (@$doc_lines)
    {
        $cline = shift @$doc_lines;
        my $chomped_line = $cline;
        if (!chomp($chomped_line) and @$doc_lines)
        { # if the line has no end of line it is concatenated with the next
          # this shouldn't happen anymore. And will certainly mess up
          # line counting. Let it be a bug.
          msg_debug ("no end of line line passed in doc_line",$line_nr);
             $doc_lines->[0] = $cline . $doc_lines->[0];
             next;
        }
        $line_nr = shift (@$doc_numbers);
        $Texi2HTML::THISDOC{'line_nr'} = $line_nr;
        print STDERR "BUG: line_nr not defined in pass_text. cline: $cline" if (!defined($cline));
	#dump_stack(\$text, \@stack, \%state);

        # make sure the current state from here is $Texi2HTML::THIS_ELEMENT
        # in case it was set by the user.
        $state{'element'} = $Texi2HTML::THIS_ELEMENT if (defined($Texi2HTML::THIS_ELEMENT));
	#print STDERR "PASS_TEXT($line_nr->{'line_nr'})$cline";
        if (!$state{'raw'} and !$state{'verb'})
        {
            my $tag = '';
            $tag = $1 if ($cline =~ /^\@(\w+)/);
            if ($tag eq 'setfilename' and $Texi2HTML::Config::IGNORE_BEFORE_SETFILENAME)
            {
                if (defined($Texi2HTML::THIS_ELEMENT))
                {
                    line_warn (sprintf(__("\@%s after the first element"), $tag), $line_nr);
                }
                else
                {
                    @{$Texi2HTML::THIS_SECTION} = ();
                }
            }

            if (($tag eq 'node') or (defined($sec2level{$tag}) and ($tag !~ /heading/)))
            {
                # in pass text node and section shouldn't appear in formats
			#print STDERR "close_stack before \@$tag\n";
			#print STDERR "text!$text%" if (! @stack);
                close_stack(\$text, \@stack, \%state, $line_nr);
                msg_debug ("text undef", $line_nr) if (!defined($text));
                push @{$Texi2HTML::THIS_SECTION}, $text if ($text ne '');
                $text = '';

                $state{'sec_num'}++ if ($sec2level{$tag} and ($tag ne 'top'));
                my $new_element;
                my $current_element;

                # handle node and structuring elements
                $current_element = shift (@all_elements);
                ########################## begin debug section
                if (!defined($current_element))
                {
                    msg_debug ("No element left for $cline", $line_nr);
                }
                if ($current_element->{'node'})
                {
                    print STDERR 'NODE ' . "$current_element->{'texi'}($current_element->{'file'})" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
                    print STDERR "($current_element->{'section_ref'}->{'texi'})" if ($current_element->{'section_ref'} and ($T2H_DEBUG & $DEBUG_ELEMENTS));
                }
                else
                {
                    print STDERR 'SECTION ' . $current_element->{'texi'} if ($T2H_DEBUG & $DEBUG_ELEMENTS);
                }
                print STDERR ": $cline" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
                ########################## end debug section

                # The element begins a new section if there is no previous
                # or the reference element is not the same
                if (defined($current_element->{'element_ref'}) and (!$Texi2HTML::THIS_ELEMENT or ($current_element->{'element_ref'} ne $Texi2HTML::THIS_ELEMENT)))
                {
                    $new_element = $current_element->{'element_ref'};

                    ########################### debug
                    my $old = 'NO_OLD';
                    $old = $Texi2HTML::THIS_ELEMENT->{'texi'} if (defined($Texi2HTML::THIS_ELEMENT));
                    print STDERR "NEW: $new_element->{'texi'}, OLD: $old\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
                    ########################### end debug
                    # print the element that just finished
                    if ($Texi2HTML::THIS_ELEMENT)
                    {
                        finish_element($Texi2HTML::THISDOC{'FH'}, $Texi2HTML::THIS_ELEMENT, $new_element, $first_section);
                        $first_section = 0;
                        $previous_is_top = 0 if (!$Texi2HTML::THIS_ELEMENT->{'top'});
                        @{$Texi2HTML::THIS_SECTION} = ();
                    }
                    else
                    {
                        print STDERR "# Writing elements:" if ($T2H_VERBOSE);
                        if ($Texi2HTML::Config::IGNORE_PREAMBLE_TEXT)
                        {
                             @{$Texi2HTML::THIS_SECTION} = ();
                        }
                        # remove empty for the first document lines
                        shift @{$Texi2HTML::THIS_SECTION} while (@{$Texi2HTML::THIS_SECTION} and ($Texi2HTML::THIS_SECTION->[0] =~ /^\s*$/));
                        my $title = &$Texi2HTML::Config::print_title();
                        unshift @{$Texi2HTML::THIS_SECTION}, $title if (defined($title) and $title ne '');
                    }
                    # begin new element
                    $Texi2HTML::THIS_ELEMENT = $new_element;
                    $state{'element'} = $Texi2HTML::THIS_ELEMENT;

                    do_element_directions($Texi2HTML::THIS_ELEMENT);
                    unref_file ($Texi2HTML::THIS_ELEMENT->{'file'});
                    #if (!defined($previous_file) or ($Texi2HTML::THIS_ELEMENT->{'file'} ne $previous_file))
                    if (!defined($current_file) or ($Texi2HTML::THIS_ELEMENT->{'file'} ne $current_file))
                    {
                        $current_file = $Texi2HTML::THIS_ELEMENT->{'file'};
                        print STDERR "\n" if ($T2H_VERBOSE and !$T2H_DEBUG);
                        print STDERR "# Writing to $docu_rdir$current_file " if $T2H_VERBOSE;
                        my $do_page_head = open_out_file($current_file);
                        if ($Texi2HTML::THIS_ELEMENT->{'top'})
                        {
                             &$Texi2HTML::Config::print_Top_header($Texi2HTML::THISDOC{'FH'}, $do_page_head);
                             $previous_is_top = 1;
                        }
                        else
                        {
                             &$Texi2HTML::Config::print_page_head($Texi2HTML::THISDOC{'FH'}) if ($do_page_head);
                             &$Texi2HTML::Config::print_chapter_header($Texi2HTML::THISDOC{'FH'}, $Texi2HTML::THIS_ELEMENT) if Texi2HTML::Config::get_conf('SPLIT') eq 'chapter';
                             &$Texi2HTML::Config::print_section_header($Texi2HTML::THISDOC{'FH'}, $Texi2HTML::THIS_ELEMENT) if Texi2HTML::Config::get_conf('SPLIT') eq 'section';
                        }
                        $first_section = 1;
                    }
                    print STDERR "." if ($T2H_VERBOSE);
                    print STDERR "\n" if ($T2H_DEBUG);
                }
                
                my $cmd_line = $cline;
                $cmd_line =~ s/\@$tag\s*//;

                ######################## begin debug
                msg_debug ("Element $current_element current_element->{'tag_level'} not defined", $line_nr)
                   if (!defined($current_element->{'tag_level'}));
                msg_debug ("Element $current_element $tag ne ".var_to_str($current_element->{'tag'}), $line_nr)
                   if ($tag ne 'node' and (!defined($current_element->{'tag'}) or $tag ne $current_element->{'tag'}));
                msg_debug ("Element $current_element ".var_to_str($current_element->{'tag'})." is not a node, but tag is a node", $line_nr)
                  if ($tag eq 'node' and !$current_element->{'node'});
                ######################## end debug

                my $heading_formatted = &$Texi2HTML::Config::element_heading($current_element, $tag, $cmd_line, substitute_line($cmd_line, "\@$tag"), undef, $one_section, $current_element->{'this'}, $first_section, $current_element->{'top'}, $previous_is_top, $cline, $current_element->{'id'}, $new_element);
                push @{$Texi2HTML::THIS_SECTION}, $heading_formatted if (defined($heading_formatted) and ($heading_formatted ne ''));
                next;
            }
        }

        set_line_nr_in_stack(\%state, \@stack, $line_nr);
        scan_line($cline, \$text, \@stack, \%state, $line_nr);

	#print STDERR "after scan_line: $cline";
	#dump_stack(\$text, \@stack, \%state);
        next if (@stack);
        if ($text ne '')
        { 
            push @{$Texi2HTML::THIS_SECTION}, $text;
            $text = '';
        }
    }
    # close stack at the end of pass text
    close_stack(\$text, \@stack, \%state, $line_nr);
    if (defined($text))
    {
        push @{$Texi2HTML::THIS_SECTION}, $text;
    }
    print STDERR "\n" if ($T2H_VERBOSE);
 
    # if no sections, then simply print document as is
    if ($one_section)
    {
        # may happen if there are 0 sections
        if (! defined($Texi2HTML::THISDOC{'FH'}))
        {
          open_out_file($docu_doc);
          &$Texi2HTML::Config::print_page_head($Texi2HTML::THISDOC{'FH'});
          shift @{$Texi2HTML::THIS_SECTION} while (@{$Texi2HTML::THIS_SECTION} and ($Texi2HTML::THIS_SECTION->[0] =~ /^\s*$/));
          my $title = &$Texi2HTML::Config::print_title();
          unshift @{$Texi2HTML::THIS_SECTION}, $title if (defined($title) and $title ne '');
        }
        if (@foot_lines)
        {
            &$Texi2HTML::Config::foot_section (\@foot_lines);
            push @{$Texi2HTML::THIS_SECTION}, @foot_lines;
        }
        print STDERR "# Write the section $Texi2HTML::THIS_ELEMENT->{'texi'}\n" if ($T2H_VERBOSE);
        &$Texi2HTML::Config::one_section($Texi2HTML::THISDOC{'FH'}, $Texi2HTML::THIS_ELEMENT);
        close_out($Texi2HTML::THISDOC{'FH'}, $docu_doc_file);
        # no misc element is done
        return;
    }

    finish_element ($Texi2HTML::THISDOC{'FH'}, $Texi2HTML::THIS_ELEMENT, undef, $first_section);

    ############################################################################
    # Print ToC, Overview, Footnotes
    #
    foreach my $direction (@element_directions)
    {
        $Texi2HTML::HREF{$direction} = undef;
        delete $Texi2HTML::HREF{$direction};
        # it is better to undef in case the references to these hash entries
        # are used, as if deleted, the
        # references are still refering to the old, undeleted element
        # (we could do both)
        $Texi2HTML::NAME{$direction} = undef;
        $Texi2HTML::NO_TEXI{$direction} = undef;
        $Texi2HTML::SIMPLE_TEXT{$direction} = undef;
        $Texi2HTML::NODE{$direction} = undef;

        $Texi2HTML::THIS_ELEMENT = undef;
    }
    my $about_body;
    $about_body = &$Texi2HTML::Config::about_body() if (defined($Texi2HTML::Config::about_body));
    # @foot_lines is emptied in finish_element if footnotestyle separate
    my %misc_page_infos = (
       'Footnotes' => { 'file' => $docu_foot_file, 
          'relative_file' => $docu_foot, 
          'process' => $Texi2HTML::Config::print_Footnotes,
          'section' => \@foot_lines },
       'Contents' => { 'file' => $docu_toc_file,
           'relative_file' => $docu_toc, 
           'process' => $Texi2HTML::Config::print_Toc,
           'section' => $Texi2HTML::TOC_LINES },
       'Overview' => { 'file' => $docu_stoc_file,
           'relative_file' => $docu_stoc, 
           'process' => $Texi2HTML::Config::print_Overview,
           'section' => $Texi2HTML::OVERVIEW },
       'About' => { 'file' => $docu_about_file,
           'relative_file' => $docu_about, 
            'process' => $Texi2HTML::Config::print_About,
            'section' => [$about_body] }
    );
    $misc_page_infos{'Footnotes'}->{'do'} = 1 if (@foot_lines);
    $misc_page_infos{'Contents'}->{'do'} = 1 if 
       (@{$Texi2HTML::TOC_LINES} and !$Texi2HTML::Config::INLINE_CONTENTS and (!Texi2HTML::Config::get_conf('setcontentsaftertitlepage') or !$Texi2HTML::Config::USE_TITLEPAGE_FOR_TITLE));
    $misc_page_infos{'Overview'}->{'do'} = 1 if
       (@{$Texi2HTML::OVERVIEW} and !$Texi2HTML::Config::INLINE_CONTENTS and (!Texi2HTML::Config::get_conf('setshortcontentsaftertitlepage') or !$Texi2HTML::Config::USE_TITLEPAGE_FOR_TITLE));
    $misc_page_infos{'About'}->{'do'} = 1 if ($about_body and $Texi2HTML::THISDOC{'do_about'});
         
    foreach my $misc_page('Footnotes', 'Contents', 'Overview', 'About')
    {
        next unless ($misc_page_infos{$misc_page}->{'do'});
        my $file = $misc_page_infos{$misc_page}->{'file'};
        my $relative_file = $misc_page_infos{$misc_page}->{'relative_file'};
        print STDERR "# writing $misc_page in $file\n" if $T2H_VERBOSE;
        my $saved_FH;
        my $open_new = 0;
        if ($relative_file ne $docu_doc)
        {
            $saved_FH = $Texi2HTML::THISDOC{'FH'};
            # Use open_out_file not to overwrite a file that the user would have
            # created
            open_out_file ($relative_file);
            print STDERR "# Opening $file for $misc_page\n" if $T2H_VERBOSE;
            $open_new = 1;
        }
        else
        {
            print STDERR "# writing $misc_page in current file\n" if $T2H_VERBOSE;
        }
        foreach my $href_page (keys(%misc_page_infos))
        {
            $Texi2HTML::HREF{$href_page} = file_target_href(
               $misc_page_infos{$href_page}->{'relative_file'}, $relative_file,
               $Texi2HTML::Config::misc_pages_targets{$href_page})
                 if ($misc_page_infos{$href_page}->{'do'});
        }
        #print STDERR "Doing hrefs for $misc_page First ";
        $Texi2HTML::HREF{'First'} = href($element_first, $relative_file);
        #print STDERR "Last ";
        $Texi2HTML::HREF{'Last'} = href($element_last, $relative_file);
        #print STDERR "Index ";
        $Texi2HTML::HREF{'Index'} = href($element_chapter_index, $relative_file) if (defined($element_chapter_index));
        #print STDERR "Top ";
        $Texi2HTML::HREF{'Top'} = href($element_top, $relative_file);
        if ($Texi2HTML::Config::INLINE_CONTENTS)
        {
            $Texi2HTML::HREF{'Contents'} = href($content_element{'contents'}, $relative_file);
            $Texi2HTML::HREF{'Overview'} = href($content_element{'shortcontents'}, $relative_file);
        }
        $Texi2HTML::HREF{$misc_page} = '#' . $Texi2HTML::Config::misc_pages_targets{$misc_page};
        $Texi2HTML::HREF{'This'} = $Texi2HTML::HREF{$misc_page};
        $Texi2HTML::NAME{'This'} = $Texi2HTML::NAME{$misc_page};
        $Texi2HTML::NO_TEXI{'This'} = $Texi2HTML::NO_TEXI{$misc_page};
        $Texi2HTML::SIMPLE_TEXT{'This'} = $Texi2HTML::SIMPLE_TEXT{$misc_page};
        $Texi2HTML::THIS_SECTION = $misc_page_infos{$misc_page}->{'section'}
            if defined($misc_page_infos{$misc_page}->{'section'});
        &{$misc_page_infos{$misc_page}->{'process'}}($Texi2HTML::THISDOC{'FH'}, $open_new, $misc_page);
        
        if ($open_new)
        {
            close_out($Texi2HTML::THISDOC{'FH'}, $file);
            $Texi2HTML::THISDOC{'FH'} = $saved_FH;
        }
    }
        
    unless (Texi2HTML::Config::get_conf('SPLIT'))
    {
        &$Texi2HTML::Config::print_page_foot($Texi2HTML::THISDOC{'FH'});
        # this leaves the possibility for external code to close the file
        # without erroring out
        close_out ($Texi2HTML::THISDOC{'FH'}, $docu_doc_file) if (fileno($Texi2HTML::THISDOC{'FH'}));
    }
    pop_state();
}

# print section, close file if needed.
sub finish_element($$$$)
{
    my $FH = shift;
    my $element = shift;
    my $new_element = shift;
    my $first_section = shift;
#print STDERR "FINISH_ELEMENT($FH)($element->{'texi'})[$element->{'file'}] counter $files{$element->{'file'}}->{'counter'}\n";

    # handle foot notes
    if (Texi2HTML::Config::get_conf('SPLIT') and scalar(@foot_lines) 
        and (Texi2HTML::Config::get_conf('footnotestyle') eq 'end')
        and  (! $new_element or
        ($element and ($new_element->{'file'} ne $element->{'file'})))
       )
    {
        if ($files{$element->{'file'}}->{'counter'})
        {# there are other elements in that page we are not on its foot
            $files{$element->{'file'}}->{'relative_foot_num'} 
               = $global_relative_foot_num;
            push @{$files{$element->{'file'}}->{'foot_lines'}},
                @foot_lines;
        }
        else
        {# we output the footnotes as we are at the file end
             unshift @foot_lines, @{$files{$element->{'file'}}->{'foot_lines'}};
             &$Texi2HTML::Config::foot_section (\@foot_lines);
             push @{$Texi2HTML::THIS_SECTION}, @foot_lines;
        }
        if ($new_element)
        {
            $global_relative_foot_num = 
               $files{$new_element->{'file'}}->{'relative_foot_num'};
        }
        @foot_lines = ();
    }

    if ($element->{'top'})
    {
        ############### debug
        #print STDERR "TOP $element->{'texi'}, @{$Texi2HTML::THIS_SECTION}\n";
        die "element->{'top'} $element ne element_top $element_top" if ($element ne $element_top);
        print STDERR "# Doing element top\n"
           if ($T2H_DEBUG & $DEBUG_ELEMENTS);
        print STDERR "[Top]" if ($T2H_VERBOSE);
        ############### end debug

        &$Texi2HTML::Config::print_Top($FH, $element->{'titlefont'}, $element);
        my $end_page = 0;
        if (Texi2HTML::Config::get_conf('SPLIT'))
        {
            if ($files{$element->{'file'}}->{'counter'} == 0)
            {
                $end_page = 1;
            }
        }
        &$Texi2HTML::Config::print_Top_footer($FH, $end_page, $element);
        close_out($FH, $docu_top_file) if ($end_page);
    }
    else
    {
        print STDERR "# do element $element->{'texi'}\n"
           if ($T2H_DEBUG & $DEBUG_ELEMENTS);
        &$Texi2HTML::Config::print_section($FH, $first_section, 0, $element);
        ################# debug
        my $new_elem_file = 'NO ELEM => no file';
        $new_elem_file = $new_element->{'file'} if (defined($new_element));
        print STDERR "# FILES new: $new_elem_file old(".fileno($FH)."): $element->{'file'}\n"
           if ($T2H_DEBUG & $DEBUG_ELEMENTS);
        ################# end debug
        if (defined($new_element) and ($new_element->{'file'} ne $element->{'file'}))
        {
            print STDERR "# End of section with change in file(".fileno($FH).") $element->{'file'} -> $new_element->{'file'}\n"
                 if ($T2H_DEBUG & $DEBUG_ELEMENTS);
             if (!$files{$element->{'file'}}->{'counter'})
             {
                 &$Texi2HTML::Config::print_chapter_footer($FH, $element) if (Texi2HTML::Config::get_conf('SPLIT') eq 'chapter');
                 &$Texi2HTML::Config::print_section_footer($FH, $element) if (Texi2HTML::Config::get_conf('SPLIT') eq 'section');
                 print STDERR "# Close file(".fileno($FH).") after $element->{'texi'}\n" 
                     if ($T2H_DEBUG & $DEBUG_ELEMENTS);
                 &$Texi2HTML::Config::print_page_foot($FH);
                 close_out($FH, "$docu_rdir$element->{'file'}");
             }
             else
             {
                 print STDERR "# Counter $files{$element->{'file'}}->{'counter'} ne 0, file(".fileno($FH).") $element->{'file'}\n"
                     if ($T2H_DEBUG & $DEBUG_ELEMENTS);
             }
        }
        elsif (!defined($new_element))
        {
            print STDERR "# End of last section, file(".fileno($FH).") $element->{'file'}, counter $files{$element->{'file'}}->{'counter'}\n"
                 if ($T2H_DEBUG & $DEBUG_ELEMENTS);
            if (Texi2HTML::Config::get_conf('SPLIT'))
            { # end of last splitted section
                &$Texi2HTML::Config::print_chapter_footer($FH, $element) if (Texi2HTML::Config::get_conf('SPLIT') eq 'chapter');
                &$Texi2HTML::Config::print_section_footer($FH, $element) if (Texi2HTML::Config::get_conf('SPLIT') eq 'section');
                &$Texi2HTML::Config::print_page_foot($FH);
                close_out($FH, "$docu_rdir$element->{'file'}");
            }
            else
            { # end of last unsplit section
                &$Texi2HTML::Config::end_section($FH, 1, $element);
            }
        }
        elsif ($new_element->{'top'})
        {
            print STDERR "# Section followed by Top, file(".fileno($FH).") counter $files{$element->{'file'}}->{'counter'}\n"
                     if ($T2H_DEBUG & $DEBUG_ELEMENTS);
            &$Texi2HTML::Config::end_section($FH, 1, $element);
        }
        else
        { # end of section followed by another one
            print STDERR "# Section followed by another one, file(".fileno($FH).") counter $files{$element->{'file'}}->{'counter'}\n"
                     if ($T2H_DEBUG & $DEBUG_ELEMENTS);
            &$Texi2HTML::Config::end_section($FH, 0, $element);
        }
    }
}

# write to files with name the node name for cross manual references.
sub do_node_files()
{
    foreach my $key (keys(%nodes))
    {
        my $node = $nodes{$key};
        next unless ($node->{'node_file'});
        my $redirection_file = $docu_doc;
        $redirection_file = $node->{'file'} if (Texi2HTML::Config::get_conf('SPLIT'));
        if (!$redirection_file)
        {
             print STDERR "Bug: file for redirection for `$node->{'texi'}' don't exist\n" unless (Texi2HTML::Config::get_conf('novalidate') or !$node->{'seen'});
             next;
        }
        next if ($redirection_file eq $node->{'node_file'});
        my $file = "${docu_rdir}$node->{'node_file'}";
        $Texi2HTML::NODE{'This'} = $node->{'text'};
        $Texi2HTML::NO_TEXI{'This'} = $node->{'no_texi'};
        $Texi2HTML::SIMPLE_TEXT{'This'} = $node->{'simple_format'};
        $Texi2HTML::NAME{'This'} = $node->{'text'};
        my $href_file = $node->{'file'};
        if (!defined($href_file))
        {
           if (Texi2HTML::Config::get_conf('novalidate'))
           {
               $href_file = '';
           }
           else
           {
               msg_debug ("Undefined file for `$node->{'texi'}' in do_node_files");
           }
        }
        $Texi2HTML::HREF{'This'} = "$href_file#$node->{'id'}";
        my $redirect = &$Texi2HTML::Config::print_redirection_page ();
        if (defined($redirect))
        {
           my $NODEFILE = open_out ($file);
           print $NODEFILE "$redirect";
           close $NODEFILE || document_error ("Can't close $file: $!", 1);
        }
    }
}

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

sub locate_include_file($)
{
    my $file = shift;

    # APA: Don't implicitely search ., to conform with the docs!
    
    # if file begins with /, ./ or ../ don't search in -I (Karl)
    if ($file =~ m,^(/|\./|\.\./),)
    {
        return "$file" if (-e "$file" && -r "$file");
        return undef;
    }
    foreach my $dir (@Texi2HTML::Config::INCLUDE_DIRS)
    {
        return "$dir/$file" if (-e "$dir/$file" && -r "$dir/$file");
    }
    return undef;
}

sub open_file($$$)
{
    my $name = shift;
#    my $line_number = shift;
    my $macro = shift;
    my $files_stack = shift;

    my $line_number;
    my $input_spool;
    
    local *FH;
    if (open(*FH, "<$name"))
    {
        my $in_encoding = Texi2HTML::Config::get_conf('IN_ENCODING');
        if (defined($in_encoding) and $Texi2HTML::Config::USE_UNICODE)
        {
            binmode(*FH, ":encoding($in_encoding)");
        }
        my $file = { 'fh' => *FH, 
           'input_spool' => { 'spool' => [], 
                              'macro' => '' },
           'name' => $name, 
           'line_nr' => 0 };
        unshift(@$files_stack, $file);
        $input_spool = $file->{'input_spool'};
        $line_number->{'file_name'} = $name;
        $line_number->{'line_nr'} = 1;
        $line_number->{'macro'} = $macro;
    }
    else
    {
        document_error ("Can't read file $name: $!", 1);
    }
    return ($line_number, $input_spool);
}

my %filehandles = ();

sub open_out($;$)
{
    my $file = shift;
    my $append = shift;
    local *FILE;
#print STDERR "open_out $file $Texi2HTML::THISDOC{'OUT_ENCODING'}\n";
    if ($file eq '-')
    {
        binmode(STDOUT, ":encoding($Texi2HTML::THISDOC{'OUT_ENCODING'})") if (defined($Texi2HTML::THISDOC{'OUT_ENCODING'}) and $Texi2HTML::Config::USE_UNICODE);
        return \*STDOUT;
    }

    my $mode = '>';
    $mode = '>>' if ($append);
    unless (open(FILE, $mode, $file))
    {
        document_error ("could not open $file for writing: $!", 1);
    }
    push @opened_files, $file;
    if (defined($Texi2HTML::THISDOC{'OUT_ENCODING'}) and $Texi2HTML::Config::USE_UNICODE)
    {
        if ($Texi2HTML::THISDOC{'OUT_ENCODING'} eq 'utf8' or $Texi2HTML::THISDOC{'OUT_ENCODING'} eq 'utf-8-strict')
        {
            binmode(FILE, ':utf8');
        }
	else
        {
            binmode(FILE, ':bytes');
            #binmode(FILE, ":encoding($Texi2HTML::THISDOC{'OUT_ENCODING'})");
        }
        # FIXME is it useful when in utf8?
        binmode(FILE, ":encoding($Texi2HTML::THISDOC{'OUT_ENCODING'})");
    }
    $file =~ s/^(\.[\/]+)*//;
    $filehandles{fileno(*FILE)} = $file;
    return *FILE;
}

sub close_out($$)
{
    my $FH = shift;
    my $file = shift;
    return if (defined($file) and $file eq '-');
    $file =~ s/^(\.[\/]+)*//;
    my $fileno = fileno($FH);
#print STDERR "close_out $file $fileno\n";
    if (!defined($fileno))
    {
       msg_debug("fileno not defined for $file") 
    }
    elsif (defined($filehandles{$fileno}) and $filehandles{$fileno} ne $file)
    {
       #msg_debug("filehandles{$fileno} $filehandles{$fileno} and file $file different")
    }
    close ($FH) || document_error ("Error when closing $file: $!");
}

sub next_line($$)
{
    my $line_number = shift;
    my $files_stack = shift;
    my $input_spool;
    while (@$files_stack)
    {
        my $file = $files_stack->[0];
        $line_number->{'file_name'} = $file->{'name'};
        $input_spool = $file->{'input_spool'};
        if (@{$input_spool->{'spool'}})
        {
             $line_number->{'macro'} = $file->{'input_spool'}->{'macro'};
             $line_number->{'line_nr'} = $file->{'line_nr'};
             my $line = shift(@{$input_spool->{'spool'}});
             print STDERR "# unspooling $line" if ($T2H_DEBUG & $DEBUG_MACROS);
             return($line, $input_spool);
        }
        else
        {
             $file->{'input_spool'}->{'macro'} = '';
             $line_number->{'macro'} = '';
        }
        my $fh = $file->{'fh'};
        no strict "refs";
        my $line = <$fh>;
        use strict "refs";
        my $chomped_line = $line;
        $file->{'line_nr'}++ if (defined($line) and chomp($chomped_line));
        $line_number->{'line_nr'} = $file->{'line_nr'};
        # do that right now, before any other treatement
        $line =~ s/\x{7F}.*\s*// if (defined($line));
        return($line, $input_spool) if (defined($line));
        no strict "refs";
        close($fh);
        use strict "refs";
        shift(@$files_stack);
    }
    return(undef, $input_spool);
}

sub check_die(;$)
{
   my $always_die = shift;

   if (!$Texi2HTML::Config::FORCE)
   {
       if (@opened_files == 1)
       {
           warn sprintf(__("%s: Removing output file `%s' due to errors; use --force to preserve.\n"), $real_command_name, $opened_files[0]);
       }
       elsif (@opened_files > 1)
       {
           warn sprintf(__("%s: Removing output files due to errors; use --force to preserve.\n"), $real_command_name);
       }
       foreach my $file (@opened_files)
       {
          unlink ($file);
       }
       foreach my $dir (@created_directories)
       {
          rmdir ($dir);
       }
   }
   if ($always_die or !$Texi2HTML::Config::FORCE)
   {
       exit (1);
   }
}

sub file_line_warn($$;$)
{
   return if ($Texi2HTML::Config::NO_WARN);
   my $text = shift;
   chomp($text);
   my $file = shift;
   my $line_nr = shift;

   if (!defined($line_nr))
   {
      warn "$file: $text\n";
   }
   else
   {
      warn "$file:$line_nr: $text\n";
   }
}

sub document_warn ($)
{
   return if ($Texi2HTML::Config::NO_WARN);
   my $text = shift;
   chomp ($text);
   warn sprintf(__p("warning: warning_message", "warning: %s\n"), $text);
}

my $error_nrs = 0;
sub check_errors()
{
   $error_nrs ++;
    die __("Too many errors!  Gave up.\n") if ($error_nrs >= $Texi2HTML::Config::ERROR_LIMIT);
}

sub msg_debug($;$)
{
   my $text = shift;
   chomp ($text);
   my $line_number = shift;
   if (defined($line_number))
   {
       warn "!! $text " . format_line_number($line_number) . "\n";
   }
   else
   {
       warn "!! $text\n";
   }
}

sub cmdline_warn ($)
{
   my $text = shift;
   #chomp ($text);
   warn sprintf(__p("command_name: warning_message", "%s: %s"), $real_command_name, $text);
}

# seems not to be used
sub cmdline_error ($)
{
   my $text = shift;
   #chomp ($text);
   warn sprintf(__p("command_name: error_message", "%s: %s"), $real_command_name, $text);
}

sub document_error($;$)
{
   my $text = shift;
   chomp ($text);
   my $die = shift;
   warn ("$text\n");
   check_die ($die);
   check_errors();
}

# echo an error
sub msg_error($;$)
{
    my $text = shift;
    my $line_number = shift;
    if (defined($line_number))
    {
         line_error ($text, $line_number);
    }
    else
    {
        document_error ($text);
    }
}

# echo a warning
sub msg_warn($;$$)
{
    my $text = shift;
    my $line_number = shift;
    my $context_string = shift;

    if (defined($line_number))
    {
         line_warn ($text, $line_number);
    }
    elsif (defined($context_string))
    {
        document_warn ("$text (in $context_string)");
    }
    else
    {
        document_warn ($text);
    }
}

# echo a warning associated with a line in the document
sub line_warn($$)
{
    return if ($Texi2HTML::Config::NO_WARN);
    my $text = shift;
    chomp ($text);
    my $line_number = shift;
    return if (!defined($line_number));
    my $file = $line_number->{'file_name'};
    # otherwise out of source build fail since the file names are different
    $file =~ s/^.*\/// if ($Texi2HTML::Config::TEST);
    if ($line_number->{'macro'} ne '')
    {
        warn sprintf(__("%s:%d: warning: %s (via \@%s)\n"), $file, $line_number->{'line_nr'}, $text, $line_number->{'macro'});
    }
    else
    {
        warn sprintf(__("%s:%d: warning: %s\n"), $file, $line_number->{'line_nr'}, $text);
    }
}

sub line_error($$)
{
    my $text = shift;
    chomp ($text);
    my $line_number = shift;
    if (defined($line_number))
    {
       my $file = $line_number->{'file_name'};
       $file =~ s/^.*\/// if ($Texi2HTML::Config::TEST);
       my $macro_text = '';
       $macro_text = " (via \@$line_number->{'macro'})" if ($line_number->{'macro'} ne '');
       warn "$file:$line_number->{'line_nr'}: $text$macro_text\n";
       check_die();
    }
    check_errors();
}

sub format_line_number(;$)
{
    my $line_number = shift;
    $line_number = $Texi2HTML::THISDOC{'line_nr'} if (!defined($line_number));
    my $macro_text = '';
    #$line_number = undef;
    return '' unless (defined($line_number));
    my $print_filename = ($line_number->{'file_name'} ne $Texi2HTML::THISDOC{'input_file_name'});
    if ($line_number->{'macro'} ne '')
    {
        if ($print_filename)
        {
            return sprintf(__("(in %s l. %d via \@%s)"), $line_number->{'file_name'}, $line_number->{'line_nr'}, $line_number->{'macro'});
        }
        else
        {
            return sprintf(__("(l. %d via \@%s)"), $line_number->{'line_nr'}, $line_number->{'macro'});
        }
    }
    elsif ($print_filename)
    {
        return sprintf(__("(in %s l. %d)"), $line_number->{'file_name'}, $line_number->{'line_nr'});
    }
    else
    {
        return sprintf(__("(l. %d)"), $line_number->{'line_nr'});
    }
}

# to debug, dump the result of pass_texi and pass_structure in a file
sub dump_texi($$;$$)
{
    my $lines = shift;
    my $pass = shift;
    my $numbers = shift;
    my $file = shift;
    $file = "$docu_rdir$docu_name" . ".pass$pass" if (!defined($file));
    my $FH = open_out($file);
    print STDERR "# Dump texi\n" if ($T2H_VERBOSE);
    my $index = 0;
    foreach my $line (@$lines)
    {
        my $number_information = '';
        my $chomped_line = $line;
        # if defined, it means that an output of the file is asked for
        if (defined($numbers))
        {
           my $basefile = $numbers->[$index]->{'file_name'};
           $basefile = 'no file' if (!defined($basefile));
           $basefile =~ s|.*/||;
           my $macro_name = $numbers->[$index]->{'macro'};
           $macro_name = '' if (!defined($macro_name));
           my $line_number = $numbers->[$index]->{'line_nr'};
           $line_number = '' if (!defined($line_number));
           $number_information = "${basefile}($macro_name,$line_number) ";
        }
        print $FH "${number_information}$line";
        $index++ if (chomp($chomped_line));
    }
    close_out ($FH, $file);
}


# return next tag on the line
sub next_tag($)
{
    my $line = shift;
    # macro_regexp
    if ($line =~ /^\s*\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/\\])/o or $line =~ /^\s*\@([a-zA-Z][\w-]*)/)
    {
        return ($1);
    }
    return '';
}

sub next_end_tag($)
{
    my $line = shift;
    if ($line =~ /^\s*\@end\s+([a-zA-Z][\w-]*)/)
    {
        return $1;
    }
    return '';
}

sub next_tag_or_end_tag($)
{
    my $line = shift;
    my $next_tag = next_tag($line);
    return $next_tag if (defined($next_tag) and $next_tag ne '');
    return next_end_tag($line);
}

sub top_stack($;$)
{
    my $stack = shift;
    my $ignore_para = shift;

    my $index = scalar (@$stack);
    return undef unless ($index);

    return $stack->[-1] unless ($ignore_para);
    if ($ignore_para == 1)
    {
       if (exists($stack->[-1]->{'format'}) and ($stack->[-1]->{'format'} eq 'paragraph' or $stack->[-1]->{'format'} eq 'preformatted'))
       {
          if (exists($stack->[-2]))
          {
              return $stack->[-2];
          }
          else 
          {
              return undef;
          }
       }
       else
       {
          return $stack->[-1];
       }
    }
    else
    {
        while ($index and 
          (
           (exists($stack->[$index-1]->{'format'})
            and ($stack->[$index-1]->{'format'} eq 'paragraph' or $stack->[$index-1]->{'format'} eq 'preformatted'))
           or (exists($stack->[$index-1]->{'style'}))
          ))
       {
           $index--;
       }
    }
    return undef unless ($index);
    return $stack->[$index-1];
}

# return the next element with balanced {}
sub next_bracketed($$$;$)
{
    my $line = shift;
    my $command = shift;
    my $line_nr = shift;
    my $report = shift;
    my $opened_braces = 0;
    my $result = '';
    my $spaces;
#print STDERR "next_bracketed  $line";
    if ($line =~ /^(\s*)$/)
    {
        return ('','',$1);
    }
    while ($line !~ /^\s*$/)
    {
#print STDERR "next_bracketed($opened_braces): $result !!! $line";
        if (!$opened_braces)
        { # beginning of item
            $line =~ s/^(\s*)//;
            $spaces = $1;
            #if ($line =~ s/^([^\{\}\s]+)//)
            if ($line =~ s/^([^\{\}]+?)(\s+)/$2/ or $line =~ s/^([^\{\}]+?)$//)
            {
                $result = $1;
                $result = trim_around_spaces($result);
                return ($result, $line, $spaces);
            }
            elsif ($line =~ s/^([^\{\}]+?)([\{\}])/$2/)
            {
                $result = $1;
            }
        }
        elsif($line =~ s/^([^\{\}]+)//)
        {
            $result .= $1;
        }
        if ($line =~ s/^([\{\}])//)
        {
            my $brace = $1;
            $opened_braces++ if ($brace eq '{');
            $opened_braces-- if ($brace eq '}');
    
            if ($opened_braces < 0)
            {
                line_error(sprintf(__("Too much '}' in \@%s"), $command), $line_nr) if ($report);
                $opened_braces = 0;
                #next;
            }
            $result .= $brace;
            return ($result, $line, $spaces) if ($opened_braces == 0);
        }
    }
    if ($opened_braces)
    {
        line_error(sprintf(__("Missing `}' on \@%s line"), $command), $line_nr) if ($report);
        return ($result, '', $spaces);
        #return ($result . ( '}' x $opened_braces), '', $spaces);
    }
    msg_debug ("BUG: at the end of next_bracketed", $line_nr);
    return undef;
}

# def prams are also split at @-commands if not in brackets
sub next_def_param($$$;$)
{
    my $line = shift;
    my $command = shift;
    my $line_nr = shift;
    my $report = shift;
    my ($item, $spaces);
    ($item, $line, $spaces) = next_bracketed($line, $command, $line_nr, $report);
    return ($item, $line, $spaces) if (!defined($item));
    if ($item =~ /^\{/)
    {
        $item =~ s/^\{(.*)\}$/$1/;
    }
    else
    { 
        my $delimeter_quoted = quotemeta($Texi2HTML::Config::def_argument_separator_delimiters);
        if ($item =~ s/^([^\@$delimeter_quoted]+)//)
        {
            $line = $item . $line;
            $item = $1;
        }
        elsif ($item =~ s/^([$delimeter_quoted])//)
        {
            $line = $item . $line;
            $item = $1;
        }
        elsif ($item =~ s/^(\@[^\@\{]+)(\@)/$2/)
        {
            $line = $item . $line;
            $item = $1;
        }
    }
    return ($item, $line, $spaces);
}

# do a href using file and id and taking care of ommitting file if it is 
# the same
# element: structuring element to point to
# file: current file
sub href($$;$)
{
    my $element = shift;
    my $file = shift;
    my $line_nr = shift;
    return '' unless defined($element);
    my $href = '';
    msg_debug("Bug: $element->{'texi'}, target undef", $line_nr) if (!defined($element->{'target'}));
    msg_debug("Bug: $element->{'texi'}, file undef", $line_nr) if (!defined($element->{'file'}));
    msg_debug("Bug: file undef in href", $line_nr) if (!defined($file));
    $href .= $element->{'file'} if (defined($element->{'file'}) and $file ne $element->{'file'});
    $href .= "#$element->{'target'}" if (defined($element->{'target'}));
    return $href;
}

sub file_target_href($$$)
{
    my $dest_file = shift;
    my $orig_file = shift;
    my $target = shift;
    my $href = '';
    $href .= $dest_file if (defined($dest_file) and ($dest_file ne $orig_file));
    $href .= "#$target" if (defined($target));
    return $href;
}

sub trim_around_spaces($)
{
   my $text = shift;
   $text =~ s/^\s*//;
   $text =~ s/(\s)\s*$/$1/;
   if ($text =~ /(\@+)\s$/)
   {
      my $arobases = $1;
      if ((length($arobases) % 2) == 0)
      {
          $text =~ s/\s$//;
      }
   }
   else
   {
      $text =~ s/\s$//;
   }
   return $text;
}

sub normalise_space($)
{
   return undef unless (defined ($_[0]));
   my $text = shift;
   $text =~ s/\s+/ /go;
   $text =~ s/ $//;
   $text =~ s/^ //;
   return $text;
}


sub normalise_texi_space($)
{
   return undef unless (defined ($_[0]));
   my $text = shift;
   $text = trim_around_spaces($text);
   $text =~ s/\s+/ /go;
   return $text;
}

sub normalise_node($)
{
    return undef unless (defined ($_[0]));
    my $text = shift;
    $text = normalise_texi_space($text);
    $text =~ s/^top$/Top/i;
    return $text;
}

sub normalise_node_array($)
{
    my $array = shift;
    my @result;
    foreach my $node (@$array)
    {
       push @result, normalise_node($node);
    }
    return @result;
}

sub do_anchor_label($$$$)
{
    my $command = shift;
    #my $anchor = shift;
    my $args = shift;
    my $anchor = $args->[0];
    my $style_stack = shift;
    my $state = shift;
    my $line_nr = shift;

    #msg_debug("do_anchor_label $state->{'region'} m_p $state->{'multiple_pass'} remove $state->{'remove_texi'} `$anchor'", $line_nr);

    $anchor = normalise_node($anchor);
    if ((defined($state->{'multiple_pass'}) and $state->{'multiple_pass'} > 0) or $state->{'outside_document'})
    {
       # no warning when outside of document.
       line_warn(sprintf(__("Anchor `%s' ignored in %s expanded more than once"),$anchor, $state->{'region'}), $line_nr) unless ($state->{'outside_document'} or defined($state->{'expansion'}));
       return '';
    }

    if (!exists($nodes{$anchor}) or !defined($nodes{$anchor}->{'id'}))
    {
        msg_debug("Unknown anchor `$anchor'", $line_nr);
    }
    return &$Texi2HTML::Config::anchor_label($nodes{$anchor}->{'id'}, $anchor, $nodes{$anchor}, $state->{'expansion'});
}

sub get_format_command($)
{
    my $format = shift;
    my $command = '';
    my $format_name = '';
    my $term = 0;
    my $item_nr;
    my $paragraph_number;
    my $enumerate_type;
    my $number;
    
    $command = $format->{'command'} if (defined($format->{'command'}));
    $format_name =  $format->{'format'} if (defined($format->{'format'}));

    return ($format_name,$command,\$format->{'paragraph_number'},$term,
        $format->{'item_nr'}, $format->{'spec'}, $format->{'number'},
        $format->{'stack_at_beginning'});
}

sub do_paragraph($$;$)
{
    my $text = shift;
    my $state = shift;
    my $stack = shift;

    if (!defined ($state->{'paragraph_context'}))
    {
        msg_debug ("paragraph_context undef", $Texi2HTML::THISDOC{'line_nr'});
        dump_stack (undef, $stack, $state);
    }

    my ($format, $paragraph_command, $paragraph_number, $term, $item_nr, 
        $enumerate_type, $number, $stack_at_beginning) 
         = get_format_command ($state->{'paragraph_context'});
    delete $state->{'paragraph_context'};

    my $indent_style = '';
    if (exists($state->{'paragraph_indent'}))
    {
        $indent_style = $state->{'paragraph_indent'};
        $state->{'paragraph_indent'} = undef;
        delete $state->{'paragraph_indent'};
    }
    my $paragraph_command_formatted;
    $state->{'paragraph_nr'}--;
    (print STDERR "Bug text undef in do_paragraph", return '') unless defined($text);
    my $align = '';
    $align = $state->{'paragraph_style'}->[-1] if ($state->{'paragraph_style'}->[-1]);
    
    if ($paragraph_command and !exists($Texi2HTML::Config::special_list_commands{$format}->{$paragraph_command}))
    {
        $paragraph_command_formatted = substitute_line("\@$paragraph_command\{\}", "paragraph \@$format \@$paragraph_command", duplicate_formatting_state($state));
    }
    return &$Texi2HTML::Config::paragraph($text, $align, $indent_style, $paragraph_command, $paragraph_command_formatted, $paragraph_number, $format, $item_nr, $enumerate_type, $number,$state->{'command_stack'},$stack_at_beginning);
}

sub do_preformatted($$;$)
{
    my $text = shift;
    my $state = shift;
    my $stack = shift;

    if (!defined ($state->{'preformatted_context'}))
    {
        msg_debug ("preformatted_context undef", $Texi2HTML::THISDOC{'line_nr'});
        dump_stack (undef, $stack, $state);
    }

    my ($format, $leading_command, $preformatted_number, $term, $item_nr, 
        $enumerate_type, $number,$stack_at_beginning) 
        = get_format_command($state->{'preformatted_context'});
    delete ($state->{'preformatted_context'});
    my $leading_command_formatted;
    my $pre_style = '';
    my $class = '';
    $pre_style = $state->{'preformatted_stack'}->[-1]->{'pre_style'} if ($state->{'preformatted_stack'}->[-1]->{'pre_style'});
    $class = $state->{'preformatted_stack'}->[-1]->{'class'};
    print STDERR "BUG: !state->{'preformatted_stack'}->[-1]->{'class'}\n" unless ($class);
    if (defined($leading_command) and $leading_command ne '' and !exists($Texi2HTML::Config::special_list_commands{$format}->{$leading_command}))
    {
        $leading_command_formatted = substitute_line("\@$leading_command\{\}", "preformatted \@$format \@$leading_command", duplicate_formatting_state($state));
    }
    return &$Texi2HTML::Config::preformatted($text, $pre_style, $class, $leading_command, $leading_command_formatted, $preformatted_number, $format, $item_nr, $enumerate_type, $number,$state->{'command_stack'},$stack_at_beginning);
}

sub do_external_href($)
{
    # node_id is a unique node identifier with only letters, digits, - and _
    # node_xhtml_id is almost the same, but xhtml id can only begin with
    # letters, so a prefix has to be appended  
    my $texi_node = shift;
    my $file = '';
    my $node_file = '';
    my $node_id = '';
    my $node_xhtml_id = '';

#print STDERR "do_external_href $texi_node\n";

    if ($texi_node =~ s/^\((.+?)\)//)
    {
         $file = $1;
    }
    $texi_node = normalise_node($texi_node);
    if ($texi_node ne '')
    {
         if (exists($nodes{$texi_node}) and ($nodes{$texi_node}->{'cross_manual_target'})) 
         {
               $node_id = $nodes{$texi_node}->{'cross_manual_target'};
               if ($Texi2HTML::Config::TRANSLITERATE_FILE_NAMES)
               {
                   $node_file = $nodes{$texi_node}->{'cross_manual_file'};
               }
         }
         else 
         {
              if ($Texi2HTML::Config::TRANSLITERATE_FILE_NAMES)
              {
                  ($node_id, $node_file) = cross_manual_line($texi_node,1);
              }
              else
              {
                  $node_id = cross_manual_line($texi_node);
              }
         }
         $node_xhtml_id = node_to_id($node_id);
         $node_file = $node_id unless ($Texi2HTML::Config::TRANSLITERATE_FILE_NAMES);
    }
    return &$Texi2HTML::Config::external_href($texi_node, $node_file, 
        $node_xhtml_id, $file);
}

# transform node for cross ref name to id suitable for xhtml: an xhtml id
# must begin with a letter.
sub node_to_id($)
{
    my $cross_ref_node_name = shift;
    $cross_ref_node_name =~ s/^([0-9_])/g_t$1/;
    return $cross_ref_node_name;
}

# return an empty string if the command is not a index command, the prefix
# if it is one
sub index_command_prefix($)
{
   my $command = shift;
   return $1 if ($command =~ /^(\w+?)index/ and ($1 ne 'print') and ($1 ne 'syncode') and ($1 ne 'syn') and ($1 ne 'def') and ($1 ne 'defcode'));
   return '';
}

# return 1 if the following tag shouldn't begin a line
sub no_line($)
{
    my $line = shift;
    my $next_tag = next_tag($line);
    return 1 if (($line =~ /^\s*$/) or $Texi2HTML::Config::no_paragraph_commands{$next_tag} or 
       ($Texi2HTML::Config::no_paragraph_commands{'cindex'} and (index_command_prefix($next_tag) ne '')) or 
       (($line =~ /^\@end\s+(\w+)/) and  $Texi2HTML::Config::no_paragraph_commands{"end $1"}) or
        ($next_tag =~ /^special_(\w+)_(\d+)$/ and $Texi2HTML::Config::no_paragraph_commands{$1})
     );
    return 0;
}

sub no_paragraph($$)
{
    my $state = shift;
    my $line = shift;
    return ($state->{'paragraph_context'} or $state->{'preformatted'} or $state->{'remove_texi'} or no_line($line) or $state->{'no_paragraph'});
}

# We restart the preformatted format which was stopped 
# by the format if in preformatted, and start a paragraph
# for the text following the end of the format, if needed
sub begin_paragraph_after_command($$$$)
{
    my $state = shift;
    my $stack = shift;
    my $command = shift;
    my $text_following = shift;
    
    #if (($state->{'preformatted'} 
    #       and !$Texi2HTML::Config::format_in_paragraph{$command})
    if ($state->{'preformatted'} 
        or (!no_paragraph($state,$text_following)))  
    {
        begin_paragraph($stack, $state); 
    }
}

# handle raw formatting, ignored regions...
# called from scan_texi, so only in first pass.
sub do_text_macro($$$$$)
{
    my $type = shift;
    my $line = shift;
    my $state = shift;
    my $stack = shift;
    my $line_nr = shift;
    my $value;
    #print STDERR "do_text_macro $type\n";

    if ($Texi2HTML::Config::texi_formats_map{$type} eq 'raw')
    {
        $state->{'raw'} = $type;
        #print STDERR "RAW\n";
        if ($state->{'raw'})
        {
             push @$stack, { 'style' => $type, 'text' => '' };
        }
    }
    elsif ($Texi2HTML::Config::texi_formats_map{$type} eq 'value')
    {
        if (($line =~ s/(\s+)($VARRE)$//) or ($line =~ s/(\s+)($VARRE)(\s)//))
        {
            $value = $1 . $2;
            $value .= $3 if defined($3);
            if ($state->{'ignored'})
            {
                if ($type eq $state->{'ignored'})
                {
                    $state->{'ifvalue_inside'}++;
                }
                # if 'ignored' we don't care about the command as long as
                # the nesting is correct
                return ($line,'');
            }
            my $open_ignored_ifvalue = 0;
            if ($type eq 'ifclear')
            {
                if (defined($value{$2}))
                {
                    $open_ignored_ifvalue = 1;
                }
                else
                {
                    push @{$state->{'text_macro_stack'}}, $type;
                }
            }
            elsif ($type eq 'ifset')
            {
                unless (defined($value{$2}))
                {
                    $open_ignored_ifvalue = 1;
                }
                else
                {
                    push @{$state->{'text_macro_stack'}}, $type;
                }
            }
            if ($open_ignored_ifvalue)
            {
                $state->{'ignored'} = $type;
                $state->{'ifvalue'} = $type;
                $state->{'ifvalue_inside'} = 1;
                # We add at the top of the stack to be able to close all
                # opened comands when closing the ifset/ifclear (and ignore
                # everything that is in those commands)
                push @$stack, { 'style' => 'ifvalue', 'text' => '' };
            }
        }
        else
        { # we accept a lone @ifset or @ifclear if it is nested in an @if*
            if ($state->{'ifvalue'} and $type eq $state->{'ifvalue'})
            {
                $state->{'ifvalue_inside'}++;
                return ($line,'');
            }
            line_error (sprintf(__("%c%s requires a name"), ord('@'), $type), $line_nr) unless ($state->{'ignored'});
        }
    }
    elsif (not $Texi2HTML::Config::texi_formats_map{$type})
    { # ignored text
        $state->{'ignored'} = $type;
        #print STDERR "IGNORED\n";
    }
    else
    {
        push @{$state->{'text_macro_stack'}}, $type unless($state->{'ignored'}) ;
    }
    my $text = "\@$type";
    $text .= $value if defined($value); 
    return ($line, $text);
}

# do regions handled specially, for example tex or math going through latex2html
sub init_special($$)
{
    my $style = shift;
    my $text = shift;
    if (defined($Texi2HTML::Config::command_handler{$style}) and
       defined($Texi2HTML::Config::command_handler{$style}->{'init'}))
    {
        $special_commands{$style}->{'count'} = 0 if (!defined($special_commands{$style}));
        if ($Texi2HTML::Config::command_handler{$style}->{'init'}($style,$text,
               $special_commands{$style}->{'count'} +1))
        {
            $special_commands{$style}->{'count'}++;  
            return "\@special_${style}_".$special_commands{$style}->{'count'}."{}";
        }
        return '';
    }
}

sub reset_index_entries($)
{
    my $region = shift;
    if (defined($Texi2HTML::THISDOC{'index_entries'}->{$region}))
    {
       foreach my $entry (values(%{$Texi2HTML::THISDOC{'index_entries'}->{$region}}))
       {
          if (scalar(@{$entry->{'entries'}}) > 1)
          {
              $entry->{'index'} = 0;
          }
       }
    }
    if (defined($Texi2HTML::THISDOC{'indices_numbers'}->{$region}))
    {
       foreach my $index_name (keys(%{$Texi2HTML::THISDOC{'indices_numbers'}->{$region}}))
       {
          $Texi2HTML::THISDOC{'indices_numbers'}->{$region}->{$index_name} = undef;
       }
    }
}

# FIXME we cannot go through the commands too 'often'. The error messages
# are duplicated and global stuff is changed.
# -> identify what is global
# -> use local state
sub do_special_region_lines($;$$)
{
    my $region = shift;
    my $state = shift;
    my $line_nr = shift;

    # this case covers something like
    # @copying
    # @insertcopying
    # @end copying
    if (defined($state) and exists($state->{'region'}) and ($region eq $state->{'region'}))
    {
         line_error(sprintf(__("Region %s inside region %s is not allowed"), $region, $state->{'region'}), $line_nr);
         return ('','', '');
    }

    print STDERR "# do_special_region_lines for region $region ['multiple_pass','region_pass']: ($region_initial_state{$region}->{'multiple_pass'}, $region_initial_state{$region}->{'region_pass'})" if ($T2H_DEBUG);
    if (!defined($state))
    {
        $state = {};
        fill_state($state);
        $state->{'outside_document'} = 1;
        print STDERR " outside document\n" if ($T2H_DEBUG);
    }
    elsif (!$state->{'outside_document'})
    {
        $region_initial_state{$region}->{'multiple_pass'}++;
        print STDERR " multiple pass $region_initial_state{$region}->{'multiple_pass'}\n" if ($T2H_DEBUG);
    }
    else
    {
        print STDERR " in $state->{'region'}, outside document\n" if ($T2H_DEBUG);
    }

    return ('','','') unless @{$region_lines{$region}};
  
    my @result;

    foreach my $context ('normal', 'remove_texi', 'simple_format')
    {
        print STDERR "# $context\n" if ($T2H_DEBUG);
        my $new_state = duplicate_formatting_state($state);
        reset_index_entries($region);
        foreach my $key (keys(%{$region_initial_state{$region}}))
        {
            $new_state->{$key} = $region_initial_state{$region}->{$key};
        }
        $new_state->{'remove_texi'} = 1 if ($context eq 'remove_texi');

        &$Texi2HTML::Config::begin_special_region($region,$new_state,$region_lines{$region})
            if (defined($Texi2HTML::Config::begin_special_region));
         

        my $line_numbers;
        my $context_string = "$region ($region_initial_state{$region}->{'multiple_pass'}, $region_initial_state{$region}->{'region_pass'})";
        if ($context eq 'normal')
        { # the line numbers are given only for the normal context, therefore
          # there will be error messages only in that case
           $line_numbers = [ @{$region_line_nrs{$region}} ];
        }
        else
        {
           $context_string = "$context $context_string";
        }
        
        my $result;
        if ($context ne 'simple_format')
        {
           $result = substitute_text($new_state, $line_numbers, 
             $context_string, @{$region_lines{$region}});
        }
        else
        {
           $result = simple_format($new_state, $line_numbers, 
             $context_string, @{$region_lines{$region}});
        }
        $result = &$Texi2HTML::Config::end_special_region($region,$new_state,$result)
           if (defined($Texi2HTML::Config::end_special_region));

        push @result, $result;
        $region_initial_state{$region}->{'region_pass'}++;
    }

    return @result;
}

sub do_insertcopying($$)
{
    my $state = shift;
    my $line_nr = shift;
    my ($text, $comment, $simple_formatted) = do_special_region_lines('copying', $state, $line_nr);
    return &$Texi2HTML::Config::insertcopying($text, $comment, $simple_formatted);
}

sub get_deff_index($$$$)
{
    my $tag = shift;
    my $line = shift;
    my $line_nr = shift;
    my $warn = shift;
   
    $tag =~ s/x$//;
    my ($command, $style, $category, $name, $type, $class, $arguments, $args_array, $args_type_array);
    ($command, $style, $category, $name, $type, $class, $arguments, $args_array, $args_type_array) = parse_def($tag, $line, $line_nr, $warn); 
    $name = &$Texi2HTML::Config::definition_index_entry($name, $class, $style, $command);
    return ($style, '') if (!defined($name) or ($name =~ /^\s*$/));
    return ($style, $name, $arguments);
}

sub parse_def($$$;$)
{
    my $command = shift;
    my $line = shift;
    my $line_nr = shift;
    my $report = shift;

    my $format = $command;

    if (!ref ($Texi2HTML::Config::def_map{$command}))
    {
        # substitute shortcuts for definition commands
        my $substituted = $Texi2HTML::Config::def_map{$command};
        $substituted =~ s/(\w+)//;
        $format = $1;
        $line = $substituted . $line;
    }
#print STDERR "PARSE_DEF($command,$format) $line";
    my ($category, $name, $type, $class, $arguments);
    my @arguments = ();
    my @args = @{$Texi2HTML::Config::def_map{$format}};
    my $style = shift @args;
    my @arg_types = ();
    while (@args and $args[0] ne 'arg' and $args[0] ne 'argtype')
    {
        my $arg = shift @args;
        # backward compatibility, it was possible to have a { in front.
        $arg =~  s/^\{//;
        my ($item, $spaces);
        ($item, $line, $spaces) = next_def_param($line, $command, $line_nr, $report);
        last if (!defined($item));
        if ($arg eq 'category')
        {
            $category = $item;
        }
        elsif ($arg eq 'name')
        {
            $name = $item;
        }
        elsif ($arg eq 'type')
        {
            $type = $item;
        }
        elsif ($arg eq 'class')
        {
            $class = $item;
        }
        push @arg_types, $arg;
        push @arguments, $item;
    }
    my $line_remaining = $line;
    $line = '';
    my $arg_and_type = 1;
    foreach my $arg (@args)
    {
        if ($arg eq 'arg')
        {
            $arg_and_type = 0;
            last;
        }
        elsif ($arg eq 'argtype')
        {
            last;
        }
    }

    my $always_delimiter_quoted = quotemeta($Texi2HTML::Config::def_always_delimiters);
    my $in_type_delimiter_quoted = quotemeta($Texi2HTML::Config::def_in_type_delimiters);
    my $after_type = 0;
    while ($line_remaining !~ /^\s*$/)
    {
        my ($item, $spaces);
        ($item, $line_remaining,$spaces) = next_def_param($line_remaining, $command, $line_nr);
        if ($item =~ /^([$always_delimiter_quoted])/ or (!$arg_and_type and  $item =~ /^([$in_type_delimiter_quoted].*)/))
        {
           $item = $1;
           push @arg_types, 'delimiter';
           $after_type = 0;
        }
        elsif (!$arg_and_type or $item =~ /^\@/ or $after_type)
        {
           push @arg_types, 'param';
           $after_type = 0;
        }
        elsif ($item =~ /^([$in_type_delimiter_quoted])/)
        {
           push @arg_types, 'delimiter';
        }
        else
        {
           push @arg_types, 'paramtype';
           $after_type = 1;
        }
        $spaces = ' ' if ($spaces);
        $line .= $spaces . $item;
        push @arguments, $spaces .$item;
    }
#print STDERR "PARSE_DEF (style $style, category $category, name $name, type $type, class $class, line $line)\n";
    return ($format, $style, $category, $name, $type, $class, $line, \@arguments, \@arg_types);
}

sub begin_paragraph($$)
{
    my $stack = shift;
    my $state = shift;

    my $command = { };
    my $top_format = top_format($stack);
    if (defined($top_format))
    {
        $command = $top_format;
    }
    $command->{'stack_at_beginning'} = [ @{$state->{'command_stack'}} ];
    my $paragraph_or_preformatted = 'paragraph';
    if ($state->{'preformatted'})
    {
        $paragraph_or_preformatted = 'preformatted';
        $state->{'preformatted_context'} = $command;
    }
    else
    {
       $state->{'paragraph_context'} = $command;
       $state->{'paragraph_nr'}++;
    }
    push @$stack, {'format' => $paragraph_or_preformatted, 'text' => '' };
    # FIXME give line, and modify line?
    &$Texi2HTML::Config::begin_paragraph_texi($paragraph_or_preformatted,
      $state->{'paragraph_macros'}, $command, $state, $stack)
        if (defined($Texi2HTML::Config::begin_paragraph_texi));
    # if there are macros which weren't closed when the previous 
    # paragraph was closed we reopen them here
    push @$stack, @{$state->{'paragraph_macros'}} if $state->{'paragraph_macros'};
    delete $state->{'paragraph_macros'};
}

sub parse_format_command($$)
{
    my $line = shift;
    my $tag = shift;
    my $command = '';

    my $orig_line = $line;
    # macro_regexp
    if ($line =~ s/^\s*\@([A-Za-z][\w-]*)(\{\})?\s*$//)
    {
         $command = $1;
         $command = $alias{$command} if (exists($alias{$command}));
    }
    return ('', $command) if ($line =~ /^\s*$/);
    chomp $line;
    $line = substitute_text ({'keep_nr' => 1, 'keep_texi' => 1, 'check_item' => $tag}, undef, "parse_format_command", $line);
    return ($line, $command);
}

sub parse_enumerate($)
{
    my $line = shift;
    my $spec;
    if ($line =~ /^\s*(\w)\b/ and ($1 ne '_'))
    {
        $spec = $1;
        $line =~ s/^\s*(\w)\s*//;
    }
    return ($line, $spec);
}

sub parse_multitable($$)
{
    my $line = shift;
    my $line_nr = shift;
    # first find the table width
    my $table_width = 0;
    my $fractions;
    my $elements;
    if ($line =~ s/^\s+\@columnfractions\s+//)
    {
        @$fractions = split /\s+/, $line;
        $table_width = scalar(@$fractions);
        foreach my $fraction (@$fractions)
        {
            unless ($fraction =~ /^(\d*\.\d+)|(\d+)\.?$/)
            { 
                line_error (sprintf(__("column fraction not a number: %s"), $fraction), $line_nr);
            }
        }
    }
    else
    {
        my $element;
        my $line_orig = $line;
        while ($line !~ /^\s*$/)
        {
            my $spaces;
            ($element, $line, $spaces) = next_bracketed($line, 'multitable', $line_nr, 1);
            if ($element =~ /^\{/)
            {
                $table_width++;
                $element =~ s/^\{//;
                $element =~ s/\}\s*$//;
                push @$elements, $element;
            }
            else
            {
                line_warn (sprintf(__("ignoring stray text `%s' after \@multitable"), $element), $line_nr);
            }
        }
    }
    return ($table_width, $fractions, $elements);
}

sub end_format($$$$$)
{
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $format = shift;
    my $line_nr = shift;
    #msg_debug ("END FORMAT $format", $line_nr);
    #dump_stack($text, $stack, $state);
    #sleep 1;
    if ($format_type{$format} eq 'menu')
    {
        $state->{$format}--;
        if ($state->{$format} < 0)
        { # FIXME currently happens, see invalid/not_closed_in_menu.texi
             line_error(sprintf(__("Too many %s closed"), $format), $line_nr);
             #print STDERR "Bug, $format counter negative: $state->{$format}\n";
             #dump_stack($text, $stack, $state);
             #exit 1;
             $state->{$format} = 0;
        }
        close_menu_comment($text, $stack, $state, "\@end $format", $line_nr); 
    }

    if ($format_type{$format} eq 'list')
    { # those functions return if they detect an inapropriate context
        add_item($text, $stack, $state, $line_nr); # handle lists
    }
    elsif ($format eq 'multitable')
    {
        add_row($text, $stack, $state, $line_nr); # handle multitable
    }
    elsif ($format_type{$format} eq 'table')
    {
        add_term($text, $stack, $state, $line_nr); # handle table
        add_line($text, $stack, $state, $line_nr); # handle table
    }

    #print STDERR "END_FORMAT\n";
    #dump_stack($text, $stack, $state);

    # set to 1 if there is a mismatch between the closed format and format
    # opened before
    my $format_mismatch = 0;
    # set to 1 in normal menu context after an end menu or detailmenu
    my $begin_menu_comment_after_end_format = 0;
	
    my $format_ref = pop @$stack;
    
    ######################### debug
    if (!defined($format_ref->{'text'}))
    {
        push @$stack, $format_ref;
        print STDERR "Bug: text undef in end_format $format\n";
        dump_stack($text, $stack, $state);
        pop @$stack;
    }
    ######################### end debug
    
    if ($region_lines{$format})
    {
        ######################### debug
        if ($format ne $state->{'region_lines'}->{'format'})
        {
            msg_debug ("Bug: mismatched region `$format' ne `$state->{'region_lines'}->{'format'}'");
        }
        ######################### end debug
        $state->{'region_lines'}->{'number'}--;
        if ($state->{'region_lines'}->{'number'} == 0)
        { 
            close_region($state);
        }
    }

    if ($format_type{$format} eq 'table' or $format_type{$format} eq 'list' or $format eq 'multitable')
    {
        if ($format_ref->{'format'} ne $format)
        { # for example vtable closing a table. Cannot be known 
          # before if in a cell
             $format_mismatch = 1;
             line_error (sprintf(__("`\@end' expected `%s', but saw `%s'"), $format_ref->{'format'}, $format), $line_nr);
             
        }
        if (!$format_ref->{'empty_first'} and $format_ref->{'item_nr'} == 0)
        {
             line_warn (sprintf(__("\@%s has text but no \@item"),$format_ref->{'format'}), $line_nr);
        }
    }

    if (defined($Texi2HTML::Config::def_map{$format}))
    {
        close_stack($text, $stack, $state, $line_nr, 'deff_item')
           unless ($format_ref->{'format'} eq 'deff_item');
        add_prev($text, $stack, &$Texi2HTML::Config::def_item($format_ref->{'text'}, $format_ref->{'only_inter_commands'}, $format_ref->{'orig_command'}));
        $format_ref = pop @$stack; # pop deff
        ######################################### debug
        if (!defined($format_ref->{'format'}) or !defined($Texi2HTML::Config::def_map{$format_ref->{'format'}}))
        {
             print STDERR "Bug: not a def* under deff_item\n";
             push (@$stack, $format_ref);
             dump_stack($text, $stack, $state);
             pop @$stack;  
        }
        ######################################### end debug
        elsif ($format_ref->{'format'} ne $format)
        {
             $format_mismatch = 1;
             line_error (sprintf(__("`\@end' expected `%s', but saw `%s'"), $format_ref->{'format'}, $format), $line_nr);
        }
        add_prev($text, $stack, &$Texi2HTML::Config::def($format_ref->{'text'}, $format_ref->{'orig_format'}));
    }
    elsif ($format eq 'float')
    {
        unless (defined($state->{'float'}))
        {
            msg_debug("state->{'float'} not defined in float", $line_nr);
            next;
        }
        my ($caption_lines, $shortcaption_lines) = &$Texi2HTML::Config::caption_shortcaption($state->{'float'});
        my ($caption_text, $shortcaption_text);
        my $caption_state = duplicate_formatting_state($state);
        push @{$caption_state->{'command_stack'}}, 'caption';
        $caption_text = substitute_text($caption_state, undef, '@caption in @end float',  @$caption_lines) if (defined($caption_lines));

        my $shortcaption_state = duplicate_formatting_state($state);
        push @{$shortcaption_state->{'command_stack'}}, 'shortcaption';
        $shortcaption_text = substitute_text($shortcaption_state, undef, '@shortcaption in @end float', @$shortcaption_lines) if (defined($shortcaption_lines));
        add_prev($text, $stack, &$Texi2HTML::Config::float($format_ref->{'text'}, $state->{'float'}, $caption_text, $shortcaption_text));
        delete $state->{'float'};
    }
    # FIXME $complex_format_map obsoleted in nov 2009
    elsif ((exists ($Texi2HTML::Config::complex_format_map->{$format}) 
         or exists ($Texi2HTML::Config::complex_format_map{$format}))
      and ($format_type{$format} ne 'menu' or $Texi2HTML::Config::SIMPLE_MENU))
    {
        $state->{'preformatted'}--;
        pop @{$state->{'preformatted_stack'}};
        my $complex_format;
        if (exists ($Texi2HTML::Config::complex_format_map->{$format}))
        {
            $complex_format = $Texi2HTML::Config::complex_format_map->{$format};
        }
        else
        {
            $complex_format = $Texi2HTML::Config::complex_format_map{$format};
        }
        # debug
        if (!defined($complex_format->{'begin'}))
        {
            msg_debug ("Bug undef $format_ref->{'format'}" . "->{'begin'} (for $format...)", $line_nr);
            dump_stack ($text, $stack, $state);
        }
        if ($fake_format{$format_ref->{'format'}} and $format_ref->{'text'} =~ /^\s*$/)
        {
           # discard empty fake formats
        }
        #print STDERR "before $format\n";
        #dump_stack ($text, $stack, $state);
        else
        {
            add_prev($text, $stack, &$Texi2HTML::Config::complex_format($format_ref->{'format'}, $format_ref->{'text'}));
        }
        #print STDERR "after $format\n";
        #dump_stack ($text, $stack, $state);
    }
    elsif ($format_type{$format} eq 'table' or $format_type{$format} eq 'list' or $format eq 'multitable')
    {
        if (exists ($Texi2HTML::Config::format_map{$format}))
        { # table or list has a simple format
            add_prev($text, $stack, end_simple_format($format_ref->{'format'}, $format_ref->{'text'}, $state));
        }
        else
        { # table or list handler defined by the user
            add_prev($text, $stack, &$Texi2HTML::Config::table_list($format_ref->{'format'}, $format_ref->{'text'}, $format_ref->{'command'}, $format_ref->{'formatted_command'}, $format_ref->{'item_nr'}, $format_ref->{'spec'}, $format_ref->{'prepended'}, $format_ref->{'prepended_formatted'}, $format_ref->{'columnfractions'}, $format_ref->{'prototype_row'}, $format_ref->{'prototype_lengths'}, $format_ref->{'max_columns'}));
        }
    } 
    elsif ($format_type{$format} eq 'quotation')
    {
        my $quotation_args = pop @{$state->{'quotation_stack'}};
        #add_prev($text, $stack, &$Texi2HTML::Config::quotation($format, $format_ref->{'text'}, $quotation_args->{'text'}, $quotation_args->{'text_texi'}));
        add_prev($text, $stack, &$Texi2HTML::Config::quotation($format, $format_ref->{'text'}, $format_ref->{'argument_text'}, $format_ref->{'argument_texi'}, $format_ref->{'quote_authors'}));
    }
    elsif ($Texi2HTML::Config::paragraph_style{$format})
    {
        if ($state->{'paragraph_style'}->[-1] eq $format)
        {
            pop @{$state->{'paragraph_style'}};
        }
        if ($fake_format{$format_ref->{'format'}} and $format_ref->{'text'} =~ /^\s*$/)
        {
           # discard empty fake formats
        }
        else
        {
            add_prev($text, $stack, &$Texi2HTML::Config::paragraph_style_command($format_ref->{'format'},$format_ref->{'text'}));
        }
    }
    elsif (exists($Texi2HTML::Config::format_map{$format}))
    {
        if ($fake_format{$format_ref->{'format'}} and $format_ref->{'text'} =~ /^\s*$/)
        {
           # discard empty fake formats
        }
        else
        {
            add_prev($text, $stack, end_simple_format($format_ref->{'format'}, $format_ref->{'text'}, $state));
        }
    }
    elsif ($format_type{$format} eq 'cartouche')
    {
        add_prev($text, $stack, &$Texi2HTML::Config::cartouche($format_ref->{'text'},$state->{'command_stack'}));
    }
    elsif ($format_type{$format} eq 'menu')
    {
    # it should be short-circuited if $Texi2HTML::Config::SIMPLE_MENU
        if ($state->{'preformatted'})
        {
            # remove the fake complex style
            $state->{'preformatted'}--;
            pop @{$state->{'preformatted_stack'}};
        }
 
        # backward compatibility with 1.78 jun 2007   
        if (defined($Texi2HTML::Config::menu))
        {
           if ($format eq 'menu')
           {
               add_prev($text, $stack, &$Texi2HTML::Config::menu($format_ref->{'text'}));
           }
           elsif ($format eq 'detailmenu') # detailmenu
           {
               add_prev($text, $stack, $format_ref->{'text'});
           }
           else # direntry
           {
           }
        }
        else
        {
           add_prev($text, $stack, &$Texi2HTML::Config::menu_command($format, $format_ref->{'text'}, $state->{'preformatted'}));
        }
        $begin_menu_comment_after_end_format = 1;
    }
    else
    {
        line_warn(sprintf(__("Unknown format %s"), $format), $line_nr);
    }
    
    # fake formats are not on the command_stack
    return 1 if ($fake_format{$format_ref->{'format'}});
    # special case for center as it is at the bottom of the stack
    my $removed_from_stack;
    if ($format eq 'center')
    {
        $removed_from_stack = shift @{$state->{'command_stack'}};
    }
    else
    {
        $removed_from_stack = pop @{$state->{'command_stack'}};
    }
    if ($removed_from_stack ne $format and !$format_mismatch)
    {
        #line_error ("Bug: removed_from_stack $removed_from_stack ne format $format", $line_nr);
        # it may not be a bug. Consider, for example a @code{in code
        # @end cartouche
        # The @code is closed when the paragraph is closed by 
        # @end cartouche but not really closed since it might have been 
        # a multiple paragraph @code. So it is not removed from 
        # command_stack but still have disapeared from the stack!
        line_error(sprintf(__("mismatched \@end %s with \@%s"), $format, $removed_from_stack), $line_nr);
    }
    if ($begin_menu_comment_after_end_format and $state->{'menu'})
    {
        begin_format($text, $stack, $state, 'menu_comment', '', $line_nr);
        return 0;
    }
    return 1;
}

sub push_complex_format_style($$$$)
{
    my $command = shift;
    my $complex_format = shift;
    my $state = shift;
    my $line_nr = shift;
    my $class = $command;

    if (!defined($state->{'preformatted_stack'}))
    {
       msg_debug ("'preformatted_stack' not defined in push_complex_format_style", $line_nr);
    }

    $class = $complex_format->{'class'} if (defined($complex_format->{'class'}));
    my $format_style = {'pre_style' =>$complex_format->{'pre_style'}, 'class' => $class, 'command' => $command };
    if (defined($complex_format->{'style'}))
    {
        $format_style->{'style'} = $complex_format->{'style'};
    }
    else
    {
        if ($state->{'preformatted'} and defined($state->{'preformatted_stack'}->[-1]->{'style'}))
        {
            $format_style->{'style'} = $state->{'preformatted_stack'}->[-1]->{'style'};
        }
        my $index = scalar(@{$state->{'preformatted_stack'}}) -1;
        # since preformatted styles are not nested, the preformatted format
        # of the first format with style has to be used
        if ($index > 0)
        {
            while ($index)
            {
                if ($state->{'preformatted_stack'}->[$index]->{'style'})
                {
                    $format_style->{'class'} = $state->{'preformatted_stack'}->[$index]->{'class'} if (defined($state->{'preformatted_stack'}->[$index]->{'class'}));
                    last;
                }
                $index--;
            }
        }
    }
    $state->{'preformatted'}++;
    push @{$state->{'preformatted_stack'}}, $format_style;
}

sub prepare_state_multiple_pass($$)
{
    my $command = shift;
    my $state = shift;
    my $return_state = { 
          'multiple_pass' => 1, 
          'element' => $state->{'element'},
          'outside_document' => $state->{'outside_document'},
          'new_state' => 1
         };
    if (defined($command))
    {
        $return_state->{'expansion'} = $command;
        $return_state->{'command_stack'} = ["$command"];
    }
    else
    {
        msg_debug("prepare_state_multiple_pass command not defined");
    }
    return $return_state;
}

sub begin_format($$$$$$);

sub begin_format($$$$$$)
{
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $macro = shift;
    my $line = shift;
    my $line_nr = shift;
    #msg_debug ("BEGIN FORMAT $macro",$line_nr);

    my $in_term;
    my $top_format = top_stack($stack, 2);
    $in_term = 1 if (defined($top_format->{'format'}) and $top_format->{'format'} eq 'term');

    if ($format_type{$macro} eq 'menu')
    {
        if ($state->{'menu'})
        {
            # there should not be any paragraph/preformatted to close
            # if the comment or the description were closed since they 
            # close it
            if (! close_menu_comment($text, $stack, $state, "\@$macro", $line_nr)
               and !close_menu_description($text, $stack, $state, "\@$macro", $line_nr))
            {
               close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
            }
        }
        else
        {
            close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
        }
        $state->{$macro}++;
    }
    elsif (!$in_term)
    {
        close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
    }

    # close def_item if this is a matching @def*x command
    if (defined($Texi2HTML::Config::def_map{$macro}))
    {
        my $top_format = top_format($stack);
        if (defined($top_format) and ("$top_format->{'format'}x" eq $macro))
        {
          # this is a matching @DEFx command.
             my $deff_item = pop @$stack;
             add_prev($text, $stack, 
                &$Texi2HTML::Config::def_item($deff_item->{'text'}, $deff_item->{'only_inter_commands'}, $deff_item->{'orig_command'}));
             #print STDERR "DEFx $macro\n";
        }
        elsif ($macro =~ /x$/)
        {
            my $base_def_command = $macro;
            $base_def_command =~ s/x$//;
            line_error(sprintf(__("Must be in `\@%s' environment to use `\@%s'"), $base_def_command, $macro), $line_nr);
        }
    }

    $line = &$Texi2HTML::Config::begin_format_texi($macro, $line, $state)
        unless($fake_format{$macro});

    push (@{$state->{'command_stack'}}, $macro) unless ($fake_format{$macro});
    if ($region_lines{$macro})
    {
        open_region($macro,$state);
    }
    # A deff like macro
    if (defined($Texi2HTML::Config::def_map{$macro}))
    {
        my $top_format = top_format($stack);
        my $orig_command = $macro;
        if (defined($top_format) and ("$top_format->{'format'}x" eq $macro))
        {
          # this is a matching @DEFx command.
          # the @DEFx macro has been put at the top of the 
          # command_stack, although there is no real format opening
             pop @{$state->{'command_stack'}};
             $macro =~ s/x$//o;
             #print STDERR "DEFx $macro\n";
        }
        else
        {
             # a new @def.
             $macro =~ s/x$//o;
             # we remove what is on the stack and put it back,
             # to make sure that it is the form without x.
             pop @{$state->{'command_stack'}};
             push @{$state->{'command_stack'}}, $macro;
             #print STDERR "DEF begin $macro\n";
             $top_format = { 'format' => $macro, 'text' => '', 'orig_format' =>$orig_command};
             push @$stack, $top_format;
        }
        #print STDERR "BEGIN_DEFF $macro\n";
        #dump_stack ($text, $stack, $state);
 
        my ($command, $style, $category, $name, $type, $class, $args_array, $args_type_array);
        ($command, $style, $category, $name, $type, $class, $line, $args_array, $args_type_array) = parse_def($macro, $line, $line_nr); 
        my $class_name_texi = &$Texi2HTML::Config::definition_index_entry($name, $class, $style, $command);

        #print STDERR "AFTER parse_def $line";
        my @formatted_args = ();
        my $arguments = '';
        my %formatted_arguments = ();
        my @types = @$args_type_array;
        my $arg_nr = 0;
        my $previous_type;
        foreach my $arg (@$args_array)
        {
            $arg_nr++;
            my $type = shift @types;
            my $substitution_state = duplicate_formatting_state($state);
            # all @def* arguments are in code_style
            $substitution_state->{'code_style'}++;
            push @formatted_args, substitute_line($arg, sprintf(__("\@%s (argument nr %d)"), $macro, $arg_nr), $substitution_state, $line_nr);
            if (grep {$_ eq $type} ('param', 'paramtype', 'delimiter'))
            {
                $arguments .= $formatted_args[-1];
            }
            else
            {
                $formatted_arguments{$type} = $formatted_args[-1];
            }

            $previous_type = $type;
        }
        $name = $formatted_arguments{'name'};
        $category = $formatted_arguments{'category'};
        $type = $formatted_arguments{'type'};
        $class = $formatted_arguments{'class'};

        $name = '' if (!defined($name));
        $category = '' if (!defined($category));
        
        my $class_category = &$Texi2HTML::Config::definition_category($category, $class, $style, $command);
        my $class_name = &$Texi2HTML::Config::definition_index_entry($name, $class, $style, $command);
        my ($index_entry, $formatted_index_entry, $index_label) = do_index_entry_label($macro, $state, $line_nr, $class_name_texi, $line);
        add_prev($text, $stack, &$Texi2HTML::Config::def_line($class_category, $name, $type, $arguments, $index_label, \@formatted_args, $args_type_array, $args_array, $command, $class_name, $category, $class, $style, $orig_command));
        $line = '';
        push @$stack, { 'format' => 'deff_item', 'text' => '', 'only_inter_commands' => 1, 'format_ref' => $top_format, 'orig_command' => $orig_command};
        begin_paragraph_after_command($state, $stack, $macro, $line);
    }
    # FIXME $complex_format_map obsoleted in nov 2009
    elsif ((exists ($Texi2HTML::Config::complex_format_map->{$macro})
         or exists ($Texi2HTML::Config::complex_format_map{$macro}))
      and ($format_type{$macro} ne 'menu' or $Texi2HTML::Config::SIMPLE_MENU))
    { # handle menu if SIMPLE_MENU. see texi2html.init
        my $complex_format;
        if (exists ($Texi2HTML::Config::complex_format_map->{$macro}))
        {
            $complex_format = $Texi2HTML::Config::complex_format_map->{$macro};
        }
        else
        {
            $complex_format = $Texi2HTML::Config::complex_format_map{$macro};
        }
        my $format = { 'format' => $macro, 'text' => '', 'pre_style' => $complex_format->{'pre_style'} };
        push_complex_format_style($macro, $complex_format, $state, $line_nr);
        push @$stack, $format;

        begin_paragraph($stack, $state);
    }
    elsif ($Texi2HTML::Config::paragraph_style{$macro})
    {
        
        push (@$stack, { 'format' => $macro, 'text' => '' });
        begin_paragraph_after_command($state,$stack,$macro,$line) unless ($in_term);
        push @{$state->{'paragraph_style'}}, $macro;
        if ($macro eq 'center')
        {
            # @center may be in a weird state with regard with
            # nesting, so we put it on the bottom of the stack
            pop @{$state->{'command_stack'}};
            unshift @{$state->{'command_stack'}}, $macro;
            # for similar reasons, we may have a bad stack nesting
            # which results in } after a closing. 
            # The following isn't really true anymore, I think: for example
            # @center @samp{something @center end of samp}
            # resulted to samp being kept in the 'command_stack'

        }
    }
    elsif ($format_type{$macro} eq 'list' or $format_type{$macro} eq 'table' or $macro eq 'multitable')
    {
        my $format;
        #print STDERR "LIST_TABLE $macro\n";
        #dump_stack($text, $stack, $state);
        if ($macro eq 'itemize' or $format_type{$macro} eq 'table')
        {
            my $command;
            my $prepended;
            ($prepended, $command) = parse_format_command($line,$macro);
            if (($command eq '') and ($macro ne 'itemize'))
            {
                $command = 'asis';
                line_error(sprintf(__("%s requires an argument: the formatter for %citem"), $macro, ord('@')), $line_nr);
            }
            my $prepended_formatted;
            $prepended_formatted = substitute_line($prepended, sprintf(__("prepended for \@%s"), $macro), prepare_state_multiple_pass('item', $state)) if (defined($prepended));
            $format = { 'format' => $macro, 'text' => '', 'command' => $command, 'prepended' => $prepended, 'prepended_formatted' => $prepended_formatted };
            $line = '';
        }
        elsif ($macro eq 'enumerate')
        {
            my $spec;
            ($line, $spec) = parse_enumerate ($line);
            $spec = 1 if (!defined($spec)); 
            $format = { 'format' => $macro, 'text' => '', 'spec' => $spec };
        }
        elsif ($macro eq 'multitable')
        {
            my ($max_columns, $fractions, $prototype_row) = parse_multitable ($line, $line_nr);
            if (!$max_columns)
            {
                line_warn (__("empty multitable"), $line_nr);
                $max_columns = 0;
            }
            my @prototype_lengths = ();
            if (defined($prototype_row))
            {
                my $prototype_nr = 0;
                foreach my $prototype (@$prototype_row)
                { 
                   $prototype_nr++;
                   push @prototype_lengths, 2+Texi2HTML::Config::t2h_default_string_width(substitute_line($prototype, sprintf(__("\@columnfraction (argument nr %d)"), $prototype_nr), prepare_state_multiple_pass('columnfractions', $state))); 
                }
            }
            $format = { 'format' => $macro, 'text' => '', 'max_columns' => $max_columns, 'columnfractions' => $fractions, 'prototype_row' => $prototype_row, 'prototype_lengths' => \@prototype_lengths, 'cell' => 1 };
        }
        $format->{'first'} = 1;
        $format->{'item_nr'} = 0;
        $format->{'paragraph_number'} = 0;
        push @$stack, $format;
        if ($format_type{$macro} eq 'table')
        {
            push @$stack, { 'format' => 'line', 'text' => '', 'format_ref' => $format, 'only_inter_commands' => 1};
        }
        elsif ($macro eq 'multitable')
        {
            push @$stack, { 'format' => 'row', 'text' => '', 'format_ref' => $format, 'item_cmd' => $macro };
            push @$stack, { 'format' => 'cell', 'text' => '', 'format_ref' => $format, 'only_inter_commands' => 1};
        }
        if ($format_type{$macro} eq 'list')
        {
            push @$stack, { 'format' => 'item', 'text' => '', 'format_ref' => $format, 'only_inter_commands' => 1};
        }
        begin_paragraph_after_command($state,$stack,$macro,$line)
           if ($macro ne 'multitable');
        return '' unless ($macro eq 'enumerate');
    }
    elsif ($macro eq 'float' or $format_type{$macro} eq 'quotation')
    {
        push @$stack, {'format' => $macro, 'text' => '' };
        if ($macro eq 'float')
        {
              
             my @args = parse_line_arguments($line, 2, "\@$macro");
             do_float_line ($macro, \@args, $state->{'style_stack'}, $state, $line_nr);
        }
        elsif ($format_type{$macro} eq 'quotation')
        {
             my @args = parse_line_arguments($line, 1, "\@$macro", $line_nr);
             do_quotation_line ($macro, $stack->[-1], \@args, $state->{'style_stack'}, $state, $line_nr);
             
        }

        $line = '';
        if ($state->{'preformatted'})
        { # inconditionally begin a preformatted section if needed
            begin_paragraph($stack, $state);
        }
        #dump_stack($text, $stack, $state);
    }
    # keep this one at the end as there are some other formats
    # which are also in format_map
    elsif (defined($Texi2HTML::Config::format_map{$macro}) or ($format_type{$macro} eq 'cartouche'))
    {
        push @$stack, { 'format' => $macro, 'text' => '' };
        $state->{'code_style'}++ if ($Texi2HTML::Config::format_code_style{$macro});
        begin_paragraph_after_command($state,$stack,$macro,$line);
    }
    elsif ($format_type{$macro} eq 'menu')
    {
        # if $Texi2HTML::Config::SIMPLE_MENU we won't get there
        # as the menu is a complex format in that case, so it 
        # is handled above
        push @$stack, { 'format' => $macro, 'text' => '' };
        if ($state->{'preformatted'})
        {
        # add a fake complex style in order to have a given pre style
            push_complex_format_style('menu', 
              $Texi2HTML::Config::MENU_PRE_COMPLEX_FORMAT, $state, $line_nr);
            begin_paragraph_after_command($state,$stack,$macro,$line);
        }
        else
        {
            begin_format($text, $stack, $state, 'menu_comment', $line, $line_nr);
        }
    }
    # this is useful for @center, and also if there was something on the 
    # line after a format that isn't there anymore, like
    # @format   @c
    # if @center line is empty we don't remove the end of line
    $line =~ s/^\s*// unless ($macro eq 'center' and $line =~ /^\s*$/);
    return $line;
}

sub do_text($;$)
{
    my $text = shift;
    my $state = shift;
    return $text if ($state->{'keep_texi'});
    my $remove_texi = 1 if ($state->{'remove_texi'} and !$state->{'simple_format'});
    my $preformatted_style = 0;
    if ($state->{'preformatted'})
    {
        $preformatted_style = $state->{'preformatted_stack'}->[-1]->{'style'};
    }
    return (&$Texi2HTML::Config::normal_text($text, $remove_texi, $preformatted_style, $state->{'code_style'}, $state->{'math_style'}, $state->{'simple_format'},$state->{'command_stack'}, $state));
}

sub end_simple_format($$$)
{
    my $command = shift;
    my $text = shift;
    my $state = shift;

    my $element = $Texi2HTML::Config::format_map{$command};

    my $result = &$Texi2HTML::Config::format($command, $element, $text);
    $state->{'code_style'}-- if ($Texi2HTML::Config::format_code_style{$command});
    return $result;
}

# only get there if not in SIMPLE_MENU and not in preformatted and 
# right in @menu
sub close_menu_comment($$$$$)
{
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $reason = shift;
    my $line_nr = shift;
  
    my $top_format = top_stack($stack,2);
    if (defined($top_format->{'format'}) and $top_format->{'format'} eq 'menu_comment')
    { # this is needed to avoid empty menu-comments <tr>...<pre></pre>
        abort_empty_preformatted($stack, $state);

        close_paragraph($text, $stack, $state, $reason, $line_nr);
        end_format($text, $stack, $state, 'menu_comment', $line_nr);
        return 1;
    }
}

# never get there if in $SIMPLE_MENU
# the last arg is used only if in description and an empty line may 
# stop it and begin a menu_comment
sub close_menu_description($$$$$;$)
{
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $reason = shift;
    my $line_nr = shift;
    my $line = shift;

    my $top_format = top_stack($stack,1);
    if (!$state->{'preformatted'})
    {
       $top_format = top_stack($stack);
    }

    if (defined($top_format->{'format'}) and $top_format->{'format'} eq 'menu_description' and (!defined($line) or $line =~ /^\s*$/) )
    {
        close_paragraph($text, $stack, $state, $reason, $line_nr) if ($state->{'preformatted'});
        my $descr = pop(@$stack);
        add_prev($text, $stack, do_menu_description($descr, $state));
        print STDERR "# close_menu: close description\n" if ($T2H_DEBUG & $DEBUG_MENU);
        $state->{'code_style'}-- if ($Texi2HTML::Config::format_code_style{'menu_description'});
        return 1;
    }
}

# Format menu link
# FIXME also pass node and name?
sub do_menu_link($$$)
{
    my $state = shift;
    my $line_nr = shift;
    my $menu_entry = shift;

    my $file = $state->{'element'}->{'file'};
    my $node_name = normalise_node($menu_entry->{'node'});
    # normalise_node is used in fact to determine if name is empty. 
    # It is not passed down to the function reference.
    my $name = normalise_node($menu_entry->{'name'});

    # there is one substitution with spaces kept, and one with spaces
    # normalized. In every cases nodes are in code_style
    my $node_substitution_state = duplicate_formatting_state($state);
    my $name_substitution_state = duplicate_formatting_state($state);
    my $node_normalized_substitution_state = duplicate_formatting_state($state);
    $node_substitution_state->{'code_style'} = 1;
    $node_normalized_substitution_state->{'code_style'} = 1;
    $name_substitution_state->{'code_style'} = 1 if ($Texi2HTML::Config::format_code_style{'menu_name'});
    my $node_formatted = substitute_line($menu_entry->{'node'}, __("node name in menu"), $node_substitution_state, $line_nr);
    my $node_normalized_formatted = substitute_line($node_name, __("normalized node name in menu"), $node_normalized_substitution_state);

    my $name_formatted;
    my $has_name = 0;
    if (defined($name) and $name ne '')
    {
        $name_formatted = substitute_line($menu_entry->{'name'}, __("menu entry name"), $name_substitution_state, $line_nr);
        $has_name = 1;
    }
    else
    {
        my $node_as_name = $menu_entry->{'node'};
        $node_as_name =~ s/^\s*//;
        $name_formatted = substitute_line($node_as_name, __("node name in menu"), $name_substitution_state);
    }

    my $entry = '';
    my $href;

    my $element;
    if ($state->{'direntry'})
    {
        $href = do_external_href($node_name);
    }
    else
    {
        $element = $nodes{$node_name};
    }

    # menu points to an unknown node
    if (defined($element) and !$element->{'seen'})
    {
        if ($menu_entry->{'node'} =~ /^\s*\(.*\)/o or Texi2HTML::Config::get_conf('novalidate'))
        {
            # menu entry points to another info manual or invalid nodes
            # and novalidate is set
            #$href = $nodes{$node_name}->{'file'};
            $href = do_external_href($node_name);
        }
        else
        {
            line_error (sprintf(__("Menu reference to nonexistent node `%s'"), $node_name), $line_nr);
            # try to find an equivalent node
            my @equivalent_nodes = equivalent_nodes($node_name);
            my $node_seen;
            foreach my $equivalent_node (@equivalent_nodes)
            {
                if ($nodes{$equivalent_node}->{'seen'})
                {
                    $node_seen = $equivalent_node;
                    last;
                }
            }
            if (defined($node_seen))
            {
                document_warn("---> but equivalent node `$node_seen' found");
                $element = $nodes{$node_seen};
            }
        }
    }

    # the original node or an equivalent node was seen
    if (defined($element) and $element->{'seen'})
    {
        if ($element->{'reference_element'})
        {
            $element = $element->{'reference_element'};
        }
    
        #print STDERR "SUBHREF in menu for `$element->{'texi'}'\n";
        $href = href($element, $file, $line_nr);
        if (! $element->{'node'})
        {
            $entry = $element->{'text'}; # this is the section/node name
            $entry = "$Texi2HTML::Config::MENU_SYMBOL $entry" if (($entry ne '') and (!defined($element->{'number'}) or ($element->{'number'} =~ /^\s*$/)) and $Texi2HTML::Config::UNNUMBERED_SYMBOL_IN_MENU);
        }
    }
    # save the element used for the href for the description
    $menu_entry->{'menu_reference_element'} = $element;

    return &$Texi2HTML::Config::menu_link($entry, $state, $href, $node_formatted, $name_formatted, $menu_entry->{'ending'}, $has_name, $state->{'command_stack'}, $state->{'preformatted'}, $node_normalized_formatted);
}

sub do_menu_description($$)
{
    my $descr = shift;
    my $state = shift;
    my $text = $descr->{'text'};
    my $menu_entry = $descr->{'menu_entry'};

    my $element = $menu_entry->{'menu_reference_element'};
    
    ############# debug
    # this is not a bug if element is not defined in direntry
    print STDERR "Bug: !defined(element) in do_menu_description\n" if (!defined($element) and ($state->{'menu'} or $state->{'detailmenu'}));
    ############# end debug
    my $element_text = '';
    $element_text = $element->{'text_nonumber'} if (defined($element));

    return &$Texi2HTML::Config::menu_description($text, duplicate_formatting_state($state),$element_text, $state->{'command_stack'}, $state->{'preformatted'});
}

sub do_xref($$$$)
{
    my $macro = shift;
    my $args = shift;
    my $style_stack = shift;
    my $state = shift;
    my $line_nr = shift;

    my $result = '';
    my @args = @$args;

    my $j;
    for ($j = 0; $j <= $#$args; $j++)
    {
        $args[$j] = normalise_texi_space($args[$j]);
    #     print STDERR " ($j)$args[$j]\n";
    }
    #print STDERR "DO_XREF: $macro\n";
    if ($macro eq 'inforef')
    {
        if ((@args < 1) or $args[0] eq '')
        {
            line_error (sprintf(__("First argument to \@%s may not be empty"), $macro), $line_nr);
            return '';
        }
    }

    my $node_texi = $args[0];
    $node_texi = normalise_node($node_texi);
    
    #print STDERR "XREF: (@args)\n";
    my $i;
    my $new_state = duplicate_formatting_state($state);
    $new_state->{'keep_texi'} = 0;
    $new_state->{'keep_nr'} = 0;

    my $remove_texi = $new_state->{'remove_texi'};

    my @formatted_args;
    for ($i = 0; $i < 5; $i++)
    {
        $args[$i] = '' if (!defined($args[$i]));
        my $in_file_style;
        $in_file_style = 1 if ($i == 2 and $macro eq 'inforef' or $i == 3 and $macro ne 'inforef');
        $new_state->{'code_style'}++ if ($in_file_style or $i == 0);
        $new_state->{'remove_texi'} = 1 if ($in_file_style);
        $formatted_args[$i] = substitute_line($args[$i], sprintf(__("\@%s (argument nr %d)"), $macro, $i), $new_state, $line_nr);
        $new_state->{'code_style'}-- if ($in_file_style or $i == 0);
        $new_state->{'remove_texi'} = $remove_texi if ($in_file_style);
    }


    my ($file_texi, $file);
    if ($macro eq 'inforef')
    {
       $file_texi = $args[2];
       $file = $formatted_args[2];
    }
    else
    {
       $file_texi = $args[3];
       $file = $formatted_args[3];
    }
    # Remark: makeinfo has this odd error message if the file is empty:
    # warning (_("Empty file name for HTML cross reference in `%s'")
    # This seems to be spurious.
    
    # can be an argument or extracted from the node name
    my $file_arg_or_node_texi = $file_texi;
    my $file_arg_or_node = $file;

    my $node_name;
    # the file in parenthesis is removed from node_without_file_texi if needed
    my $node_without_file_texi = $node_texi;
    # node with file, like (file)node
    my $node_and_file_texi;
    # the file in parenthesis present with the node
    my ($file_of_node_texi, $file_of_node);
    if ($node_without_file_texi =~ s/^\(([^\)]+)\)\s*//)
    {
       $file_of_node_texi = $1;
       $file_of_node = substitute_line($file_of_node_texi, sprintf(__p("\@*ref", "\@%s node file"), $macro), $new_state);
       $node_name = substitute_line($node_without_file_texi, sprintf(__p("\@*ref", "\@%s node name"), $macro), $new_state);
       $file_arg_or_node_texi = $file_of_node_texi if ($file_arg_or_node_texi eq '');
       $file_arg_or_node = $file_of_node if ($file_arg_or_node eq '');
       # the file argument takes precedence
       $node_and_file_texi = "($file_arg_or_node_texi)$node_without_file_texi";
    }
    else
    {
        # normalized node name
        $new_state->{'code_style'}++;
        $node_name = substitute_line($node_without_file_texi, sprintf(__p("\@*ref", "\@%s node name"), $macro), $new_state);
        $new_state->{'code_style'}--;
        if (defined ($file_texi) and $file_texi ne '')
        {
            $node_and_file_texi = "($file_texi)$node_texi";
        }
    }

    my $node_and_file;
    if (defined($node_and_file_texi))
    {
       $node_and_file = substitute_line($node_and_file_texi, sprintf(__p("\@*ref","\@%s node with file name"), $macro), $new_state);
    }
    else
    {
       $node_and_file_texi = $node_texi;
       $node_and_file = $node_name;
    }

    my $cross_ref_texi = $args[1];
    my $cross_ref = $formatted_args[1];
    
    my ($manual_texi, $section_texi, $manual, $section);
    if ($macro ne 'inforef')
    {
        $manual_texi = $args[4];
        $section_texi = $args[2];
        $manual = $formatted_args[4];
        $section = $formatted_args[2];
    }
    else
    {
        $manual = $section = '';
    }
    
    #print STDERR "XREF: (@args)\n";
    
    if (($macro eq 'inforef') or ($file_arg_or_node_texi ne '') or ($manual_texi ne ''))
    {# external ref
        my $href = '';
        if ($file_arg_or_node_texi ne '')
        {
            $href = do_external_href($node_and_file_texi);
        }
        else
        {
            $node_and_file = '';
        }
        #my $section_or_node = '';
        #if ($manual ne '')
        #{
        #    $section_or_node = $node_name;
        #    if ($section ne '')
        #    {
        #        $section_or_node = $section;
        #    }
        #}
        #$result = &$Texi2HTML::Config::external_ref($macro, $section_or_node, $manual, $node_and_file, $href, $cross_ref, \@args, \@formatted_args);
        $result = &$Texi2HTML::Config::external_ref($macro, $section, $manual, $file_arg_or_node, $href, $cross_ref, \@args, \@formatted_args, $node_name);
    }
    else
    {
        my $element = $nodes{$node_without_file_texi};
        if ($element and $element->{'seen'})
        {
            if ($element->{'reference_element'})
            {
                $element = $element->{'reference_element'};
            }
            my $file = '';
            if (defined($state->{'element'}))
            {
                $file = $state->{'element'}->{'file'};
            }
            else
            {
                line_warn (sprintf(__("\@%s not in text (in anchor, node, section...)"), $macro), $line_nr);
                # if Texi2HTML::Config::SPLIT the file is '' which ensures 
                # a href with the file name. if ! Texi2HTML::Config::SPLIT 
                # the 2 file will be the same thus there won't be the file name
                $file = $element->{'file'} unless (Texi2HTML::Config::get_conf('SPLIT'));
            }
	    #print STDERR "SUBHREF in ref to node `$node_texi'";
            my $href = href($element, $file, $line_nr);
            my $section_or_cross_ref = $section;
            $section_or_cross_ref = $cross_ref if ($section eq '');
            if ($element->{'float'} and $section_or_cross_ref eq '')
            {
                my $style = substitute_line(&$Texi2HTML::Config::listoffloats_float_style($element->{'style_texi'}, $element), __("\@listoffloats \@float type"));
                $section_or_cross_ref = $style if (defined($style));
            }
            my $name = $section_or_cross_ref;
            my $short_name = $section_or_cross_ref;
            if ($section_or_cross_ref eq '')
            {
                # FIXME maybe one should use 'text' instead of 'text_nonumber'
                # However the real fix would be to have an internal_ref call
                # with more informations 
                $name = $element->{'text_nonumber'};
                $short_name = $node_name;
            }
            $result = &$Texi2HTML::Config::internal_ref ($macro, $href, $short_name, $name, $element->{'section'}, \@args, \@formatted_args, $element);
        }
        else
        {
           if (($node_texi eq '') or (! Texi2HTML::Config::get_conf('novalidate')))
           {
               line_error (sprintf(__("\@%s reference to nonexistent node `%s'"), $macro, $node_texi), $line_nr);
               my $text = '';
               for (my $i = 0; $i < @$args -1; $i++)
               {
                    $text .= $args->[$i] .',';
               }
               $text .= $args->[-1];
               $result = "\@$macro"."{${text}}";
           }
           else
           {
               #$result = &$Texi2HTML::Config::external_ref($macro, '', '', $node_name, do_external_href($node_texi), $cross_ref, \@args, \@formatted_args);
               $result = &$Texi2HTML::Config::external_ref($macro, '', '', '', do_external_href($node_texi), $cross_ref, \@args, \@formatted_args, $node_name);
           }
        }
    }
    return $result;
}

sub do_acronym_like($$$$$)
{
    my $command = shift;
    my $args = shift;
    my $acronym_texi = shift @$args;
    my $explanation = shift @$args;
    my $style_stack = shift;
    my $state = shift;
    my $line_nr = shift;

    my $explanation_lines;
    my $explanation_text;
    my $explanation_simple_format;

    if (defined($explanation))
    {
        $explanation = trim_around_spaces($explanation);
        $explanation = undef if ($explanation eq '');
    }
    $acronym_texi = trim_around_spaces($acronym_texi);
    
    return '' if ($acronym_texi eq '');
    
    my $with_explanation = 0;
    my $normalized_text =  cross_manual_line(normalise_node($acronym_texi));
    if (defined($explanation))
    {
        $with_explanation = 1;
        $acronyms_like{$command}->{$normalized_text} = $explanation;
    }
    elsif (exists($acronyms_like{$command}->{$normalized_text}))
    {
        $explanation = $acronyms_like{$command}->{$normalized_text};
    }

    if (defined($explanation))
    {
         @$explanation_lines = map {$_ = $_."\n"} split (/\n/, $explanation);
         my $text = '';
         foreach my $line(@$explanation_lines)
         {
              $line .= ' ' if (chomp ($line));
              $text .= $line
         }
         $text =~ s/ $//;
         $explanation_simple_format = simple_format($state, [ $line_nr ], "simple_format \@$command explanation", $text);
         $explanation_text = substitute_line($text, sprintf(__p("\@abbr or \@acronym", "\@%s explanation"), $command), duplicate_formatting_state($state), $line_nr);
    }
    return &$Texi2HTML::Config::acronym_like($command, $acronym_texi, substitute_line($acronym_texi, "\@$command", duplicate_formatting_state($state), $line_nr), 
       $with_explanation, $explanation_lines, $explanation_text, $explanation_simple_format);
}

sub do_caption_shortcaption($$$$$$)
{
    my $command = shift;
    my $args = shift;
    my $text_texi = $args->[0];
    my $style_stack = shift;
    my $state = shift;
    my $line_nr = shift;
    my $kept_line_nrs = shift;

    if (!exists($state->{'float'}))
    {
         line_error(sprintf(__("\@%s not meaningful outside `\@float' environment"), $command), $line_nr);
         return '';
    }
    my $float = $state->{'float'};
    my @texi_lines = map {$_ = $_."\n"} split (/\n/, $text_texi);
    $float->{"${command}_texi"} = \@texi_lines;
    if (defined($kept_line_nrs))
    {
       $float->{"${command}_keep_line_nr"} = [ @$kept_line_nrs ];
       msg_debug ("Empty $kept_line_nrs", $line_nr) unless (@{$kept_line_nrs});
    }
    else
    {
        $float->{"${command}_keep_line_nr"} = [ $line_nr ];
        msg_debug("do_caption_shortcaption $command, $float, kept_line_nrs not defined", $line_nr);
    }
    #print STDERR "GGGGGGG @$kept_line_nrs\n";
    return  &$Texi2HTML::Config::caption_shortcaption_command($command, 
       substitute_text(prepare_state_multiple_pass($command, $state), $kept_line_nrs, "\@$command in do_caption_shortcaption", @texi_lines), \@texi_lines, $float);
}

# function called when a @float is encountered. Don't do any output
# but prepare $state->{'float'}
sub do_float_line($$$$$)
{
    my $command = shift;
    my $args = shift;
    my $style_stack = shift;
    my $state = shift;
    my $line_nr = shift;

    my @args = @$args;
    my $style_texi = shift @args;
    my $label_texi = shift @args;

    $style_texi = undef if (defined($style_texi) and $style_texi=~/^\s*$/);
    $label_texi = undef if (defined($label_texi) and $label_texi=~/^\s*$/);

    $style_texi = normalise_texi_space($style_texi) if (defined($style_texi));

    if (defined($label_texi))
    { # the float is considered as a node as it may be a target for refs.
      # it was entered as a node in the pass_structure and the float
      # line was parsed at that time
         $state->{'float'} = $nodes{normalise_node($label_texi)};
         #msg_debug("float: $state->{'float'}, $state->{'float'}->{'texi'}", $line_nr);  
    }
    else 
    { # a float without label. It can't be the target for refs.
         $state->{'float'} = { 'float' => 1 };
         if (defined($style_texi))
         {
              $state->{'float'}->{'style_texi'} = $style_texi;
              $state->{'float'}->{'style_id'} = 
                  cross_manual_line($state->{'float'}->{'style_texi'});
         }
         #print STDERR "float: (no label) $state->{'float'}\n";
    }
    $state->{'float'}->{'style'} = substitute_line($state->{'float'}->{'style_texi'}, __("\@float style"), undef, $line_nr);
    return '';
}

sub do_quotation_line($$$$$$)
{
    my $command = shift;
    my $format_ref = shift;
    my $args = shift;
    my @args = @$args;
    my $text_texi = shift @args;
    my $style_stack = shift;
    my $state = shift;
    my $line_nr = shift;
    my $text;

    $text_texi = undef if (defined($text_texi) and $text_texi=~ /^\s*$/);
    if (defined($text_texi))
    {
         $text_texi = trim_around_spaces($text_texi);
         $text = substitute_line($text_texi, sprintf(__p("\@*quotation", "\@%s argument"), $command), duplicate_formatting_state($state), $line_nr);
         #$text =~ s/\s*$//;
    }
    my $quotation_args = { 'text' => $text, 'text_texi' => $text_texi };
    push @{$state->{'quotation_stack'}}, $quotation_args;
    $format_ref->{'argument_text'} = $text;
    $format_ref->{'argument_texi'} = $text_texi;
    $state->{'prepend_text'} = &$Texi2HTML::Config::quotation_prepend_text($command, $text_texi);
    return '';
}

sub do_footnote($$$$$$)
{
    my $command = shift;
    my $args = shift;
    my $text = $args->[0];
    my $style_stack = shift;
    my $doc_state = shift;
    my $line_nr = shift;
    my $kept_line_nrs = shift;

    $text .= "\n";
    $text = &$Texi2HTML::Config::footnote_texi($text, $doc_state, $style_stack)
        if (defined($Texi2HTML::Config::footnote_texi));

    my $foot_state = duplicate_state($doc_state);
    fill_state($foot_state);
    push @{$foot_state->{'command_stack'}}, 'footnote';

    push_state($foot_state);

    my ($foot_num, $relative_foot_num);
    my $special_place;
    if (!defined($foot_state->{'expansion'}) and !defined($foot_state->{'region'}))
    {
        $foot_num = \$global_foot_num;
        $relative_foot_num = \$global_relative_foot_num;
    }
    else
    {
        $special_place = $foot_state->{'expansion'};
        $special_place = $foot_state->{'region'} if (!defined($special_place));
        $foot_num = \$doc_state->{'foot_num'};
        $relative_foot_num = \$doc_state->{'relative_foot_num'};
    }
    $$foot_num++;
    $$relative_foot_num++;   
 
    my $docid  = "DOCF$$foot_num";
    my $footid = "FOOT$$foot_num";
    if (defined($special_place))
    {
        $docid = $target_prefix . $special_place . "_$docid";
        $footid = $target_prefix . $special_place . "_$footid";
    }
    my $from_file = $docu_doc;
    if ($doc_state->{'element'})
    { 
        $from_file = $doc_state->{'element'}->{'file'};
    }
    
    if (Texi2HTML::Config::get_conf('footnotestyle') eq 'separate')
    {
        $foot_state->{'element'} = $footnote_element;
    }
    
    $foot_state->{'footnote_number_in_doc'} = $$foot_num;
    $foot_state->{'footnote_number_in_page'} = $$relative_foot_num;
    $foot_state->{'footnote_footnote_id'} = $footid;
    $foot_state->{'footnote_place_id'} = $docid;
    $foot_state->{'footnote_document_file'} = $from_file;
    $foot_state->{'footnote_footnote_file'} = $foot_state->{'element'}->{'file'};
    $foot_state->{'footnote_document_state'} = $doc_state;
    
    # FIXME use split_lines ? It seems to work like it is now ?
    msg_debug ("No line nnumbers in footnote", $line_nr) if (!defined($kept_line_nrs) or !@$kept_line_nrs);
    my @lines;
    if (defined($text))
    {
        @lines = substitute_text($foot_state, $kept_line_nrs, '@footnote', map {$_ = $_."\n"} split (/\n/, $text));
    }
    my ($foot_lines, $foot_label) = &$Texi2HTML::Config::foot_line_and_ref($$foot_num,
         $$relative_foot_num, $footid, $docid, $from_file, $foot_state->{'element'}->{'file'}, \@lines, $doc_state);
    if ($doc_state->{'outside_document'} or (defined($doc_state->{'multiple_pass'}) and $doc_state->{'multiple_pass'} > 0))
    {
#print STDERR "multiple_pass $doc_state->{'multiple_pass'}, 'outside_document' $doc_state->{'outside_document'}\n";
#print STDERR "REGION FOOTNOTE($$foot_num): $doc_state->{'region'} ($doc_state->{'region_pass'})\n";
        $region_initial_state{$doc_state->{'region'}}->{'footnotes'}->{$$foot_num}->{$doc_state->{'region_pass'}} = $foot_lines if (defined($doc_state->{'region'}));
    }
    else
    {
#print STDERR "GLOBAL FOOTNOTE($$foot_num)\n";
         push(@foot_lines, @{$foot_lines});
    }
    pop_state();
    return $foot_label;
}

sub do_image($$$$$)
{
    # replace images
    my $command = shift;
    my $args = shift;
    my $style_stack = shift;
    my $state = shift;
    my $line_nr = shift;
    my @args;
    foreach my $arg (@$args)
    {
       $arg = trim_around_spaces($arg) if (defined($arg));
       push @args, $arg;
    }
    my $base = substitute_line($args[0], __("\@image base name"),{'code_style' => 1, 'remove_texi' => 1});
    my $base_simple = substitute_line($args[0], __("\@image base name"), {'simple_format' => 1, 'code_style' => 1});
    if ($base eq '')
    {
         line_error ("\@image missing filename argument", $line_nr);
         return '';
    }
    $args[4] = '' if (!defined($args[4]));
    $args[3] = '' if (!defined($args[3]));
    my $image;
    my $extension = substitute_line($args[4], __("\@image extension"), {'code_style' => 1, 'remove_texi' => 1});
    my $extension_simple = substitute_line($args[4], __("\@image extension"), {'simple_format' => 1, 'code_style' => 1});
    my ($file_name, $image_name, $simple_file_name);
    my @file_locations;
    my @file_names = &$Texi2HTML::Config::image_files($base,$extension,$args[0],$args[4]);
#    $image = locate_include_file("$base.$args[4]") if ($args[4] ne '');
    foreach my $file (@file_names)
    {
        my $simple_file = substitute_line($file->[1], __("\@image file name"), {'simple_format' => 1, 'code_style' => 1});
        if ($image = locate_include_file($file->[0]))
        {
            if (!defined($file_name))
            {
                $file_name = $file->[0];
                $image_name = $image;
                $simple_file_name = $simple_file;
            }
            push @file_locations, [$file, $image, $simple_file];
        }
        else
        {
            push @file_locations, [$file, undef, $simple_file];
        }
    }
    $image_name = '' if (!defined($image_name));
    $simple_file_name = '' if (!defined($simple_file_name));
    
    my $alt; 
    if ($args[3] =~ /\S/)
    {
        $alt = substitute_line($args[3], __("\@image alt text"), {'simple_format' => 1}, $line_nr);
    }
    return &$Texi2HTML::Config::image($path_to_working_dir . $image_name, 
        $base, 
        $state->{'preformatted'}, $file_name, $alt, $args[1], $args[2], 
        $args[3], $extension, $path_to_working_dir, $image_name, 
        $state->{'paragraph_context'}, \@file_locations, $base_simple,
        $extension_simple, $simple_file_name, $line_nr);
}

# usefull if we want to duplicate only the global state, nothing related with
# formatting
sub duplicate_state($)
{
    my $state = shift;
    my $new_state = { 'element' => $state->{'element'},
         'multiple_pass' => $state->{'multiple_pass'},
         'region_pass' => $state->{'region_pass'},
         'region' => $state->{'region'},
         'expansion' => $state->{'expansion'},
         'sec_num' => $state->{'sec_num'},
         'outside_document' => $state->{'outside_document'},
         'inside_document' => $state->{'inside_document'},
         'duplicated' => 1
    };
    return $new_state;
}

# duplicate global and formatting state.
sub duplicate_formatting_state($)
{
    my $state = shift;
    my $new_state = duplicate_state($state);

    # Things passed here should be things that are not emptied/set to 0 by
    # any command. Also they shouldn't need anything to be on the 
    # stack. This rules out paragraphs, for example.
    foreach my $format_key ('preformatted', 'code_style', 'keep_texi',
          'keep_nr', 'preformatted_stack')
    {
        $new_state->{$format_key} = $state->{$format_key}; 
    }
# this is needed for preformatted
    my $command_stack = $state->{'command_stack'};
    $command_stack = [] if (!defined($command_stack));
    $new_state->{'command_stack'} = [ @$command_stack ];
    $new_state->{'preformatted_context'} = {'stack_at_beginning' => [ @$command_stack ]};
    $new_state->{'code_style'} = 0 if (!defined($new_state->{'code_style'}));
    return $new_state;
}

sub expand_macro($$$$$)
{
    my $name = shift;
    my $args = shift;
    my $end_line = shift;
    my $line_nr = shift;
    my $state = shift;

    # we dont expand macros when in ignored environment.
    return if ($state->{'ignored'});

    die "Bug end_line not defined" if (!defined($end_line));
    
    my $index = 0;
    foreach my $arg (@$args)
    { # expand @macros in arguments. It is complicated because we must be
      # carefull not to expand macros in @ignore section or the like, and 
      # still keep every single piece of text (including the @ignore macros).
        $args->[$index] = substitute_text({'texi' => 1, 'arg_expansion' => 1}, undef, "expand_macro in $name", split_lines($arg));
        $index++;
    }
    # retrieve the macro definition
    my $macrobody = $macros->{$name}->{'body'};
    my $formal_args = $macros->{$name}->{'args'};
    my $args_index =  $macros->{$name}->{'args_index'};

    my $i;    
    for ($i=0; $i<=$#$formal_args; $i++)
    {
        $args->[$i] = "" unless (defined($args->[$i]));
        print STDERR "# arg($i): $args->[$i]\n" if ($T2H_DEBUG & $DEBUG_MACROS);
    }
    line_error (sprintf(__("Macro `%s' called with too many args"), $name), $line_nr) if (defined($args->[$i + 1]));
    my $result = '';
    while ($macrobody ne '')
    {
        if ($macrobody =~ s/^([^\\]*)\\//o)
        {
            $result .= $1 if defined($1);
            if ($macrobody =~ s/^\\//)
            {
                $result .= '\\';
            }
            elsif ($macrobody =~ s/^(\@end\sr?macro)$// or $macrobody =~ s/^(\@end\sr?macro\s)// or $macrobody =~ s/^(\@r?macro\s+\w+\s*.*)//)
            { # \ protect @end macro
                $result .= $1;
            }
            elsif ($macrobody =~ s/^([^\\]*)\\//)
            {
               my $arg = $1;
               if (defined($args_index->{$arg}))
               {
                   $result .= $args->[$args_index->{$arg}];
               }
               else
               {
                   line_error (sprintf(__("\\ in macro expansion followed `%s' instead of parameter name or \\"), $arg), $macros->{$name}->{'line_nr'});
                   $result .= '\\' . $arg;
               }
            }
            next;
        }
        $result .= $macrobody;
        last;
    }
    my @result = split(/^/m, $result);
    # for a completly empty macro, $result = '', and the split leads
    # to an empty array, so add back an empty string
    @result = ('') if (!scalar(@result));
    # Add the result of the macro expansion back to the input_spool.
    # Set the macro name if in the outer macro
    if ($state->{'arg_expansion'})
    { # in that case we are in substitute_text for an arg
        unshift @{$state->{'spool'}}, (@result, $end_line);
    }
    else
    {
        #$result[-1].=$end_line;
#foreach my $res (@result)
#{
#   print STDERR "RESULT:$res";
#}
#print STDERR "#########end->$end_line";
        my $last_line = $result[-1];
        if (chomp($last_line))
        {
            push @result, $end_line;
        }
        else
        {
            $result[-1] .= $end_line;
        }
        unshift @{$state->{'input_spool'}->{'spool'}}, (@result); #, $end_line);
        $state->{'input_spool'}->{'macro'} = $name if ($state->{'input_spool'}->{'macro'} eq '');
    }
    if ($T2H_DEBUG & $DEBUG_MACROS)
    {
        print STDERR "# macro expansion result:\n";
        #print STDERR "$first_line";
        foreach my $line (@result)
        {
            print STDERR "$line";
        }
        print STDERR "# macro expansion result end\n";
    }
}

sub do_index_summary_file($$)
{
    my $name = shift;
    my $docu_name = shift;
    &$Texi2HTML::Config::index_summary_file_begin ($name, $printed_indices{$name}, $docu_name);
    print STDERR "# writing $name index summary for $docu_name\n" if $T2H_VERBOSE;

    foreach my $letter_entries (@{$Texi2HTML::THISDOC{'index_letters_array'}->{$name}})
    {
      foreach my $entry (@{$letter_entries->{'entries'}})
      {
        #my $entry = $entries->{$key};
        my $indexed_element = $entry->{'element'};
        my $entry_element = $indexed_element;
        $entry_element = $entry_element->{'element_ref'} if (defined($entry_element->{'element_ref'}));
        my $origin_href = $entry->{'file'};
   #print STDERR "$entry $entry->{'entry'}, real elem $indexed_element->{'texi'}, section $entry_element->{'texi'}, real $indexed_element->{'file'}, entry file $entry->{'file'}\n";
        if ($entry->{'target'})
        { 
             $origin_href .= '#' . $entry->{'target'};
        }
        else
        {
            $origin_href .= '#' . $indexed_element->{'target'};
        }
        &$Texi2HTML::Config::index_summary_file_entry ($name,
          $entry->{'key'}, $origin_href, 
          substitute_line($entry->{'entry'}, "\@$entry->{'command'}"), $entry->{'entry'},
          href($entry_element, ''),
          $entry_element->{'text'},
          $printed_indices{$name},
          $docu_name);
       }
    }
    &$Texi2HTML::Config::index_summary_file_end ($name, $printed_indices{$name}, $docu_name);
}

sub get_index_entry_infos($$;$)
{
    my $entry = shift;
    my $element = shift;
    my $line_nr = shift;
    my $index_heading_element = $entry->{'element'};
    my $entry_heading_element = $index_heading_element;
    my $real_index_element = $entry->{'real_element'};

    if (!defined($entry->{'real_element'}))
    {
        print STDERR "BUG: entry->{'real_element'} not defined\n";
    }
    # we always use the associated element_ref, instead of the original
    # element
    $entry_heading_element = $entry_heading_element->{'element_ref'} 
        if (defined($entry_heading_element->{'element_ref'}));
    if ($entry->{'real_element'} eq $element_before_anything)
    {
       $real_index_element = $element_top;
    }
    else
    {
       $real_index_element = $entry->{'real_element'}->{'element_ref'};
       if (!defined($real_index_element))
       { # happens when $USE_NODES = 0 and there are only sections, 
         # and vice-versa
          $real_index_element = $entry->{'real_element'};
       }
    }

    my $origin_href = '';
    print STDERR "BUG: entry->{'file'} not defined for `$entry->{'entry'}'\n"
       if (!defined($entry->{'file'}));
    print STDERR "BUG: element->{'file'} not defined for `$entry->{'entry'}', `$element->{'texi'}'\n"
       if (!defined($element->{'file'}));
    $origin_href = $entry->{'file'} if ($entry->{'file'} ne $element->{'file'});
#print STDERR "$entry $entry->{'entry'}, real heading elem $index_heading_element->{'texi'}, section $entry_element->{'texi'}, real $index_heading_element->{'file'}, entry file $entry->{'file'}\n";
    if (defined($entry->{'target'}))
    { 
         $origin_href .= '#' . $entry->{'target'};
    }
    else
    { # this means that the index entry is in a special region like @copying...
         $origin_href .= '#' . $index_heading_element->{'target'};
    }
   #print STDERR "SUBHREF in index entry `$entry->{'entry'}' for `$entry_element->{'texi'}'\n";
    return ($origin_href, 
            $entry->{'file'},
            $element->{'file'},
            $entry->{'target'},
            $index_heading_element->{'target'},
            substitute_line($entry->{'entry'}, "\@$entry->{'command'} index infos"),
            href($entry_heading_element, $element->{'file'}, $line_nr),
            $entry_heading_element->{'text'},
            (!$entry->{'seen_in_output'} and defined($entry->{'region'})));
}

# remove texi commands, replacing with what seems adequate. see simple_map_texi
# and texi_map.
# Doesn't protect html
sub remove_texi(@)
{
    return substitute_text ({ 'remove_texi' => 1}, undef, undef, @_);
}

# Same as remove texi but protect text and use special maps for @-commands
sub simple_format($$$@)
{
    my $state = shift;
    my $line_nrs = shift;
    my $context = shift;
    if (!defined($state))
    {
        $state = {};
    }
    else
    {
        $state = duplicate_formatting_state($state);
    }
    $state->{'remove_texi'} = 1;
    $state->{'simple_format'} = 1;
    $::simple_map_texi_ref = \%Texi2HTML::Config::simple_format_simple_map_texi;
    $::style_map_texi_ref = \%Texi2HTML::Config::simple_format_style_map_texi;
    $::texi_map_ref = \%Texi2HTML::Config::simple_format_texi_map;
    my $text = substitute_text($state, $line_nrs, $context, @_);
    $::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi;
    $::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi;
    $::texi_map_ref = \%Texi2HTML::Config::texi_map;
    return $text;
}

sub index_entry_command_prefix($$$)
{
    my $command = shift;
    my $line = shift;
    my $line_nr = shift;
    if ($command =~ /^(v|f)table$/)
    {
       return $1;
    }
    elsif (defined($Texi2HTML::Config::def_map{$command}))
    {
       my ($prefix, $entry, $argument) = get_deff_index($command, $line, undef, 0);
       return $prefix;
    }
    my $prefix = index_command_prefix($command);
    line_error(sprintf(__("No index prefix found for \@%s"),$command),$line_nr) if ($prefix eq '');
    return $prefix;
}

sub enter_table_index_entry($$$$)
{
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $line_nr = shift;
    if ($state->{'item'})
    {
         my $item_command = $state->{'item'};
         delete $state->{'item'};
         my $item = pop @$stack;
         if ($state->{'table_stack'}->[-1] =~ /^(v|f)table$/)
         {
             my $index = $1;
             enter_index_entry($index, $line_nr, 
               $item->{'text'}, $state->{'table_stack'}->[-1], $state);
         }
         add_prev($text, $stack, "\@$item_command" . $item->{'text'});
    }
}

sub end_macro($$$)
{
    my $state = shift;
    my $end_string = shift;
    my $remaining_on_the_line = shift;

    $state->{'macro_inside'}--;
    return (0, undef) if ($state->{'ignored'});
    if ($state->{'macro_inside'})
    {
        $state->{'macro'}->{'body'} .= $end_string;
        return (0, undef);
    }
    my $macro_text = $state->{'macro'}->{'header'} . $state->{'macro'}->{'body'}.$end_string;
    chomp $state->{'macro'}->{'body'};
    print STDERR "# end macro def. Body:\n$state->{'macro'}->{'body'}"
      if ($T2H_DEBUG & $DEBUG_MACROS);
    $macros->{$state->{'macro'}->{'name'}} = $state->{'macro'} unless ($state->{'arg_expansion'});
    delete $state->{'macro'};
    return (1, $macro_text.$remaining_on_the_line) if ($remaining_on_the_line =~ /^\s*$/);
    return (0, $macro_text);
}

sub close_macro_arg($$$)
{
   my $state = shift;
   my $current_line = shift;
   my $line_nr = shift;

   # balanced } ends the macro call, otherwise it is in the arg
   $state->{'macro_depth'}--;
   if ($state->{'macro_depth'} == 0)
   {
#print STDERR "BEFORE: $current_line";
      print STDERR "# expanding macro $state->{'macro_name'}\n" if ($T2H_DEBUG & $DEBUG_MACROS);
      #$current_line = 
      expand_macro($state->{'macro_name'}, $state->{'macro_args'}, $current_line, $line_nr, $state);
      delete $state->{'macro_name'};
      delete $state->{'macro_depth'};
      delete $state->{'macro_args'};
#print STDERR "AFTER: $current_line";
      #return $current_line;
      return 1;
   }
   else
   {
       print STDERR "# macro call: closing }\n" if ($T2H_DEBUG & $DEBUG_MACROS);
       add_text('}', \$state->{'macro_args'}->[-1]);
       return undef;
   }
}

sub close_style_texi($$$$;$)
{
    my $style = shift;
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $no_close = shift;

    $no_close = 0 if (!defined($no_close));

    my $result;
    if (!defined($style->{'style'}))
    {
        msg_debug("'style' not defined in close_style_texi ($no_close)");
        foreach my $key (keys(%$style))
        {
            print STDERR "  --> $key: ".var_to_str($style->{$key})."\n";
        }
    }

    if (($style->{'style'} ne '') and exists($info_enclose{$style->{'style'}}) and !$state->{'arg_expansion'})
    {
        $result = $info_enclose{$style->{'style'}}->[0] . $style->{'text'} . $info_enclose{$style->{'style'}}->[1];
    }
    elsif ($style->{'style'} ne '')
    {
        $result = '@' . $style->{'style'} . '{' . $style->{'text'};
        $result .= '}' unless ($no_close);
    }
    else
    {
        $result = '{' . $style->{'text'};
        # don't close { if we are closing stack as we are not
        # sure this is a { ... } construct. i.e. we are
        # not sure that the user properly closed the matching
        # brace, so we don't close it ourselves
        $result .= '}' unless ($no_close or $state->{'arg_expansion'});
    }
    if ($state->{'ignored'})
    {# ARG_EXPANSION
        print STDERR "# Popped `$style->{'style'}' in ifset/ifclear\n" if ($T2H_DEBUG);
    }
    else
    {
        add_prev ($text, $stack, $result);
    }
}

sub close_ignored ($$)
{
    my $state = shift;
    my $stack = shift;
    if (($state->{'ifvalue_inside'}) and $state->{'ignored'} eq $state->{'ifvalue'})
    {
        if ($state->{'ifvalue_inside'} == 1)
        {# closing still opened @-commands with braces
            pop (@$stack) while (@$stack and $stack->[-1]->{'style'} ne 'ifvalue')
        }
        pop (@$stack);
        $state->{'ifvalue_inside'}--;
    }
    $state->{'ignored'} = undef;
    delete $state->{'ignored'};
    # We are stil in the ignored ifset or ifclear section
    $state->{'ignored'} = $state->{'ifvalue'} if ($state->{'ifvalue_inside'});
    #dump_stack($text, $stack, $state);
}


# Called in 2 contexts: 
# * in main document
# * from substitute_text, called in turn from arg_expansion. In that case
#   'texi' is true, and so is 'arg_expansion'. In that case constructs are
#   expanded but no action is performed. Therefore $line_nr is not of use.
sub scan_texi($$$$;$)
{
    my $scanned_line = shift;
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $line_nr = shift;
    
    die "stack not an array ref"  unless (ref($stack) eq "ARRAY");
    my $cline = $scanned_line;

    while(1)
    {
        # scan_texi
        #print STDERR "WHILE(t):$cline";
        #print STDERR "ARG_EXPANSION: $state->{'arg_expansion'}\n" if ($state->{'arg_expansion'});
        #dump_stack($text, $stack, $state);
        #print STDERR "ifvalue_inside $state->{'ifvalue_inside'}\n";


        # first we handle special cases:
        # macro definition: $state->{'macro_inside'}
        # macro arguments:  $state->{'macro_name'}
        # raw format:       $state->{'raw'}
        # @verb:            $state->{'verb'}
        # ignored:          $state->{'ignored'}
        # and then the remaining text/macros.

        # in macro definition
        if ($state->{'macro_inside'})
        {
            if ($cline =~ s/^([^\\\@]*\\)//)
            {# protected character or @end macro
                 $state->{'macro'}->{'body'} .= $1 unless ($state->{'ignored'});
                 if ($cline =~ s/^\\//)
                 {
                      $state->{'macro'}->{'body'} .= '\\' unless ($state->{'ignored'});
                      next;
                 }
                 # I believe it is correct, although makeinfo don't do that.
                 elsif ($cline =~ s/^(\@end\sr?macro)$//o or $cline =~ s/^(\@end\sr?macro\s)//o
                      or $cline =~ s/^(\@r?macro\s+\w+\s*.*)//o) 
                 {
                      $state->{'macro'}->{'body'} .= $1 unless ($state->{'ignored'});
                      next;
                 }
            }
            #if ($cline =~ s/^(.*?)\@end\sr?macro$//o or $cline =~ s/^(.*?)\@end\sr?macro\s+//o)
            if ($cline =~ s/^(\@end\sr?macro)$//o or $cline =~ s/^(\@end\sr?macro\s+)//o)
            {
                 my ($no_remaining, $result) = end_macro($state, $1, $cline);
                 add_prev ($text, $stack, $result) if (defined($result));
                 return 1 if ($no_remaining);
                 next;
            }

            elsif($cline =~ /^(\@r?macro\s+\w+\s*.*)/)
            {
                 $state->{'macro'}->{'body'} .= $cline unless ($state->{'ignored'});
                 $state->{'macro_inside'}++;
                 #return;
                 return 1;
            }
            elsif ($cline =~ s/^\@(.)//)
            {
                 $state->{'macro'}->{'body'} .= '@' . $1 unless ($state->{'ignored'});
                 next;
            }
            elsif ($cline =~ s/^\@//)
            {
                 $state->{'macro'}->{'body'} .= '@' unless ($state->{'ignored'});
                 next;
            }
            else
            {
                 $cline =~ s/([^\@\\]*)//;
                 if ($state->{'ignored'})
                 {
                     return if ($cline =~ /^$/);
                     next;
                 }
                 $state->{'macro'}->{'body'} .= $1 if (defined($1));
                 if ($cline =~ /^$/)
                 {
                      $state->{'macro'}->{'body'} .= $cline;
                      #return;
                      return 1;
                 }
                 next;
            }
        }
        # in macro arguments parsing/expansion. Here \ { } and , if this is a
        # multi args macro have a signification, the remaining is passed 
        # unmodified
        if (defined($state->{'macro_name'}))
        {
            my $special_chars = quotemeta ('\{}');
            my $multi_args = 0;
            my $formal_args = $macros->{$state->{'macro_name'}}->{'args'};
            $multi_args = 1 if ($#$formal_args >= 1);
            $special_chars .= quotemeta(',') if ($multi_args);
            if ($state->{'macro_args'}->[-1] eq '')
            {# remove space at the very beginning
                $cline =~ s/^\s*//o;
            }
            if ($cline =~ s/^([^$special_chars]*)([$special_chars])//)
            {
                $state->{'macro_args'}->[-1] .= $1 if defined($1);
                # \ protects any character in macro arguments
                if ($2 eq '\\')
                {
                    print STDERR "# macro call: protected char\n" if ($T2H_DEBUG & $DEBUG_MACROS);
                    if ($cline =~ s/^(.)//)
                    {
                        $state->{'macro_args'}->[-1] .= $1;
                    }
                    else
                    {
                        $state->{'macro_args'}->[-1] .= '\\';
                    }
                }
                elsif ($2 eq ',')
                { # in texinfo 4.8.90 a comma in braces is protected
                    if ($state->{'macro_depth'} > 1)
                    {
                        $state->{'macro_args'}->[-1] .= ',';
                    }
                    else
                    { # separate args
                        print STDERR "# macro call: new arg\n" if ($T2H_DEBUG & $DEBUG_MACROS);
                        $cline =~ s/^\s*//o;
                        push @{$state->{'macro_args'}}, '';
                    }
                }
                elsif ($2 eq '}')
                { 
                    #my $macro_result_line = close_macro_arg($state, $cline);
                    return if (close_macro_arg($state, $cline, $line_nr));
                    #if (defined($macro_result_line))
                    #{
                    #    $cline = $macro_result_line;
                    #    return;
                    #}
                }
                elsif ($2 eq '{')
                {
                    print STDERR "# macro call: opening {\n" if ($T2H_DEBUG & $DEBUG_MACROS);
                    $state->{'macro_depth'}++;
                    add_text('{', \$state->{'macro_args'}->[-1]);
                }
                next;
            }
            print STDERR "# macro call: end of line\n" if ($T2H_DEBUG & $DEBUG_MACROS);
            $state->{'macro_args'}->[-1] .= $cline;
            return;
        }
        # in a raw format, verbatim, tex or html
        if ($state->{'raw'}) 
        {
            my $tag = $state->{'raw'};

            # debugging
            if (! @$stack or ($stack->[-1]->{'style'} ne $tag))
            {
                print STDERR "Bug: raw or special: $tag but not on top of stack\n";
                print STDERR "line: $cline";
                dump_stack($text, $stack, $state);
                exit 1;
            }
	    
            # macro_regexp
            if ($cline =~ /^(.*?)\@end\s([a-zA-Z][\w-]*)/o and ($2 eq $tag))
            {
                $cline =~ s/^(.*?)(\@end\s$tag)//;
            # we add it even if 'ignored', it'll be discarded just below
            # with the @end
                add_prev ($text, $stack, $1);
                my $end = $2;
                my $style = pop @$stack;
                # if 'arg_expansion' and 'ignored' are both true text 
                # is ignored.
                add_prev ($text, $stack, $style->{'text'} . $end) unless ($state->{'ignored'});
                delete $state->{'raw'};
                next;
            }
            else
            {# we add it even if 'ignored', it'll be discarded when there is 
             # the @end
                 add_prev ($text, $stack, $cline);
                 last;
            }
        }

        # in a @verb{ .. } macro
        if (defined($state->{'verb'}))
        {
            #dump_stack($text, $stack, $state);
            my $char = quotemeta($state->{'verb'});
            #print STDERR "VERB $char\n";
            if ($cline =~ s/^(.*?)$char\}/\}/)
            {# we add it even if 'ignored', it'll be discarded when closing
                 add_prev($text, $stack, $1 . $state->{'verb'});
                 $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'};
                 delete $state->{'verb'};
                 next;
            }
            else
            {# we add it even if 'ignored', it'll be discarded when closing
                 add_prev($text, $stack, $cline);
                 last;
            }
        }
        # In ignored region
        if ($state->{'ignored'})
        {
            #print STDERR "IGNORED(ifvalue($state->{'ifvalue_inside'})): $state->{'ignored'}\n";
            if ($cline =~ /^.*?\@end(\s+)([a-zA-Z]\w+)/)
            {
                if ($2 eq $state->{'ignored'})
                {
                    $cline =~ s/^(.*?\@end)(\s+)([a-zA-Z]\w+)//; 
                    my $end_ignore = $1.$2.$3;
                    close_ignored($state, $stack);
                    #dump_stack($text, $stack, $state);
                    # MACRO_ARG => keep ignored text
                    if ($state->{'arg_expansion'})
                    {# this may not be very usefull as it'll be remove later
                        add_prev ($text, $stack, $end_ignore);
                        next;
                    }
                    return if ($cline =~ /^\s*$/o);
                    next;
                }
            }
            add_prev ($text, $stack, $cline) if ($state->{'arg_expansion'});
            # we could theoretically continue for ignored commands other
            # than ifset or ifclear, however it isn't usefull.
            return unless ($state->{'ifvalue_inside'} and ($state->{'ignored'} eq $state->{'ifvalue'}));
        }

	
        # an @end tag
        # macro_regexp
        if ($cline =~ s/^([^{}@]*)\@end(\s+)([a-zA-Z][\w-]*)//)
        {
            my $leading_text = $1;
            my $space = $2;
            my $end_tag = $3;
            # when 'ignored' we don't open environments that aren't associated
            # with ignored regions, so we don't need to close them.
            next if ($state->{'ignored'});# ARG_EXPANSION
            add_prev($text, $stack, $leading_text);
            if (defined($state->{'text_macro_stack'})
               and @{$state->{'text_macro_stack'}}
               and ($end_tag eq $state->{'text_macro_stack'}->[-1]))
            {
                pop @{$state->{'text_macro_stack'}};
                # we keep menu and titlepage for the following pass
                if (($Texi2HTML::Config::texi_formats_map{$end_tag} eq 'normal') or ($region_lines{$end_tag}) or $state->{'arg_expansion'})
                {
                     add_prev($text, $stack, "\@end${space}$end_tag");
                }
                else
                {
                    #print STDERR "End $end_tag\n";
                    #dump_stack($text, $stack, $state);
                    return if ($cline =~ /^\s*$/);
                }
            }
            elsif ($Texi2HTML::Config::texi_formats_map{$end_tag})
            {
                line_error (sprintf(__("Unmatched `%c%s'"), ord('@'), 'end'), $line_nr);
            }
            else # a format that is not handled during the first pass
            {# ARG_EXPANSION
                add_prev($text, $stack, "\@end${space}$end_tag");
            }
            next;
        }
        # macro_regexp
        elsif ($cline =~ s/^([^{}@]*)\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/\\])//o or $cline =~ s/^([^{}@]*)\@([a-zA-Z][\w-]*)//o)
        {# ARG_EXPANSION
            add_prev($text, $stack, $1) unless $state->{'ignored'};
            my $command = $2;
            # FIXME: if it is an alias, it is substituted below, in the
            # diverse add_prev and output of \@$command. Maybe it could be
            # kept and only substituted in the last passes?
            $command = $alias{$command} if (exists($alias{$command}));
	    #print STDERR "MACRO $command\n";
            # handle skipped @-commands
            $state->{'bye'} = 1 if ($command eq 'bye' and !$state->{'ignored'} and !$state->{'arg_expansion'});
            # 'ignored' and 'arg_expansion' are handled in misc_command_texi
            # these are the commands in which the @value and @macro
            # and @-commands in general should not be expanded
            if (defined($Texi2HTML::Config::misc_command{$command}) and
                 ($command eq 'c' or $command eq 'comment' or $command eq 'set' 
                   or $command eq 'clear' or $command eq 'bye' or $command eq 'alias'))
            {
                my $cmd_arg;
                ($cline, $cmd_arg) = misc_command_texi($cline, $command, $state,
                       $line_nr);
                add_prev ($text, $stack, "\@$command" . $cmd_arg) unless $state->{'ignored'};
            }
            elsif ($command eq 'setfilename' or $command eq 'documentencoding'
                      or $command eq 'definfoenclose' or $command eq 'include')
            { # special commands whose arguments will have @macro and
              # @value expanded, and that are processed in this pass
                if ($state->{'ignored'} or ($line_nr->{'file_name'} ne $Texi2HTML::THISDOC{'input_file_name'} and $command eq 'setfilename'))
                { # @setfilename is ignored in @include file as said in the manual
                    $cline = '';
                }
                elsif ($state->{'arg_expansion'})
                {
                    add_prev($text, $stack, "\@$command" . $cline);
                    return;
                }
                else
                {
                    $cline =~ s/^(\s+)//;
                    my $space = $1;
                    # not sure if it happpens at end of line, or with 
                    # special char following the @-command or only at end of file
                    $space = '' if (!defined($space));
                    if (!$state->{'line_command'})
                    { 
                        #print STDERR "LINE_COMMAND Start line_command $command, cline $cline";
                        $state->{'line_command'} = $command;
                        push @$stack, { 'line_command' => $command, 'text' => $space };
                    }
                    else
                    {
                        line_error (sprintf(__("\@%s not allowed in argument to \@%s"), $command, $state->{'line_command'}), $line_nr);
                        #add_prev($text, $stack, "\@$command" . $space);
                        add_prev($text, $stack, $space);
                    }
                }
            }
            # pertusus: it seems that value substitution are performed after
            # macro argument expansions: if we have 
            # @set comma ,
            # and a call to a macro @macro {arg1 @value{comma} arg2}
            # the macro arg is arg1 , arg2 and the comma don't separate
            # args. Likewise it seems that the @value are not expanded
            # in macro definitions

            elsif ($command =~ /^r?macro$/)
            { # in 'arg_expansion' (ie within another macro call arguments)
              # the macro is parsed as usual, but isn't registered in 
              # end_macro.
                if ($cline =~ /^\s+(\w[\w-]*)\s*(.*)/)
                {
                    my $name = $1;
                    my $args_def = $2;
                    unless ($state->{'ignored'} or $state->{'arg_expansion'})
                    {
                         if (exists($macros->{$name}))
                         {
                             #line_warn ("macro `$name' already defined " . 
                             #    format_line_number($macros->{$name}->{'line_nr'}) . " redefined", $line_nr);
                             line_warn (sprintf(__("macro `%s' previously defined"), $name), $line_nr);
                             line_warn (sprintf(__("here is the previous definition of `%s'"), $name), $macros->{$name}->{'line_nr'});
                         }
                    }
                    $state->{'macro_inside'} = 1;

                    next if ($state->{'ignored'});
                    my @args = ();
                    if ($args_def =~ /^\s*{\s*(.*?)\s*}\s*/)
                    {
                        @args = split(/\s*,\s*/ , $1)
                    }
                    # keep the context information of the definition
                    my $macro = { 'name' => $name };
                    $macro->{'line_nr'} = { 'file_name' => $line_nr->{'file_name'}, 
                         'line_nr' => $line_nr->{'line_nr'}, 'macro' => $line_nr->{'macro'} } if (defined($line_nr));
                    $macro->{'args'} = \@args;
                    $macro->{'header'} = "\@$command" .$cline;
                    my $arg_index = 0;
                    my $debug_msg = '';
                    foreach my $arg (@args)
                    { # when expanding macros, the argument index is retrieved
                      # with args_index
                        $macro->{'args_index'}->{$arg} = $arg_index;
                        $debug_msg .= "$arg($arg_index) ";
                        $arg_index++;
                    }
                    $macro->{'body'} = '';
                    $state->{'macro'} = $macro;
                    print STDERR "# macro def $name: $debug_msg\n"
                         if ($T2H_DEBUG & $DEBUG_MACROS);
                }
                else
                {# it means we have a macro without a name
                    line_error (sprintf(__("Macro definition without macro name: %s"), $cline), $line_nr)
                        unless ($state->{'ignored'});
                }
                return 1;
            }
            elsif (defined($Texi2HTML::Config::texi_formats_map{$command}))
            {
                my $tag;
                ($cline, $tag) = do_text_macro($command, $cline, $state, $stack, $line_nr); 
                # if it is a raw formatting command or a menu command
                # we must keep it for later, unless we are in an 'ignored'.
                # if in 'arg_expansion' we keep everything.
                my $command_kept;
                if ((($state->{'raw'} or ($Texi2HTML::Config::texi_formats_map{$command} eq 'normal') or (exists($region_lines{$command}))) and !$state->{'ignored'}) or $state->{'arg_expansion'})
                {
                    add_prev($text, $stack, $tag);
                    $command_kept = 1;
                }
                #dump_stack ($text, $stack, $state);
                next if $command_kept;
                return if ($cline =~ /^\s*$/);
            }
            elsif ($command eq 'value')
            {
                if ($cline =~ s/^{($VARRE)}//)
                {
                    my $value = $1;
                    if ($state->{'arg_expansion'})
                    {
                        add_prev($text, $stack, "\@$command" .'{'. $value .'}');
                        next;
                    }
                    next if ($state->{'ignored'});
                    my $expansion;
                    if (defined($value{$value}))
                    {
                        $expansion = $value{$value} 
                    }
                    else
                    {
                        $expansion = gdt('@{No value for `{value}\'@}', {'value' => $value}, {'keep_texi'=> 1});
                        line_warn (sprintf(__("undefined flag: %s"), $value), $line_nr);
                    }
                    $cline = $expansion . $cline;
                }
                else
                {
                    if ($state->{'arg_expansion'})
                    {
                        add_prev($text, $stack, "\@$command");
                        next;
                    }
                    next if ($state->{'ignored'});
                    line_error (__("Bad syntax for \@value"), $line_nr);
                }
            }
            elsif ($command eq 'unmacro')
            { #FIXME with 'arg_expansion' should it be passed unmodified ?
                if ($state->{'ignored'})
                {
                    $cline =~ s/^\s+(\w+)//;
                }
                else
                {
                    delete $macros->{$1} if ($cline =~ s/^\s+(\w+)//);
                }
                return if ($cline =~ /^\s*$/);
                $cline =~ s/^\s*//;
            }
            elsif (exists($macros->{$command}))
            {# it must be before the handling of {, otherwise it is considered
             # to be regular texinfo @-command. Maybe it could be placed higher
             # if we want user defined macros to override texinfo @-commands

             # in 'ignored' we parse macro defined args anyway as it removes 
             # some text, but we don't expand the macro

                my $ref = $macros->{$command}->{'args'};
                my $args_number = $#$ref +1;
                # we remove any space/new line before the argument
                if ($cline =~ s/^\s*{\s*//)
                { # the macro has args
                    $state->{'macro_args'} = [ "" ];
                    $state->{'macro_name'} = $command;
                    $state->{'macro_depth'} = 1;
                }
                elsif (($args_number >= 2) or ($args_number <1))
                { # no brace -> no arg
                    #$cline = 
                    #line_warn("\@$command defined with $args_number arguments should be invoked with {}", $line_nr);
                    line_warn(sprintf(__("\@%s defined with zero or more than one argument should be invoked with {}"), $command), $line_nr);
                    expand_macro ($command, [], $cline, $line_nr, $state);
                    return;
                }
                else
                { # macro with one arg on the line
                    chomp $cline;
                    #$cline = 
                    expand_macro ($command, [$cline], "\n", $line_nr, $state);
                    return;
                }
            }
            elsif ($cline =~ s/^{//)
            {# we add nested commands in a stack. verb is also on the stack
             # but handled specifically.
             # we add it the comands even in 'ignored' as their result is 
             # discarded when the closing brace appear, or the ifset or 
             # iclear is closed.
                if ($command eq 'verb')
                {
                    if ($cline =~ /^$/)
                    {
                        line_error (sprintf(__("\@%s without associated character"), $command), $line_nr);
                    }
                    else
                    {
                        $cline =~ s/^(.)//;
                        $state->{'verb'} = $1;
                    }
                }
                if ($state->{'line_command'} and $command eq 'verb')
                { # have to close it now to catch if it is not 
                  # closed at te end of the line. In subsequent passes this
                  # is done in scan_line_separator.
                    my $result;
                    if (defined($state->{'verb'}))
                    {   
                        $result = '@verb{'.$state->{'verb'};
                        my $verb_char = quotemeta($state->{'verb'});
                        if ($cline =~ s/^(.*?${verb_char}\})//)
                        {
                            $result .= $1;
                        }
                        else
                        {
                            $cline =~ s/^(.*)//;
                            $result .= $1;
                        }
                        delete $state->{'verb'};
                    }
                    else
                    {
                        $result = '@verb{'
                    }
                    add_prev($text, $stack, $result) unless($state->{'ignored'});
                }
                else
                {
                    push (@$stack, { 'style' => $command, 'text' => '' });
                }
            }
            else
            {
                $cline = do_unknown(0, $command, $cline, $text, $stack, $state, $line_nr);
            }
            next;
        }
        #elsif(s/^([^{}@]*)\@(.)//o)
        elsif($cline =~ s/^([^{}@]*)\@([^\s\}\{\@]*)//o)
        {# ARG_EXPANSION
            # No need to warn here for @ followed by a character that
            # is not in any @-command and it is done later
            add_prev($text, $stack, $1) unless($state->{'ignored'});
            $cline = do_unknown(0, $2, $cline, $text, $stack, $state, $line_nr);
            next;
        }
        elsif ($cline =~ s/^([^{}]*)([{}])//o)
        {
         # in ignored section we cannot be sure that there is an @-command
         # already opened so we must discard the text.
         # ARG_EXPANSION
            add_prev($text, $stack, $1) unless($state->{'ignored'});
            if ($2 eq '{')
            {
              # this empty style is for a lone brace.
              # we add it even in 'ignored' as it is discarded when the closing
              # brace appear, or the ifset or iclear is closed.
                push @$stack, { 'style' => '', 'text' => '' };
            }
            else
            {
                if (@$stack)
                {
                    my $style = pop @$stack;
                    close_style_texi($style, $text, $stack, $state);
                    #print STDERR "MACRO end $style->{'style'} remaining: $cline";
                    next;
                }
                else
                {# ARG_EXPANSION
                    # we warn in the last pass that there is a } without open
                    add_prev ($text, $stack, '}') unless($state->{'ignored'});
                }
            }
        }
        else
        {# ARG_EXPANSION
            #print STDERR "END_LINE $cline";
            add_prev($text, $stack, $cline) unless($state->{'ignored'});
            if ($state->{'line_command'})
            {
               if (!scalar(@$stack))
               {
                   print STDERR "BUG: empty state for $state->{'line_command'}\n";
                   return;
                   delete $state->{'line_command'};
               }
               while (!defined($stack->[-1]->{'line_command'}))
               {
                  my $top = pop @$stack;
                  # defer this to later?
                  #line_error ("unclosed command in \@$state->{'line_command'}: $top->{'style'}");
                  add_prev($text, $stack, "\@$top->{'style'}".'{'.$top->{'text'}.'}');
               }
               my $command = pop @$stack;
               ###################### debug
               if (!defined($command) or !defined($command->{'text'}) or 
                 !defined($command->{'line_command'}) or ($command->{'line_command'} ne $state->{'line_command'}))
               {
                   msg_debug ("BUG: messed $state->{'line_command'} stack", $line_nr);
                   delete $state->{'line_command'};
                   return;
               }
               ###################### end debug
               else
               {
                   delete $state->{'line_command'};
                   my $macro = $command->{'line_command'};
                   # include are not kept
                   if ($macro eq 'include')
                   {
                    #if (s/^\s+([\/\w.+-]+)//o)
                       if ($command->{'text'} =~ s/^(\s+)(.+)//o)
                       {
                           my $file_name = $2;
                           # FIXME scan_line_separators
                           $file_name = trim_around_spaces($file_name);
                           $file_name = substitute_line($file_name, "\@$macro", {'code_style' => 1, 'remove_texi' => 1});
                           my $file = locate_include_file($file_name);
                           if (defined($file))
                           {
                               my ($line_nr_file, $input_spool_file) = open_file($file, $line_nr->{'macro'}, $state->{'files_stack'});
                               ($line_nr, $state->{'input_spool'}) = ($line_nr_file, $input_spool_file) if (defined($line_nr_file));
                               print STDERR "# including $file\n" if $T2H_VERBOSE;
                           }
                           else
                           {
                              line_error (sprintf(__("\@%s: Cannot find %s"), $macro, $file_name), $line_nr);
                           }
                       }
                       else
                       {
                           line_error (sprintf(__("Bad argument to \@%s: %s"), $macro, $command->{'text'}), $line_nr);
                       }
                       return;
                   }
                   else
                   { # these are kept (setfilename, documentencoding, definfoenclose)
                       if ($macro eq 'setfilename' and $Texi2HTML::Config::USE_SETFILENAME)
                       {
                           if (defined(Texi2HTML::Config::get_conf ('setfilename')))
                           {
                               line_error (sprintf(__("\@%s already set"), $macro), $line_nr);
                               # the line is removed, because we don't want to reset 
                               # get_conf('setfilename') between passes, and we don't want
                               # the last one to be picked up
                               $cline = "\n";
                               next;
                           }
                       }
                       my $cmd_arg;
                       ($cline, $cmd_arg) = misc_command_texi($command->{'text'}, 
                         $macro, $state, $line_nr);
                       add_prev ($text, $stack, "\@$macro" . $cmd_arg);
                       next;
                   }
               }
            }
            last;
        }
    }
    return undef if ($state->{'ignored'});
    return 1;
} # end scan_texi

sub close_structure_command($$$$)
{
    my $cmd_ref = shift;
    my $state = shift;
    my $unclosed_commands = shift;
    my $line_nr = shift;
    my $result;
    
    #print STDERR "close_structure_command $cmd_ref->{'style'}\n";
    # If the anchor is in @titlepage or @copying, it is nevertheless only 
    # expanded once in pass_structure, during the @copying or @titlepage 
    # expansion.
    # It is not true, however if INLINE_INSERTCOPYING is true.
    # See indices/index_special_region.texi tests.
    if ($cmd_ref->{'style'} eq 'anchor')
    {
        my $anchor = $cmd_ref->{'text'};
        $anchor = normalise_node($anchor);
        #print STDERR "Anchor $anchor\n";
        if ($nodes{$anchor})
        {# makeinfo error message are the following:
         # "Anchor `%s' and node `%s' map to the same file name"
         # "This @anchor command ignored; references to it will not work"
         # "Rename this anchor or use the `--no-split' option"
         #
         # "Anchors `%s' and `%s' map to the same file name"
         # "Anchor `%s' and node `%s' map to the same file name"
         # "@anchor command ignored; references to it will not work"
         # "Rename this anchor or use the `--no-split' option"
            line_error (sprintf(__("Anchor `%s' previously defined %s"), $anchor, format_line_number($nodes{$anchor}->{'line_nr'})), $line_nr);
            return '';
        }
        elsif ($anchor =~ /^\(.+\)/)
        {
            line_error (sprintf(__("Syntax for an external node used for `%s'"), $anchor), $line_nr);
            return '';
        }
        $document_anchor_num++;
        $nodes{$anchor} = { 'anchor' => 1, 'seen' => 1, 'texi' => $anchor, 'id' => 'ANC' . $document_anchor_num, 'line_nr' => $line_nr, 'tag' => 'anchor'};
        push @{$state->{'place'}}, $nodes{$anchor};
    }
    elsif ($cmd_ref->{'style'} eq 'footnote')
    {
        if (Texi2HTML::Config::get_conf('footnotestyle') eq 'separate')
        {
            $state->{'heading_element'} = $state->{'footnote_heading_element'};
            $state->{'place'} = $state->{'footnote_place'};
        }
    }
    elsif ($cmd_ref->{'style'} eq 'caption' or $cmd_ref->{'style'}
       eq 'shortcaption' and $state->{'float'})
    {
        my @texi_lines = map {$_ = $_."\n"} split (/\n/, $cmd_ref->{'text'});
        $state->{'float'}->{$cmd_ref->{'style'} . "_texi"} = \@texi_lines;
    }
    if (($cmd_ref->{'style'} eq 'titlefont') and ($cmd_ref->{'text'} =~ /\S/))
    {
        $state->{'heading_element'}->{'titlefont'} = $cmd_ref->{'text'} unless ((exists($state->{'region'}) and ($state->{'region'} eq 'titlepage')) or defined($state->{'heading_element'}->{'titlefont'})) ;
    }
    if (defined($Texi2HTML::Config::command_handler{$cmd_ref->{'style'}}))
    {
        $result = init_special($cmd_ref->{'style'},$cmd_ref->{'text'});
        if ($unclosed_commands)
        {
            $result .= "\n"; # the end of line is eaten by init_special
            line_error(sprintf(__("No closing brace for specially handled command %s"), $cmd_ref->{'style'}),$line_nr);
        }
    }
    elsif ($cmd_ref->{'style'})
    {
        $result = '@' . $cmd_ref->{'style'} . '{' . $cmd_ref->{'text'};
        $result .= '}' unless ($unclosed_commands);
    }
    else
    {
        $result = '{' . $cmd_ref->{'text'};
        # don't close { if we are closing stack as we are not
        # sure this is a licit { ... } construct.
        $result .= '}' unless ($unclosed_commands);
    }
    return $result;
}

sub end_format_structure($$$$$$)
{
    my $end_tag = shift;
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $line_nr = shift;
    my $remaining_on_line = shift;

    if (defined($state->{'text_macro_stack'})
       and @{$state->{'text_macro_stack'}}
       and ($end_tag eq $state->{'text_macro_stack'}->[-1]))
    {
        pop @{$state->{'text_macro_stack'}};
        if (exists($region_lines{$end_tag}))
        { # end a region_line macro, like documentdescription, copying
             print STDERR "Bug: end_tag $end_tag ne $state->{'region_lines'}->{'format'}\n"
                if ($end_tag ne $state->{'region_lines'}->{'format'});
             print STDERR "Bug: end_tag $end_tag ne $state->{'region'}\n"
                if ($end_tag ne $state->{'region'});
             $state->{'region_lines'}->{'number'}--;
             if ($state->{'region_lines'}->{'number'} == 0)
             {
                 close_region($state);
             }
             #dump_stack($text, $stack, $state);
        }
        if (($Texi2HTML::Config::texi_formats_map{$end_tag} eq 'normal') or $Texi2HTML::Config::region_formats_kept{$end_tag})
        {
             $state->{$end_tag}-- if ($Texi2HTML::Config::texi_formats_map{$end_tag} eq 'normal');
             add_prev($text, $stack, "\@end $end_tag");
        }
        else
        {
             #print STDERR "End $end_tag\n";
             #dump_stack($text, $stack, $state);
             return 1 if ($remaining_on_line =~ /^\s*$/);
        }
    }
    elsif ($Texi2HTML::Config::texi_formats_map{$end_tag})
    {
        line_error (sprintf(__("Unmatched `%c%s'"), ord('@'), 'end'), $line_nr);
        #dump_stack($text, $stack, $state);
    }
    elsif ($end_tag eq 'detailmenu' or $end_tag eq 'direntry')
    {
        $state->{$end_tag}-- if $state->{$end_tag};
        add_prev($text, $stack, "\@end $end_tag");
    }
    else
    {
        if ($end_tag eq 'float' and $state->{'float'})
        {
            delete $state->{'float'};
        }
        elsif ($end_tag eq $state->{'table_stack'}->[-1])
        {
            enter_table_index_entry($text, $stack, $state, $line_nr);
            pop @{$state->{'table_stack'}};
        }
        #add end tag
        add_prev($text, $stack, "\@end $end_tag");
    }
    return 0;
}

sub parse_menu_entry($)
{
   my $menu_line = shift;
   my ($node, $name, $ending, $remaining);

   return ($node, $name, $ending, $remaining) unless $menu_line =~ s/^\*//;

   my ($before_colon, $separator);
   ($before_colon, $remaining, $separator) = scan_line_separators($menu_line, ':', 'menu entry');
   if (defined($before_colon) and defined($separator))
   {
      if ($remaining =~ s/^://)
      {
          $node = $before_colon;
          $ending = '::';
      }
      elsif ($remaining =~ /\S/)
      {
          my $after_colon;
          $ending = "";
          ($after_colon, $remaining, $separator) = scan_line_separators($remaining, '\t,\.', 'menu entry node');
          # this certainly corresponds with an error in the node.
          # this is considered not to be a menu entry.
          return (undef, $name, $ending, $remaining) if (!defined($after_colon));
          $node = $after_colon;

          while (1)
          {
              if (!defined($separator) or (defined($separator) and $separator ne '.') or (defined($separator) and (!defined($remaining) or $remaining =~ /^\s/)))
              {
                  last;
              }
              $node .= $separator;
              my $after_dot;
              ($after_dot, $remaining, $separator) = scan_line_separators($remaining, '\t,\.', 'menu entry node');
              $after_dot = '' if (!defined($after_dot));
              $node .= $after_dot;
          }
          $name = $before_colon;
          $ending = $separator if (defined($separator));
          # only spaces after the :, this is not a menu entry:
          $node = undef if ($node !~ /\S/);
      }
   }
   # remaining may be defined even if $node isn't.
   #print STDERR "\nLLLL $menu_line";
   #print STDERR " -->  node:$node, name:$name, ending:$ending -> $remaining";
   return ($node, $name, $ending, $remaining);
}

sub scan_structure($$$$;$)
{
    my $line = shift;
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $line_nr = shift;

    die "stack not an array ref"  unless (ref($stack) eq "ARRAY");
    my $cline = $line;
    #print STDERR "SCAN_STRUCTURE: $line";
    #dump_stack ($text, $stack, $state); 
    if (!$state->{'raw'} and (!exists($state->{'region_lines'})))
    { 
        #if (!$state->{'verb'} and $state->{'menu'} and $cline =~ /^\*\s+/o)
        if (!$state->{'verb'} and $state->{'menu'})
        {
        # new menu entry
            my ($node, $name, $ending, $remaining) = parse_menu_entry($cline);
            if (defined($node))
            {
                menu_entry_texi(normalise_node($node), $state, $line_nr);
            }
        }
    }

    while(1)
    {
        # scan structure
	#dump_stack($text, $stack, $state);
	#print STDERR "WHILE(s):$cline";

        # as texinfo 4.5
        # verbatim might begin at another position than beginning
        # of line, and end verbatim might too. To end a verbatim section
        # @end verbatim must have exactly one space between end and verbatim
        # things following end verbatim are not ignored.
        #
        # html might begin at another position than beginning
        # of line, but @end html must begin the line, and have
        # exactly one space. Things following end html are ignored.
        # tex and ignore works like html
        #
        # ifnothtml might begin at another position than beginning
        # of line, and @end  ifnothtml might too, there might be more
        # than one space between @end and ifnothtml but nothing more on 
        # the line.
        # @end itemize, @end ftable works like @end ifnothtml.
        # except that @item on the same line than @end vtable doesn't work
        # 
        # text right after the itemize before an item is displayed.
        # @item might be somewhere in a line. 
        # strangely @item on the same line than @end vtable doesn't work
        # there should be nothing else than a command following @itemize...
        #
        # see more examples in formatting directory

        if ($state->{'raw'}) 
        {
            my $tag = $state->{'raw'};
            ################# debug 
            if (! @$stack or ($stack->[-1]->{'style'} ne $tag))
            {
                print STDERR "Bug: raw or special: $tag but not on top of stack\n";
                print STDERR "line: $cline";
                dump_stack($text, $stack, $state);
                exit 1;
            }
            ################# end debug 
            if ($tag eq 'macro')
            {
                if ($cline =~ /^\s*\@macro\s+(\w[\w-]*)\s*(.*)/)
                {
                    $state->{$tag}++;
                }
            }
            # macro_regexp
            if ($cline =~ /^(.*?)\@end\s([a-zA-Z][\w-]*)/o and ($2 eq $tag))
            {
                $cline =~ s/^(.*?)(\@end\s$tag)//;
                add_prev ($text, $stack, $1);
                my $end_text = $2;
                if ($tag eq 'macro')
                {
                    $state->{$tag}--;
                    if ($state->{$tag})
                    {
                        add_prev ($text, $stack, $end_text);
                        next;
                    }
                }
                delete $state->{'raw'};
                my $style = pop @$stack;
                if (defined($Texi2HTML::Config::command_handler{$tag})) 
                { # replace the special region by what init_special give
                    if ($style->{'text'} !~ /^\s*$/)
                    {
                        add_prev ($text, $stack, init_special($style->{'style'}, $style->{'text'}));
                    }
                }
                else
                {
                    add_prev ($text, $stack, $style->{'text'} . "\@end $tag");
                }
                next;
            }
            else
            {
                add_prev ($text, $stack, $cline);
                return if (defined($Texi2HTML::Config::command_handler{$tag})); 
                last;
            }
        }
	
        if (defined($state->{'verb'}))
        {
            my $char = quotemeta($state->{'verb'});
            if ($cline =~ s/^(.*?)$char\}/\}/)
            {
                add_prev($text, $stack, $1 . $state->{'verb'});
                $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'};
                delete $state->{'verb'};
                next;
            }
            else
            {
                add_prev($text, $stack, $cline);
                last;
            }
        }
	
        # macro_regexp
        if ($cline =~ s/^([^{}@]*)\@end\s+([a-zA-Z][\w-]*)//)
        {
            add_prev($text, $stack, $1);
            my $end_tag = $2;
            #print STDERR "END STRUCTURE $end_tag\n";
            return if (end_format_structure($end_tag, $text, $stack, $state, $line_nr, $cline));
            next;
        }
        # macro_regexp
        elsif ($cline =~ s/^([^{}@]*)\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/\\])//o or $cline =~ s/^([^{}@]*)\@([a-zA-Z][\w-]*)//o)
        {
            add_prev($text, $stack, $1);
            my $macro = $2;
            #print STDERR "MACRO $macro\n";
            $macro = $alias{$macro} if (exists($alias{$macro}));
            if (defined($Texi2HTML::Config::deprecated_commands{$macro}))
            {
              # makeinfo has 
              # "%c%s is obsolete; use %c%s instead"
                if ($Texi2HTML::Config::deprecated_commands{$macro} eq '')
                {
                   line_warn(sprintf(__("%c%s is obsolete."), ord('@'), $macro), $line_nr);
                }
                else
                {
                   line_warn(sprintf(__("%c%s is obsolete; %s"),ord('@'), $macro, __($Texi2HTML::Config::deprecated_commands{$macro})), $line_nr);
                }
            }
            if (defined($Texi2HTML::Config::misc_command{$macro}))
            {
                my $line;
                ($cline, $line) = misc_command_structure($cline, $macro, $state, 
                      $line_nr);
                add_prev ($text, $stack, "\@$macro".$line); 
                next;
            }
            elsif ($macro eq 'printindex' and ($cline =~ /^\s+(\w+)/))
            {
                my $index_name = $1;
                if (!exists($index_names{$index_name}))
                {
                   line_error (sprintf(__("Unknown index `%s' in \@printindex"),$index_name), $line_nr);
                }
                my $associated_element;
                if ($state->{'current_element'} eq $element_before_anything)
                {
                   line_warn (sprintf(__("Printindex before document beginning: \@printindex %s"), $index_name), $line_nr);
                }
                else
                {
                # $element_index is the first element with index
                  $element_index = $state->{'current_element'} unless (defined($element_index));
                  $associated_element = $state->{'current_element'};
                }
                my $region = $state->{'region'};
                $region = 'document' if (!defined($region));
                # FIXME use 'index_name' instead of 'name'
                my $printindex = { 'associated_element' => $associated_element, 'name' => $index_name, 'region' => $region, 'command' => 'printindex' };
                # prepare association of the index to the element by 
                # putting it in the current place
                push @{$state->{'place'}}, $printindex;
                push @{$Texi2HTML::THISDOC{'indices'}->{$region}->{$index_name}}, $printindex;
                #print STDERR "PRINTINDEX add($printindex) region $region name $index_name, nr ".scalar(@{$Texi2HTML::THISDOC{'indices'}->{$region}->{$index_name}})."\n";
                add_prev ($text, $stack, "\@$macro" .  $cline);
                last;
            }
            elsif ($macro eq 'listoffloats')
            {
                add_prev ($text, $stack, "\@$macro" .  $cline);
                last;
            }
            elsif ($sec2level{$macro})
            {
                if ($cline =~ /^\s*(.*)$/)
                {
                    my $name = $1;
                    my $heading_ref = new_section_heading($macro, $name, $state, $line_nr);
                    if (exists($state->{'region_lines'}) and $state->{'region_lines'}->{'format'})
                    {
                        my $region = $state->{'region_lines'}->{'format'};
                        $state->{'region_lines'}->{'head_num'}++;
                        my $num = $state->{'region_lines'}->{'head_num'};
                        $heading_ref->{'id'} = "${target_prefix}${region}_HEAD$num";
                        $heading_ref->{'sec_num'} = "${region}_$num";
                        $heading_ref->{'region'} = $region;
                        $heading_ref->{'region_head_num'} = $num;
                    }
                    else
                    {
                        $document_head_num++;
                        $heading_ref->{'id'} = "HEAD$document_head_num";
                        $heading_ref->{'sec_num'} = $document_head_num;
                    }
                    # this is only used when there is a index entry after the 
                    # heading
                    $heading_ref->{'target'} = $heading_ref->{'id'};
                    $heading_ref->{'heading'} = 1;
                    $heading_ref->{'tag_level'} = $macro;
                    $heading_ref->{'number'} = '';

                    $state->{'heading_element'} = $heading_ref;
                    push @{$state->{'place'}}, $heading_ref;
                    $headings{$heading_ref->{'sec_num'}} = $heading_ref;
                }
                add_prev ($text, $stack, "\@$macro" .  $cline);
                last;
            }
            elsif (index_command_prefix($macro) ne '')
            { # if we are already in a (v|f)table the construct is quite 
              # wrong
              # FIXME should it be discarded?
                if ($state->{'item'})
                {
                   line_error(sprintf(__("ignored \@%s already in an \@%s entry"), $macro, $state->{'item'}), $line_nr);
                   next;
                }
                my $index_prefix = index_command_prefix($macro);
                enter_index_entry($index_prefix, $line_nr, $cline, $macro, $state);
                add_prev ($text, $stack, "\@$macro" .  $cline);
                last;
            }
            elsif (defined($Texi2HTML::Config::texi_formats_map{$macro}))
            {
                my $macro_kept; 
                #print STDERR "TEXT_MACRO: $macro\n";
                if ($Texi2HTML::Config::texi_formats_map{$macro} eq 'raw')
                {
                    $state->{'raw'} = $macro;
                    $state->{$macro}++ if ($macro eq 'macro');
                    #print STDERR "RAW\n";
                }
                elsif ($Texi2HTML::Config::texi_formats_map{$macro} eq 'normal')
                {
                    if ($macro eq 'menu')
                    {
                       delete ($state->{'prev_menu_node'});
                       if (!$state->{'node_ref'})
                       {
                          line_error (sprintf(__("\@%s seen before first \@node"), $macro), $line_nr);
                          line_error (__("perhaps your \@top node should be wrapped in \@ifnottex rather than \@ifinfo?"), $line_nr);
                       }
                       if ($state->{'menu_in_node'})
                       {
                          line_error (sprintf(__("Multiple \@%s"), $macro), $line_nr);
                       }
                       $state->{'menu_in_node'}++;
                    }
                    $state->{$macro}++;
                    push @{$state->{'text_macro_stack'}}, $macro;
                    #print STDERR "MENU (text_macro_stack: @{$state->{'text_macro_stack'}})\n";
                }
                elsif (exists($region_lines{$macro}))
                {
                    if (exists($state->{'region_lines'}) and ($state->{'region_lines'}->{'format'} ne $macro))
                    {
                        line_error(sprintf(__("\@%s not allowed within %s"), $macro, $state->{'region_lines'}->{'format'}), $line_nr);
                        next;
                    }
                    open_region ($macro, $state);
                    if ($Texi2HTML::Config::region_formats_kept{$macro})
                    {
                        add_prev($text, $stack, "\@$macro");
                        $macro_kept = 1;
                        $state->{'region_lines'}->{'first_line'} = 1;
                    }
                    push @{$state->{'text_macro_stack'}}, $macro;
                }
                # if it is a raw formatting command or a menu command
                # we must keep it for later
                if (($state->{'raw'} and (!defined($Texi2HTML::Config::command_handler{$macro}))) or ($Texi2HTML::Config::texi_formats_map{$macro} eq 'normal'))
                {
                    add_prev($text, $stack, "\@$macro");
                    $macro_kept = 1;
                }
                if ($state->{'raw'})
                {
                    push @$stack, { 'style' => $macro, 'text' => '' };
                }
                next if $macro_kept;
                #dump_stack ($text, $stack, $state);
                return if ($cline =~ /^\s*$/);
            }
            elsif ($macro eq 'detailmenu' or $macro eq 'direntry')
            {
                if ($macro eq 'detailmenu' and !$state->{'node_ref'})
                {
                   line_error (sprintf(__("\@%s seen before first \@node"), $macro), $line_nr);
                }
                add_prev ($text, $stack, "\@$macro" .  $cline);
                $state->{$macro}++;
                last;
            }
            elsif ($macro eq 'float')
            { 
                my ($style_texi, $label_texi) = parse_line_arguments($cline, 2, "\@$macro", $line_nr);
                $style_texi = normalise_texi_space($style_texi);
                $label_texi = undef if (defined($label_texi) and ($label_texi =~ /^\s*$/));
                if (defined($label_texi))
                { # The float may be a target for refs if it has a label
                    my $error_with_label = 1;
                    $label_texi = normalise_node($label_texi);
                    if (exists($nodes{$label_texi}) and defined($nodes{$label_texi})
                         and $nodes{$label_texi}->{'seen'})
                    {
                        line_error (sprintf(__("Float label `%s' previously defined %s"), $label_texi, format_line_number($nodes{$label_texi}->{'line_nr'})), $line_nr);
                    }
                    elsif ($label_texi =~ /^\(.+\)/)
                    {
                        line_error (sprintf(__("Syntax for an external node used for `%s'"), $label_texi), $line_nr);
                    }
                    else
                    {
                        $error_with_label = 0;
                        my $float = { };
                        if (exists($nodes{$label_texi}) and defined($nodes{$label_texi}))
                        { # float appeared in a menu
                            $float = $nodes{$label_texi};
                        }
                        else
                        {
                            $nodes{$label_texi} = $float;
                        }
                        $float->{'float'} = 1;
                        $float->{'tag'} = 'float';
                        $float->{'texi'} = $label_texi;
                        $float->{'seen'} = 1;
                        $float->{'id'} = $label_texi;
                        $float->{'target'} = $label_texi;
#print STDERR "FLOAT: $float $float->{'texi'}, place $state->{'place'}\n";
                        push @{$state->{'place'}}, $float;
                        $float->{'element'} = $state->{'current_element'};
                        $state->{'float'} = $float;
                        $float->{'style_texi'} = $style_texi;
                        $float->{'line_nr'} = $line_nr;
                        push @floats, $float;
                    }

                    if ($error_with_label)
                    {
                        while ($cline =~ /,/)
                        {
                            $cline =~ s/,.*$//;
                        }
                    }
                }
                add_prev($text, $stack, "\@$macro" . $cline);
                last;
            }
            elsif (defined($Texi2HTML::Config::def_map{$macro}))
            {
                # @ may protect end of line in @def. We reconstruct lines here.
                # in the texinfo manual is said that spaces after @ collapse 
                if ($cline =~ /(\@+)\s*$/)
                {
                    my $at_at_end_of_line = $1;
                    if ((length($at_at_end_of_line) % 2) == 1)
                    {
                        #print STDERR "Line continue $cline";
                        my $def_line = $cline;
                        $def_line =~ s/\@\s*$//;
                        chomp($def_line);
                        $state->{'in_deff_line'} = "\@$macro" .$def_line;
                        return;
                    }
                }
                #We must enter the index entries
                my ($prefix, $entry, $argument) = get_deff_index($macro, $cline, $line_nr,1);
                # use deffn instead of deffnx for @-command record 
                # associated with index entry
                my $idx_macro = $macro;
                $idx_macro =~ s/x$//;
                enter_index_entry($prefix, $line_nr, $entry, $idx_macro, $state) 
                      if ($prefix);
                $cline =~ s/(.*)//;
                add_prev($text, $stack, "\@$macro" . $1);
            }
            elsif ($macro =~ /^itemx?$/)
            {
                enter_table_index_entry($text, $stack, $state, $line_nr);
                if ($state->{'table_stack'}->[-1] =~ /^(v|f)?table$/)
                {
                    $state->{'item'} = $macro;
                    push @$stack, { 'format' => 'index_item', 'text' => '', 'command' => $macro };
                }
                else
                {
                   add_prev($text, $stack, "\@$macro");
                }
            }
            elsif ($format_type{$macro} and ($format_type{$macro} eq 'table' or $format_type{$macro} eq 'list' or $macro eq 'multitable'))
            { # We must enter the index entries of (v|f)table thus we track
              # in which table we are
                push @{$state->{'table_stack'}}, $macro;
                add_prev($text, $stack, "\@$macro");
            }
            elsif ($cline =~ s/^{//)
            {
                if ($macro eq 'verb')
                {
                    if ($cline =~ /^$/)
                    {
                        # We already warned in pass texi
                    }
                    else
                    {
                        $cline =~ s/^(.)//;
                        $state->{'verb'} = $1;
                    }
                }
                elsif ($macro eq 'footnote' and (Texi2HTML::Config::get_conf('footnotestyle') eq 'separate'))
                {
                    $state->{'footnote_heading_element'} = $state->{'heading_element'};
                    $state->{'footnote_place'} = $state->{'place'};
                    $state->{'heading_element'} = $footnote_element;
                    $state->{'place'} = $footnote_element->{'place'};
                }
                push (@$stack, { 'style' => $macro, 'text' => '' });
            }
            else
            {
                $cline = do_unknown (1, $macro, $cline, $text, $stack, $state, $line_nr);
            }
            next;
        }
        #elsif($cline =~ s/^([^{}@]*)\@(.)//o)
        elsif($cline =~ s/^([^{}@]*)\@([^\s\}\{\@]*)//o)
        {
            add_prev($text, $stack, $1);
            $cline = do_unknown (1, $2, $cline, $text, $stack, $state, $line_nr);
            next;
        }
        elsif ($cline =~ s/^([^{}]*)([{}])//o)
        {
            add_prev($text, $stack, $1);
            if ($2 eq '{')
            {
                push @$stack, { 'style' => '', 'text' => '' };
            }
            else
            {
                if (@$stack)
                {
                    my $style = pop @$stack;
                    my $result;
                    add_prev ($text, $stack, 
                        close_structure_command($style, $state, 0, $line_nr));
                    next;
                }
                else
                {
                    # We warn in the last pass
                    add_prev ($text, $stack, '}');
                }
            }
        }
        else
        {
            add_prev($text, $stack, $cline);
            # in case of user mistake, with an @-command not closed on an @item line
            close_stack_structure($text, $stack, $state, $line_nr, 1) if ($state->{'item'});
            enter_table_index_entry($text, $stack, $state, $line_nr);
            #print STDERR "END_LINE(s) $cline";
            #dump_stack($text, $stack, $state);
            last;
        }
    }
    return 1;
} # end scan_structure

sub check_bad_end_argument ($$$)
{
  my $command = shift;
  my $line = shift;
  my $line_nr = shift;

  if ($line =~ /^(\S+)/)
  {
    my $symbols = $1;
    line_error (sprintf(__("Bad argument `%s' to `\@%s', using `%s'"), "${command}${symbols}", 'end', $command), $line_nr);
  }
}

sub close_style_command($$$$$;$)
{
  my $text = shift;
  my $stack = shift;
  my $state = shift;
  my $line_nr = shift;
  my $line = shift;
  # not the end of the style, but the paragraph the style is in is closed
  my $no_close = shift;

  my $style = pop @$stack;
  my $command = $style->{'style'};
  my $result;
  if (!defined($command))
  {
     print STDERR "Bug: empty style in pass_text\n";
     return ($result, $command);
  }
  if (ref($::style_map_ref->{$command}) eq 'HASH')
  {
    push (@{$style->{'args'}}, $style->{'text'});
    $style->{'fulltext'} .= $style->{'text'};
    if (!defined($style->{'arg_nr'}))
    {
       msg_debug("Bug: undefined 'arg_nr' for $command", $line_nr);
    }
    #print STDERR "DEBUG $command ($style->{'arg_nr'})\n";
    #my $number = 0;
    #foreach my $arg(@{$style->{'args'}})
    #{
    #  print STDERR "  $number: $arg\n";
    #     $number++;
    #}
    #print STDERR "END DEBUG\n";
    $style->{'text'} = $style->{'fulltext'};
    $state->{'keep_texi'} = 0 if (
     ($::style_map_ref->{$command}->{'args'}->[$style->{'arg_nr'}] eq 'keep')
    and ($state->{'keep_nr'} == 1));
  }
  if ($no_paragraph_macro{$command})
  {
     $state->{'no_paragraph'}--;
     pop @{$state->{'no_paragraph_stack'}};
  }
  if ($::style_map_ref->{$command} and (defined($style_type{$command})) and ((!$no_close and ($style_type{$command} eq 'style')) or ($style_type{$command} eq 'accent')))
  {
    my $style_command = pop @{$state->{'command_stack'}};
    if ($style_command ne $command)
    {
      #line_warn ("Bug: $style_command on 'command_stack', not $command", $line_nr);
      # This can be a bug in case of bad nesting, see bad_style_nesting.texi
      line_warn("Bad nesting of \@$style_command and \@$command", $line_nr);
      push @{$state->{'command_stack'}}, $style_command;
    ############################ debug
      if ($T2H_DEBUG)
      {
        push @$stack, $style;
        print STDERR "Stacks before pop top:\n";
        dump_stack($text, $stack, $state);
        pop @$stack;
    ############################ end debug
      }
    }
  }
  if ($state->{'keep_texi'})
  { # don't expand @-commands in anchor, refs...
    close_arg ($command, $style->{'arg_nr'}, $state);
    $result = '@' . $command . '{' . $style->{'text'} . '}';
  }
  elsif ($::things_map_ref->{$command})
  {
    $result = do_thing_command ($command, $style->{'text'}, $state, $line_nr);
  }
  else
  {
    $result = do_style_command($command, $style->{'text'}, $state, $style->{'args'}, $line_nr, $style->{'no_open'}, $no_close, $style->{'keep_line_nr'});
    if ($state->{'code_style'} < 0)
    {
      msg_debug ("Bug: negative code_style: $state->{'code_style'}, line:$line", $line_nr);
    }
    if ($state->{'math_style'} < 0)
    {
      msg_debug ("Bug: negative math_style: $state->{'math_style'}, line:$line", $line_nr);
    }
  }
  return ($result, $command);
}

sub top_stack_is_menu($)
{
   my $stack = shift;
   my $top_stack = top_stack($stack, 1);
   return 0 if (!$format_type{$top_stack->{'format'}} or $format_type{$top_stack->{'format'}} ne 'menu');
   return 1;
}


sub scan_line($$$$;$)
{
    my $original_line = shift;
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $line_nr = shift;

    die "stack not an array ref"  unless (ref($stack) eq "ARRAY");
    my $cline = $original_line;
    #msg_debug("SCAN_LINE (@{$state->{'command_stack'}}): $original_line", $line_nr);
    #dump_stack($text, $stack, $state);
    my $new_menu_entry; # true if there is a new menu entry
#    my $menu_description_in_format; # true if we are in a menu description 
#                                # but in another format section (@table....)

    # this can happen currently with quotations
    if (defined($state->{'prepend_text'}))
    {
        $cline = $state->{'prepend_text'} . $cline;
        $state->{'prepend_text'} = undef;
        delete $state->{'prepend_text'};
    }

    if (!$state->{'raw'} and !$state->{'verb'} and ($state->{'menu'} or $state->{'direntry'}))
    { # new menu entry
        my ($node, $name, $ending, $remaining) = parse_menu_entry($cline);
        if (defined($node))
        {
            $cline = $remaining;
            print STDERR "# Potential menu entry: $node\n" if ($T2H_DEBUG & $DEBUG_MENU);
            $new_menu_entry = 1;
            my $menu_entry = { 'name' => $name, 'node' => $node, 'ending' => $ending };
            # in SIMPLE_MENU case we don't begin a description, description is 
            # just some normal (preformatted) text
            if ($Texi2HTML::Config::SIMPLE_MENU)
            {
                add_prev ($text, $stack, do_menu_link($state, $line_nr, $menu_entry));
                #dump_stack($text, $stack, $state);
            }
            else
            {
                # close description and comment, if they are opened.
                #dump_stack($text, $stack, $state);
                if (!close_menu_comment($text, $stack, $state, __("new menu entry"), $line_nr) 
                  and !close_menu_description($text, $stack, $state, __("new menu entry"), $line_nr)
                  and $state->{'preformatted'})
                {
                    close_paragraph($text, $stack, $state, __("new menu entry"), $line_nr);
                }
                print STDERR "# New menu entry: $node\n" if ($T2H_DEBUG & $DEBUG_MENU);
                #dump_stack($text, $stack, $state);
                my $fusionned_description = 0;
                # fusionned looks better in preformatted. But some formats
                # want to always distinguish link and description 
                if ($Texi2HTML::Config::SEPARATE_DESCRIPTION or !$state->{'preformatted'})
                {
                    add_prev ($text, $stack, do_menu_link($state, $line_nr, $menu_entry));
                }
                else
                {
                    $fusionned_description = 1;
                }
                push @$stack, {'format' => 'menu_description', 'text' => '', 'menu_entry' => $menu_entry, 'fusionned_description' => $fusionned_description};
                $state->{'code_style'}++ if ($Texi2HTML::Config::format_code_style{'menu_description'});
                if ($fusionned_description)
                {
                    begin_paragraph($stack, $state) if $state->{'preformatted'};
                    add_prev ($text, $stack, do_menu_link($state, $line_nr, $menu_entry));
                }
             }
        }
        # we may be in a menu entry description, we close it 
        # if there is an empty line, so the last arg is $cline.
        # also if right in menu we always open a menu_comment, it
        # means that there was no menu entry seen since the menu beginning.
        if (!$new_menu_entry and (close_menu_description($text, $stack, $state, "end menu description", $line_nr, $cline) or ($stack->[-1]->{'format'} and $format_type{$stack->[-1]->{'format'}} and $format_type{$stack->[-1]->{'format'}} eq 'menu')))
        {
            if ($state->{'preformatted'})
            {
                begin_paragraph($stack, $state);
            }
            else
            {
               # only start a menu_comment if right in menu and not in 
               # a format below a menu because if not right
               # in a menu we have no way to distinguish a menu_comment
               # and some normal text in the format.
               # also it is not started in preformatted environment
               begin_format($text, $stack, $state, 'menu_comment', $cline, $line_nr) if ($stack->[-1]->{'format'} and $format_type{$stack->[-1]->{'format'}} and $format_type{$stack->[-1]->{'format'}} eq 'menu');
            }
        }
    }

    unless ($state->{'raw'} or $state->{'verb'} or $state->{'keep_texi'})
    {
    # first the line commands are taken into account
        my $next_command = next_tag($cline);
        if (defined($next_command) and defined($Texi2HTML::Config::line_command_map{$next_command}))
        {
            close_paragraph($text, $stack, $state, "\@$next_command", $line_nr, 1) if (stop_paragraph_command($next_command));
            my $arg_texi = $cline;
            $arg_texi =~ s/^\s*\@$next_command\s*//;
            $arg_texi = trim_comment_spaces ($arg_texi, "\@$next_command", $line_nr);
            my $arg_line = substitute_line($arg_texi, "\@$next_command", duplicate_formatting_state($state));
            add_prev ($text, $stack, &$Texi2HTML::Config::line_command($next_command, $arg_line, $arg_texi, $state));
            enter_author_command ($next_command, $arg_texi, $arg_line, $stack, $state, $line_nr);
            return '';
        }
        elsif (defined($next_command) and ($next_command eq 'contents') or ($next_command eq 'summarycontents') or ($next_command eq 'shortcontents'))
        {
            my $element_tag = $next_command;
            $element_tag = 'shortcontents' if ($element_tag ne 'contents');
            # at that point the content_element is defined for sure since
            # we already saw the tag
            if ($Texi2HTML::Config::INLINE_CONTENTS and !Texi2HTML::Config::get_conf('set' . $element_tag . 'aftertitlepage'))
            {
                my $content_element = shift (@{$all_content_elements{$element_tag}});
                my $toc_lines = &$Texi2HTML::Config::inline_contents($Texi2HTML::THISDOC{'FH'}, $element_tag, $content_element, \@sections_list);
                add_prev ($text, $stack, join('',@$toc_lines)) if (defined($toc_lines));
            }
            return '' unless (exists($Texi2HTML::Config::misc_command{$next_command}) and $Texi2HTML::Config::misc_command{$next_command}->{'keep'});
        }

    # The commands to ignore are ignored now in case after ignoring them
    # there is an empty line, to be able to stop the paragraph
        #my $leading_spaces = '';
        
        while (1)
        {
            my $next_tag = next_tag($cline);
            close_paragraph($text, $stack, $state, "\@$next_tag", $line_nr, 1) if (stop_paragraph_command($next_tag));
            if (defined($next_tag) and defined($Texi2HTML::Config::misc_command{$next_tag}) and !$Texi2HTML::Config::misc_command{$next_tag}->{'keep'})
            {
                $cline =~ s/^(\s*)\@$next_tag//;
                #$leading_spaces .= $1;
                add_prev ($text, $stack, do_text($1, $state));
                my $result;
                ($cline, $result) = misc_command_text($cline, $next_tag, $stack, $state, $text, $line_nr);
                add_prev($text, $stack, $result) if (defined($result));
            }
            else
            {
                last;
            }
        }
        #add_prev ($text, $stack, $leading_spaces);
        return '' if (!defined($cline) or $cline eq '');
    }
    my $top_stack = top_stack($stack);
    if (($top_stack->{'format'} and $top_stack->{'format'} eq 'menu_description') or $state->{'raw'} or $state->{'preformatted'}  or $state->{'no_paragraph'} or $state->{'keep_texi'} or $state->{'remove_texi'})
    { # empty lines are left unmodified in these contexts.
      # it is also possible to be in preformatted within a menu_description
        if ($cline =~ /^\s*$/)
        {
            if ($state->{'raw'})
            {
                print STDERR "#within raw $state->{'raw'}(empty line):$cline" if ($T2H_DEBUG & $DEBUG_FORMATS);
                add_prev($text, $stack, $cline);
            }
            else
            {
                add_prev($text, $stack, do_text($cline,$state));
            }
            return;
        }
    }
    else
    {
        if ($cline =~ /^\s*$/)
        {
            if ($state->{'paragraph_context'})
            { # An empty line ends a paragraph
                close_paragraph($text, $stack, $state, __("paragraph end"), $line_nr);
            }
            add_prev($text, $stack, &$Texi2HTML::Config::empty_line($cline,$state));
            return 1;
        }
        else
        {
            if (!no_paragraph($state,$cline))
            { # open a paragraph, unless the line begins with a macro that
              # shouldn't trigger a paragraph opening
                begin_paragraph($stack, $state);
            }
        }
    }
    # we flag specially deff_item and table line that contain only 
    # inter_item_command, which typically is be @c, @comment, @*index, such
    # that the formatter can treat those specifically.
    my $top_format = top_stack($stack,2);
    if ($top_format->{'only_inter_commands'} and !$state->{'keep_texi'})
    {
        my $real_format = $top_format->{'format_ref'}->{'format'};
        my $next_tag = next_tag($cline);
        $next_tag = '' if (!defined($next_tag));
        my $next_end_tag = next_end_tag($cline);
        $next_end_tag = '' if (!defined($next_end_tag));
        #msg_debug("$top_format->{'format'} $next_tag, end $next_end_tag :::$cline");
        delete $top_format->{'only_inter_commands'} unless
         (
          $Texi2HTML::Config::inter_item_commands{$next_tag} or 
          (index_command_prefix($next_tag) ne '' and $Texi2HTML::Config::inter_item_commands{'cindex'}) or
          ($top_format->{'format'} eq 'deff_item' and "${real_format}x" eq $next_tag) or
          ($top_format->{'format'} ne 'deff_item' and $next_tag =~ /^itemx?$/) or
          ( $next_end_tag eq $real_format )
         );
          #print STDERR "STILL $top_format->{'only_inter_commands'}\n" if ($top_format->{'only_inter_commands'});
    }

    while(1)
    {
        # scan_line
        #print STDERR "WHILE(l): $cline|";
        #msg_debug("Dump stack in scan_line", $line_nr);
        #dump_stack($text, $stack, $state);
        # we're in a raw format (html, tex if !L2H, verbatim)
        if (defined($state->{'raw'})) 
        {
            (dump_stack($text, $stack, $state), die "Bug for raw ($state->{'raw'})") if (! @$stack or ! ($stack->[-1]->{'style'} eq $state->{'raw'}));
            if ($state->{'raw'} eq 'macro')
            {
                if ($cline =~ /^\s*\@macro\s+(\w[\w-]*)\s*(.*)/)
                {
                    $state->{$state->{'raw'}}++;
                }
            }
            # macro_regexp
            if ($cline =~ /^(.*?)\@end\s([a-zA-Z][\w-]*)/o and ($2 eq $state->{'raw'}))
            # don't protect html, it is done by Texi2HTML::Config::raw if needed
            {
                $cline =~ s/^(.*?)(\@end\s$state->{'raw'})//;
                my $remaining = $1;
                my $end_text = $2;
                if ($state->{'raw'} eq 'macro')
                {
                    $state->{$state->{'raw'}}--;
                    if ($state->{$state->{'raw'}})
                    {
                        add_prev ($text, $stack, $remaining.$end_text);
                        last;
                    }
                }
                check_bad_end_argument ($state->{'raw'}, $cline, $line_nr);
                add_prev ($text, $stack, $remaining);
                my $style = pop @$stack;
                if ($style->{'text'} !~ /^\s*$/)
                {
                    if ($state->{'keep_texi'})
                    {
                        add_prev ($text, $stack, $style->{'text'} . "\@end $state->{'raw'}");
                    }
                    elsif ($state->{'remove_texi'})
                    {
                        add_prev ($text, $stack, &$Texi2HTML::Config::raw_no_texi($style->{'style'}, $style->{'text'}));
                    }
                    else
                    { 
                        add_prev($text, $stack, &$Texi2HTML::Config::raw($style->{'style'}, $style->{'text'}, $line_nr));
                    }
                }
                if (!$state->{'keep_texi'} and !$state->{'remove_texi'})
                {
                    # reopen preformatted if it was interrupted by the raw format
                    # if raw format is html the preformatted wasn't interrupted
                    begin_paragraph($stack, $state) if ($state->{'preformatted'} and (!$Texi2HTML::Config::format_in_paragraph{$state->{'raw'}})); 
                    delete $state->{'raw'};
                    return if ($cline =~ /^\s*$/);
                }
                delete $state->{'raw'};
                return if (($cline =~ /^\s*$/) and $state->{'remove_texi'});
                next;
            }
            else
            {
                print STDERR "#within raw $state->{'raw'}:$cline" if ($T2H_DEBUG & $DEBUG_FORMATS);
                add_prev ($text, $stack, $cline);
                last;
            }
        }

        # we are within a @verb
        if (defined($state->{'verb'}))
        {
            my $char = quotemeta($state->{'verb'});
            if ($cline =~ s/^(.*?)$char\}/\}/)
            {
                 if ($state->{'keep_texi'})
                 {
                     add_prev($text, $stack, $1 . $state->{'verb'});
                     $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'};
                 }
                 else
                 {
                     add_prev($text, $stack, do_text($1, $state));
                 }
                 delete $state->{'verb'};
                 next;
            }
            else
            {
                 add_prev($text, $stack, $cline);
                 last;
            }
        }

        # We handle now the end tags 
        # macro_regexp
        if ($cline =~ s/^([^{}@]*)\@end\s+([a-zA-Z][\w-]*)//)
        {
            my $end_tag = $2;
            my $prev_text = $1;
            if ($state->{'keep_texi'})
            {
                add_prev($text, $stack, $prev_text . "\@end $end_tag");
                next;
            }
            elsif ($state->{'remove_texi'})
            {
                add_prev($text, $stack, $prev_text);
                next;
            }

            add_prev($text, $stack, do_text($prev_text, $state));
	    #print STDERR "END_MACRO $end_tag\n";
	    #dump_stack ($text, $stack, $state);

            # First we test if the stack is not empty.
            # Then we test if the end tag is a format tag.
            # We then close paragraphs and preformatted at top of the stack.
            # We handle the end tag (even when it was not the tag which appears
            # on the top of the stack; in that case we close anything 
            # until that element)
            my $top_stack = top_stack($stack);
            if (!$top_stack)
            {
                line_error (sprintf(__("Unmatched `%c%s'"), ord('@'), 'end'), $line_nr);
                add_prev($text, $stack, "\@end $end_tag");
                next;
            }

            if (!$format_type{$end_tag})
            {
                line_warn ("Unknown \@end $end_tag", $line_nr);
                add_prev($text, $stack, "\@end $end_tag");
                next;
            }
            check_bad_end_argument ($end_tag, $cline, $line_nr);
            if (!close_menu_description($text, $stack, $state, "\@end $end_tag", $line_nr))
            {
               close_paragraph($text, $stack, $state, "\@end $end_tag", $line_nr); 
            }

            $top_stack = top_stack($stack);
            if (!$top_stack or (!defined($top_stack->{'format'})))
            {
                line_error (sprintf(__("Unmatched `%c%s'"), ord('@'), 'end'), $line_nr);
                add_prev($text, $stack, "\@end $end_tag");
                dump_stack ($text, $stack, $state) if ($T2H_DEBUG);
                next;
            }
            # Warn if the format on top of stack is not compatible with the 
            # end tag, and find the end tag.
            unless (
                ($top_stack->{'format'} eq $end_tag)
                or
                (
                 $format_type{$end_tag} eq 'menu' and
                  $top_stack->{'format'} eq 'menu_comment'
                ) or
                (
                 $end_tag eq 'multitable' and $top_stack->{'format'} eq 'cell'
                ) or
                (
                 $format_type{$end_tag} eq 'list' and $top_stack->{'format'} eq 'item'
                ) or
                (
                  $format_type{$end_tag} eq 'table'
                  and
                  ($top_stack->{'format'} eq 'term' or $top_stack->{'format'} eq 'line')
                ) or
                (
                 defined($Texi2HTML::Config::def_map{$end_tag}) and
                 $top_stack->{'format'} eq 'deff_item'
                )
               )
            {
                # this is not the right format. We try to close other
                # formats to find the format we are searching for.
                # First we close paragraphs, as with a wrong $end_format
                # they may not be closed properly.

                #print STDERR "  MISMATCH got $top_stack->{'format'} waited \@end $end_tag($top_stack->{'format'})\n";
                #dump_stack ($text, $stack, $state);
                close_paragraph($text, $stack, $state, "\@end $end_tag", $line_nr);
                $top_stack = top_stack($stack);
                if (!$top_stack or (!defined($top_stack->{'format'})))
                {
                    line_error (sprintf(__("Unmatched `%c%s'"), ord('@'), 'end'), $line_nr);
                    add_prev($text, $stack, "\@end $end_tag");
                    # at that point the dump_stack is not very useful, since
                    # close_paragraph above may hide interesting info
                    dump_stack ($text, $stack, $state) if ($T2H_DEBUG);
                    next;
                }
                my $waited_format = $top_stack->{'format'};
                $waited_format = $fake_format{$top_stack->{'format'}} if ($format_type{$top_stack->{'format'}} eq 'fake');
                if ($end_tag ne $waited_format)
                {
                    line_error (sprintf(__("`\@end' expected `%s', but saw `%s'"), $waited_format, $end_tag), $line_nr);
                }
                else
                {
                    msg_debug ("\@end is $end_tag, was waiting for $top_stack->{'format'}", $line_nr);
                    dump_stack ($text, $stack, $state);
                }
                close_stack($text, $stack, $state, $line_nr, $end_tag);
                # FIXME this is too complex
                # an empty preformatted may appear when closing things as
                # when closed, formats reopen the preformatted environment
                # in case there is some text following, but we know it isn't 
                # the case here, thus we can close paragraphs.
                close_paragraph($text, $stack, $state, "\@end $end_tag");
                my $new_top_stack = top_stack($stack);
                next unless ($new_top_stack and defined($new_top_stack->{'format'}) and (($new_top_stack->{'format'} eq $end_tag) 
                   or (($format_type{$new_top_stack->{'format'}} eq 'fake') and ($fake_format{$new_top_stack->{'format'}} eq $format_type{$end_tag}))));
            }
            # We should now be able to handle the format
            if (defined($format_type{$end_tag}))
            {# remove the space or new line following the @end command
                $cline =~ s/\s//;
                if (end_format($text, $stack, $state, $end_tag, $line_nr))
                { # if end_format is false, paragraph is already begun
                    begin_paragraph_after_command($state,$stack,$end_tag,$cline);
                }
            }
            next;
        }
        # This is a macro
	#elsif (s/^([^{}@]*)\@([a-zA-Z]\w*|["'~\@\}\{,\.!\?\s\*\-\^`=:\/])//o)
        # macro_regexp
        elsif ($cline =~ s/^([^{},@]*)\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/\\])//o or $cline =~ s/^([^{}@,]*)\@([a-zA-Z][\w-]*)//o)
        {
            my $before_macro = $1;
            my $macro = $2;
            $macro = $alias{$macro} if (exists($alias{$macro}));
            my $punct;
            if (!$state->{'keep_texi'} and $macro eq ':' and $before_macro =~ /(.)$/ and $Texi2HTML::Config::colon_command_punctuation_characters{$1})
            {
                $before_macro =~ s/(.)$//;
                $punct = $1;
            }
            add_prev($text, $stack, do_text($before_macro, $state));
            add_prev($text, $stack, &$Texi2HTML::Config::colon_command($punct)) if (defined($punct));
	    #print STDERR "MACRO $macro\n";
	    #print STDERR "LINE $cline";
	    #dump_stack ($text, $stack, $state);

            close_paragraph($text, $stack, $state, "\@$macro", $line_nr, 1) if (stop_paragraph_command($macro) and !$state->{'keep_texi'});

            if ($macro eq 'listoffloats' or $macro eq 'printindex')
            {
                if ($state->{'keep_texi'})
                {
                    if ($cline =~ s/(.*)//o)
                    {
                        add_prev($text, $stack, "\@$macro" . $1);
                    }
                    next;
                }
                close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
                return undef if ($state->{'remove_texi'});
                if ($macro eq 'listoffloats')
                { 
                    # remove possible comments 
                    my $arg = normalise_texi_space(trim_comment_spaces ($cline, "\@$macro", $line_nr));

                    my $style_id = cross_manual_line($arg);
                    my $style = substitute_line (&$Texi2HTML::Config::listoffloats_style($arg), __("\@listoffloats type"), undef, $line_nr);
                    my $style_no_texi = remove_texi (&$Texi2HTML::Config::listoffloats_style($arg));
                    if (exists ($floats{$style_id}))
                    {
                         my @listoffloats_entries = ();
                         foreach my $float (@{$floats{$style_id}->{'floats'}})
                         {
                              my $float_style = substitute_line(&$Texi2HTML::Config::listoffloats_float_style($arg, $float), __("\@listoffloats \@float type"));
                              my ($caption_lines, $caption_or_shortcaption) = &$Texi2HTML::Config::listoffloats_caption($float);
                              # we set 'multiple_pass', and 'expansion'
                              # such that index entries
                              # and anchors are not handled one more time;
                              # the caption has already been formatted, 
                              # and these have been handled at the right place
                              # FIXME footnotes?
                              my $caption = '';
                              $caption = substitute_text(prepare_state_multiple_pass($macro, $state), undef, "\@$caption_or_shortcaption in listoffloats", @$caption_lines) if (defined($caption_or_shortcaption));
                              push @listoffloats_entries, &$Texi2HTML::Config::listoffloats_entry($arg, $float, $float_style, $caption, href($float, $state->{'element'}->{'file'}, $line_nr));
                         }
                         add_prev($text, $stack, &$Texi2HTML::Config::listoffloats($arg, $style, \@listoffloats_entries));
                    }
                    else
                    {
                         line_warn (sprintf(__("Requested float type `%s' not previously used"), $arg), $line_nr); 
                    }
                }
                elsif ($macro eq 'printindex' and $cline =~ s/\s+(\w+)\s*//)
                {
                    my $index_name = $1;
                    my $region = $state->{'region'};
                    $region = 'document' if (!defined($region));

                    if (!defined($Texi2HTML::THISDOC{'indices'}->{$region}))
                    {
                      msg_debug ("\@printindex $index_name THISDOC{'indices'}->{$region} not defined", $line_nr);
                    }
                    elsif (!defined($Texi2HTML::THISDOC{'indices'}->{$region}->{$index_name}))
                    {
                      msg_debug ("\@printindex $index_name THISDOC{'indices'}->{$region}->{$index_name} not defined", $line_nr);
                    }

                    if (!defined($Texi2HTML::THISDOC{'indices_numbers'}->{$region}->{$index_name}))
                    {
                      $Texi2HTML::THISDOC{'indices_numbers'}->{$region}->{$index_name} = -1;
                    }
                    $Texi2HTML::THISDOC{'indices_numbers'}->{$region}->{$index_name}++;
                    my $printindex = $Texi2HTML::THISDOC{'indices'}->{$region}->{$index_name}->[$Texi2HTML::THISDOC{'indices_numbers'}->{$region}->{$index_name}];
                    if (!defined($printindex))
                    {
                      # this printindex hasn't been seen in the previous pass.
                      # rint STDERR "Index $index_name not in sync, number $Texi2HTML::THISDOC{'indices_numbers'}->{$index_name} not defined\n";
                      line_warn("\@printindex $index_name expanded more than once may lead to wrong references", $line_nr);
                      $printindex = $Texi2HTML::THISDOC{'indices'}->{$region}->{$index_name}->[-1];
                    }
                    elsif ($printindex->{'name'} ne $index_name)
                    {
                      print STDERR "BUG: THISDOC{'indices'} $printindex->{'name'} ne $index_name\n";
                    }
                    #print STDERR "PRINTINDEX use($printindex) region $region, name $index_name number $Texi2HTML::THISDOC{'indices_numbers'}->{$region}->{$index_name}\n";
                    add_prev($text, $stack, &$Texi2HTML::Config::printindex($index_name, $printindex));
                }
                else
                {
                    $cline =~ s/^\s*//;
                    chomp ($cline);
                    line_error (sprintf(__("Bad argument to \@%s: %s"), $macro, $cline), $line_nr);
                }
                begin_paragraph ($stack, $state) if ($state->{'preformatted'});
                return undef;
            }
            if (defined($Texi2HTML::Config::misc_command{$macro}))
            {
                # Handle the misc command
                my $result;
                ($cline, $result) = misc_command_text($cline, $macro, $stack, $state, $text, $line_nr);
                add_prev($text, $stack, $result) if (defined($result));
                return unless (defined($cline));
                unless ($Texi2HTML::Config::misc_command{$macro}->{'keep'})
                {
                     begin_paragraph($stack, $state) if 
                       (!no_paragraph($state,$cline));
                     next;
                }
            }
            # This is a @macroname{...} construct. We add it on top of stack
            # It will be handled when we encounter the '}'
            # There is a special case for def macros as @deffn{def} is licit
            if (!$Texi2HTML::Config::def_map{$macro} and $cline =~ s/^{//) #}
            {
                if ($macro eq 'verb')
                {
                    if ($cline =~ /^$/)
                    {
                        # Allready warned 
                    }
                    else
                    {
                        $cline =~ s/^(.)//;
                        $state->{'verb'} = $1;
                    }
                } 
                # currently if remove_texi and anchor/ref/footnote
                # the text within the command is ignored
                # see t2h_remove_command in texi2html.init
                my $new_command_ref = { 'style' => $macro, 'text' => '', 'arg_nr' => 0, 'line_nr' => $line_nr };
                push (@$stack, $new_command_ref);
                if ($no_paragraph_macro{$macro})
                {
                   $state->{'no_paragraph'}++;
                   push @{$state->{'no_paragraph_stack'}}, "\@$macro";
                }
                open_arg($macro, 0, $state);
                if ($state->{'keep_texi'})
                {
                   $new_command_ref->{'keep_line_nr'} = [ $line_nr ];
                } 
                my $real_style_command = 0;
                if (defined($style_type{$macro}) and (($style_type{$macro} eq 'style') or ($style_type{$macro} eq 'accent')))
                {
                     push (@{$state->{'command_stack'}}, $macro);
                     $real_style_command = 1;
                     #print STDERR "# Stacked $macro (@{$state->{'command_stack'}})\n" if ($T2H_DEBUG); 
                }
                # FIXME give line, and modify line?
                &$Texi2HTML::Config::begin_style_texi($macro, $state, $stack, $real_style_command, $state->{'remove_texi'})
                  if (defined($Texi2HTML::Config::begin_style_texi) 
                      and !($state->{'keep_texi'}));
                next;
            }

            # special case if we are checking itemize line. In that case
            # we want to make sure that there is no @item on the @itemize
            # line, otherwise it will be added on the front of another @item,
            # leading to an infinite loop...

            if ($state->{'check_item'} and ($macro =~ /^itemx?$/ or $macro eq 'headitem'))
            {
                line_error(sprintf(__("\@%s not allowed in argument to \@%s"), $macro, $state->{'check_item'}), $line_nr);
                next;
            }

            # if we're keeping texi unmodified we can do it now
            if ($state->{'keep_texi'})
            {
                # We treat specially formats accepting {} on command line
                if ($macro eq 'multitable' or defined($Texi2HTML::Config::def_map{$macro}) or defined($sec2level{$macro}) or $macro eq 'macro')
                {
                    add_prev($text, $stack, "\@$macro" . $cline);
                    $cline = '';
                    next;
                }

                add_prev($text, $stack, "\@$macro");
                if ($Texi2HTML::Config::texi_formats_map{$macro} and $Texi2HTML::Config::texi_formats_map{$macro} eq 'raw')
                {
                    $state->{'raw'} = $macro;
                    $state->{$macro}++ if ($macro eq 'macro');
                    push (@$stack, {'style' => $macro, 'text' => ''});
                }
                next;
            }

            # If we are removing texi, the following macros are not removed 
            # as is but modified. So they are collected first, as if we were
            # in normal text

            # a raw macro beginning
            if ($Texi2HTML::Config::texi_formats_map{$macro} and $Texi2HTML::Config::texi_formats_map{$macro} eq 'raw')
            {
                if (!$Texi2HTML::Config::format_in_paragraph{$macro})
                { # close paragraph before verbatim (and tex if !L2H)
                    close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
                }
                $state->{'raw'} = $macro;
                push (@$stack, {'style' => $macro, 'text' => ''});
                $state->{$macro}++ if ($macro eq 'macro');
                return if ($cline =~ /^\s*$/ or ($macro eq 'macro'));
                next;
            }
            my $simple_macro = 1;
            # An accent macro
            if (exists($Texi2HTML::Config::accent_map{$macro}))
            {
                # the command itself is not in the command stack, since with
                # braces, it is already popped when do_simple is called
                #push (@{$state->{'command_stack'}}, $macro);
                if ($macro =~ /^[a-zA-Z]/)
                {
                    $cline =~ s/^\s*//;
                }
                elsif ($cline =~ /^\s/)
                {
                    line_warn (sprintf(__("Accent command `\@%s' must not be followed by whitespace"), $macro), $line_nr);
                }
                if ($cline =~ /^\@/)
                {
                    line_error (sprintf(__("Use braces to give a command as an argument to \@%s"), $macro), $line_nr);
                }
                if ($cline =~ s/^(\S)//o)
                {
                    add_prev($text, $stack, do_style_command($macro, $1, $state, [ $1 ], $line_nr, undef, undef, undef));
                }
                else
                { # The accent is at end of line
                    # FIXME warn? And test case? Maybe this is catched 
                    # above, by "Accent command `@%s' must not be followed by whitespace"
                    # for commands with letter.
                    add_prev($text, $stack, do_text($macro, $state));
                }
                #pop @{$state->{'command_stack'}};
            }
            # an @-command which should be like @command{}. We handle it...
            elsif ($::things_map_ref->{$macro})
            {
                line_error (sprintf(__("\@%s expected braces"), $macro), $line_nr);
                add_prev($text, $stack, do_thing_command($macro, '', $state, $line_nr));
            }
            # an @-command like @command
            elsif (defined($::simple_map_ref->{$macro}) or ($state->{'math_style'} and defined($::simple_map_math_ref->{$macro})))
            {
                add_prev($text, $stack, do_simple_command($macro, $state, $line_nr));
            }
            else
            {
                $simple_macro = 0;
            }
            if ($simple_macro)
            {# if the macro didn't triggered a paragraph start it might now
                begin_paragraph($stack, $state) if 
                   ($Texi2HTML::Config::no_paragraph_commands{$macro} and !no_paragraph($state,$cline));
                next;
            }
            # the following macros are modified or ignored if we are 
            # removing texi, and they are not handled like macros in normal text
            if ($state->{'remove_texi'})
            {
                 # handle specially some macros
                 if ((index_command_prefix($macro) ne '') or 
                      ($macro eq 'itemize') or 
                      ($format_type{$macro} and ($format_type{$macro} eq 'table' or $format_type{$macro} eq 'quotation'))
                      or ($macro eq 'multitable'))
                 {
                      return;
                 }
                 elsif ($macro eq 'enumerate')
                 {
                      my $spec;
                      ($cline, $spec) = parse_enumerate ($cline);
                      return if ($cline =~ /^\s*$/);
                      next;
                 }
                 elsif (defined($Texi2HTML::Config::def_map{$macro}))
                 {
                     my ($command, $style, $category, $name, $type, $class, $arguments, $args_array);
                     ($command, $style, $category, $name, $type, $class, $arguments, $args_array) = parse_def($macro, $cline, $line_nr); 
                     # FIXME -- --- ''... lead to simple text in texi2html
                     # while they are kept as is in html coments by makeinfo
                     $category = remove_texi($category) if (defined($category));
                     $name = remove_texi($name) if (defined($name));
                     $type = remove_texi($type) if (defined($type));
                     $class = remove_texi($class) if (defined($class));
                     $arguments = remove_texi($arguments) if (defined($arguments));
                     chomp($arguments);
                     add_prev($text, $stack, &$Texi2HTML::Config::def_line_no_texi($category, $name, $type, $arguments));
                     return;
                }
                elsif (defined($sec2level{$macro}))
                { #FIXME  there is certainly more intelligent stuff to do
                    my $num;
                    if ($state->{'region'})
                    {
                        $state->{'head_num'}++;
                        $num = "$state->{'region'}_$state->{'head_num'}";
                    }
                    else
                    {
                        $num = $global_head_num;
                    }
                    my $heading_element = $headings{$num};
                    $cline = trim_comment_spaces ($cline, "\@$macro");
                    add_prev($text, $stack, &$Texi2HTML::Config::heading_no_texi($heading_element, $macro, $cline));
                    return;
                }

                # ignore other macros
                next;
            }

            # handle the other macros, we are in the context of normal text
            if (defined($sec2level{$macro}))
            {
                 #dump_stack($text, $stack, $state);
                 my $num;
                 if ($state->{'region'})
                 {
                     $state->{'head_num'}++;
                     $num = "$state->{'region'}_$state->{'head_num'}";
                 }
                 else
                 {
                     $global_head_num++;
                     $num = $global_head_num;
                 }
                 my $heading_element = $headings{$num};
                 $cline = trim_comment_spaces($cline, "\@$macro", $line_nr);
                 add_prev($text, $stack, &$Texi2HTML::Config::element_label($heading_element->{'id'}, $heading_element, $macro, $cline));
                 add_prev($text, $stack, &$Texi2HTML::Config::heading($heading_element, $macro, $cline, substitute_line($cline, "\@$macro"), $state->{'preformatted'}));
                 return;
            }

            if (index_command_prefix($macro) ne '')
            {
                my $index_name = index_command_prefix($macro);
                my $entry_texi = trim_comment_spaces($cline, "\@$macro", $line_nr);
                chomp($entry_texi);
                # multiple_pass is not really necessary, since it may be the place
                # where it is expanded once. However, this ensures that things 
                # that are ignored with multiple_pass are ignored.
                my $entry_text = substitute_line($entry_texi, "\@$macro", prepare_state_multiple_pass($macro, $state));
                my ($index_entry, $formatted_index_entry, $index_label) = do_index_entry_label($macro,$state,$line_nr, $entry_texi);

                if (defined($index_entry))
                {
                   msg_debug ("(bug?) Index out of sync `$index_entry->{'texi'}' ne `$entry_texi'", $line_nr) if ($index_entry->{'texi'} ne $entry_texi);
                }
                add_prev($text, $stack, &$Texi2HTML::Config::index_entry_command($macro, $index_name, $index_label, $entry_texi, $entry_text, $index_entry));
                # it eats the end of line and therefore don't start
                # table entries nor close @center. These should be stopped
                # on the next line, though.
                return;
            }
            if ($macro eq 'insertcopying')
            {
                #close_paragraph($text, $stack, $state, $line_nr);
                add_prev($text, $stack, do_insertcopying($state, $line_nr));
                # reopen a preformatted format if it was interrupted by the macro
                begin_paragraph ($stack, $state) if ($state->{'preformatted'});
                return;
            }
            if ($macro =~ /^itemx?$/o or ($macro eq 'headitem'))
            {
		    #print STDERR "ITEM: $cline";
		    #dump_stack($text, $stack, $state);
                abort_empty_preformatted($stack, $state);
                # FIXME let the user be able not to close the paragraph
                close_paragraph($text, $stack, $state, "\@$macro", $line_nr);

		    #print STDERR "ITEM after close para: $cline";
		    #dump_stack($text, $stack, $state);
                # these functions return the format if in the right context
                my $in_list_enumerate;
                my $format;
                if ($format = add_item($text, $stack, $state, $line_nr))
                { # handle lists
                    $in_list_enumerate = 1;
                    if ($macro ne 'item')
                    {
                        line_error (sprintf(__("\@%s not meaningful inside `\@%s' block"), $macro, $format->{'format'}), $line_nr);
                    }
                }
                elsif ($format = add_term($text, $stack, $state, $line_nr))
                { # close table term
                }
                elsif ($format = add_line($text, $stack, $state, $line_nr)) 
                { # close table definition
                }
                if ($format)
                {
                    if ($macro eq 'headitem')
                    {
                        line_error (sprintf(__("\@%s not meaningful inside `\@%s' block"), $macro, $format->{'format'}), $line_nr);
                    }
                    if (defined($Texi2HTML::Config::tab_item_texi))
                    {
                        my $resline = &$Texi2HTML::Config::tab_item_texi($macro, $state->{'command_stack'}, $stack, $state, $cline, $line_nr);
                        $cline = $resline if (defined($resline));
                    }
                    if ($in_list_enumerate)
                    {
                        push (@$stack, { 'format' => 'item', 'text' => '', 'format_ref' => $format, 'item_cmd' => $macro });
                        begin_paragraph($stack, $state) if ($state->{'preformatted'} or !no_line($cline));
                    }
                    else
                    {# handle table @item term and restart another one
                     # or after table text restart a term
                        push (@$stack, { 'format' => 'term', 'text' => '', 'format_ref' => $format, 'item_cmd' => $macro  });
                    }
                    $format->{'texi_line'} = $cline;
                    my ($line, $open_command) = &$Texi2HTML::Config::format_list_item_texi($format->{'format'}, $cline, $format->{'prepended'}, $format->{'command'}, $format->{'number'});
                    $cline = $line if (defined($line));
                    #if ($open_command)
                    #{ 
                    #     open_arg($format->{'command'},0, $state);
                    #     $format->{'command_opened'} = 1;
                    #}
                    $format->{'item_cmd'} = $macro;
                    $format->{'texi_line_texi_formatted'} = $cline;
                    next;
                }
                $format = add_row ($text, $stack, $state, $line_nr); # handle multitable
                if (!$format)
                { # makeinfo has:
                  # "@%s not meaningful inside `@%s' block" for menu/quotation...
                  # and, if outside of any format
                  # "%c%s found outside of an insertion block"
                  # The following error message seems better.
                    line_error (sprintf(__("\@%s outside of table or list"), $macro), $line_nr);
                }
                else
                {
                    push @$stack, {'format' => 'row', 'text' => '', 'item_cmd' => $macro, 'format_ref' => $format };
                    push @$stack, {'format' => 'cell', 'text' => '', 'format_ref' => $format};
                    $format->{'cell'} = 1;
                    if ($format->{'max_columns'})
                    {
                        if (defined($Texi2HTML::Config::tab_item_texi))
                        {
                            my $resline = &$Texi2HTML::Config::tab_item_texi($macro, $state->{'command_stack'}, $stack, $state, $cline, $line_nr);
                            $cline = $resline if (defined($resline));
                        }
                        begin_paragraph_after_command($state,$stack,$macro,$cline);
                    }
                    else
                    {
                        line_warn (sprintf(__("\@%s in empty multitable"), $macro), $line_nr);
                    }
                }
                next;
            }

            if ($macro eq 'tab')
            {
                abort_empty_preformatted($stack, $state);
                # FIXME let the user be able not to close the paragraph?
                close_paragraph($text, $stack, $state, "\@$macro", $line_nr);

                my $format = add_cell ($text, $stack, $state, $line_nr);
                if (!$format)
                {
                    line_error(__("ignoring \@tab outside of multitable"), $line_nr);
                }
                else
                {
                    push @$stack, {'format' => 'cell', 'text' => '', 'format_ref' => $format};
                    if (!$format->{'max_columns'})
                    {
                       line_warn (__("ignoring \@tab in empty multitable"), $line_nr);
                    }
                    elsif ($format->{'cell'} > $format->{'max_columns'})
                    {
                       line_error (sprintf(__("Too many columns in multitable item (max %d)"), $format->{'max_columns'}), $line_nr);
                    }
                    else
                    {
                       if (defined($Texi2HTML::Config::tab_item_texi))
                       {
                          my $resline = &$Texi2HTML::Config::tab_item_texi($macro, $state->{'command_stack'}, $stack, $state, $cline, $line_nr);
                          $cline = $resline if (defined($resline));
                       }
                    }
                }
                begin_paragraph_after_command($state,$stack,$macro,$cline);
                next;
            }
            # Macro opening a format (table, list, deff, example...)
            if ($format_type{$macro} and ($format_type{$macro} ne 'fake'))
            {
                my $ignore_center = 0;
                # @center is forbidden in @-command with braces, @*table
                # @item line, @multitable, or another @center
                if ($macro eq 'center' and @$stack)
                {
                   my $top_stack = top_stack($stack, 1);
                   if (exists($top_stack->{'style'}) or (defined($top_stack->{'format'}) and ($top_stack->{'format'} eq 'term' or $top_stack->{'format'} eq 'cell')) or $state->{'preformatted'} or $state->{'paragraph_style'}->[-1] eq 'center')
                   {
                       $ignore_center = 1;
                   }
                   #dump_stack ($text, $stack, $state);
                }
                if ($ignore_center)
                {
                    line_error(__("\@center should not appear in another format"), $line_nr);
                }
                else
                {
                    $cline = begin_format($text, $stack, $state, $macro, $cline, $line_nr);
                }
                # we keep the end of line for @center, and for formats
                # that have cmd_line opened and need to see the end of line
                next if (($macro eq 'center') or 
                   (defined($Texi2HTML::Config::def_map{$macro}))
                   or ($macro eq 'float') or ($format_type{$macro} eq 'quotation'));
                return if ($cline =~ /^\s*$/);
                next;
            }
            $cline = do_unknown (2, $macro, $cline, $text, $stack, $state, $line_nr);
            next;
        }
        elsif($cline =~ s/^([^{}@,]*)\@([^\s\}\{\@]*)//o)
        { # A macro with a character which shouldn't appear in macro name
            add_prev($text, $stack, do_text($1, $state));
            $cline = do_unknown (2, $2, $cline, $text, $stack, $state, $line_nr);
            next;
        }
        # a brace
        elsif ($cline =~ s/^([^{},]*)([{}])//o)
        {
            my $leading_text = $1;
            my $brace = $2;
            add_prev($text, $stack, do_text($leading_text, $state));
            if (defined($brace) and ($brace eq '{')) #'}'
            {
                add_prev($text, $stack, do_text('{',$state)); #}
                if ($state->{'math_style'})
                {
                    $state->{'math_brace'}++;
                }
                else 
                {
                    unless ($state->{'keep_texi'} or $state->{'remove_texi'})
                    {
                        line_error (sprintf(__("Misplaced %c"), ord('{')), $line_nr);
                    }
                }
            }
            elsif (defined($brace) and ($brace eq '}') and 
                    (!@$stack or (!defined($stack->[-1]->{'style'}))
            # braces are allowed in math
                    or $state->{'math_brace'}))
            {
                if ($state->{'keep_texi'})
                {
                    add_prev($text, $stack, '}');
                }
                elsif($state->{'math_style'} and $state->{'math_brace'})
                {
                    add_prev($text, $stack, do_text('}',$state));
                    $state->{'math_brace'}--;
                }
                else
                {
                    line_error (sprintf(__("Misplaced %c"), ord('}')), $line_nr);
                    #dump_stack($text, $stack, $state);
                }
            }
            else
            { # A @-command{ ...} is closed
                my ($result, $command) = close_style_command($text, $stack, $state, $line_nr, $cline);
                add_prev($text, $stack, $result);
                if ($Texi2HTML::Config::no_paragraph_commands{$command} 
                  and !$state->{'keep_texi'} and !no_paragraph($state,$cline))
                {
                   begin_paragraph($stack, $state);
                }
            }
        }
        elsif ($cline =~ s/^([^,]*)[,]//o)
        {
             add_prev($text, $stack, do_text($1, $state));
             if (@$stack and defined($stack->[-1]->{'style'})
                  and (ref($::style_map_ref->{$stack->[-1]->{'style'}}) eq 'HASH'))
             {
                  my $macro = $stack->[-1]->{'style'};
                  my $style_args = $::style_map_ref->{$macro}->{'args'};
                  if (defined($style_args->[$stack->[-1]->{'arg_nr'} + 1]))
                  {
                       push (@{$stack->[-1]->{'args'}}, $stack->[-1]->{'text'});
                       $stack->[-1]->{'fulltext'} .= $stack->[-1]->{'text'} . do_text(',', $state);
                       $stack->[-1]->{'text'} = '';
                       close_arg ($macro, $stack->[-1]->{'arg_nr'}, $state);
                       $stack->[-1]->{'arg_nr'}++;
                       open_arg ($macro, $stack->[-1]->{'arg_nr'}, $state);
                       next;
                  }
             }
             add_prev($text, $stack, do_text(',', $state));
        }
        else
        { # no macro nor '}', but normal text
            add_prev($text, $stack, do_text($cline, $state));
            # @center/line term is closed at the end of line. When a 
            # @-command which 
            # keeps the texi as is happens on the @center line, the @center
            # is closed at the end of line appearing after the @-command
            # closing (for example @ref, @footnote).
            last if ($state->{'keep_texi'});
            #print STDERR "END_LINE(l):$cline!!!\n";
            #dump_stack($text, $stack, $state);
            my $maybe_format_to_close = 1;
            my $in_table;
            while ($maybe_format_to_close)
            {
               $maybe_format_to_close = 0;
               #my $top_format = top_stack($stack, 1);
               my $top_format = top_stack($stack, 2);
               # the stack cannot easily be used, because there may be 
               # opened commands in paragraphs if the center is in a 
               # style command, like
               # @b{
               # bold
               #
               # @center centered bold
               # 
               # }
               #
               # Therefore $state->{'paragraph_style'}->[-1] is used.
               #
               # The close_stack until 'center' is needed because
               # of constructs like 
               #
               # @center something @table
               #
               # In that case what would be removed from the stack after
               # paragraph closing wold not be the @center. Such construct
               # is certainly incorrect, though.
               #
               # when 'closing_center' is true we don't retry to close 
               # the @center line.
               if ($state->{'paragraph_style'}->[-1] eq 'center' 
                   and !$state->{'closing_center'} and !$state->{'keep_texi'})
               {
                   $state->{'closing_center'} = 1;
                   close_paragraph($text, $stack, $state, "\@center", $line_nr); 
                   close_stack($text, $stack, $state, $line_nr, 'center');
                   delete $state->{'closing_center'};
                   my $center = pop @$stack;
                   add_prev($text, $stack, &$Texi2HTML::Config::paragraph_style_command('center',$center->{'text'}));
                   my $top_paragraph_style = pop @{$state->{'paragraph_style'}};
                   
                   # center is at the bottom of the comand_stack because it 
                   # may be nested in many way
                   my $bottom_command_stack = shift @{$state->{'command_stack'}};
                   print STDERR "Bug: closing center, top_paragraph_style: $top_paragraph_style, bottom_command_stack: $bottom_command_stack.\n"
                      if ($bottom_command_stack ne 'center' or $top_paragraph_style ne 'center');
                   $maybe_format_to_close = 1;
                   next;
               }
               
               # @item line is closed by end of line. In general there should
               # not be a paragraph in a term. However it may currently
               # happen in construct like
               #
               # @table @asis
               # @item @cindex index entry
               # some text still in term, and in paragraph
               # Not in term anymore
               # ....
               #
               if (defined($top_format->{'format'}) and $top_format->{'format'} eq 'term')
               {
                   #close_paragraph($text, $stack, $state, $line_nr)
                   #    if ($state->{'paragraph_context'});
                   close_stack($text, $stack, $state, $line_nr, 'term');
                   $in_table = add_term($text, $stack, $state, $line_nr);
                   if ($in_table)
                   {
                      $maybe_format_to_close = 1;
                      next;
                   }
               }
            }
            if ($in_table)
            {
               push (@$stack, { 'format' => 'line', 'text' => '', 'only_inter_commands' => 1, 'format_ref' => $in_table });
               begin_paragraph($stack, $state) if ($state->{'preformatted'});
            }
            last;
        }
    }
    return 1;
} # end scan_line

sub open_arg($$$)
{
    my $macro = shift;
    my $arg_nr = shift;
    my $state = shift;
    if (ref($::style_map_ref->{$macro}) eq 'HASH')
    {
         my $arg = $::style_map_ref->{$macro}->{'args'}->[$arg_nr];
         if ($arg eq 'keep')
         {
             $state->{'keep_nr'}++;
             $state->{'keep_texi'} = 1;
         }
         elsif (!$state->{'keep_texi'})
         {
             if ($arg eq 'code')
             {
                 $state->{'code_style'}++;
             }
             elsif ($arg eq 'math')
             {
                 $state->{'math_style'}++;
                 $state->{'code_style'}++;
                 if ($state->{'math_style'} == 1)
                 {
                     $state->{'math_brace'} = 0;
                 }
             }
         }
    }
    elsif ($code_style_map{$macro} and !$state->{'keep_texi'})
    {
         $state->{'code_style'}++;
    }
}

sub close_arg($$$)
{
    my $macro = shift;
    my $arg_nr = shift;
    my $state = shift;
    if (ref($::style_map_ref->{$macro}) eq 'HASH')
    {
         my $arg = $::style_map_ref->{$macro}->{'args'}->[$arg_nr];
         if ($arg eq 'keep')
         {
             $state->{'keep_nr'}--;
             $state->{'keep_texi'} = 0 if ($state->{'keep_nr'} == 0);
         }
         elsif (!$state->{'keep_texi'})
         {
             if ($arg eq 'code')
             {
                 $state->{'code_style'}--;
             }
             elsif ($arg eq 'math')
             {
                 $state->{'math_style'}--;
                 $state->{'code_style'}--;
             }
         }
#print STDERR "c $arg_nr $macro $arg $state->{'code_style'}\n";
    }
    elsif ($code_style_map{$macro} and !$state->{'keep_texi'})
    {
         $state->{'code_style'}--;
    }
}

# add a special style on the top of the stack. This is used for commands
# that extend until the end of the line. Also add an entry in the @-command
# hashes for this fakes style.
#sub open_cmd_line($$$$$)
#{
#    my $command = shift;
#    my $stack = shift;
#    my $state = shift;
#    my $args = shift;
#    my $function = shift;
#    push @$stack, {'style' => 'cmd_line', 'text' => '', 'arg_nr' => 0};
#    foreach my $hash (\%Texi2HTML::Config::style_map, \%Texi2HTML::Config::style_map_pre, \%Texi2HTML::Config::style_map_texi, \%Texi2HTML::Config::simple_format_style_map_texi)
#    {
#         $hash->{'cmd_line'}->{'args'} = $args;
#         $hash->{'cmd_line'}->{'function'} = $function;
#    }
#    $state->{'no_paragraph'}++;
#    push @{$state->{'no_paragraph_stack'}}, "\@$command line";
##    $state->{'cmd_line'} = 1;
#    open_arg ('cmd_line', 0, $state);
#}

# finish @item line in @*table
sub add_term($$$$)
{
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $line_nr = shift;

    my $top_format = top_stack($stack,2);

    return unless (defined($top_format->{'format'}) and $top_format->{'format'} eq 'term');
    #print STDERR "ADD_TERM\n";

    my $term = pop @$stack;
    my $format = $stack->[-1];
    $format->{'paragraph_number'} = 0;
    chomp ($term->{'text'});

    my ($index_label, $formatted_index_entry);
    if ($format->{'format'} =~ /^(f|v)/o)
    {
        my $index_entry;
        ($index_entry, $formatted_index_entry, $index_label) = do_index_entry_label($format->{'format'}, $state,$line_nr, $format->{'texi_line'});
        print STDERR "Bug: no index entry for $term->{'text'}\n" unless defined($index_label);
    }

    my $item_result = &$Texi2HTML::Config::table_item($term->{'text'}, $index_label,$format->{'format'},$format->{'command'}, $state->{'command_stack'}, $term->{'item_cmd'}, $formatted_index_entry);
    add_prev($text, $stack, $item_result);
    return $format;
}

sub add_row($$$$)
{
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $line_nr = shift;
    
    my $top_format = top_stack($stack);
    # @center a @item
    # will lead to row not being closed since a close paragraph doesn't
    # end the center.
    return unless (defined($top_format->{'format'}) and $top_format->{'format'} eq 'cell');
    my $cell = $top_format;
    my $format = $stack->[-3];
    print STDERR "Bug under row cell row not a multitable\n" if (!defined($format->{'format'}) or $format->{'format'} ne 'multitable'); 
    #print STDERR "ADD_ROW $format->{'item_nr'} first: $format->{'first'}\n";
    # dump_stack($text, $stack, $state);

    $format->{'item_nr'}++ unless ($format->{'first'});
    my $empty_first;
    if ($format->{'first'} and $format->{'cell'} == 1 and $stack->[-1]->{'text'} =~ /^\s*$/)
    {
       $empty_first = 1;
       $format->{'empty_first'} = 1;
    }
    if ($format->{'cell'} > $format->{'max_columns'} or $empty_first)
    {
       my $cell = pop @$stack;
       print STDERR "Bug: not a cell ($cell->{'format'}) in multitable\n" if ($cell->{'format'} ne 'cell');
    }
    else
    {
       add_cell($text, $stack, $state);
    }
    my $row = pop @$stack;
    print STDERR "Bug: not a row ($row->{'format'}) in multitable\n" if ($row->{'format'} ne 'row');
    if ($format->{'max_columns'} and !$empty_first)
    {
       # FIXME have the cell count in row and not in table. table could have
       # the whole structure, but cell count doesn't make much sense 
       add_prev($text, $stack, &$Texi2HTML::Config::row($row->{'text'}, $row->{'item_cmd'}, $format->{'columnfractions'}, $format->{'prototype_row'}, $format->{'prototype_lengths'}, $format->{'max_columns'}, $cell->{'only_inter_commands'}, $format->{'first'}));
    }

    $format->{'first'} = 0 if ($format->{'first'});

    return $format;
}

# FIXME remove and merge, too much double checks and code
sub add_cell($$$$)
{
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $line_nr = shift;
    my $top_format = top_stack($stack);

    #print STDERR "ADD_CELL\n";
    return unless (defined($top_format) and $top_format->{'format'} eq 'cell');
   # print STDERR "ADD_CELL, really\n";

    my $cell = pop @$stack;
    my $row = top_stack($stack);
    print STDERR "Bug: top_stack of cell not a row\n" if (!defined($row->{'format'}) or ($row->{'format'} ne 'row'));
    my $format = $stack->[-2];
    print STDERR "Bug under cell row not a multitable\n" if (!defined($format->{'format'}) or $format->{'format'} ne 'multitable'); 

    if ($format->{'first'} and $format->{'cell'} == 1)
    {
        line_warn(__("\@tab before \@item"), $line_nr);
    }

    if ($format->{'cell'} <= $format->{'max_columns'})
    {
        #print STDERR "ADD_CELL, really, really\n";
        add_prev($text, $stack, &$Texi2HTML::Config::cell($cell->{'text'}, $row->{'item_cmd'}, $format->{'columnfractions'}, $format->{'prototype_row'}, $format->{'prototype_lengths'}, $format->{'max_columns'}, $cell->{'only_inter_commands'}, $format->{'first'}));
    }
    $format->{'cell'}++;
    $format->{'first'} = 0 if ($format->{'first'});
    return $format;
}

sub add_line($$$$)
{
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $line_nr = shift;
    my $top_stack = top_stack($stack);

    # if there is something like
    # @center centered @item new item
    # the item isn't opened since it is in @center, and center isn't closed 
    # by an @item appearing here (unlike a paragraph).
    # the error message is '@item outside of table or list'.
    # texi2dvi also has issue, but makeinfo is happy, however it 
    # produces bad nesting.
    return unless(defined($top_stack->{'format'}) and $top_stack->{'format'} eq 'line');
    #print STDERR "ADD_LINE\n";
    #dump_stack($text, $stack, $state);

    my $line = pop @$stack;
    my $format = $stack->[-1];
    $format->{'paragraph_number'} = 0;
    if ($format->{'first'})
    {
        $format->{'first'} = 0;
        # we must have <dd> or <dt> following <dl> thus we do a 
        # &$Texi2HTML::Config::table_line here too, although it could have
        # been a normal paragraph.
        if ($line->{'text'} =~ /\S/o)
        {
           add_prev($text, $stack, &$Texi2HTML::Config::table_line($line->{'text'}, $line->{'only_inter_commands'}, 1));
           $format->{'empty_first'} = 1 if ($line->{'only_inter_commands'});
        }
        else
        {
           $format->{'empty_first'} = 1;
        }
    }
    else
    {
        $format->{'item_nr'}++;
        add_prev($text, $stack, &$Texi2HTML::Config::table_line($line->{'text'}, $line->{'only_inter_commands'}, 0));
    }
    return $format;
}

# finish @enumerate or @itemize @item
sub add_item($$$$)
{
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $line_nr = shift;

    my $top_stack = top_stack($stack);

    return unless (defined($top_stack->{'format'}) and $top_stack->{'format'} eq 'item');
    #print STDERR "ADD_ITEM: \n";
    #dump_stack($text, $stack, $state);
    # as in pre the end of line are kept, we must explicitely abort empty
    # preformatted, close_stack doesn't do that.
    my $item = pop @$stack;
    my $format = $stack->[-1];
    #my $item_command = $item->{'format'};
    my $item_command = $item->{'item_cmd'};
    # first has no associated item, it is more like a 'title'
    $item_command = '' if ($format->{'first'});

    # debug message if it is the first item (much like a title) although 
    # there is an item command.
    msg_debug("First in $format->{'format'} but item_cmd defined $item->{'item_cmd'}",$line_nr) if ($format->{'first'} and defined($item->{'item_cmd'}));
    
    $format->{'paragraph_number'} = 0;
    
    #dump_stack ($text, $stack, $state);
    # the element following ol or ul must be li. Thus even though there
    # is no @item we put a normal item.
    # don't do an item if it is the first and it is empty
    if (!$format->{'first'} or ($item->{'text'} =~ /\S/o))
    {
        my $formatted_command;
        if (defined($format->{'command'}) and $format->{'command'} ne '')# and exists($::things_map_ref->{$format->{'command'}}))
        {
            $formatted_command = substitute_line("\@$format->{'command'}\{\}", "\@item \@$format->{'command'}", duplicate_formatting_state($state));
            $format->{'formatted_command'} = $formatted_command;
        }
	#chomp($item->{'text'});
        add_prev($text, $stack, &$Texi2HTML::Config::list_item($item->{'text'},$format->{'format'},$format->{'command'}, $formatted_command, $format->{'item_nr'}, $format->{'spec'}, $format->{'number'}, $format->{'prepended'}, $format->{'prepended_formatted'}, $item->{'only_inter_commands'}, $format->{'first'},$item_command));
    } 
    else
    {
        $format->{'empty_first'} = 1;
    }
    if ($format->{'first'})
    {
        $format->{'first'} = 0;
    }
    else
    {
        $format->{'item_nr'}++;
    }

    if ($format->{'format'} eq 'enumerate')
    {
        $format->{'number'} = '';
        my $spec = $format->{'spec'};
        if ($spec =~ /^[0-9]$/)
        {
            $format->{'number'} = $spec + $format->{'item_nr'};
        }
        else
        {
            my $base_letter = ord('a');
            $base_letter = ord('A') if (ucfirst($spec) eq $spec);

            my @letter_ords = decompose(ord($spec) - $base_letter + $format->{'item_nr'}, 26);
            foreach my $ord (@letter_ords)
            {# FIXME we go directly to 'ba' after 'z', and not 'aa'
             #because 'ba' is 1,0 and 'aa' is 0,0.
                $format->{'number'} = chr($base_letter + $ord) . $format->{'number'};
            }
        }
    }

    return $format;
}

# format ``simple'' macros, that is macros without arg or style macros
sub do_simple_command($$$)
{
    my $macro = shift;
    my $state = shift;
    my $line_nr = shift;
    
#msg_debug ("DO_SIMPLE $macro $args $arg_nr (@$args)", $line_nr) if (defined($args));
    if ($state->{'remove_texi'})
    {
#print STDERR "DO_SIMPLE remove_texi $macro\n";
        return  $::simple_map_texi_ref->{$macro};
    }
    else
    {
        return &$Texi2HTML::Config::simple_command($macro, $state->{'preformatted'}, $state->{'math_style'}, $line_nr, $state);
    }
}

sub do_thing_command($$$$)
{
    my $macro = shift;
    my $text = shift;
    my $state = shift;
    my $line_nr = shift;

    if ($state->{'remove_texi'})
    {
       return  $::texi_map_ref->{$macro}.$text;
#print STDERR "DO_SIMPLE remove_texi texi_map $macro\n";
    }
    else
    {
        return &$Texi2HTML::Config::thing_command($macro, $text, $state->{'preformatted'}, $state->{'math_style'}, $line_nr, $state);
    }
}

sub do_style_command($$$$$$$$)
{
    my $macro = shift;
    my $text = shift;
    my $state = shift;
    my $args = shift;
    my $line_nr = shift;
    my $no_open = shift;
    my $no_close = shift;
    my $kept_line_nrs = shift;

    my $arg_nr = 0;
    $arg_nr = @$args - 1 if (defined($args));
    
    if (defined($::style_map_ref->{$macro}))
    {
        my $style;
        my $result;
        if ($state->{'remove_texi'})
        {
#print STDERR "REMOVE $macro, $style_map_texi_ref->{$macro}, fun $style_map_texi_ref->{$macro}->{'function'} remove cmd " . \&Texi2HTML::Config::t2h_remove_command . " ascii acc " . \&t2h_default_accent;
            $style = $::style_map_texi_ref->{$macro};
        }
        elsif ($state->{'math_style'} and defined($::style_map_math_ref->{$macro}))
        { # FIXME we are still in math when the @math is closed here, since 
          # close_arg that does 'math_style'-- is called below.
            $style = $::style_map_math_ref->{$macro};
        }
        elsif ($state->{'preformatted'})
        {
            if ($macro eq 'kbd' and (Texi2HTML::Config::get_conf('kbdinputstyle') ne 'distinct'))
            {
                $style = $::style_map_pre_ref->{'code'};
            }
            else
            {
                $style = $::style_map_pre_ref->{$macro};
            }
        }
        else
        {
            # kbd is in code_style, so it is 'code_style' > 1
            if ($macro eq 'kbd' and ((Texi2HTML::Config::get_conf('kbdinputstyle') eq 'code') or ($state->{'code_style'} > 1 and Texi2HTML::Config::get_conf('kbdinputstyle') eq 'example')))
            {
                $style = $::style_map_ref->{'code'};
            }
            else
            {
                $style = $::style_map_ref->{$macro};
            }
        }
        if ($macro eq 'dotless')
        {
           if (scalar(@$args) ne 1)
           {
               line_error(sprintf(__("%c%s expects a single character `i' or `j' as argument"), ord('@'), $macro), $line_nr);
           }
           elsif ($args->[0] ne 'i' and $args->[0] ne 'j')
           { # FIXME an unformatted arg would have been better. Not a big deal.
               line_error (sprintf(__("%c%s expects `i' or `j' as argument, not `%s'"), ord('@'), $macro, $args->[0]), $line_nr);
           }
        }
        if (defined($style))
        {                           # known style
            $result = &$Texi2HTML::Config::style($style, $macro, $text, $args, $no_close, $no_open, $line_nr, $state, $state->{'command_stack'}, $kept_line_nrs);
        }
        if (!$no_close)
        { 
            close_arg($macro,$arg_nr, $state);
        }
        return $result;
    }
    elsif ($macro =~ /^special_(\w+)_(\d+)$/o)
    {
        my $style = $1;
        my $count = $2;

        msg_debug ("Bug? text in \@$macro not empty", $line_nr) if ($text ne '');  
        if (defined($Texi2HTML::Config::command_handler{$style}) and
          defined($Texi2HTML::Config::command_handler{$style}->{'expand'}))
        {
            my $struct_count = 1+ $special_commands{$style}->{'max'} - $special_commands{$style}->{'count'};
            # may happen for text expanded more than once, for example
            # in invalid/tex_in_copying
            if (($count != $struct_count) and $T2H_DEBUG)
            {
                msg_debug ("count $count in \@special $style and structure $struct_count differ", $line_nr);
            }
            $special_commands{$style}->{'count'}--;  
        }
        my $result = $Texi2HTML::Config::command_handler{$style}->{'expand'}
              ($style,$count,$state,$text);
        $result = '' if (!defined($result));
        return $result;
    }
    # Unknown macro
    my $result = '';
    my ($done, $result_text, $message) = &$Texi2HTML::Config::unknown_style($macro, $text,$state,$no_close, $no_open);
    if ($done)
    {
        line_warn($message, $line_nr) if (defined($message));
        if (defined($result_text))
        {
            $result = $result_text;
        }
    }
    else 
    { 
        unless ($no_open)
        { # we warn only if no_open is true, i.e. it is the first time we 
          # close the macro for a multiline macro
            line_error (sprintf(__("Unknown command with braces `\@%s'"), $macro), $line_nr);
            $result = do_text("\@$macro") . "{";
        }
        $result .= $text;
        $result .= '}' unless ($no_close);
    }
    return $result;
}

sub do_unknown($$$$$$$)
{
    my $pass = shift;
    my $macro = shift;
    my $line = shift;
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $line_nr = shift;
    #print STDERR "do_unknown[$pass]($macro) ::: $line"; 

    my ($result_line, $result, $result_text, $message) = &$Texi2HTML::Config::unknown($macro, $line, $pass, $stack,$state);
    if ($result)
    {
         add_prev ($text, $stack, $result_text) if (defined($result_text));
         line_warn($message, $line_nr) if (defined($message));
         # if $state->{'preformatted'}, assume that the preformatted is 
         # already opened. Otherwise we may end up opening one each time
         # there is an unknown command.
         begin_paragraph_after_command($state, $stack, $macro, $result_line)
              if (!$state->{'preformatted'});
         return $result_line;
    }
    elsif ($pass == 2)
    { 
         if ($Texi2HTML::Config::style_map{$macro})
         {
             line_error (sprintf(__("%c%s expected braces"), ord('@'), $macro), $line_nr);
         }
         else
         {
             line_error (sprintf(__("Unknown command `%s'"), $macro), $line_nr);
         }
         add_prev ($text, $stack, do_text("\@$macro"));
         return $line;
    }
    elsif ($pass == 1)
    {
         add_prev ($text, $stack, "\@$macro");
         return $line;
    }
    elsif ($pass == 0)
    {
         add_prev ($text, $stack, "\@$macro") unless($state->{'ignored'});
         return $line;
    }
}

# used only during @macro processing
sub add_text($@)
{
    my $string = shift;

    return if (!defined($string));
    foreach my $scalar_ref (@_)
    {
        next unless defined($scalar_ref);
        if (!defined($$scalar_ref))
        {
            $$scalar_ref = $string;
        }
        else
        {
            $$scalar_ref .= $string;
        }
        return;
    }
}

sub add_prev ($$$)
{
    my $text = shift;
    my $stack = shift;
    my $string = shift;

    unless (defined($text) and ref($text) eq "SCALAR")
    {
       die "text not a SCALAR ref: " . ref($text) . "";
    }
    
    return if (!defined($string));
    if (@$stack)
    {
        $stack->[-1]->{'text'} .= $string;
        return;
    }

    if (!defined($$text))
    {
         $$text = $string;
    }
    else
    {
         $$text .= $string;
    }
}

sub close_stack_texi($$$$)
{
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $line_nr = shift;

    
    return undef unless (@$stack or $state->{'raw'} or $state->{'macro'} or $state->{'macro_name'} or $state->{'ignored'});

    if ($state->{'ignored'})
    {
        line_error (sprintf(__("Reached eof before matching \@end %s"), $state->{'ignored'}), $line_nr); 
        close_ignored($state, $stack);
    }

    if ($state->{'macro'})
    {
       my ($no_remaining, $result) = end_macro($state, '@end macro', "\n");
       add_prev ($text, $stack, $result) if (defined($result));
       line_error (sprintf(__("%cend macro not found"), ord('@')), $line_nr);
    }
    elsif ($state->{'macro_name'})
    {
       #line_warn ("closing $state->{'macro_name'} ($state->{'macro_depth'} braces missing)", $line_nr); 
       line_error (sprintf(__("\@%s missing close brace"), $state->{'macro_name'}), $line_nr); 
       while ($state->{'macro_name'})
       {
           close_macro_arg($state, '', $line_nr);
       }
    }
    elsif ($state->{'verb'})
    {
        # warning in next pass
        #line_warn ("closing \@verb", $line_nr);
        $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'};
        delete $state->{'verb'};
    }
    elsif ($state->{'raw'})
    {
        line_error (sprintf(__("Expected \@end %s"), $state->{'raw'}), $line_nr);
        my $style = pop @$stack;
        add_prev ($text, $stack, $style->{'text'} . "\@end $state->{'raw'}");
        delete $state->{'raw'};
    }

    my $stack_level = $#$stack + 1;
    
    while ($stack_level--)
    {
        my $style = pop(@$stack);
        # would be better in close_stack_structure
        #line_warn ("closing \@-command $style->{'style'}", $line_nr) if ($style->{'style'} ne '');
        close_style_texi($style, $text, $stack, $state, 1);
    }
    #$stack = [ ];
}


sub close_stack_structure($$$$;$)
{
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $line_nr = shift;
    my $close_only_item = shift;
    $close_only_item = 0 if (!defined($close_only_item));

    return undef unless (@$stack or $state->{'raw'});

    #print STDERR "close_stack_structure ($close_only_item)\n";
    #dump_stack ($text, $stack, $state);
    my $stack_level = $#$stack + 1;
    my $string = '';
    
    if ($state->{'verb'})
    {
        $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'};
        #$string .= $state->{'verb'};
    }

    while ($stack_level--)
    {
        last if ($close_only_item and defined($stack->[-1]->{'format'}));
        my $top_stack = pop @$stack;
        if ($top_stack->{'format'})
        {
            my $format = $top_stack->{'format'};
            if ($format eq 'index_item')
            {
                enter_table_index_entry($text, $stack, $state, $line_nr);
            }
            elsif (!defined($format_type{$format}) or ($format_type{$format} ne 'fake'))
            {
                end_format_structure($format_type{$format}, $text, $stack, $state, $line_nr, "\n");
            }
        }
        elsif (defined($top_stack->{'style'}))
        {
            add_prev($text, $stack, 
              close_structure_command($top_stack, $state, 1, $line_nr));
        }
    }
    #$stack = [ ];
}

# This is used in pass 2 and 3.
sub open_region($$)
{
    my $command = shift;
    my $state = shift;
    if (!exists($state->{'region_lines'}))
    {
    # FIXME 'format' is badly choosen 'region_name' would be much better
        $state->{'region_lines'}->{'format'} = $command;
        $state->{'region_lines'}->{'number'} = 1;
        $state->{'region_lines'}->{'kept_place'} = $state->{'place'};
        $state->{'place'} = $no_element_associated_place;
        $state->{'region'} = $command;
        $state->{'multiple_pass'}++;
        $state->{'region_pass'} = 1;
    }
    else
    {
        $state->{'region_lines'}->{'number'}++;
    }
}

# close region like @insertcopying, titlepage...
# restore $state and delete the structure
# This is used in pass 2 and 3.
sub close_region($)
{
    my $state = shift;
    $state->{'place'} = $state->{'region_lines'}->{'kept_place'};
    $state->{'multiple_pass'}--;
    delete $state->{'region_lines'}->{'number'};
    delete $state->{'region_lines'}->{'format'};
    delete $state->{'region_lines'}->{'kept_place'};
    delete $state->{'region_lines'};
    delete $state->{'region'};
    delete $state->{'region_pass'};
}

# close the stack, closing @-commands and formats left open.
# if a $format is given if $format is encountered the closing stops
sub close_stack($$$$;$)
{
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $line_nr = shift;
    my $format = shift;
    
    #print STDERR "sub_close_stack\n";
    if (@$stack)
    {
      my $stack_level = $#$stack + 1;
    
      #debugging
      #my $print_format = 'NO FORMAT';
      #$print_format = $format if ($format);
      #msg_debug ("Close_stack:  format $print_format", $line_nr);
    
      while ($stack_level--)
      {
        if ($stack->[$stack_level]->{'format'})
        {
            my $stack_format = $stack->[$stack_level]->{'format'};
            last if (defined($format) and $stack_format eq $format);
            # We silently close paragraphs, preformatted sections and fake formats
            if ($stack_format eq 'paragraph')
            {
                my $paragraph = pop @$stack;
                add_prev ($text, $stack, do_paragraph($paragraph->{'text'}, $state, $stack));
            }
            elsif ($stack_format eq 'preformatted')
            {
                my $paragraph = pop @$stack;
                add_prev ($text, $stack, do_preformatted($paragraph->{'text'}, $state, $stack));
            }
            else
            {
                if ($fake_format{$stack_format})
                {
                    warn "# Closing a fake format `$stack_format'\n" if ($T2H_VERBOSE);
                }
                elsif ($stack_format ne 'center')
                { # we don't warn for center
                    line_error (sprintf(__("No matching `%cend %s'"), ord('@'), $stack_format), $line_nr); 
                    #dump_stack ($text, $stack, $state);
                }
                if ($state->{'keep_texi'})
                {
                   add_prev($text, $stack, "\@end $stack_format");
                }
                elsif (!$state->{'remove_texi'})
                {
                   end_format($text, $stack, $state, $stack_format, $line_nr)
                        unless ($format_type{$stack_format} eq 'fake');
                }
            }
        }
        else
        {
            my $style =  $stack->[$stack_level]->{'style'};
            ########################## debug
            if (!defined($style))
            {
                print STDERR "Bug: style not defined, on stack\n";
                dump_stack ($text, $stack, $state); # bug
            }
            ########################## end debug
            my $located_line_nr = $line_nr;
            # use the beginning of the @-command for the error message
            # line number if available.
            $located_line_nr = $stack->[$stack_level]->{'line_nr'} if (defined($stack->[$stack_level]->{'line_nr'}));
            line_error (sprintf(__("%c%s missing close brace"), ord('@'), $style), $located_line_nr);
            my ($result, $command) = close_style_command($text, $stack, $state, $line_nr, '');

            add_prev($text, $stack, $result) if (defined($result));
        }
      }
    }

    # This tries to avoid cases where the command_stack is not empty 
    # for a good reason, for example when doing a @def formatting the 
    # outside command_stack is preserved. Also when expanding for
    # example @titleplage or @copying.
    # FIXME sort out which cases it is.
    return if ($format or (defined($state->{'multiple_pass'}) and $state->{'multiple_pass'} > 0) or $state->{'no_paragraph'}); 

    # The pending style commands are cleared here; And are closed next.
    delete $state->{'paragraph_macros'};
    # go through the command_stack and warn for each opened style format
    # and remove it. Those should be there because there is an opened style
    # that was stopped by a paragraph
    my @command_stack = @{$state->{'command_stack'}};
    @{$state->{'command_stack'}} = ();
    while (@command_stack)
    {
       my $latest_command = pop @command_stack;
       if (defined($style_type{$latest_command}) and $style_type{$latest_command} ne 'special')
       {
          line_error (sprintf(__("%c%s missing close brace"), ord('@'), $latest_command), $line_nr);
       }
       else
       {
          unshift @{$state->{'command_stack'}}, $latest_command;
       }
    }
}

# given a stack and a list of formats, return true if the stack contains 
# these formats, first on top
sub stack_order($@)
{
    my $stack = shift;
    my $stack_level = $#$stack + 1;
    while (@_)
    {
        my $format = shift;
        while ($stack_level--)
        {
            if ($stack->[$stack_level]->{'format'})
            {
                if ($stack->[$stack_level]->{'format'} eq $format)
                {
                    $format = undef;
                    last;
                }
                else
                {
                    return 0;
                }
            }
        }
        return 0 if ($format);
    }
    return 1;
}	

sub top_format($)
{
    my $stack = shift;
    my $stack_level = $#$stack + 1;
    while ($stack_level--)
    {
        if ($stack->[$stack_level]->{'format'} and !$fake_format{$stack->[$stack_level]->{'format'}})
        {
             return $stack->[$stack_level];
        }
    }
    return undef;
}

sub close_paragraph($$$$;$$)
{
    my $text = shift;
    my $stack = shift;
    my $state = shift;
    my $reason = shift;
    my $line_nr = shift;
    my $no_preformatted_closing = shift;
    #print STDERR "CLOSE_PARAGRAPH\n";
    #dump_stack($text, $stack, $state);

    #  close until the first format, 
    #  duplicate stack of styles not closed
    my $new_stack;
    my $stack_level = $#$stack + 1;

    # In general close_paragraph is called because of a end of line, or 
    # a format is opened or closed, or there is a @tab or @item and other 
    # similar cases. In most cases there is a paragraph to be closed or 
    # there are no style opened since most @-commands cause paragraph 
    # opening and those that don't should not lead to a style opening.
    #
    # But in term or in @index (and maybe @node, @section, @ref), if 
    # there is a command opened it won't be closed, since it is in 
    # 'no_paragraph'. But @-commands that trigger close_paragraph should not 
    # be called when in those no_paragraph settings.

    if ($state->{'no_paragraph'})
    { # This plays the role of "Multiline command %c%s used improperly"
        line_error(sprintf(__("%s should not appear in %s"), $reason, $state->{'no_paragraph_stack'}->[-1]), $line_nr);
    }

    while ($stack_level--)
    {
        last if ($stack->[$stack_level]->{'format'});
        my $style = $stack->[$stack_level]->{'style'};

        # the !exists($style_type{$style}) condition catches the unknown 
        # @-commands: by default they are considered as style commands
        if (!$state->{'no_paragraph'})
        {
            if (!exists($style_type{$style}) or $style_type{$style} eq 'style')
            {
                unshift @$new_stack, { 'style' => $style, 'text' => '', 'no_open' => 1, 'arg_nr' => 0 };
            }
            elsif (($style_type{$style} eq 'simple_style') or ($style_type{$style} eq 'accent'))
            {
            }
            else
            {
                # it shouldn't be possible to have 'special' styles, like
                # images, footnotes, xrefs, anchors, as 
                # close_paragraph shouldn't be called with keep_texi
                # and when the arguments are expanded, there is a 
                # substitute_line or similar with a new stack.
                msg_debug("BUG: special $style while closing paragraph", $line_nr);
            }
        }
        # if not in a paragraph, the command is simply closed, and not recorded
        # in new_stack.
        my ($result, $command) = close_style_command($text, $stack, $state, $line_nr, '', (!$state->{'no_paragraph'}));
        add_prev($text, $stack, $result) if (defined($result));
    }

    if (!$state->{'paragraph_context'} and !$state->{'preformatted'} and defined($new_stack) and scalar(@$new_stack))
    { # in that case the $new_stack isn't recorded in $state->{'paragraph_macros'}
      # and therefore, it is lost
       msg_debug ("closing paragraph, but not in paragraph/preformatted, and new_stack not empty", $line_nr);
       dump_stack($text, $stack, $state);
    }
    my $top_stack = top_stack($stack);
    if ($top_stack and !defined($top_stack->{'format'}))
    { #debug
         msg_debug("Bug: no format on top stack", $line_nr);
         dump_stack($text, $stack, $state);
    }
    if ($top_stack and ($top_stack->{'format'} eq 'paragraph'))
    {
        my $paragraph = pop @$stack;
        add_prev($text, $stack, do_paragraph($paragraph->{'text'}, $state, $stack));
        $state->{'paragraph_macros'} = $new_stack;
        return 1;
    }
    elsif ($top_stack and ($top_stack->{'format'} eq 'preformatted') and !$no_preformatted_closing)
    {
        my $paragraph = pop @$stack;
        add_prev($text, $stack, do_preformatted($paragraph->{'text'}, $state, $stack));
        $state->{'paragraph_macros'} = $new_stack;
        return 1;
    }
    return;
}

sub abort_empty_preformatted($$)
{
    my $stack = shift;
    my $state = shift;
    if (@$stack and $stack->[-1]->{'format'} 
       and ($stack->[-1]->{'format'} eq 'preformatted')
       and ($stack->[-1]->{'text'} !~ /\S/))
    {
        if (defined($Texi2HTML::Config::empty_preformatted))
        {
           return if (&$Texi2HTML::Config::empty_preformatted($stack->[-1]->{'text'}));
        }
        pop @$stack;
    }
}

# for debugging
sub dump_stack($$$)
{
    my $text = shift;
    my $stack = shift;
    my $state = shift;

    if (defined($$text))
    {
        print STDERR "text: $$text\n";
    }
    else
    {
        print STDERR "text: UNDEF\n";
    }
    my $in_remove = 0;
    my $in_simple_format = 0;
    my $in_keep = 0;
    $in_keep = 1 if ($state->{'keep_texi'});
    if (!$in_keep)
    {
        $in_simple_format = 1 if ($state->{'simple_format'});
        $in_remove = 1 if ($state->{'remove_texi'}  and !$in_simple_format);
    }
    print STDERR "state[$state](k${in_keep}s${in_simple_format}r${in_remove}): ";
    foreach my $key (keys(%$state))
    {
        my $value = 'UNDEF';
        $value = $state->{$key} if (defined($state->{$key}));
        print STDERR "$key: $value " if (!ref($value));
    }
    print STDERR "\n";
    my $stack_level = $#$stack + 1;
    while ($stack_level--)
    {
        print STDERR " $stack_level-> ";
        foreach my $key (keys(%{$stack->[$stack_level]}))
        {
            my $value = 'UNDEF';
            $value = $stack->[$stack_level]->{$key} if 
                (defined($stack->[$stack_level]->{$key}));
            print STDERR "$key: $value ";
        }
        print STDERR "\n";
    }
    if (defined($state->{'command_stack'})) 
    {
        print STDERR "command_stack: ";
        foreach my $style (@{$state->{'command_stack'}})
        {
            print STDERR "($style) ";
        }
        print STDERR "\n";
    }
    if (defined($state->{'region_lines'}))
    {
        print STDERR "region_lines($state->{'region_lines'}->{'number'}): $state->{'region_lines'}->{'format'}\n";
    }
    if (defined($state->{'paragraph_macros'}))
    {
        print STDERR "paragraph_macros: ";
        foreach my $style (@{$state->{'paragraph_macros'}})
        {
            print STDERR "($style->{'style'})";
        }
        print STDERR "\n";
    }
    if (defined($state->{'preformatted_stack'}))
    {
        print STDERR "preformatted_stack: ";
        foreach my $preformatted_style (@{$state->{'preformatted_stack'}})
        {
            if ($preformatted_style eq '')
            {
               print STDERR ".";
               next;
            }
            my $pre_style = '';
            $pre_style = $preformatted_style->{'pre_style'} if (exists $preformatted_style->{'pre_style'});
            my $class = '';
            $class = $preformatted_style->{'class'} if (exists $preformatted_style->{'class'});
            my $style = '';
            $style = $preformatted_style->{'style'} if (exists $preformatted_style->{'style'});
            print STDERR "($pre_style, $class,$style)";
        }
        print STDERR "\n";
    }
    if (defined($state->{'text_macro_stack'}) and @{$state->{'text_macro_stack'}})
    {
        print STDERR "text_macro_stack: (@{$state->{'text_macro_stack'}})\n";
    }
}

# for debugging 
sub print_elements($)
{
    my $elements = shift;
    foreach my $elem(@$elements)
    {
        if ($elem->{'node'})
        {
            print STDERR "node-> $elem ";
        }
        else
        {
            print STDERR "chap=> $elem ";
        }
        foreach my $key (keys(%$elem))
        {
            my $value = "UNDEF";
            $value = $elem->{$key} if (defined($elem->{$key}));
            print STDERR "$key: $value ";
        }
        print STDERR "\n";
    }
}

# for debugging
sub context_string(;$$$)
{
   my $state = shift;
   my $line_nr = shift;
   my $message = shift;
   
   $state = $Texi2HTML::THISDOC{'state'} 
      if (!defined($state) and defined($Texi2HTML::THISDOC{'state'}));
   $line_nr = $Texi2HTML::THISDOC{'line_nr'}
      if (!defined($line_nr) and defined($Texi2HTML::THISDOC{'line_nr'}));
   my $result = "Pass $global_pass";
   my $line_info = ', no line information';
   $line_info = ' ' .format_line_number($line_nr) if (defined($line_nr));
   $result .= $line_info;
   if (!defined($state))
   {
      $result .= ', no state information';
   }
   else
   {
      $result .= ", context $state->{'context'}" if defined($state->{'context'});
      my $expand = '';
      if ($state->{'keep_texi'})
      {
         $expand .= ' no expansion'; 
      }
      if ($state->{'remove_texi'})
      {
         $expand .= ' raw'; 
      }
      if ($state->{'preformatted'})
      {
         $expand .= ' preformatted';
      }
      if ($state->{'code_style'})
      {
         $expand .= " 'code'";
      }
      if ($state->{'simple_format'})
      {
         $expand .= ' simple';
      }
      $expand = ' normal' if (!$expand);
      $result .= ',' . $expand;
      if ($state->{'expansion'})
      {
          $result .= ", \@$state->{'expansion'}";
      }
      if ($state->{'region'})
      {
          $result .= ", region $state->{'region'}";
      }
      if ($state->{'outside_document'})
      {
          $result .= "; out";
      }
      if ($state->{'inside_document'})
      {
          $result .= "; in";
      }
      if ($state->{'multiple_pass'})
      {
          $result .= "; multiple $state->{'multiple_pass'}";
      }
      if ($state->{'new_state'})
      {
          $result .= "; new";
      }
      if ($state->{'duplicated'})
      {
          $result .= "; duplicated";
      }
   }
   $result .= "(in @{$Texi2HTML::THISDOC{'command_stack'}})" 
     if (defined ($Texi2HTML::THISDOC{'command_stack'}) and @{$Texi2HTML::THISDOC{'command_stack'}});
   $result .= ' ' .$message if ($message);
   return $result;
}


my @states_stack = ();

sub push_state($)
{
   my $new_state = shift;
   push @states_stack, $new_state;
   $Texi2HTML::THISDOC{'state'} = $new_state;
}

sub pop_state()
{
   pop @states_stack;
   if (@states_stack)
   {
       $Texi2HTML::THISDOC{'state'} = $states_stack[-1];
   }
   else
   {
       $Texi2HTML::THISDOC{'state'} = undef;
   }
}

sub substitute_line($$;$$)
{
    my $line = shift;
    my $context_string = shift;
    my $state = shift;
    my $line_nr = shift;
    $state = {} if (!defined($state));
    $state->{'no_paragraph'} = 1;

    if (($state->{'inside_document'} or $state->{'outside_document'}) and (!$state->{'duplicated'} and !$state->{'new_state'}))
    {
        msg_debug("substitute_line with main state in: ".var_to_str($context_string), $line_nr);
    }
    push @{$state->{'no_paragraph_stack'}}, $context_string;
    # this is usefull when called from &$I, and also for image files 
    return simple_format($state, [ $line_nr ], $context_string, $line) if ($state->{'simple_format'});
    return substitute_text($state, [ $line_nr ], $context_string, $line);
}

sub substitute_text($$$@)
{
    my $state = shift;
    my $line_nrs = shift;
    my $context = shift;
    my @stack = ();
    my $text = '';
    my $result = '';
    my $line_nr;
    if ($state->{'structure'})
    {
        initialise_state_structure($state);
    }
    elsif ($state->{'texi'})
    { # only in arg_expansion
        initialise_state_texi($state);
        msg_bug("substitute_text, 'texi' true but not 'arg_expansion'") if (!$state->{'arg_expansion'});
    }
    else
    {
#print STDERR "FILL_STATE substitute_text ($state->{'preformatted'}): @_\n";
        if (($state->{'inside_document'} or $state->{'outside_document'}) and (!$state->{'duplicated'} and !$state->{'new_state'}))
        {
            msg_debug("substitute_text with main state in: ".var_to_str($context), $line_nr);
        }
        fill_state($state);
        $state->{'context'} = $context;
    }
    $state->{'spool'} = [];
    #print STDERR "SUBST_TEXT ".var_to_str($context)."\n";
    push_state($state);

    my $line_nrs_kept = $Texi2HTML::THISDOC{'line_nr'};
    $Texi2HTML::THISDOC{'line_nr'} = undef;
    
    while (@_ or @{$state->{'spool'}} or $state->{'in_deff_line'})
    {
        my $line;
        if ($line_nrs and @{$line_nrs})
        {
             $line_nr = shift @{$line_nrs};
             $Texi2HTML::THISDOC{'line_nr'} = $line_nr;
        }
        if (@{$state->{'spool'}})
        {
             $line = shift @{$state->{'spool'}};
        }
        else
        {
            $line = shift @_;
        }
        # msg_debug ("SUBSTITUTE_TEXT $line", $line_nr) if (defined($line_nr));
        if ($state->{'in_deff_line'})
        {
            if (defined($line))
            {
                $line = $state->{'in_deff_line'} . $line;
            }
            else
            {
                $line = $state->{'in_deff_line'};
            }
            delete $state->{'in_deff_line'};
        }
        else
        {
            next unless (defined($line));
        }
        #{ my $p_line = $line; chomp($p_line); print STDERR "SUBST_TEXT $p_line\n"; }
        if ($state->{'structure'})
        {
            scan_structure ($line, \$text, \@stack, $state);
        }
        elsif ($state->{'texi'})
        {
            scan_texi ($line, \$text, \@stack, $state);
        }
        else
        {
            set_line_nr_in_stack($state, \@stack, $line_nr);
            scan_line($line, \$text, \@stack, $state, $line_nr);
        }
        next if (@stack);
        $result .= $text;
        $text = '';
    }
    if ($line_nrs and @{$line_nrs})
    {
        $line_nr = shift @{$line_nrs};
        $Texi2HTML::THISDOC{'line_nr'} = $line_nr;
    }
    # close stack in substitute_text
    if ($state->{'texi'})
    {
        close_stack_texi(\$text, \@stack, $state, $line_nr);
    }
    elsif ($state->{'structure'})
    {
        close_stack_structure(\$text, \@stack, $state, $line_nr);
    }
    else
    {
        close_stack(\$text, \@stack, $state, $line_nr);
    }
    #print STDERR "SUBST_TEXT end\n";
    pop_state();
    $Texi2HTML::THISDOC{'line_nr'} = $line_nrs_kept;
    return $result . $text;
}

sub print_lines($;$)
{
    my ($fh, $lines) = @_;
    $lines = $Texi2HTML::THIS_SECTION unless $lines;
    my @cnt;
    my $cnt;
    for my $line (@$lines)
    {
        print $fh $line;
	if (defined($Texi2HTML::Config::WORDS_IN_PAGE) and (Texi2HTML::Config::get_conf('SPLIT') eq 'node'))
        {
            @cnt = split(/\W*\s+\W*/, $line);
            $cnt += scalar(@cnt);
        }
    }
    return $cnt;
}

sub do_index_entry_label($$$$;$)
{
    my $command = shift;
    my $state = shift;
    my $line_nr = shift;
    my $entry_texi = shift;
    # this is only needed for definitions since the whole line is parsed to
    # reuse get_deff_index.
    my $line = shift;

    my $prefix = index_entry_command_prefix($command, $line, $line_nr);
    my $index_name = $index_prefix_to_name{$prefix};

    msg_debug("do_index_entry_label($command): Undefined entry_texi", $line_nr)
       if (!defined($entry_texi));
    $entry_texi = trim_comment_spaces($entry_texi, "index label in \@$command", $line_nr);

    # index entries are not entered in special regions
    my $region = 'document';
    $region = $state->{'region'} if (defined($state->{'region'}));

    my $entry;
    # Can be within a @caption expanded within a listoffloat. In that
    # case the 2 conditions on state are not set.
    if (defined($state->{'region'}) or !defined($state->{'expansion'}))
    {
       # index entry on a line that is not searched for index entries, like
       # a @def* line
       if (!defined($Texi2HTML::THISDOC{'index_entries'}->{$region}) or !defined($Texi2HTML::THISDOC{'index_entries'}->{$region}->{$entry_texi}))
       {
          line_warn(sprintf(__("Index entry not caught: `%s' in %s"), $entry_texi, $region), $line_nr);
       }
       else
       {
          my $entry_ref = $Texi2HTML::THISDOC{'index_entries'}->{$region}->{$entry_texi};
          # ============================ debug
          if (!defined($entry_ref->{'entries'}))
          {
              msg_debug("BUG, not defined: {'index_entries'}->{$region}->{$entry_texi}->{'entries'}", $line_nr);
          }
          # ============================  end debug
          if (scalar(@{$entry_ref->{'entries'}}) > 1)
          {
              if (!defined($entry_ref->{'index'}))
              {
                  $entry_ref->{'index'} = 0;
              }
              $entry = $entry_ref->{'entries'}->[$entry_ref->{'index'}];
              $entry_ref->{'index'}++;
          }
          else
          {
              $entry = $entry_ref->{'entries'}->[0];
          }
          $entry->{'seen_in_output'} = 1 if (!$state->{'outside_document'});
          ############################################# debug
          # verify that the old way of getting index entries (in an array) is
          # synchronized with the document
          if (!$state->{'region'})
          {
             my $entry_from_array = shift @index_labels;
             if ($entry_from_array ne $entry)
             {
                msg_debug ("entry `$entry->{'texi'}' ne entry_from_array `$entry_from_array->{'texi'}'", $line_nr);
             }
             if (!defined($entry_from_array))
             {
                mesg_debug ("Not enough index entries !", $line_nr);
             }
          }
          ############################################# end debug
       }
    }

    if (!defined($entry))
    {
        # this can happen for listoffloats and caption without being a user 
        # error. Well, in fact, it could be argued that it is indeed a user
        # error, putting an index entry in a snippet that can be expanded
        # more than once and is not strictly associated with a node/section.

        #print STDERR "Entry for index $index_name not gathered in usual places ($region)\n";
        $entry = {
          'command' => $command,
          'texi' => $entry_texi,
          'entry' => $entry_texi,
          'prefix' => $prefix,
          'index_name' => $index_name,
        };
        $entry->{'key'} = sorted_line($entry_texi);
        $entry->{'entry'} = '@code{'.$entry->{'entry'}.'}'
            if (defined($index_name) and
             defined($index_names{$index_name}->{'prefixes'}) and
             $index_names{$index_name}->{'prefixes'}->{$prefix}
             and $entry->{'key'} =~ /\S/);
    }

    ###################################### debug
    else
    {
         if ($entry->{'prefix'} ne $prefix)
         {
             msg_debug ("prefix in entry $entry->{'prefix'} ne $prefix from $command", $line_nr);
         }
    }

    if ($command ne $entry->{'command'})
    {
        # happened with bad texinfo with a line like
        # @deffn func aaaa args  @defvr c--ategory d--efvr_name
        # now this case is caught above by "Index entry not caught:
        msg_debug ("($region) Waiting for index cmd \@$entry->{'command'} got \@$command", $line_nr);
    }

    if ($entry->{'texi'} ne $entry_texi)
    {
        msg_debug ("Waiting for index `$entry->{'texi'}', got `$entry_texi'", $line_nr);
    }
    
    my $id = 'no id';
    $id = $entry->{'id'} if (defined($entry->{'id'}));
    print STDERR "(index($index_name) $command) [$entry->{'entry'}] $id\n"
        if ($T2H_DEBUG & $DEBUG_INDEX);
    ###################################### end debug

    #return (undef,'','') if ($state->{'region'});
    if ($entry->{'key'} =~ /^\s*$/)
    {
        line_warn(sprintf(__("Empty index entry for \@%s"), $command), $entry->{'line_nr'});
    }
    my $formatted_entry = substitute_line($entry->{'entry'}, "\@$command", prepare_state_multiple_pass("${command}_index", $state),$entry->{'line_nr'});
    my $formatted_entry_reference = substitute_line($entry->{'texi'}, "\@$command", prepare_state_multiple_pass("${command}_index", $state));
    return ($entry, $formatted_entry, &$Texi2HTML::Config::index_entry_label ($entry->{'id'}, $state->{'preformatted'}, $formatted_entry, 
      $index_name,
       $command, $entry->{'texi'}, $formatted_entry_reference, 
       (!$entry->{'seen_in_output'} and defined($entry->{'region'})),$entry)); 
}

# decompose a decimal number on a given base. The algorithm looks like
# the division with growing powers (division suivant les puissances
# croissantes) ?
sub decompose($$)
{  
    my $number = shift;
    my $base = shift;
    my @result = ();

    return (0) if ($number == 0);
    my $power = 1;
    my $remaining = $number;

    while ($remaining)
    {
         my $factor = $remaining % ($base ** $power);
         $remaining -= $factor;
         push (@result, $factor / ($base ** ($power - 1)));
         $power++;
    }
    return @result;
}

# process a css file
sub process_css_file ($$)
{
    my $fh =shift;
    my $file = shift;
    my $in_rules = 0;
    my $in_comment = 0;
    my $in_import = 0;
    my $in_string = 0;
    my $rules = [];
    my $imports = [];
    my $line_nr = 0;
    while (my $line = <$fh>)
    {
        $line_nr++;
	    #print STDERR "Line: $line";
        if ($in_rules)
        {
            push @$rules, $line;
            next;
        }
        my $text = '';
        while (1)
        { 
		#sleep 1;
		#print STDERR "${text}!in_comment $in_comment in_rules $in_rules in_import $in_import in_string $in_string: $line";
             if ($in_comment)
             {
                 if ($line =~ s/^(.*?\*\/)//)
                 {
                     $text .= $1;
                     $in_comment = 0;
                 }
                 else
                 {
                     push @$imports, $text . $line;
                     last;
                 }
             }
             elsif (!$in_string and $line =~ s/^\///)
             { # what do '\' do here ?
                 if ($line =~ s/^\*//)
                 {
                     $text .= '/*';
                     $in_comment = 1;
                 }
                 else
                 {
                     push (@$imports, $text. "\n") if ($text ne '');
                     push (@$rules, '/' . $line);
                     $in_rules = 1;
                     last;
                 }
             }
             elsif (!$in_string and $in_import and $line =~ s/^([\"\'])//)
             { # strings outside of import start rules
                 $text .= "$1";
                 $in_string = quotemeta("$1");
             }
             elsif ($in_string and $line =~ s/^(\\$in_string)//)
             {
                 $text .= $1;
             }
             elsif ($in_string and $line =~ s/^($in_string)//)
             {
                 $text .= $1;
                 $in_string = 0;
             }
             elsif ((! $in_string and !$in_import) and ($line =~ s/^([\\]?\@import)$// or $line =~ s/^([\\]?\@import\s+)//))
             {
                 $text .= $1;
                 $in_import = 1;
             }
             elsif (!$in_string and $in_import and $line =~ s/^\;//)
             {
                 $text .= ';';
                 $in_import = 0;
             }
             elsif (($in_import or $in_string) and $line =~ s/^(.)//)
             {
                  $text .= $1;
             }
             elsif (!$in_import and $line =~ s/^([^\s])//)
             { 
                  push (@$imports, $text. "\n") if ($text ne '');
                  push (@$rules, $1 . $line);
                  $in_rules = 1;
                  last;
             }
             elsif ($line =~ s/^(\s)//)
             {
                  $text .= $1;
             }
             elsif ($line eq '')
             {
                  push (@$imports, $text);
                  last;
             }
        } 
    }
    #file_line_warn (__("string not closed in css file"), $file) if ($in_string);
    #file_line_warn (__("--css-file ended in comment"), $file) if ($in_comment);
    #file_line_warn (__("\@import not finished in css file"), $file)  if ($in_import and !$in_comment and !$in_string);
    warn (sprintf(__("%s:%d: string not closed in css file"), $file, $line_nr)) if ($in_string);
    warn (sprintf(__("%s:%d: --css-file ended in comment"), $file, $line_nr)) if ($in_comment);
    warn (sprintf(__("%s:%d \@import not finished in css file"), $file, $line_nr))  if ($in_import and !$in_comment and !$in_string);
    return ($imports, $rules);
}

sub collect_all_css_files()
{
   my @css_import_lines;
   my @css_rule_lines;

  # process css files
   return ([],[]) if ($Texi2HTML::Config::NO_CSS);
   foreach my $file (@Texi2HTML::Config::CSS_FILES)
   {
      my $css_file_fh;
      my $css_file;
      if ($file eq '-')
      {
         $css_file_fh = \*STDIN;
         $css_file = '-';
      }
      else
      {
         $css_file = locate_include_file ($file);
         unless (defined($css_file))
         {
            document_warn ("css file $file not found");
            next;
         }
         unless (open (CSSFILE, "$css_file"))
         {
            warn (sprintf(__("%s: could not open --css-file %s: %s\n"), $real_command_name, $css_file, $!));
            next;
         }
         $css_file_fh = \*CSSFILE;
      }
      my ($import_lines, $rules_lines);
      ($import_lines, $rules_lines) = process_css_file ($css_file_fh, $css_file);
      push @css_import_lines, @$import_lines;
      push @css_rule_lines, @$rules_lines;
   }


   if ($T2H_DEBUG & $DEBUG_USER)
   {
      if (@css_import_lines)
      {
         print STDERR "# css import lines\n";
         foreach my $line (@css_import_lines)
         {
            print STDERR "$line";
         }
      }
      if (@css_rule_lines)
      {
         print STDERR "# css rule lines\n";
         foreach my $line (@css_rule_lines)
         {
            print STDERR "$line";
         }
      }
   }
   return (\@css_import_lines, \@css_rule_lines);
}

sub init_with_file_name($)
{
   my $base_file = shift;
   set_docu_names($base_file, $Texi2HTML::THISDOC{'input_file_number'});

   foreach my $handler(@Texi2HTML::Config::command_handler_init)
   {
      &$handler;
   }
}


#######################################################################
#
# Main processing, process all the files given on the command line
#
#######################################################################

my @input_files = @ARGV;
# use STDIN if not a tty, like makeinfo does
@input_files = ('-') if (!scalar(@input_files) and !-t STDIN);
die sprintf(__("%s: missing file argument.\n"), $real_command_name) .$T2H_FAILURE_TEXT unless (scalar(@input_files) >= 1);

my $file_number = 0;
# main processing
while(@input_files)
{
   my $input_file_arg = shift(@input_files);

   %Texi2HTML::THISDOC = ();
   $Texi2HTML::THIS_ELEMENT = undef;

   # Otherwise Texi2HTML::THISDOC wouldn't be set in case there was no call
   # to set_conf.
   foreach my $global_conf_vars('SPLIT', 'SPLIT_SIZE')
   {
      $Texi2HTML::THISDOC{$global_conf_vars} = Texi2HTML::Config::get_conf($global_conf_vars);
   }

   foreach my $global_key (keys(%Texi2HTML::GLOBAL))
   {
      $Texi2HTML::THISDOC{$global_key} = $Texi2HTML::GLOBAL{$global_key};
   }

   my $input_file_name;
   # try to concatenate with different suffixes. The last suffix is ''
   # such that the plain file name is checked.
   foreach my $suffix (@Texi2HTML::Config::INPUT_FILE_SUFFIXES)
   {
      $input_file_name = $input_file_arg.$suffix if (-e $input_file_arg.$suffix);
   }
   # in case no file was found, still set the file name
   $input_file_name = $input_file_arg if (!defined($input_file_name));

   $Texi2HTML::THISDOC{'input_file_name'} = $input_file_name;
   $Texi2HTML::THISDOC{'input_file_number'} = $file_number;
   $Texi2HTML::THISDOC{'input_directory'} = '.';
   if ($input_file_name =~ /(.*\/)/)
   {
      $Texi2HTML::THISDOC{'input_directory'} = $1;
   }

   my $input_file_base = $input_file_name;
   $input_file_base =~ s/\.te?x(i|info)?$//;

   @{$Texi2HTML::TOC_LINES} = ();            # table of contents
   @{$Texi2HTML::OVERVIEW} = ();           # short table of contents
   # this could be done here, but perl warns that 
   # `"Texi2HTML::TITLEPAGE" used only once' and it is reset in 
   # &$Texi2HTML::Config::titlepage anyway
   # $Texi2HTML::TITLEPAGE = undef;        
   @{$Texi2HTML::THIS_SECTION} = ();

   # the reference to these hashes may be used before this point (for example
   # see makeinfo.init), so they should be kept as is and the values undef
   # but the key should not be deleted because the ref is on the key.
   foreach my $hash (\%Texi2HTML::HREF, \%Texi2HTML::NAME, \%Texi2HTML::NODE,
        \%Texi2HTML::NO_TEXI, \%Texi2HTML::SIMPLE_TEXT)
   {
       foreach my $key (keys(%$hash))
       {
           $hash->{$key} = undef;
       }
   }

   %region_lines = ();
   %region_line_nrs = ();
   foreach my $region (@special_regions)
   {
      $region_lines{$region} = [];
      $region_line_nrs{$region} = [];
   }

   @created_directories = ();

   $docu_dir = undef;    # directory of the document
   $docu_name = undef;   # basename of the document
   $docu_rdir = undef;   # directory for the output
   $docu_toc = undef;    # document's table of contents
   $docu_stoc = undef;   # document's short toc
   $docu_foot = undef;   # document's footnotes
   $docu_about = undef;  # about this document
   $docu_top = undef;    # document top
   $docu_doc = undef;    # document (or document top of split)
   $docu_frame = undef;  # main frame file
   $docu_toc_frame = undef;       # toc frame file
   $path_to_working_dir = undef;  # relative path leading to the working 
                                  # directory from the document directory
   $docu_doc_file = undef;
   $docu_toc_file = undef;
   $docu_stoc_file = undef;
   $docu_foot_file = undef;
   $docu_about_file = undef;
   $docu_top_file = undef;
   $docu_frame_file = undef;
   $docu_toc_frame_file = undef;

   $global_pass = '0';

   # done before any processing, this is not necessarily 
   # the case with command_handler_init
   foreach my $handler(@Texi2HTML::Config::command_handler_setup)
   {
      &$handler;
   }

   if (!$Texi2HTML::Config::USE_SETFILENAME)
   {
      init_with_file_name ($input_file_base);
   }

   # FIXME when to do that?
   ($Texi2HTML::THISDOC{'css_import_lines'}, $Texi2HTML::THISDOC{'css_rule_lines'}) 
      = collect_all_css_files();

   texinfo_initialization(0);

   print STDERR "# reading from $input_file_name\n" if $T2H_VERBOSE;

   $macros = undef;         # macros. reference on a hash
   %info_enclose = ();      # macros defined with definfoenclose
   @floats = ();            # floats list
   %floats = ();            # floats by style
   %nodes = ();             # nodes hash. The key is the texi node name
   %cross_reference_nodes = ();  # normalized node names arrays


   $global_pass = '1';
   my ($texi_lines, $first_texi_lines, $lines_numbers) 
        = pass_texi($input_file_name);

   if ($Texi2HTML::Config::USE_SETFILENAME and !defined($docu_name))
   {
      init_with_file_name ($input_file_base);
   }

   $global_pass = '1 expand macros';
   Texi2HTML::Config::t2h_default_set_out_encoding();
   dump_texi($texi_lines, 'texi', $lines_numbers) if ($T2H_DEBUG & $DEBUG_TEXI);
   if (defined($Texi2HTML::Config::MACRO_EXPAND))
   {
       my @texi_lines = (@$first_texi_lines, @$texi_lines);
       dump_texi(\@texi_lines, '', undef, $Texi2HTML::Config::MACRO_EXPAND);
   }

   %content_element = ();
   foreach my $command('contents', 'shortcontents')
   {
       $all_content_elements{$command} = [];
       foreach my $key (keys(%{$reference_content_element{$command}}))
       {
           $content_element{$command}->{$key} = $reference_content_element{$command}->{$key};
       }
   }

   %sec2level = %reference_sec2level;

   $element_before_anything =
   { 
      'before_anything' => 1,
      'place' => [],
      'texi' => 'VIRTUAL ELEMENT BEFORE ANYTHING',
   };


   $footnote_element = 
   { 
      'id' => $Texi2HTML::Config::misc_pages_targets{'Footnotes'},
      'target' => $Texi2HTML::Config::misc_pages_targets{'Footnotes'},
      'file' => $docu_foot,
      'footnote' => 1,
      'place' => [],
   };

   %region_initial_state = ();
   foreach my $region (@special_regions)
   {
      $region_initial_state{$region} = { };
   }

# to determine if a command has to be processed the following are interesting 
# (and can be faked):
# 'region': the name of the special region we are processing
# 'region_pass': the number of passes in that specific region (both outside
#                of the main document, and in the main document)
# 'multiple_pass': the number of pass in the formatting of the region in the
#                  main document
#                  It is set to 0 the first time the region is seen, before
#                  it will be -1, for example when doing the 
#                  copying_comment, the titlepage... before starting with
#                  the document itself.
# 'outside_document': set to 1 if outside of the main document formatting

   foreach my $key (keys(%region_initial_state))
   {
      $region_initial_state{$key}->{'multiple_pass'} = -1;
      $region_initial_state{$key}->{'region_pass'} = 0;
      $region_initial_state{$key}->{'num_head'} = 0;
      $region_initial_state{$key}->{'foot_num'} = 0;
      $region_initial_state{$key}->{'relative_foot_num'} = 0;
      $region_initial_state{$key}->{'region'} = $key;
   }

   @opened_files = (); # all the files opened by the program to remove
                       # them if FORCE is not set and an error occured

   texinfo_initialization(1);

    
   $no_element_associated_place = [];

   $document_idx_num = 0;
   $document_sec_num = 0;
   $document_head_num = 0;
   $document_anchor_num = 0;

   @nodes_list = ();        # nodes in document reading order
                            # each member is a reference on a hash
   @sections_list = ();     # sections in reading order
                            # each member is a reference on a hash
   @all_elements = ();      # sectioning elements (nodes and sections)
                            # in reading order. Each member is a reference
                            # on a hash which also appears in %nodes,
                            # @sections_list @nodes_list, @elements_list
   @elements_list = ();     # all the resulting elements in document order
   %sections = ();          # sections hash. The key is the section number
   %headings = ();          # headings hash. The key is the heading number
   $section_top = undef;    # @top section
   $element_top = undef;    # Top element
   $node_top = undef;       # Top node
   $node_first = undef;     # First node
   $element_index = undef;  # element with first index
   $element_chapter_index = undef;  # chapter with first index
   $element_first = undef;  # first element
   $element_last = undef;   # last element
   %special_commands = ();  # hash for the commands specially handled 
                            # by the user

   @index_labels = ();             # array corresponding with @?index commands
                                   # constructed during pass_texi, used to
                                   # put labels in pass_text
                                   # right now it is only used for debugging
                                   # purposes.
   @unknown_index_index_entries = ();  # holds index entries not associated
                                       # with any index
   %{$Texi2HTML::THISDOC{'index_entries_array'}} = (); # holds the index 
                              # entries in order of appearance in the document
                              # for each index name.
   %{$Texi2HTML::THISDOC{'index_letters_array'}} = (); # holds the sorted
                            # index letters for each index name. The sorted
                            # letters hold the sorted index entries

   $global_pass = 2;
   my ($doc_lines, $doc_numbers) = pass_structure($texi_lines, $lines_numbers);

   foreach my $handler(@Texi2HTML::Config::command_handler_names)
   {
       &$handler;
   }

   if ($T2H_DEBUG & $DEBUG_TEXI)
   {
      dump_texi($doc_lines, 'first', $doc_numbers);
      if (defined($Texi2HTML::Config::MACRO_EXPAND and $Texi2HTML::Config::DUMP_TEXI))
      {
          my @all_doc_lines = (@$first_texi_lines, @$doc_lines);
          #push (@$doc_lines, "\@bye\n");
          dump_texi(\@all_doc_lines, '', undef, $Texi2HTML::Config::MACRO_EXPAND . ".first");
      }
   }
   next if ($Texi2HTML::Config::DUMP_TEXI);

   foreach my $style (keys(%special_commands))
   {
      $special_commands{$style}->{'max'} = $special_commands{$style}->{'count'};
   }

   %files = ();   # keys are files. This is used to avoid reusing an already
                  # used file name
   %printed_indices = (); # value is true for an index name not empty and
                          # printed
   $global_pass = '2 prepare indices';
   prepare_indices();
   $global_pass = '2 element directions';
   rearrange_elements();
   do_names();

   $global_pass = '2-3 user functions';
#Texi2HTML::LaTeX2HTML::latex2html();
   foreach my $handler(@Texi2HTML::Config::command_handler_process)
   {
       &$handler;
   }

# maybe do that later to have more elements ready?
   &$Texi2HTML::Config::toc_body(\@sections_list);

   &$Texi2HTML::Config::css_lines($Texi2HTML::THISDOC{'css_import_lines'}, 
        $Texi2HTML::THISDOC{'css_rule_lines'});


   $global_head_num = 0;       # heading index. it is global for the main doc, 
                               # and taken from the state if in multiple_pass.
   $global_foot_num = 0;
   $global_relative_foot_num = 0;
   @foot_lines = ();           # footnotes
   $copying_comment = '';      # comment constructed from text between
                               # @copying and @end copying with licence
   %acronyms_like = ();        # acronyms or similar commands associated texts
                               # the key are the commands, the values are
                               # hash references associating shorthands to
                               # texts.
   @states_stack = ();

   pass_text($doc_lines, $doc_numbers);
   print STDERR "BUG: " . scalar(@index_labels) . " index entries pending\n" 
      if (scalar(@index_labels));
   foreach my $special (keys(%special_commands))
   {
      my $count = $special_commands{$special}->{'count'};
      if (($count != 0) and $T2H_VERBOSE)
      {
         document_warn ("$count special \@$special were not processed.\n");
      }
   }
   if ($Texi2HTML::Config::IDX_SUMMARY)
   {
      foreach my $entry (keys(%index_names))
      {
         do_index_summary_file($entry, $docu_name);
      }
   }
   if (defined($Texi2HTML::Config::INTERNAL_LINKS))
   {
      my $FH = open_out($Texi2HTML::Config::INTERNAL_LINKS);
      &$Texi2HTML::Config::internal_links($FH, \@elements_list, $Texi2HTML::THISDOC{'index_letters_array'});
      close ($FH);
   }
   do_node_files() if ($Texi2HTML::Config::NODE_FILES);
#l2h_FinishFromHtml() if ($Texi2HTML::Config::L2H);
#l2h_Finish() if($Texi2HTML::Config::L2H);
#Texi2HTML::LaTeX2HTML::finish();
   foreach my $handler(@Texi2HTML::Config::command_handler_finish)
   {
       &$handler;
   }
   &$Texi2HTML::Config::finish_out();

   print STDERR "# File ($file_number) $input_file_name processed\n" if $T2H_VERBOSE;
   $file_number++;
}
print STDERR "# that's all folks\n" if $T2H_VERBOSE;
exit(0);


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

# 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 ############
    .so /usr/local/man/man1/texi2html.1