1#! /usr/bin/perl -- # perl
2'di ';
3'ig 00 ';
4#+##############################################################################
5#
6# texi2html: Program to transform Texinfo documents to HTML
7#
8#    Copyright (C) 1999-2005  Patrice Dumas <dumas@centre-cired.fr>,
9#                             Derek Price <derek@ximbiot.com>,
10#                             Adrian Aichner <adrian@xemacs.org>,
11#                           & others.
12#
13#    This program is free software; you can redistribute it and/or modify
14#    it under the terms of the GNU General Public License as published by
15#    the Free Software Foundation; either version 2 of the License, or
16#    (at your option) any later version.
17#
18#    This program is distributed in the hope that it will be useful,
19#    but WITHOUT ANY WARRANTY; without even the implied warranty of
20#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21#    GNU General Public License for more details.
22#
23#    You should have received a copy of the GNU General Public License
24#    along with this program; if not, write to the Free Software
25#    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26#    02110-1301  USA
27#
28#-##############################################################################
29# The man page for this program is included at the end of this file and can be
30# viewed using the command 'nroff -man texi2html'.
31
32# for POSIX::setlocale and File::Spec
33require 5.00405;
34# Perl pragma to restrict unsafe constructs
35use strict;
36# used in case of tests, to revert to "C" locale.
37use POSIX qw(setlocale LC_ALL LC_CTYPE);
38# used to obtain the name of the current working directory
39use Cwd;
40# used to find a relative path back to the current working directory
41use File::Spec;
42
43#
44# According to
45# larry.jones@sdrc.com (Larry Jones)
46# this pragma is not present in perl5.004_02:
47#
48# Perl pragma to control optional warnings
49# use warnings;
50
51#++##########################################################################
52#
53# NOTE FOR DEBUGGING THIS SCRIPT:
54# You can run 'perl texi2html.pl' directly, provided you have
55# the environment variable T2H_HOME set to the directory containing
56# the texi2html.init, T2h_i18n.pm, translations.pl, l2h.init,
57# T2h_l2h.pm files
58#
59#--##########################################################################
60
61# CVS version:
62# $Id: texi2html.pl,v 1.182 2007/05/07 22:56:02 pertusus Exp $
63
64# Homepage:
65my $T2H_HOMEPAGE = "https://www.nongnu.org/texi2html/";
66
67# Authors (appears in comments):
68my $T2H_AUTHORS = <<EOT;
69Written by: Lionel Cons <Lionel.Cons\@cern.ch> (original author)
70            Karl Berry  <karl\@freefriends.org>
71            Olaf Bachmann <obachman\@mathematik.uni-kl.de>
72            and many others.
73Maintained by: Many creative people.
74Send bugs and suggestions to <texi2html-bug\@nongnu.org>
75EOT
76
77# Version: set in configure.in
78my $THISVERSION = '1.78a';
79my $THISPROG = "texi2html $THISVERSION"; # program name and version
80
81#+++########################################################################
82#                                                                          #
83# Paths and file names                                                     #
84#                                                                          #
85#---########################################################################
86
87# set by configure, prefix for the sysconfdir and so on
88my $prefix = '/usr/local';
89my $sysconfdir;
90my $pkgdatadir;
91my $datadir;
92
93# We need to eval as $prefix has to be expanded. However when we haven't
94# run configure @sysconfdir will be expanded as an array, thus we verify
95# whether configure was run or not
96if ('${prefix}/etc' ne '@' . 'sysconfdir@')
97{
98    $sysconfdir = eval '"${prefix}/etc"';
99}
100else
101{
102    $sysconfdir = "/usr/local/etc";
103}
104
105if ('${prefix}/share' ne '@' . 'datadir@')
106{
107    $pkgdatadir = eval '"${prefix}/share/texi2html"';
108    $datadir = eval '"${prefix}/share"';
109}
110else
111{
112    $pkgdatadir = "/usr/local/share/texi2html";
113    $datadir = "/usr/local/share";
114}
115
116my $i18n_dir = 'i18n'; # name of the directory containing the per language files
117my $conf_file_name = 'Config' ;
118my $texinfo_htmlxref = 'htmlxref.cnf';
119
120# directories for texi2html init files
121my @texi2html_config_dirs = ('./');
122push @texi2html_config_dirs, "$ENV{'HOME'}/.texi2html/" if (defined($ENV{'HOME'}));
123push @texi2html_config_dirs, "$sysconfdir/texi2html/" if (defined($sysconfdir));
124push @texi2html_config_dirs, "$pkgdatadir" if (defined($pkgdatadir));
125
126# directories for texinfo configuration files
127my @texinfo_config_dirs = ('./.texinfo/');
128push @texinfo_config_dirs, "$ENV{'HOME'}/.texinfo/" if (defined($ENV{'HOME'}));
129push @texinfo_config_dirs, "$sysconfdir/texinfo/" if (defined($sysconfdir));
130push @texinfo_config_dirs, "$datadir/texinfo/" if (defined($datadir));
131
132
133#+++########################################################################
134#                                                                          #
135# Constants                                                                #
136#                                                                          #
137#---########################################################################
138
139my $DEBUG_MENU   =  1;
140my $DEBUG_INDEX =  2;
141my $DEBUG_TEXI  =  4;
142my $DEBUG_MACROS =  8;
143my $DEBUG_FORMATS   = 16;
144my $DEBUG_ELEMENTS  = 32;
145my $DEBUG_USER  = 64;
146my $DEBUG_L2H   = 128;
147
148my $ERROR = "***";                 # prefix for errors
149my $WARN  = "**";                  # prefix for warnings
150
151my $VARRE = '[\w\-]+';          # RE for a variable name
152my $NODERE = '[^:]+';             # RE for node names
153
154my $MAX_LEVEL = 4;
155my $MIN_LEVEL = 1;
156
157#+++###########################################################################
158#                                                                             #
159# Initialization                                                              #
160# Some declarations, some functions that are GPL and therefore cannot be in   #
161# texi2html.init, some functions that are not to be customized.               #
162# Pasted content of File $(srcdir)/texi2html.init: Default initializations    #
163#                                                                             #
164#---###########################################################################
165
166{
167package Texi2HTML::Config;
168
169
170sub load($)
171{
172    my $file = shift;
173    eval { require($file) ;};
174    if ($@ ne '')
175    {
176        print STDERR "error loading $file: $@\n";
177        return 0;
178    }
179    return 1;
180}
181
182# customization options variables
183
184use vars qw(
185$DEBUG
186$PREFIX
187$VERBOSE
188$SUBDIR
189$IDX_SUMMARY
190$SPLIT
191$SHORT_REF
192@EXPAND
193$EXPAND
194$TOP
195$DOCTYPE
196$FRAMESET_DOCTYPE
197$CHECK
198$TEST
199$DUMP_TEXI
200$MACRO_EXPAND
201$USE_GLOSSARY
202$INVISIBLE_MARK
203$USE_ISO
204$TOP_FILE
205$TOC_FILE
206$FRAMES
207$SHOW_MENU
208$NUMBER_SECTIONS
209$USE_NODES
210$USE_UNICODE
211$USE_UNIDECODE
212$TRANSLITERATE_NODE
213$NODE_FILES
214$NODE_NAME_IN_MENU
215$AVOID_MENU_REDUNDANCY
216$SECTION_NAVIGATION
217$SHORTEXTN
218$EXTENSION
219$OUT
220$NOVALIDATE
221$DEF_TABLE
222$LANG
223$DO_CONTENTS
224$DO_SCONTENTS
225$SEPARATED_FOOTNOTES
226$TOC_LINKS
227$L2H
228$L2H_L2H
229$L2H_SKIP
230$L2H_TMP
231$L2H_CLEAN
232$L2H_FILE
233$L2H_HTML_VERSION
234$EXTERNAL_DIR
235@INCLUDE_DIRS
236@PREPEND_DIRS
237@CONF_DIRS
238$IGNORE_PREAMBLE_TEXT
239@CSS_FILES
240$INLINE_CONTENTS
241);
242
243# customization variables
244# ENCODING is deprecated
245use vars qw(
246$ENCODING
247
248$ENCODING_NAME
249$DOCUMENT_ENCODING
250$OUT_ENCODING
251$IN_ENCODING
252$DEFAULT_ENCODING
253$MENU_PRE_STYLE
254$CENTER_IMAGE
255$EXAMPLE_INDENT_CELL
256$SMALL_EXAMPLE_INDENT_CELL
257$SMALL_FONT_SIZE
258$SMALL_RULE
259$DEFAULT_RULE
260$MIDDLE_RULE
261$BIG_RULE
262$TOP_HEADING
263$INDEX_CHAPTER
264$SPLIT_INDEX
265$HREF_DIR_INSTEAD_FILE
266$USE_MENU_DIRECTIONS
267$AFTER_BODY_OPEN
268$PRE_BODY_CLOSE
269$EXTRA_HEAD
270$VERTICAL_HEAD_NAVIGATION
271$WORDS_IN_PAGE
272$ICONS
273$UNNUMBERED_SYMBOL_IN_MENU
274$SIMPLE_MENU
275$MENU_SYMBOL
276$OPEN_QUOTE_SYMBOL
277$CLOSE_QUOTE_SYMBOL
278$TOC_LIST_STYLE
279$TOC_LIST_ATTRIBUTE
280$TOP_NODE_FILE
281$TOP_NODE_UP
282$NODE_FILE_EXTENSION
283$BEFORE_OVERVIEW
284$AFTER_OVERVIEW
285$BEFORE_TOC_LINES
286$AFTER_TOC_LINES
287$NEW_CROSSREF_STYLE
288$USER
289$USE_NUMERIC_ENTITY
290$DATE
291%ACTIVE_ICONS
292%NAVIGATION_TEXT
293%PASSIVE_ICONS
294%BUTTONS_NAME
295%BUTTONS_GOTO
296%BUTTONS_EXAMPLE
297@CHAPTER_BUTTONS
298@MISC_BUTTONS
299@SECTION_BUTTONS
300@SECTION_FOOTER_BUTTONS
301@NODE_FOOTER_BUTTONS
302@IMAGE_EXTENSIONS
303);
304
305# customization variables which may be guessed in the script
306#our $ADDRESS;
307use vars qw(
308$BODYTEXT
309$CSS_LINES
310$DOCUMENT_DESCRIPTION
311$EXTERNAL_CROSSREF_SPLIT
312);
313
314# I18n
315use vars qw(
316$I
317$LANGUAGES
318);
319
320# customizable subroutines references
321use vars qw(
322$print_section
323$one_section
324$end_section
325$print_Top_header
326$print_Top_footer
327$print_Top
328$print_Toc
329$print_Overview
330$print_Footnotes
331$print_About
332$print_misc_header
333$print_misc_footer
334$print_misc
335$print_section_header
336$print_section_footer
337$print_chapter_header
338$print_chapter_footer
339$print_page_head
340$print_page_foot
341$print_head_navigation
342$print_foot_navigation
343$button_icon_img
344$print_navigation
345$about_body
346$print_frame
347$print_toc_frame
348$toc_body
349$titlepage
350$css_lines
351$print_redirection_page
352$init_out
353$finish_out
354$node_file_name
355$element_file_name
356$inline_contents
357
358$protect_text
359$anchor
360$def_item
361$def
362$menu
363$menu_link
364$menu_description
365$menu_comment
366$simple_menu_link
367$ref_beginning
368$info_ref
369$book_ref
370$external_href
371$external_ref
372$internal_ref
373$table_item
374$table_line
375$row
376$cell
377$list_item
378$comment
379$def_line
380$def_line_no_texi
381$raw
382$raw_no_texi
383$heading
384$paragraph
385$preformatted
386$foot_line_and_ref
387$foot_section
388$address
389$image
390$image_files
391$index_entry_label
392$index_entry
393$index_letter
394$print_index
395$index_summary
396$summary_letter
397$complex_format
398$cartouche
399$sp
400$definition_category
401$table_list
402$copying_comment
403$index_summary_file_entry
404$index_summary_file_end
405$index_summary_file_begin
406$style
407$format
408$normal_text
409$empty_line
410$unknown
411$unknown_style
412$float
413$caption_shortcaption
414$listoffloats
415$listoffloats_entry
416$listoffloats_caption
417$listoffloats_float_style
418$listoffloats_style
419$acronym_like
420$quotation
421$quotation_prepend_text
422$paragraph_style_command
423$heading_texi
424$index_element_heading_texi
425
426$PRE_ABOUT
427$AFTER_ABOUT
428);
429
430# hash which entries might be redefined by the user
431use vars qw(
432$complex_format_map
433%accent_map
434%def_map
435%format_map
436%simple_map
437%simple_map_pre
438%simple_map_texi
439%style_map
440%style_map_pre
441%style_map_texi
442%simple_format_simple_map_texi
443%simple_format_style_map_texi
444%simple_format_texi_map
445%command_type
446%paragraph_style
447%things_map
448%pre_map
449%texi_map
450%unicode_map
451%unicode_diacritical
452%transliterate_map
453%transliterate_accent_map
454%no_transliterate_map
455%ascii_character_map
456%ascii_simple_map
457%ascii_things_map
458%numeric_entity_map
459%perl_charset_to_html
460%iso_symbols
461%misc_command
462%css_map
463%format_in_paragraph
464%special_list_commands
465%accent_letters
466%unicode_accents
467%special_accents
468@command_handler_init
469@command_handler_process
470@command_handler_finish
471%command_handler
472);
473
474# needed in this namespace for translations
475$I = \&Texi2HTML::I18n::get_string;
476
477#
478# Function refs covered by the GPL as part of the texi2html.pl original
479# code. As such they cannot appear in texi2html.init which is public
480# domain (at least the things coded by me, and, if I'm not wrong also the
481# things coded by Olaf -- Pat).
482#
483
484$toc_body                 = \&T2H_GPL_toc_body;
485$style                    = \&T2H_GPL_style;
486$format                   = \&T2H_GPL_format;
487
488sub T2H_GPL_toc_body($)
489{
490    my $elements_list = shift;
491    return unless ($DO_CONTENTS or $DO_SCONTENTS or $FRAMES);
492    my $current_level = 0;
493    my $ul_style = $NUMBER_SECTIONS ? $TOC_LIST_ATTRIBUTE : '';
494    foreach my $element (@$elements_list)
495    {
496        next if ($element->{'top'} or $element->{'index_page'});
497        my $ind = '  ' x $current_level;
498        my $level = $element->{'toc_level'};
499        print STDERR "Bug no toc_level for ($element) $element->{'texi'}\n" if (!defined ($level));
500        if ($level > $current_level)
501        {
502            while ($level > $current_level)
503            {
504                $current_level++;
505                my $ln = "\n$ind<ul${ul_style}>\n";
506                $ind = '  ' x $current_level;
507                push(@{$Texi2HTML::TOC_LINES}, $ln);
508            }
509        }
510        elsif ($level < $current_level)
511        {
512            while ($level < $current_level)
513            {
514                $current_level--;
515                $ind = '  ' x $current_level;
516                my $line = "</li>\n$ind</ul>";
517                $line .=  "</li>" if ($level == $current_level);
518                push(@{$Texi2HTML::TOC_LINES}, "$line\n");
519
520            }
521        }
522        else
523        {
524            push(@{$Texi2HTML::TOC_LINES}, "</li>\n");
525        }
526        my $file = '';
527        $file = $element->{'file'} if ($SPLIT);
528        my $text = $element->{'text'};
529        #$text = $element->{'name'} unless ($NUMBER_SECTIONS);
530        my $entry = "<li>" . &$anchor ($element->{'tocid'}, "$file#$element->{'id'}",$text);
531        push (@{$Texi2HTML::TOC_LINES}, $ind . $entry);
532        push(@{$Texi2HTML::OVERVIEW}, $entry. "</li>\n") if ($level == 1);
533    }
534    while (0 < $current_level)
535    {
536        $current_level--;
537        my $ind = '  ' x $current_level;
538        push(@{$Texi2HTML::TOC_LINES}, "</li>\n$ind</ul>\n");
539    }
540    @{$Texi2HTML::TOC_LINES} = () unless ($DO_CONTENTS);
541    if (@{$Texi2HTML::TOC_LINES})
542    {
543        unshift @{$Texi2HTML::TOC_LINES}, $BEFORE_TOC_LINES;
544        push @{$Texi2HTML::TOC_LINES}, $AFTER_TOC_LINES;
545    }
546    @{$Texi2HTML::OVERVIEW} = () unless ($DO_SCONTENTS or $FRAMES);
547    if (@{$Texi2HTML::OVERVIEW})
548    {
549        unshift @{$Texi2HTML::OVERVIEW}, "<ul${ul_style}>\n";
550        push @{$Texi2HTML::OVERVIEW}, "</ul>\n";
551        unshift @{$Texi2HTML::OVERVIEW}, $BEFORE_OVERVIEW;
552        push @{$Texi2HTML::OVERVIEW}, $AFTER_OVERVIEW;
553    }
554}
555
556sub T2H_GPL_style($$$$$$$$$)
557{                           # known style
558    my $style = shift;
559    my $command = shift;
560    my $text = shift;
561    my $args = shift;
562    my $no_close = shift;
563    my $no_open = shift;
564    my $line_nr = shift;
565    my $state = shift;
566    my $style_stack = shift;
567
568    my $do_quotes = 0;
569    my $use_attribute = 0;
570    my $use_begin_end = 0;
571    if (ref($style) eq 'HASH')
572    {
573        #print STDERR "GPL_STYLE $command\n";
574        #print STDERR " @$args\n";
575        $do_quotes = $style->{'quote'};
576        if ((@{$style->{'args'}} == 1) and defined($style->{'attribute'}))
577        {
578            $style = $style->{'attribute'};
579            $use_attribute = 1;
580            $text = $args->[0];
581        }
582        elsif (defined($style->{'function'}))
583        {
584            $text = &{$style->{'function'}}($command, $args, $style_stack, $state, $line_nr);
585        }
586    }
587    else
588    {
589        if ($style =~ s/^\"//)
590        {                       # add quotes
591            $do_quotes = 1;
592        }
593        if ($style =~ s/^\&//)
594        {                       # custom
595            $style = 'Texi2HTML::Config::' . $style;
596            eval "\$text = &$style(\$text, \$command, \$style_stack)";
597        }
598        elsif ($style ne '')
599        {
600            $use_attribute = 1;
601        }
602        else
603        {                       # no style
604        }
605    }
606    if ($use_attribute)
607    {                       # good style
608        my $attribute_text = '';
609        if ($style =~ /^(\w+)(\s+.*)/)
610        {
611            $style = $1;
612            $attribute_text = $2;
613        }
614#        $text = "<${style}$attribute_text>$text</$style>" ;
615        $text = "<${style}$attribute_text>" . "$text" if (!$no_open);
616        $text .= "</$style>" if (!$no_close);
617        if ($do_quotes)
618        {
619             $text = $OPEN_QUOTE_SYMBOL . "$text" if (!$no_open);
620             $text .= $CLOSE_QUOTE_SYMBOL if (!$no_close);
621        }
622    }
623    if (ref($style) eq 'HASH')
624    {
625        if (defined($style->{'begin'}) and !$no_open)
626        {
627             $text = $style->{'begin'} . $text;
628        }
629        if (defined($style->{'end'}) and !$no_close)
630        {
631            $text = $text . $style->{'end'};
632        }
633    }
634    if ($do_quotes and !$use_attribute)
635    {
636        $text = $OPEN_QUOTE_SYMBOL . "$text" if (!$no_open);
637        $text .= $CLOSE_QUOTE_SYMBOL if (!$no_close);
638    }
639    return $text;
640}
641
642sub T2H_GPL_format($$$)
643{
644    my $tag = shift;
645    my $element = shift;
646    my $text = shift;
647    return '' if (!defined($element) or ($text !~ /\S/));
648    return $text if ($element eq '');
649    my $attribute_text = '';
650    if ($element =~ /^(\w+)(\s+.*)/)
651    {
652        $element = $1;
653        $attribute_text = $2;
654    }
655    return "<${element}$attribute_text>\n" . $text. "</$element>\n";
656}
657
658# leave this within comments, and keep the require statement
659# This way, you can directly run texi2html.pl, if
660# $ENV{T2H_HOME}/texi2html.init exists.
661
662# @INIT@
663# -*-perl-*-
664######################################################################
665# File: texi2html.init
666#
667# Default values for command-line arguments and for various customizable
668# procedures are set in this file.
669#
670# A copy of this file is pasted into the beginning of texi2html by
671# running './configure'.
672#
673# Copy this file, rename it and make changes to it, if you like.
674# Afterwards, load the file with command-line
675# option -init-file <your_init_file>
676#
677# $Id: texi2html.init,v 1.116 2007/05/07 22:56:02 pertusus Exp $
678
679######################################################################
680# The following variables can also be set by command-line options
681#
682#
683# The default values are set in this file, texi2html.init and the content
684# of this file is included at the beginning of the texi2html script file.
685# Those values may be overrided by values set in $sysconfdir/texi2htmlrc
686# and then by values set in $HOME/texi2htmlrc.
687#
688# command line switches may override these values, and values set in files
689# specified by -init-file are also taken into account.
690# values set in these files overwrite values set by the command-line
691# options appearing before -init-file and might still be overwritten by
692# command-line arguments following the -init-file option.
693
694# -debug
695# The integer value specifies what kind of debugging output is generated.
696$DEBUG = 0;
697
698# -doctype
699# The value is the 'SystemLiteral' which identifies the canonical DTD
700# for the document.
701# Definition: The SystemLiteral is called the entity's system
702# identifier. It is a URI, which may be used to retrieve the entity.
703# See https://www.xml.com/axml/target.html#NT-ExternalID
704$DOCTYPE = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html401/loose.dtd">';
705
706# -frameset-doctype
707# When frames are used, this SystemLiteral identifies the DTD used for
708# the file containing the frame description.
709$FRAMESET_DOCTYPE = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html401/frameset.dtd">';
710
711# -test
712# If this value is true, some variables which should be dynamically generated
713# (the date, the user running texi2html, the version of texi2html) are set to
714# fix and given values. This is usefull in case the resulting manual is
715# compared with a reference. For example this is used in the tests of test.sh.
716$TEST = 0;
717
718# -dump-texi
719# This value is usefull for debugging purposes. The result of the first pass is
720# put in <document name>.passtexi, the result of the second pass is put in
721# <document name>.passfirst.
722$DUMP_TEXI = 0;
723
724# -expand
725# the @EXPAND array contains the expanded section names.
726@EXPAND = ('html');
727
728# -invisible
729# This seems obsolete and is not used anywhere.
730# This was a workaround for a known bug of many WWW browsers, including
731# netscape. This was used to create invisible destination in anchors.
732$INVISIBLE_MARK = '';
733# $INVISIBLE_MARK = '&#160;';
734
735# -iso
736# if this value is true, ISO8859 characters are used for special symbols
737# (like copyright, etc).
738$USE_ISO = 1;
739
740# -I
741# add a directory to the list of directories where @include files are
742# searched for (besides the directory of the file). additional '-I'
743# args are appended to this list.
744# (APA: Don't implicitely search ., to conform with the docs!)
745# my @INCLUDE_DIRS = (".");
746@INCLUDE_DIRS = ();
747
748# -P
749# prepend a directory to the list of directories where @include files are
750# searched for before the directory of the file. additional '-P'
751# args are prepended to this list.
752@PREPEND_DIRS = ();
753
754# --conf-dir
755# append to the files searched for init files.
756@CONF_DIRS = ();
757
758# -top-file
759# This file name is used for the top-level file.
760# The extension is set appropriately, if necessary.
761# If empty, <basename of document>.html is used.
762# Typically, you would set this to "index.html".
763$TOP_FILE = '';
764
765# -toc-file
766# This file name is used for the table of contents.  The
767# extension is set appropriately, if necessary.
768# If empty, <basename of document>_toc.html is used.
769$TOC_FILE = '';
770
771# -frames
772# if the value is true, HTML 4.0 "frames" are used.
773# A file describing the frame layout is generated, together with a file
774# with the short table of contents.
775$FRAMES = 0;
776
777# -menu | -nomenu
778# if the value is true the Texinfo menus are shown.
779$SHOW_MENU = 1;
780
781# -number | -nonumber
782# if this is set the sections are numbered, and section names and numbers
783# are used in references and menus (instead of node names).
784$NUMBER_SECTIONS = 1;
785
786# -use-nodes
787# if this is set the nodes are used as sectionning elements.
788# Otherwise the nodes are incorporated in sections.
789$USE_NODES = 0;
790
791# -node-files
792# if this is set one file per node is generated, which can be a target for
793# cross manual references.
794$NODE_FILES = 0;
795
796# -split section|chapter|node|none
797# if $SPLIT is set to 'section' (resp. 'chapter') one html file per section
798# (resp. chapter) is generated. If $SPLIT is set to 'node' one html file per
799# node or sectionning element is generated. In all these cases separate pages
800# for Top, Table of content (Toc), Overview and About are generated.
801# Otherwise a monolithic html file that contains the whole document is
802# created.
803#$SPLIT = 'section';
804$SPLIT = '';
805
806# -sec-nav|-nosec-nav
807# if this is set then navigation panels are printed at the beginning of each
808# section.
809# If the document is split at nodes then navigation panels are
810# printed at the end if there were more than $WORDS_IN_PAGE words on page.
811#
812# If the document is split at sections this is ignored.
813#
814# This is most useful if you do not want to have section navigation
815# with -split chapter. There will be chapter navigation panel at the
816# beginning and at the end of chapters anyway.
817$SECTION_NAVIGATION = 1;
818
819# -separated-footnotes
820# if this is set footnotes are on a separated page. Otherwise they are at
821# the end of each file (if the document is split).
822$SEPARATED_FOOTNOTES = 1;
823
824# -toc-links
825# if this is set, links from headings to toc entries are created.
826$TOC_LINKS = 0;
827
828# -subdir
829# If this is set, then put result files into the specified directory.
830# If not set, then result files are put into the current directory.
831#$SUBDIR = 'html';
832$SUBDIR = '';
833
834# -short-extn
835# If this is set, then all HTML files will have extension ".htm" instead of
836# ".html". This is helpful when shipping the document to DOS-based systems.
837$SHORTEXTN = 0;
838
839# -prefix
840# This set the output file prefix, prepended to all .html, .gif and .pl files.
841# By default, this is the basename of the document.
842$PREFIX = '';
843
844# -o filename
845# If this is set a monolithic document is outputted into $filename.
846$OUT = '';
847
848# -no-validate
849# suppress node cross-reference validation
850$NOVALIDATE = 0;
851
852# -short-ref
853# if this is set cross-references are given without section numbers.
854$SHORT_REF = '';
855
856# -idx-sum
857# if value is set, then for each @printindex <index name>
858# <document name>_<index name>.idx is created which contains lines of the form
859# key ref sorted alphabetically (case matters).
860$IDX_SUMMARY = 0;
861
862# -def-table
863# If this is set a table construction for @def.... instead of definition
864# lists.
865# (New Option: 27.07.2000 Karl Heinz Marbaise)
866$DEF_TABLE = 0;
867
868# -verbose
869# if this is set chatter about what we are doing.
870$VERBOSE = '';
871
872# -lang
873# use &$I('my string') if you want to have translations of 'my string'
874# and provide the translations in $LANGUAGES->{$LANG} with 'my string'
875# as key.
876# To add a new language use ISO 639 language codes (see e.g. perl module
877# Locale-Codes-1.02 for  definitions). Supply translations in the
878# $LANGUAGES hash and put it in a file with $LANG as name in an i18n
879# directory.
880# Default's to 'en' if not set or no @documentlanguage is specified.
881$LANG = 'en';
882
883# -ignore-preamble-text
884# If this is set the text before @node and sectionning commands is ignored.
885$IGNORE_PREAMBLE_TEXT = 0;
886
887# -html-xref-prefix
888# base directory for external manuals.
889#$EXTERNAL_DIR = '../';
890$EXTERNAL_DIR = undef;
891
892# -l2h
893# if this is set, latex2html is used for generation of math content.
894$L2H = '';
895
896# -css-include
897# All the specified css files are used. More precisely the @import sections
898# are added to the beginning of the CSS_LINES the remaining is added at
899# the end of the CSS_LINES (after the css rules generated by texi2html).
900# cf texinfo manual for more info.
901# - means STDIN
902@CSS_FILES = ();
903
904######################
905# The following options are only relevant if $L2H is set
906#
907# -l2h-l2h
908# name/location of latex2html program
909$L2H_L2H = "latex2html";
910
911# -l2h-skip
912# If this is set the actual call to latex2html is skipped. The previously
913# generated content is reused, instead.
914$L2H_SKIP = '';
915
916# -l2h-tmp
917# If this is set l2h uses the specified directory for temporary files. The path
918# leading to this directory may not contain a dot (i.e., a ".");
919# otherwise, l2h will fail.
920$L2H_TMP = '';
921
922# -l2h-file
923# If set, l2h uses the file as latex2html init file
924$L2H_FILE = 'l2h.init';
925
926# -l2h-clean
927# if this is set the intermediate files generated by texi2html in relation with
928# latex2html are cleaned (they all have the prefix <document name>_l2h_).
929$L2H_CLEAN = 1;
930
931##############################################################################
932#
933# The following can only be set in the init file
934#
935##############################################################################
936
937# If true do table of contents even if there is no @content
938$DO_CONTENTS = 0;
939
940# If true do short table of contents even if there is no @shortcontent
941$DO_SCONTENTS = 0;
942
943# if set, output the contents where the command is located
944$INLINE_CONTENTS = 1;
945
946# if this variable is true, numeric entities are used when there is no
947# corresponding textual entity.
948$USE_NUMERIC_ENTITY = 1;
949
950# if set, then use node names in menu entries, instead of section names
951$NODE_NAME_IN_MENU = 0;
952
953# new style for crossrefs
954$NEW_CROSSREF_STYLE = 1;
955
956# transliterate node names for external refs (and internal if NODE_FILES)
957$TRANSLITERATE_NODE = 1;
958
959# if set and menu entry equals menu description, then do not print
960# menu description.
961# Likewise, if node name equals entry name, do not print entry name.
962$AVOID_MENU_REDUNDANCY = 1;
963
964# if set, center @image by default
965# otherwise, do not center by default
966# Deprecated and not used anymore
967$CENTER_IMAGE = 1;
968
969# used as identation for block enclosing command @example, etc
970# If not empty, must be enclosed in <td></td>
971$EXAMPLE_INDENT_CELL = '<td>&nbsp;</td>';
972
973# same as above, only for @small
974$SMALL_EXAMPLE_INDENT_CELL = '<td>&nbsp;</td>';
975
976# font size for @small
977$SMALL_FONT_SIZE = '-1';
978
979# horizontal rules
980$SMALL_RULE = '<hr size="1">';
981$DEFAULT_RULE = '<hr>';
982$MIDDLE_RULE = '<hr size="2">';
983$BIG_RULE = '';
984
985# if non-empty, and no @..heading appeared in Top node, then
986# use this as header for top node/section, otherwise use value of
987# @settitle or @shorttitle (in that order)
988$TOP_HEADING = '';
989
990# if set, use this chapter for 'Index' button, else
991# use first chapter with @printindex
992$INDEX_CHAPTER = '';
993
994# if set and $SPLIT is set, then split index pages at the next letter
995# after they have more than that many entries
996$SPLIT_INDEX = 100;
997
998# symbol put at the beginning of nodes entry in menu (and optionnaly of
999# unnumbered in menus, see next variable)
1000$MENU_SYMBOL = '&bull;';
1001#$MENU_SYMBOL = '*';
1002
1003$SIMPLE_MENU = 0;
1004
1005$OPEN_QUOTE_SYMBOL = "\`";
1006$CLOSE_QUOTE_SYMBOL = "'";
1007
1008# if true put a $MENU_SYMBOL before unnumbered in menus
1009$UNNUMBERED_SYMBOL_IN_MENU = 0;
1010
1011# extension for nodes files when NODE_FILES is true
1012$NODE_FILE_EXTENSION = "html";
1013
1014# extension
1015$EXTENSION = "html";
1016
1017# file name used for Top node when NODE_FILES is true
1018$TOP_NODE_FILE = "index";
1019
1020# node name used for Top node when automatic node directions are used
1021$TOP_NODE_UP = '(dir)';
1022
1023# this controls the pre style for menus
1024$MENU_PRE_STYLE = 'font-family: serif';
1025
1026# This controls the ul style for toc
1027$TOC_LIST_STYLE = 'list-style: none';
1028$TOC_LIST_ATTRIBUTE = ' class="toc"';
1029
1030# These lines are inserted before and after the shortcontents
1031$BEFORE_OVERVIEW = "<div class=\"shortcontents\">\n";
1032$AFTER_OVERVIEW = "</div>\n";
1033
1034# These lines are inserted before and after the contents
1035$BEFORE_TOC_LINES = "<div class=\"contents\">\n";
1036$AFTER_TOC_LINES = "</div>\n";
1037
1038# if set (e.g., to index.html) replace hrefs to this file
1039# (i.e., to index.html) by ./
1040# Obsolete. Worked around a bug that is fixed now.
1041$HREF_DIR_INSTEAD_FILE = '';
1042
1043# text inserted after <body ...>
1044$AFTER_BODY_OPEN = '';
1045
1046# text inserted before </body>, this will be automatically inside <p></p>
1047$PRE_BODY_CLOSE = '';
1048
1049# this is added inside <head></head> after <title> and some <meta name>
1050# stuff, it can be used for eg. <style>, <script>, <meta> etc. tags.
1051$EXTRA_HEAD = '';
1052
1053# Specifies the minimum page length required before a navigation panel
1054# is placed at the bottom of a page
1055# FIXME this is not true:
1056# THIS_WORDS_IN_PAGE holds number of words of current page
1057$WORDS_IN_PAGE = 300;
1058
1059# if this is set a vertical navigation panel is used.
1060$VERTICAL_HEAD_NAVIGATION = 0;
1061
1062# html version for latex2html
1063$L2H_HTML_VERSION = "4.0";
1064
1065# use the information given by menus to complete the node directions
1066$USE_MENU_DIRECTIONS = 1;
1067
1068# specify in this array which "buttons" should appear in which order
1069# in the navigation panel for sections; use ' ' for empty buttons (space)
1070@SECTION_BUTTONS =
1071    (
1072     'Back', 'Forward', ' ', 'FastBack', 'Up', 'FastForward',
1073     ' ', ' ', ' ', ' ',
1074     'Top', 'Contents', 'Index', 'About',
1075    );
1076
1077# buttons for misc stuff
1078@MISC_BUTTONS = ('Top', 'Contents', 'Index', 'About');
1079
1080# buttons for chapter file footers
1081# (and headers but only if SECTION_NAVIGATION is false)
1082@CHAPTER_BUTTONS =
1083    (
1084     'FastBack', 'FastForward', ' ',
1085     ' ', ' ', ' ', ' ',
1086     'Top', 'Contents', 'Index', 'About',
1087    );
1088
1089# buttons for section file footers
1090@SECTION_FOOTER_BUTTONS =
1091    (
1092     'Back', 'Forward', ' ', 'FastBack', 'Up', 'FastForward'
1093    );
1094
1095@NODE_FOOTER_BUTTONS =
1096    (
1097     'Back', 'Forward', ' ', 'FastBack', 'Up', 'FastForward',
1098     ' ', ' ', ' ', ' ',
1099     'Top', 'Contents', 'Index', 'About',
1100#     'Back', 'Forward', ' ', 'FastBack', 'Up', 'FastForward'
1101    );
1102
1103$ICONS = 0;
1104
1105# insert here name of icon images for buttons
1106# Icons are used, if $ICONS and resp. value are set
1107%ACTIVE_ICONS =
1108    (
1109     'Top',         '',
1110     'Contents',    '',
1111     'Overview',    '',
1112     'Index',       '',
1113     'This',        '',
1114     'Back',        '',
1115     'FastBack',    '',
1116     'Prev',        '',
1117     'Up',          '',
1118     'Next',        '',
1119     'NodeUp',      '',
1120     'NodeNext',    '',
1121     'NodePrev',    '',
1122     'Following',   '',
1123     'Forward',     '',
1124     'FastForward', '',
1125     'About' ,      '',
1126     'First',       '',
1127     'Last',        '',
1128     ' ',           ''
1129    );
1130
1131# insert here name of icon images for these, if button is inactive
1132%PASSIVE_ICONS =
1133    (
1134     'Top',         '',
1135     'Contents',    '',
1136     'Overview',    '',
1137     'Index',       '',
1138     'This',        '',
1139     'Back',        '',
1140     'FastBack',    '',
1141     'Prev',        '',
1142     'Up',          '',
1143     'Next',        '',
1144     'NodeUp',      '',
1145     'NodeNext',    '',
1146     'NodePrev',    '',
1147     'Following',   '',
1148     'Forward',     '',
1149     'FastForward', '',
1150     'About',       '',
1151     'First',       '',
1152     'Last',        '',
1153    );
1154
1155@IMAGE_EXTENSIONS = ('png','jpg','jpeg','gif');
1156
1157$init_out    = \&t2h_default_init_out;
1158$finish_out    = \&t2h_default_finish_out;
1159
1160# We have to do this dynamically because of internationalization and because
1161# in body $LANG could be used.
1162sub t2h_default_init_out()
1163{
1164# Names of text as alternative for icons
1165# FIXME maybe get those in simple_format?
1166    %NAVIGATION_TEXT =
1167    (
1168     'Top',         &$I('Top'),
1169     'Contents',    &$I('Contents'),
1170     'Overview',    &$I('Overview'),
1171     'Index',       &$I('Index'),
1172     ' ',           ' &nbsp; ',
1173     'This',        &$I('current'),
1174     'Back',        ' &lt; ',
1175     'FastBack',    ' &lt;&lt; ',
1176     'Prev',        &$I('Prev'),
1177     'Up',          &$I(' Up '),
1178     'Next',        &$I('Next'),
1179     'NodeUp',      &$I('Node up'),
1180     'NodeNext',    &$I('Next node'),
1181     'NodePrev',    &$I('Previous node'),
1182     'Following',   &$I('Following node'),
1183     'Forward',     ' &gt; ',
1184     'FastForward', ' &gt;&gt; ',
1185     'About',       ' ? ',
1186     'First',       ' |&lt; ',
1187     'Last',        ' &gt;| '
1188    );
1189
1190    %BUTTONS_GOTO =
1191    (
1192     'Top',         &$I('Cover (top) of document'),
1193     'Contents',    &$I('Table of contents'),
1194     'Overview',    &$I('Short table of contents'),
1195     'Index',       &$I('Index'),
1196     'This',        &$I('Current section'),
1197     'Back',        &$I('Previous section in reading order'),
1198     'FastBack',    &$I('Beginning of this chapter or previous chapter'),
1199     'Prev',        &$I('Previous section on same level'),
1200     'Up',          &$I('Up section'),
1201     'Next',        &$I('Next section on same level'),
1202     'NodeUp',      &$I('Up node'),
1203     'NodeNext',    &$I('Next node'),
1204     'NodePrev',    &$I('Previous node'),
1205     'Following',   &$I('Node following in node reading order'),
1206     'Forward',     &$I('Next section in reading order'),
1207     'FastForward', &$I('Next chapter'),
1208     'About' ,      &$I('About (help)'),
1209     'First',       &$I('First section in reading order'),
1210     'Last',        &$I('Last section in reading order'),
1211    );
1212
1213    %BUTTONS_NAME =
1214    (
1215     'Top',         &$I('Top'),
1216     'Contents',    &$I('Contents'),
1217     'Overview',    &$I('Overview'),
1218     'Index',       &$I('Index'),
1219     ' ',           ' ',
1220     'This',        &$I('This'),
1221     'Back',        &$I('Back'),
1222     'FastBack',    &$I('FastBack'),
1223     'Prev',        &$I('Prev'),
1224     'Up',          &$I('Up'),
1225     'Next',        &$I('Next'),
1226     'NodeUp',      &$I('NodeUp'),
1227     'NodeNext',    &$I('NodeNext'),
1228     'NodePrev',    &$I('NodePrev'),
1229     'Following',   &$I('Following'),
1230     'Forward',     &$I('Forward'),
1231     'FastForward', &$I('FastForward'),
1232     'About',       &$I('About'),
1233     'First',       &$I('First'),
1234     'Last',        &$I('Last')
1235    );
1236
1237    # Set the default body text, inserted between <body ... >
1238    $BODYTEXT = 'lang="' . $LANG . '" bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#800080" alink="#FF0000"' unless (defined($BODYTEXT));
1239    if (!defined($EXTERNAL_CROSSREF_SPLIT))
1240    {
1241        if ($SPLIT)
1242        {
1243            $EXTERNAL_CROSSREF_SPLIT = 1;
1244        }
1245        else
1246        {
1247            $EXTERNAL_CROSSREF_SPLIT = 0;
1248        }
1249    }
1250
1251    $ENCODING_NAME = $ENCODING if (!defined($ENCODING_NAME) and
1252         defined($ENCODING));
1253
1254    if (!defined($OUT_ENCODING) and (defined($ENCODING_NAME)))
1255    {
1256        $OUT_ENCODING = main::encoding_alias ($ENCODING_NAME);
1257        $OUT_ENCODING = $ENCODING_NAME if (!defined($OUT_ENCODING));
1258    }
1259    if (!defined($OUT_ENCODING) and (defined($IN_ENCODING)))
1260    {
1261        $OUT_ENCODING = $IN_ENCODING;
1262    }
1263    if (!defined($OUT_ENCODING) and (defined($DOCUMENT_ENCODING)))
1264    {
1265        $OUT_ENCODING = main::encoding_alias ($DOCUMENT_ENCODING);
1266        $OUT_ENCODING = $DOCUMENT_ENCODING if (!defined($OUT_ENCODING));
1267    }
1268
1269    if (!defined($ENCODING_NAME))
1270    {
1271         if (defined($OUT_ENCODING) and defined($perl_charset_to_html{$OUT_ENCODING}))
1272         {
1273             $ENCODING_NAME = $perl_charset_to_html{$OUT_ENCODING};
1274         }
1275         elsif (defined($IN_ENCODING) and defined($perl_charset_to_html{$IN_ENCODING}))
1276         {
1277             $ENCODING_NAME = $perl_charset_to_html{$IN_ENCODING};
1278         }
1279         elsif (defined($DOCUMENT_ENCODING) and defined($perl_charset_to_html{$DOCUMENT_ENCODING}))
1280         {
1281             $ENCODING_NAME = $perl_charset_to_html{$DOCUMENT_ENCODING};
1282         }
1283         elsif (defined($OUT_ENCODING))
1284         {
1285             $ENCODING_NAME = $OUT_ENCODING;
1286         }
1287         elsif (defined($IN_ENCODING))
1288         {
1289             $ENCODING_NAME = $IN_ENCODING;
1290         }
1291         elsif (defined($DOCUMENT_ENCODING))
1292         {
1293             $ENCODING_NAME = $DOCUMENT_ENCODING;
1294         }
1295         elsif (defined($perl_charset_to_html{$DEFAULT_ENCODING}))
1296         {
1297             $ENCODING_NAME = $perl_charset_to_html{$DEFAULT_ENCODING};
1298         }
1299         else
1300         {
1301             $ENCODING_NAME = 'us-ascii';
1302         }
1303    }
1304    my $out_encoding = $OUT_ENCODING;
1305    $out_encoding = 'UNDEF' if (!defined($out_encoding));
1306    my $in_encoding = $IN_ENCODING;
1307    $in_encoding = 'UNDEF' if (!defined($in_encoding));
1308    my $document_encoding = $DOCUMENT_ENCODING;
1309    $document_encoding = 'UNDEF' if (!defined($document_encoding));
1310    print STDERR "# Encodings: doc $document_encoding, in $in_encoding out $out_encoding, name $ENCODING_NAME\n" if ($VERBOSE);
1311
1312    if ($SIMPLE_MENU and !defined($complex_format_map->{'menu'}))
1313    {
1314        $complex_format_map->{'menu'} = { 'begin' => q{''} , 'end' => q{''},
1315           'pre_style' => "$MENU_PRE_STYLE", 'class' => 'menu-preformatted' };
1316    }
1317
1318    return $OUT_ENCODING;
1319};
1320
1321sub t2h_default_finish_out()
1322{
1323}
1324
1325#######################################################################
1326#
1327# Values guessed if not set here, set in init_out
1328#
1329#######################################################################
1330
1331$BODYTEXT = undef;
1332
1333# default used in init_out for the setting of the ENCODING_NAME variable
1334$DEFAULT_ENCODING = 'utf8';
1335
1336# In file encoding. The @documentencoding overrides that variable.
1337$DOCUMENT_ENCODING = undef;
1338
1339# In file encoding, understandable by perl. Set according to DOCUMENT_ENCODING
1340$IN_ENCODING = undef;
1341
1342# Formatted document encoding name. If undef, set in init_out based on
1343# $OUT_ENCODING or $DOCUMENT_ENCODING if they are defined
1344$ENCODING_NAME = undef;
1345
1346# Out files encoding, understandable by perl. If undef, set in init_out
1347# using $ENCODING_NAME or $IN_ENCODING if they are defined
1348$OUT_ENCODING = undef;
1349
1350# if undef set to @documentdescription. If there is no @documentdescription,
1351# set in page_head
1352$DOCUMENT_DESCRIPTION = undef;
1353
1354# if undef set 1 if SPLIT, to 0 otherwise
1355$EXTERNAL_CROSSREF_SPLIT = undef;
1356
1357$USER = undef;
1358$DATE = undef;
1359
1360
1361########################################################################
1362# Control of Page layout:
1363# You can make changes of the Page layout at two levels:
1364# 1.) For small changes, it is often enough to change the value of
1365#     some global string/hash/array variables
1366# 2.) For larger changes, reimplement one of the T2H_DEFAULT_<fnc>* routines,
1367#     give them another name, and assign them to the respective
1368#     $<fnc> variable.
1369
1370# As a general interface, the hashes Texi2HTML::HREF, Texi2HTML::NAME, Texi2HTML::NODE, Texi2HTML::NO_TEXI, hold
1371# href, html-name, node-name, name after removal of texi commands of
1372# This     -- current section (resp. html page)
1373# Top      -- top element
1374# Contents -- Table of contents element
1375# Overview -- Short table of contents element
1376# Index    -- Index page element
1377# About    -- page which explain "navigation buttons" element
1378# First    -- first node element
1379# Last     -- last node element
1380#
1381# Whether or not the following hash values are set, depends on the context
1382# (all values are w.r.t. 'This' section)
1383# Next        -- next element of texinfo
1384# Prev        -- previous element of texinfo
1385# NodeUp      -- up node of texinfo
1386# Following   -- following node in node reading order, taking menu into account
1387# Forward     -- next node in reading order
1388# Back        -- previous node in reading order
1389# Up          -- parent given by sectionning commands
1390# FastForward -- if leave node, up and next, else next node
1391# FastBackward-- if leave node, up and prev, else prev node
1392#
1393# Furthermore, the following global variabels are set:
1394# $Texi2HTML::THISDOC{title}          -- title as set by @setttile
1395# $Texi2HTML::THISDOC{title_no_texi}  -- title without texi (without html elements)
1396# $Texi2HTML::THISDOC{title_texi}     -- title with texinfo @-commands
1397# $Texi2HTML::THISDOC{fulltitle}      -- full title as set by @title...
1398# $Texi2HTML::THISDOC{subtitle}       -- subtitle as set by @subtitle
1399# $Texi2HTML::THISDOC{author}         -- author as set by @author
1400# $Texi2HTML::THISDOC{copying}        -- text of @copying and @end copying in comment
1401#
1402# $Texi2HTML::THISDOC{program}          -- name and version of texi2html
1403# $Texi2HTML::THISDOC{program_homepage} -- homepage for texi2html
1404# $Texi2HTML::THISDOC{program_authors}  -- authors of texi2html
1405# $Texi2HTML::THISDOC{today}            -- date formatted with pretty_date
1406# $Texi2HTML::THISDOC{toc_file}         -- table of contents file
1407# $Texi2HTML::THISDOC{file_base_name}   -- base name of the texinfo manual file
1408# $Texi2HTML::THISDOC{destination_directory}
1409                                 #      -- directory for the resulting files
1410# $Texi2HTML::THISDOC{user}             -- user running the script
1411# $Texi2HTML::THISDOC{css_import_lines} -- ref on @import lines in css files
1412# $Texi2HTML::THISDOC{css_lines}        -- ref on css rules lines
1413# other $Texi2HTML::THISDOC keys corresponds with texinfo commands, the value
1414# being the command arg, for the following commands:
1415# kbdinputstyle, paragraphindent, setchapternewpage, headings, footnotestyle,
1416# exampleindent, firstparagraphindent, everyheading, everyfooting,
1417# evenheading, evenfooting, oddheading, oddfooting
1418#
1419# and pointer to arrays of lines which need to be printed by main::print_lines
1420# $Texi2HTML::THIS_SECTION  -- lines of 'This' section
1421# $Texi2HTML::THIS_HEADER   -- lines preceding navigation panel of 'This' section
1422# $Texi2HTML::OVERVIEW      -- lines of short table of contents
1423# $Texi2HTML::TOC_LINES     -- lines of table of contents
1424# $Texi2HTML::TITLEPAGE     -- lines of title page
1425#
1426# $Texi2HTML::THIS_ELEMENT  holds the element reference.
1427
1428#
1429# There are the following subs which control the layout:
1430#
1431$print_section            = \&T2H_DEFAULT_print_section;
1432$end_section              = \&T2H_DEFAULT_end_section;
1433$one_section              = \&T2H_DEFAULT_one_section;
1434$print_Top_header         = \&T2H_DEFAULT_print_Top_header;
1435$print_Top_footer	      = \&T2H_DEFAULT_print_Top_footer;
1436$print_Top		      = \&T2H_DEFAULT_print_Top;
1437$print_Toc		      = \&T2H_DEFAULT_print_Toc;
1438$print_Overview	      = \&T2H_DEFAULT_print_Overview;
1439$print_Footnotes	      = \&T2H_DEFAULT_print_Footnotes;
1440$print_About	      = \&T2H_DEFAULT_print_About;
1441$print_misc_header	      = \&T2H_DEFAULT_print_misc_header;
1442$print_misc_footer	      = \&T2H_DEFAULT_print_misc_footer;
1443$print_misc		      = \&T2H_DEFAULT_print_misc;
1444$print_section_footer     = \&T2H_DEFAULT_print_section_footer;
1445$print_chapter_header     = \&T2H_DEFAULT_print_chapter_header;
1446$print_section_header     = \&T2H_DEFAULT_print_section_header;
1447$print_chapter_footer     = \&T2H_DEFAULT_print_chapter_footer;
1448$print_page_head	      = \&T2H_DEFAULT_print_page_head;
1449$print_page_foot	      = \&T2H_DEFAULT_print_page_foot;
1450$print_head_navigation    = \&T2H_DEFAULT_print_head_navigation;
1451$print_foot_navigation    = \&T2H_DEFAULT_print_foot_navigation;
1452$button_icon_img	      = \&T2H_DEFAULT_button_icon_img;
1453$print_navigation	      = \&T2H_DEFAULT_print_navigation;
1454$about_body		      = \&T2H_DEFAULT_about_body;
1455$print_frame              = \&T2H_DEFAULT_print_frame;
1456$print_toc_frame          = \&T2H_DEFAULT_print_toc_frame;
1457#$toc_body                 = \&T2H_DEFAULT_toc_body;
1458$titlepage                 = \&T2H_DEFAULT_titlepage;
1459$css_lines                 = \&T2H_DEFAULT_css_lines;
1460$print_redirection_page    = \&T2H_DEFAULT_print_redirection_page;
1461$node_file_name            = \&T2H_DEFAULT_node_file_name;
1462$inline_contents           = \&T2H_DEFAULT_inline_contents;
1463
1464########################################################################
1465# Layout for html for every sections
1466#
1467sub T2H_DEFAULT_print_section
1468{
1469    my $fh = shift;
1470    my $first_in_page = shift;
1471    my $previous_is_top = shift;
1472    my $buttons = \@SECTION_BUTTONS;
1473
1474    if ($first_in_page and $SECTION_NAVIGATION)
1475    {
1476        &$print_head_navigation($fh, $buttons);
1477    }
1478    else
1479    { # got to do this here, as it isn't done in print_head_navigation
1480        main::print_lines($fh, $Texi2HTML::THIS_HEADER);
1481        &$print_navigation($fh, $buttons) if ($SECTION_NAVIGATION);
1482    }
1483    my $nw = main::print_lines($fh);
1484    if (defined $SPLIT
1485        and (($SPLIT eq 'node') && $SECTION_NAVIGATION))
1486    {
1487        &$print_foot_navigation($fh);
1488        print $fh "$SMALL_RULE\n";
1489        &$print_navigation($fh, \@NODE_FOOTER_BUTTONS) if (!defined($WORDS_IN_PAGE) or (defined ($nw)
1490                                    and $nw >= $WORDS_IN_PAGE));
1491    }
1492}
1493
1494sub T2H_DEFAULT_one_section($)
1495{
1496    my $fh = shift;
1497    main::print_lines($fh, $Texi2HTML::THIS_HEADER);
1498    main::print_lines($fh);
1499    print $fh "$SMALL_RULE\n";
1500    &$print_foot_navigation($fh);
1501    &$print_page_foot($fh);
1502}
1503
1504###################################################################
1505# Layout of top-page I recommend that you use @ifnothtml, @ifhtml,
1506# @html within the Top texinfo node to specify content of top-level
1507# page.
1508#
1509# If you enclose everything in @ifnothtml, then title, subtitle,
1510# author and overview is printed
1511# Texi2HTML::HREF of Next, Prev, Up, Forward, Back are not defined
1512# if $T2H_SPLIT then Top page is in its own html file
1513sub T2H_DEFAULT_print_Top_header($$)
1514{
1515    my $fh = shift;
1516    my $do_page_head = shift;
1517    &$print_page_head($fh) if ($do_page_head);
1518}
1519sub T2H_DEFAULT_print_Top_footer($$)
1520{
1521    my $fh = shift;
1522    my $end_page = shift;
1523    my $buttons = \@MISC_BUTTONS;
1524    &$print_foot_navigation($fh);
1525    print $fh "$SMALL_RULE\n";
1526    if ($end_page)
1527    {
1528        &$print_navigation($fh, $buttons);
1529        &$print_page_foot($fh);
1530    }
1531}
1532sub T2H_DEFAULT_print_Top($$)
1533{
1534    my $fh = shift;
1535    my $has_top_heading = shift;
1536
1537    # for redefining navigation buttons use:
1538    # my $buttons = [...];
1539    # as it is, 'Top', 'Contents', 'Index', 'About' are printed
1540    my $buttons = \@MISC_BUTTONS;
1541    &$print_head_navigation($fh, $buttons) if ($SPLIT or $SECTION_NAVIGATION);
1542    my $nw;
1543    if (@$Texi2HTML::THIS_SECTION)
1544    {
1545        # if top-level node has content, then print it with extra header
1546        #print $fh "<h1>$Texi2HTML::NAME{Top}</h1>\n"
1547        print $fh "<h1 class=\"settitle\">$Texi2HTML::NAME{Top}</h1>\n"
1548            unless ($has_top_heading);
1549        $nw = main::print_lines($fh, $Texi2HTML::THIS_SECTION);
1550    }
1551    else
1552    {
1553        # top-level node is fully enclosed in @ifnothtml
1554        # print fulltitle, subtitle, author, Overview or table of contents
1555        print $fh $Texi2HTML::TITLEPAGE;
1556        if (@{$Texi2HTML::OVERVIEW} and !$Texi2HTML::THISDOC{'setshortcontentsaftertitlepage'})
1557        {
1558             print $fh '<h2> ' . $Texi2HTML::NAME{'Overview'} . "</h2>\n" . "<blockquote\n";
1559             my $nw = main::print_lines($fh, $Texi2HTML::OVERVIEW);
1560             print $fh "</blockquote>\n";
1561        }
1562        elsif (@{$Texi2HTML::TOC_LINES} and !$Texi2HTML::THISDOC{'setcontentsaftertitlepage'})
1563        {
1564             print $fh '<h1> ' . $Texi2HTML::NAME{'Contents'}  . "</h1>\n";
1565             my $nw = main::print_lines($fh, $Texi2HTML::TOC_LINES);
1566        }
1567    }
1568}
1569
1570###################################################################
1571# Layout of Toc, Overview, and Footnotes pages
1572# By default, we use "normal" layout
1573# Texi2HTML::HREF of Next, Prev, Up, Forward, Back, etc are not defined
1574# use: my $buttons = [...] to redefine navigation buttons
1575sub T2H_DEFAULT_print_Toc
1576{
1577    return &$print_misc(@_);
1578}
1579sub T2H_DEFAULT_print_Overview
1580{
1581    return &$print_misc(@_);
1582}
1583sub T2H_DEFAULT_print_Footnotes
1584{
1585    return &$print_misc(@_);
1586}
1587sub T2H_DEFAULT_print_About
1588{
1589    # if there is no section navigation and it is not split, the
1590    # navigation information is useless
1591    return &$print_misc(@_) if ($SPLIT or $SECTION_NAVIGATION);
1592}
1593
1594sub T2H_DEFAULT_print_misc_header
1595{
1596    my $fh = shift;
1597    my $buttons = shift;
1598    &$print_page_head($fh) if $SPLIT;
1599    &$print_head_navigation($fh, $buttons) if ($SPLIT or $SECTION_NAVIGATION);
1600}
1601
1602sub T2H_DEFAULT_print_misc_footer
1603{
1604    my $fh = shift;
1605    my $buttons = shift;
1606    my $nwords = shift;
1607    &$print_foot_navigation($fh, $buttons);
1608    print $fh "$SMALL_RULE\n";
1609    if ($SPLIT)
1610    {
1611        &$print_navigation($fh, $buttons);# if ($SPLIT ne 'node');
1612        &$print_page_foot($fh);
1613    }
1614}
1615
1616sub T2H_DEFAULT_print_misc
1617{
1618    my $fh = shift;
1619    my $buttons = \@MISC_BUTTONS;
1620    &$print_misc_header($fh, $buttons);
1621    print $fh "<h1>$Texi2HTML::NAME{This}</h1>\n";
1622    main::print_lines($fh);
1623    &$print_misc_footer($fh, $buttons);
1624}
1625##################################################################
1626# section_footer is only called if SPLIT eq 'section'
1627# section_footer: after print_section of last section, before print_page_foot
1628#
1629
1630sub T2H_DEFAULT_print_section_footer
1631{
1632    my $fh = shift;
1633    my $buttons = \@SECTION_FOOTER_BUTTONS;
1634    &$end_section ($fh, 1);
1635    &$print_navigation($fh, $buttons);
1636}
1637
1638###################################################################
1639# chapter_header and chapter_footer are only called if
1640# SPLIT eq 'chapter'
1641# chapter_header: after print_page_head, before print_section
1642# chapter_footer: after print_section of last section, before print_page_foot
1643#
1644# If you want to get rid of navigation stuff after each section,
1645# redefine print_section such that it does not call print_navigation,
1646# and put print_navigation into print_chapter_header
1647sub T2H_DEFAULT_print_chapter_header
1648{
1649    # nothing to do there, by default, the navigation panel
1650    # is the section navigation panel
1651    if (! $SECTION_NAVIGATION)
1652    { # in this case print_navigation is called here.
1653        my $fh = shift;
1654        my $buttons = \@CHAPTER_BUTTONS;
1655        &$print_head_navigation($fh, $buttons); #do that instead ?
1656        #&$print_head_navigation($fh, $buttons); # FIXME VERTICAL_HEAD_NAVIGATION ?
1657        print $fh "\n$MIDDLE_RULE\n";
1658    }
1659}
1660
1661sub T2H_DEFAULT_print_chapter_footer
1662{
1663    my $fh = shift;
1664    my $buttons = \@CHAPTER_BUTTONS;
1665    &$print_foot_navigation($fh);
1666    print $fh "$BIG_RULE\n";
1667    &$print_navigation($fh, $buttons);
1668}
1669
1670sub T2H_DEFAULT_print_section_header
1671{
1672    # nothing to do there, by default
1673    if (! $SECTION_NAVIGATION)
1674    { # in this case print_navigation is called here.
1675        my $fh = shift;
1676        my $buttons = \@SECTION_BUTTONS;
1677        &$print_head_navigation($fh, $buttons);
1678    }
1679}
1680
1681###################################################################
1682# Layout of standard header and footer
1683#
1684
1685sub T2H_DEFAULT_print_page_head($)
1686{
1687    my $fh = shift;
1688    my $longtitle = "$Texi2HTML::THISDOC{'title_simple_format'}";
1689    $longtitle .= ": $Texi2HTML::SIMPLE_TEXT{'This'}" if (defined ($Texi2HTML::SIMPLE_TEXT{'This'}) and ($Texi2HTML::SIMPLE_TEXT{'This'} !~ /^\s*$/) and $SPLIT);
1690    my $description = $DOCUMENT_DESCRIPTION;
1691    $description = $longtitle if (!defined($description));
1692    $description = "<meta name=\"description\" content=\"$description\">" if
1693         ($description ne '');
1694    my $encoding = '';
1695    $encoding = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$ENCODING_NAME\">" if (defined($ENCODING_NAME) and ($ENCODING_NAME ne ''));
1696    print $fh <<EOT;
1697$DOCTYPE
1698<html>
1699$Texi2HTML::THISDOC{'copying'}<!-- Created on $Texi2HTML::THISDOC{today} by $Texi2HTML::THISDOC{program} -->
1700<!--
1701$Texi2HTML::THISDOC{program_authors}
1702-->
1703<head>
1704<title>$longtitle</title>
1705
1706$description
1707<meta name="keywords" content="$longtitle">
1708<meta name="resource-type" content="document">
1709<meta name="distribution" content="global">
1710<meta name="Generator" content="$Texi2HTML::THISDOC{program}">
1711$encoding
1712$CSS_LINES
1713$EXTRA_HEAD
1714</head>
1715
1716<body $BODYTEXT>
1717$AFTER_BODY_OPEN
1718EOT
1719}
1720
1721sub program_string()
1722{
1723    my $user = $Texi2HTML::THISDOC{'user'};
1724    my $date = $Texi2HTML::THISDOC{'today'};
1725    $user = '' if (!defined($user));
1726    $date = '' if (!defined($date));
1727    if (($user ne '') and ($date ne ''))
1728    {
1729        return  &$I('This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.', {
1730           'user' => $user, 'date' => $date, 'program_homepage' => $Texi2HTML::THISDOC{'program_homepage'}, 'program' => $Texi2HTML::THISDOC{'program'} });
1731    }
1732    elsif ($user ne '')
1733    {
1734        return  &$I('This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.', {
1735           'user' => $user, 'program_homepage' => $Texi2HTML::THISDOC{'program_homepage'}, 'program' => $Texi2HTML::THISDOC{'program'} });
1736    }
1737    elsif ($date ne '')
1738    {
1739        return  &$I('This document was generated on @i{%{date}} using @uref{%{program_homepage}, @i{%{program}}}.', {
1740           'date' => $date, 'program_homepage' => $Texi2HTML::THISDOC{'program_homepage'}, 'program' => $Texi2HTML::THISDOC{'program'} });
1741    }
1742    return &$I('This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.', {
1743       'program_homepage' => $Texi2HTML::THISDOC{'program_homepage'}, 'program'
1744=> $Texi2HTML::THISDOC{'program'} });
1745}
1746
1747sub T2H_DEFAULT_end_section($$)
1748{
1749    my $fh = shift;
1750    my $end_foot_navigation = shift;
1751    &$print_foot_navigation($fh) if ($end_foot_navigation);
1752    print $fh "$BIG_RULE\n";
1753}
1754
1755sub T2H_DEFAULT_print_page_foot($)
1756{
1757    my $fh = shift;
1758    my $program_string = program_string();
1759    print $fh <<EOT;
1760<p>
1761 <font size="-1">
1762  $program_string
1763 </font>
1764 <br>
1765$PRE_BODY_CLOSE
1766</p>
1767</body>
1768</html>
1769EOT
1770}
1771
1772###################################################################
1773# Layout of navigation panel
1774
1775sub T2H_DEFAULT_print_head_navigation($$)
1776{
1777    my $fh = shift;
1778    my $buttons = shift;
1779    if ($VERTICAL_HEAD_NAVIGATION)
1780    {
1781        print $fh <<EOT;
1782<table border="0" cellpadding="0" cellspacing="0">
1783<tr valign="top">
1784<td align="left">
1785EOT
1786    }
1787    main::print_lines($fh, $Texi2HTML::THIS_HEADER);
1788    &$print_navigation($fh, $buttons, $VERTICAL_HEAD_NAVIGATION);
1789    if ($VERTICAL_HEAD_NAVIGATION)
1790    {
1791        print $fh <<EOT;
1792</td>
1793<td align="left">
1794EOT
1795    }
1796    elsif (defined $SPLIT
1797           and ($SPLIT eq 'node'))
1798    {
1799        print $fh "$SMALL_RULE\n";
1800    }
1801}
1802
1803sub T2H_DEFAULT_print_foot_navigation
1804{
1805    my $fh = shift;
1806    if ($VERTICAL_HEAD_NAVIGATION)
1807    {
1808        print $fh <<EOT;
1809</td>
1810</tr>
1811</table>
1812EOT
1813    }
1814}
1815
1816######################################################################
1817# navigation panel
1818#
1819# how to create IMG tag
1820sub T2H_DEFAULT_button_icon_img
1821{
1822    my $button = shift;
1823    my $icon = shift;
1824    my $name = shift;
1825    return '' if (!defined($icon));
1826    $button = "" if (!defined ($button));
1827    $name = '' if (!defined($name));
1828    my $alt = '';
1829    if ($name ne '')
1830    {
1831        if ($button ne '')
1832        {
1833            $alt = "$button: $name";
1834        }
1835        else
1836        {
1837            $alt = $name;
1838        }
1839    }
1840    else
1841    {
1842        $alt = $button;
1843    }
1844    return qq{<img src="$icon" border="0" alt="$alt" align="middle">};
1845}
1846
1847sub T2H_DEFAULT_print_navigation
1848{
1849    my $fh = shift;
1850    my $buttons = shift;
1851    my $vertical = shift;
1852    my $spacing = 1;
1853    print $fh '<table cellpadding="', $spacing, '" cellspacing="', $spacing,
1854      "\" border=\"0\">\n";
1855
1856    print $fh "<tr>" unless $vertical;
1857    for my $button (@$buttons)
1858    {
1859        print $fh qq{<tr valign="top" align="left">\n} if $vertical;
1860        print $fh qq{<td valign="middle" align="left">};
1861
1862        if (ref($button) eq 'CODE')
1863        {
1864            &$button($fh, $vertical);
1865        }
1866        elsif (ref($button) eq 'SCALAR')
1867        {
1868            print $fh "$$button" if defined($$button);
1869        }
1870        elsif (ref($button) eq 'ARRAY')
1871        {
1872            my $text = $button->[1];
1873            my $button_href = $button->[0];
1874            # verify that $button_href is simple text and text is a reference
1875            if (defined($button_href) and !ref($button_href)
1876               and defined($text) and (ref($text) eq 'SCALAR') and defined($$text))
1877            {             # use given text
1878                if ($Texi2HTML::HREF{$button_href})
1879                {
1880                  print $fh "" .
1881                        &$anchor('',
1882                                    $Texi2HTML::HREF{$button_href},
1883                                    $$text
1884                                   )
1885                                    ;
1886                }
1887                else
1888                {
1889                  print $fh $$text;
1890                }
1891            }
1892        }
1893        elsif ($button eq ' ')
1894        {                       # handle space button
1895            print $fh
1896                ($ICONS && $ACTIVE_ICONS{' '}) ?
1897                    &$button_icon_img($BUTTONS_NAME{$button}, $ACTIVE_ICONS{' '}) :
1898                        $NAVIGATION_TEXT{' '};
1899            #next;
1900        }
1901        elsif ($Texi2HTML::HREF{$button})
1902        {                       # button is active
1903            my $btitle = $BUTTONS_GOTO{$button} ?
1904                'title="' . $BUTTONS_GOTO{$button} . '"' : '';
1905            if ($ICONS && $ACTIVE_ICONS{$button})
1906            {                   # use icon
1907                print $fh '' .
1908                    &$anchor('',
1909                        $Texi2HTML::HREF{$button},
1910                        &$button_icon_img($BUTTONS_NAME{$button},
1911                                   $ACTIVE_ICONS{$button},
1912                                   $Texi2HTML::SIMPLE_TEXT{$button}),
1913                        $btitle
1914                      );
1915            }
1916            else
1917            {                   # use text
1918                print $fh
1919                    '[' .
1920                        &$anchor('',
1921                                    $Texi2HTML::HREF{$button},
1922                                    $NAVIGATION_TEXT{$button},
1923                                    $btitle
1924                                   ) .
1925                                       ']';
1926            }
1927        }
1928        else
1929        {                       # button is passive
1930            print $fh
1931                $ICONS && $PASSIVE_ICONS{$button} ?
1932                    &$button_icon_img($BUTTONS_NAME{$button},
1933                                          $PASSIVE_ICONS{$button},
1934                                          $Texi2HTML::SIMPLE_TEXT{$button}) :
1935
1936                                              "[" . $NAVIGATION_TEXT{$button} . "]";
1937        }
1938        print $fh "</td>\n";
1939        print $fh "</tr>\n" if $vertical;
1940    }
1941    print $fh "</tr>" unless $vertical;
1942    print $fh "</table>\n";
1943}
1944
1945######################################################################
1946# Frames: this is from "Richard Y. Kim" <ryk@coho.net>
1947# Should be improved to be more conforming to other _print* functions
1948# FIXME pass toc_file and main_file as args or in $Texi2HTML::THISDOC ?
1949
1950sub T2H_DEFAULT_print_frame
1951{
1952    my $fh = shift;
1953    my $toc_file = shift;
1954    my $main_file = shift;
1955    print $fh <<EOT;
1956$FRAMESET_DOCTYPE
1957<html>
1958<head><title>$Texi2HTML::THISDOC{title}</title></head>
1959<frameset cols="140,*">
1960  <frame name="toc" src="$toc_file">
1961  <frame name="main" src="$main_file">
1962</frameset>
1963</html>
1964EOT
1965}
1966
1967sub T2H_DEFAULT_print_toc_frame
1968{
1969    my $fh = shift;
1970    my $stoc_lines = shift;
1971    &$print_page_head($fh);
1972    print $fh <<EOT;
1973<h2>Content</h2>
1974EOT
1975    print $fh map {s/\bhref=/target="main" href=/; $_;} @$stoc_lines;
1976    print $fh "</body></html>\n";
1977}
1978
1979# This subroutine is intended to fill @Texi2HTML::TOC_LINES and
1980# @Texi2HTML::OVERVIEW with the table of contents and short table of
1981# contents.
1982#
1983# arguments:
1984# ref on an array containing all the elements
1985
1986# each element is a reference on a hash. The following keys might be of
1987# use:
1988# 'top': true if this is the top element
1989# 'index_page': true if the element is an index page added because of index
1990#               splitting
1991# 'toc_level': level of the element in the table of content. Highest level
1992#              is 1 for the @top element and for chapters, appendix and so on,
1993#              2 for section, unnumberedsec and so on...
1994# 'tocid': label used for reference linking to the element in table of
1995#          contents
1996# 'file': the file containing the element, usefull to do href to that file
1997#         in case the document is split.
1998# 'text': text of the element, with section number
1999# 'text_nonumber': text of the element, without section number
2000
2001# Relevant configuration variables are:
2002# $NUMBER_SECTIONS
2003# $TOC_LIST_ATTRIBUTE: usefull in case a list is used
2004# $FRAMES: @Texi2HTML::OVERVIEW is used in one of the frames.
2005# $BEFORE_OVERVIEW
2006# $AFTER_OVERVIEW
2007# $BEFORE_TOC_LINES
2008# $AFTER_TOC_LINES
2009# $DO_CONTENTS
2010# $DO_SCONTENTS
2011
2012sub T2H_DEFAULT_toc_body($)
2013{
2014}
2015
2016sub T2H_DEFAULT_inline_contents($$$)
2017{
2018    my $fh = shift;
2019    my $command = shift;
2020    my $element = shift;
2021    my $name;
2022    my $lines;
2023
2024    my $result = undef;
2025
2026    if ($command eq 'contents')
2027    {
2028        $name = $Texi2HTML::NAME{'Contents'};
2029        $lines = $Texi2HTML::TOC_LINES;
2030    }
2031    else
2032    {
2033        $name = $Texi2HTML::NAME{'Overview'};
2034        $lines = $Texi2HTML::OVERVIEW;
2035    }
2036    if (@{$lines})
2037    {
2038         $result = [ "".&$anchor($element->{'id'})."\n",
2039            "<h1>$name</h1>\n" ];
2040         push @$result, @$lines;
2041    }
2042
2043    return $result;
2044}
2045
2046sub T2H_DEFAULT_css_lines ($$)
2047{
2048    my $import_lines = shift;
2049    my $rule_lines = shift;
2050    return if (defined($CSS_LINES) or (!@$rule_lines and !@$import_lines and (! keys(%css_map))));
2051    $CSS_LINES = "<style type=\"text/css\">\n<!--\n";
2052    $CSS_LINES .= join('',@$import_lines) . "\n" if (@$import_lines);
2053    foreach my $css_rule (sort(keys(%css_map)))
2054    {
2055        next unless ($css_map{$css_rule});
2056        $CSS_LINES .= "$css_rule {$css_map{$css_rule}}\n";
2057    }
2058    $CSS_LINES .= join('',@$rule_lines) . "\n" if (@$rule_lines);
2059    $CSS_LINES .= "-->\n</style>\n";
2060}
2061
2062######################################################################
2063# About page
2064#
2065
2066# PRE_ABOUT can be a function reference or a scalar.
2067# Note that if it is a scalar, T2H_InitGlobals has not been called,
2068# and all global variables like $ADDRESS are not available.
2069$PRE_ABOUT = sub
2070{
2071    return '  ' . program_string() .  "\n";
2072};
2073
2074# If customizing $AFTER_ABOUT, be sure to put the content inside <p></p>.
2075$AFTER_ABOUT = '';
2076
2077%BUTTONS_EXAMPLE =
2078    (
2079     'Top',         ' &nbsp; ',
2080     'Contents',    ' &nbsp; ',
2081     'Overview',    ' &nbsp; ',
2082     'Index',       ' &nbsp; ',
2083     'This',        '1.2.3',
2084     'Back',        '1.2.2',
2085     'FastBack',    '1',
2086     'Prev',        '1.2.2',
2087     'Up',          '1.2',
2088     'Next',        '1.2.4',
2089     'NodeUp',      '1.2',
2090     'NodeNext',    '1.2.4',
2091     'NodePrev',    '1.2.2',
2092     'Following',   '1.2.4',
2093     'Forward',     '1.2.4',
2094     'FastForward', '2',
2095     'About',       ' &nbsp; ',
2096     'First',       '1.',
2097     'Last',        '1.2.4',
2098    );
2099
2100sub T2H_DEFAULT_about_body
2101{
2102    my $about = "<p>\n";
2103    if (ref($PRE_ABOUT) eq 'CODE')
2104    {
2105        $about .= &$PRE_ABOUT();
2106    }
2107    else
2108    {
2109        $about .= $PRE_ABOUT;
2110    }
2111    $about .= <<EOT;
2112</p>
2113<p>
2114EOT
2115    $about .= &$I('  The buttons in the navigation panels have the following meaning:') . "\n";
2116    $about .= <<EOT;
2117</p>
2118<table border="1">
2119  <tr>
2120EOT
2121    $about .= '    <th> ' . &$I('Button') . " </th>\n" .
2122'    <th> ' . &$I('Name') . " </th>\n" .
2123'    <th> ' . &$I('Go to') . " </th>\n" .
2124'    <th> ' . &$I('From 1.2.3 go to') . "</th>\n" . "  </tr>\n";
2125
2126    for my $button (@SECTION_BUTTONS)
2127    {
2128        next if $button eq ' ' || ref($button) eq 'CODE' || ref($button) eq 'SCALAR' || ref($button) eq 'ARRAY';
2129        $about .= "  <tr>\n    <td align=\"center\">";
2130        $about .=
2131            ($ICONS && $ACTIVE_ICONS{$button} ?
2132             &$button_icon_img($BUTTONS_NAME{$button}, $ACTIVE_ICONS{$button}) :
2133             ' [' . $NAVIGATION_TEXT{$button} . '] ');
2134        $about .= "</td>\n";
2135        $about .= <<EOT;
2136    <td align="center">$BUTTONS_NAME{$button}</td>
2137    <td>$BUTTONS_GOTO{$button}</td>
2138    <td>$BUTTONS_EXAMPLE{$button}</td>
2139  </tr>
2140EOT
2141    }
2142
2143    $about .= <<EOT;
2144</table>
2145
2146<p>
2147EOT
2148    $about .= &$I('  where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:') . "\n";
2149
2150#  where the <strong> Example </strong> assumes that the current position
2151#  is at <strong> Subsubsection One-Two-Three </strong> of a document of
2152#  the following structure:
2153    $about .= <<EOT;
2154</p>
2155
2156<ul>
2157EOT
2158    $about .= '  <li> 1. ' . &$I('Section One') . "\n" .
2159"    <ul>\n" .
2160'      <li>1.1 ' . &$I('Subsection One-One') . "\n";
2161    $about .= <<EOT;
2162        <ul>
2163          <li>...</li>
2164        </ul>
2165      </li>
2166EOT
2167    $about .= '      <li>1.2 ' . &$I('Subsection One-Two') . "\n" .
2168"        <ul>\n" .
2169'          <li>1.2.1 ' . &$I('Subsubsection One-Two-One') . "</li>\n" .
2170'          <li>1.2.2 ' . &$I('Subsubsection One-Two-Two') . "</li>\n" .
2171'          <li>1.2.3 ' . &$I('Subsubsection One-Two-Three') . " &nbsp; &nbsp;\n"
2172.
2173'            <strong>&lt;== ' . &$I('Current Position') . " </strong></li>\n" .
2174'          <li>1.2.4 ' . &$I('Subsubsection One-Two-Four') . "</li>\n" .
2175"        </ul>\n" .
2176"      </li>\n" .
2177'      <li>1.3 ' . &$I('Subsection One-Three') . "\n";
2178    $about .= <<EOT;
2179        <ul>
2180          <li>...</li>
2181        </ul>
2182      </li>
2183EOT
2184    $about .= '      <li>1.4 ' . &$I('Subsection One-Four') . "</li>\n";
2185    $about .= <<EOT;
2186    </ul>
2187  </li>
2188</ul>
2189$AFTER_ABOUT
2190EOT
2191    return $about;
2192}
2193
2194sub T2H_DEFAULT_titlepage()
2195{
2196    my $result = '';
2197    if (@{$Texi2HTML::THISDOC{'titles'}}
2198        or @{$Texi2HTML::THISDOC{'subtitles'}}
2199        or @{$Texi2HTML::THISDOC{'authors'}})
2200    {
2201        $result = "<div align=\"center\">\n";
2202        foreach my $title (@{$Texi2HTML::THISDOC{'titles'}})
2203        {
2204            $result .= '<h1>' . $title . "</h1>\n";
2205        }
2206        foreach my $subtitle (@{$Texi2HTML::THISDOC{'subtitles'}})
2207        {
2208            $result .= '<h2>' . $subtitle . "</h2>\n";
2209        }
2210        foreach my $author (@{$Texi2HTML::THISDOC{'authors'}})
2211        {
2212            $result .= '<strong> ' . $author . " </strong><br>\n";
2213        }
2214        $result .= "</div>\n$DEFAULT_RULE\n";
2215    }
2216
2217    $Texi2HTML::TITLEPAGE = $result . $Texi2HTML::TITLEPAGE;
2218
2219    if ($Texi2HTML::THISDOC{'setcontentsaftertitlepage'} and @{$Texi2HTML::THISDOC{'inline_contents'}->{'contents'}})
2220    {
2221        foreach my $line(@{$Texi2HTML::THISDOC{'inline_contents'}->{'contents'}})
2222        {
2223            $Texi2HTML::TITLEPAGE .= $line;
2224        }
2225        $Texi2HTML::TITLEPAGE .= "$DEFAULT_RULE\n";
2226    }
2227    if ($Texi2HTML::THISDOC{'setshortcontentsaftertitlepage'} and @{$Texi2HTML::THISDOC{'inline_contents'}->{'shortcontents'}})
2228    {
2229        foreach my $line(@{$Texi2HTML::THISDOC{'inline_contents'}->{'shortcontents'}})
2230        {
2231            $Texi2HTML::TITLEPAGE .= $line;
2232        }
2233        $Texi2HTML::TITLEPAGE .= "$DEFAULT_RULE\n";
2234    }
2235}
2236
2237# FIXME Honor DOCUMENT_DESCRIPTION?
2238sub T2H_DEFAULT_print_redirection_page($)
2239{
2240    my $fh = shift;
2241    my $longtitle = "$Texi2HTML::THISDOC{'title_simple_format'}";
2242    $longtitle .= ": $Texi2HTML::SIMPLE_TEXT{'This'}" if exists $Texi2HTML::SIMPLE_TEXT{'This'};
2243    my $description = $longtitle;
2244    my $encoding = '';
2245    $encoding = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$ENCODING_NAME\">" if (defined($ENCODING_NAME) and ($ENCODING_NAME ne ''));
2246    my $href = &$anchor('', $Texi2HTML::HREF{'This'}, $Texi2HTML::NAME{'This'});
2247    my $string = &$I('The node you are looking for is at %{href}.',
2248       { 'href' => $href });
2249    print $fh <<EOT;
2250$DOCTYPE
2251<html>
2252<!-- Created on $Texi2HTML::THISDOC{'today'} by $Texi2HTML::THISDOC{'program'} -->
2253<!--
2254$Texi2HTML::THISDOC{'program_authors'}
2255-->
2256<head>
2257<title>$longtitle</title>
2258
2259<meta name="description" content="$description">
2260<meta name="keywords" content="$longtitle">
2261<meta name="resource-type" content="document">
2262<meta name="distribution" content="global">
2263<meta name="Generator" content="$Texi2HTML::THISDOC{program}">
2264$encoding
2265$CSS_LINES
2266<meta http-equiv="Refresh" content="2; url=$Texi2HTML::HREF{'This'}">
2267$EXTRA_HEAD
2268</head>
2269
2270<body $BODYTEXT>
2271$AFTER_BODY_OPEN
2272<p>$string</p>
2273</body>
2274EOT
2275}
2276
2277sub T2H_DEFAULT_node_file_name($$)
2278{
2279    my $node = shift;
2280    my $type = shift;
2281    return undef if ($node->{'external_node'} or $node->{'index_page'}
2282       or ($type eq 'top' and !$NEW_CROSSREF_STYLE));
2283    my $node_file_base;
2284    if ($type eq 'top' and defined($TOP_NODE_FILE))
2285    {
2286        $node_file_base = $TOP_NODE_FILE;
2287    }
2288    elsif ($NEW_CROSSREF_STYLE)
2289    {
2290        if ($TRANSLITERATE_NODE)
2291        {
2292            $node_file_base = $node->{'cross_manual_file'};
2293        }
2294        else
2295        {
2296            $node_file_base = $node->{'cross_manual_target'};
2297        }
2298    }
2299    else
2300    {
2301         $node_file_base = main::remove_texi($node->{'texi'});
2302         $node_file_base =~ s/[^\w\.\-]/-/g;
2303    }
2304    if (defined($NODE_FILE_EXTENSION) and $NODE_FILE_EXTENSION ne '')
2305    {
2306        return ($node_file_base . ".$NODE_FILE_EXTENSION");
2307    }
2308    return $node_file_base;
2309}
2310
2311########################################################################
2312# Control of formatting:
2313# 1.) For some changes, it is often enough to change the value of
2314#     some global map. It might necessitate building a little
2315#     function along with the change in hash, if the change is the use
2316#     of another function (in style_map).
2317# 2.) For other changes, reimplement one of the t2h_default_<fnc>* routines,
2318#     give them another name, and assign them to the respective
2319#     $<fnc> variable (below).
2320
2321
2322#
2323# This hash should have keys corresponding with the nonletter command accent
2324# whose following character is considered to be the argument
2325# This hash associates an accent macro to the ISO name for the accent if any.
2326# The customary use of this map is to find the ISO name appearing in html
2327# entity (like &eacute;) associated with a texinfo accent macro.
2328#
2329# The keys of the hash are
2330# ": umlaut
2331# ~: tilda accent
2332# ^: circumflex accent
2333# `: grave accent
2334# ': acute accent
2335# =: macron accent
2336%accent_map = (
2337          '"',  'uml',
2338          '~',  'tilde',
2339          '^',  'circ',
2340          '`',  'grave',
2341          "'", 'acute',
2342          '=', '',
2343         );
2344
2345#
2346# texinfo "simple things" (@foo) to HTML ones
2347#
2348%simple_map = (
2349           "*", "<br>",     # HTML+
2350           ' ', '&nbsp;',
2351           "\t", '&nbsp;',
2352           "\n", '&nbsp;',
2353     # "&#173;" or "&shy;" could also be possible for @-, but it seems
2354     # that some browser will consider this as an always visible hyphen mark
2355     # which is not what we want (see http://www.cs.tut.fi/~jkorpela/shy.html)
2356           '-', '',  # hyphenation hint
2357           '|', '',  # used in formatting commands @evenfooting and friends
2358           '/', '',
2359       # spacing commands
2360           ':', '',
2361           '!', '!',
2362           '?', '?',
2363           '.', '.',
2364           '@', '@',
2365           '}', '}',
2366           '{', '{',
2367          );
2368
2369# this map is used in preformatted text
2370%simple_map_pre = %simple_map;
2371$simple_map_pre{'*'} = "\n";
2372
2373#
2374# texinfo "things" (@foo{}) to HTML ones
2375#
2376%things_map = (
2377               'TeX'          => 'TeX',
2378               'LaTeX'          => 'LaTeX',
2379# pertusus: unknown by makeinfo, not in texinfo manual (@* is the right thing)
2380#               'br', '<br>',     # paragraph break
2381               'bullet'       => '*',
2382#               #'copyright' => '(C)',
2383               'copyright'    => '&copy;',
2384               'registeredsymbol'   => '&reg;',
2385               'dots'         => '<small class="dots">...</small>',
2386               'enddots'      => '<small class="enddots">....</small>',
2387               'equiv'        => '==',
2388# FIXME i18n
2389               'error'        => 'error--&gt;',
2390               'expansion'    => '==&gt;',
2391               'minus'        => '-',
2392               'point'        => '-!-',
2393               'print'        => '-|',
2394               'result'       => '=&gt;',
2395               # set in code using the language
2396               # 'today', &pretty_date,
2397               'today'        => '',
2398               'aa'           => '&aring;',
2399               'AA'           => '&Aring;',
2400               'ae'           => '&aelig;',
2401               'oe'           => '&oelig;', #pertusus: also &#156;. &oelig; not in html 3.2
2402               'AE'           => '&AElig;',
2403               'OE'           => '&OElig;', #pertusus: also &#140;. &OElig; not in html 3.2
2404               'o'            =>  '&oslash;',
2405               'O'            =>  '&Oslash;',
2406               'ss'           => '&szlig;',
2407               'l'            => '&#322;',
2408               'L'            => '&#321;',
2409               'exclamdown'   => '&iexcl;',
2410               'questiondown' => '&iquest;',
2411               'pounds'       => '&pound;',
2412               'ordf'         => '&ordf;',
2413               'ordm'         => '&ordm;',
2414               'comma'        => ',',
2415               'euro'         => '&euro;',
2416               'tie'          => '&nbsp;',
2417             );
2418
2419# This map is used in preformatted environments
2420%pre_map = %things_map;
2421$pre_map{'dots'} = '...';
2422$pre_map{'enddots'} = '....';
2423#$pre_map{'br'} = "\n";
2424
2425# ascii representation of @-commands
2426%ascii_simple_map = (
2427           "*", "\n",     # HTML+
2428           ' ', ' ',
2429           "\t", "\t",
2430           "\n", "\n",
2431           '-', '',  # hyphenation hint
2432           '|', '',  # used in formatting commands @evenfooting and friends
2433           '/', '',
2434           ':', '',
2435           '!', '!',
2436           '?', '?',
2437           '.', '.',
2438           '@', '@',
2439           '}', '}',
2440           '{', '{',
2441);
2442
2443%ascii_things_map = (
2444               'TeX'          => 'TeX',
2445               'LaTeX'          => 'LaTeX',
2446               'bullet'       => '*',
2447               'copyright' => '(C)',
2448               'registeredsymbol'   => '(R)',
2449               'dots'         => '...',
2450               'enddots'      => '....',
2451               'equiv'        => '==',
2452# FIXME i18n
2453               'error'        => 'error-->',
2454               'expansion'    => '==>',
2455               'minus'        => '-',
2456               'point'        => '-!-',
2457               'print'        => '-|',
2458               'result'       => '=>',
2459               'today'        => '',
2460               'aa'           => 'aa',
2461               'AA'           => 'AA',
2462               'ae'           => 'ae',
2463               'oe'           => 'oe',
2464               'AE'           => 'AE',
2465               'OE'           => 'OE',
2466               'o'            => '/o',
2467               'O'            => '/O',
2468               'ss'           => 'ss',
2469               'l'            => '/l',
2470               'L'            => '/L',
2471               'exclamdown'   => '?',
2472               'questiondown' => '!',
2473               'pounds'       => '#',
2474               'ordf'         => 'a',
2475               'ordm'         => 'o',
2476               'comma'        => ',',
2477               'euro'         => 'Euro',
2478               'tie'          => ' ',
2479);
2480
2481#
2482# This map is used when texi elements are removed and replaced
2483# by simple text
2484#
2485%simple_map_texi = (
2486           "*", "",
2487           " ", " ",
2488           "\t", " ",
2489           "-", "-",  # soft hyphen
2490           "\n", "\n",
2491           "|", "",
2492        # spacing commands
2493           ":", "",
2494           "!", "!",
2495           "?", "?",
2496           ".", ".",
2497           "-", "",
2498           '@', '@',
2499           '}', '}',
2500           '{', '{',
2501          );
2502
2503# text replacing macros when texi commands are removed and plain text is
2504# produced
2505%texi_map = (
2506               'TeX', 'TeX',
2507               'LaTeX', 'LaTeX',
2508               'bullet', '*',
2509               'copyright', 'C',
2510               'registeredsymbol', 'R',
2511               'dots', '...',
2512               'enddots', '....',
2513               'equiv', '==',
2514               'error', 'error-->',
2515               'expansion', '==>',
2516               'minus', '-',
2517               'point', '-!-',
2518               'print', '-|',
2519               'result', '=>',
2520               'today'        => '',
2521               'aa', 'aa',
2522               'AA', 'AA',
2523               'ae', 'ae',
2524               'oe', 'oe',
2525               'AE', 'AE',
2526               'OE', 'OE',
2527               'o',  'o',
2528               'O',  'O',
2529               'ss', 'ss',
2530               'l', 'l',
2531               'L', 'L',
2532               'exclamdown', '! upside-down',
2533               #'exclamdown', '&iexcl;',
2534               'questiondown', '? upside-down',
2535               #'questiondown', '&iquest;',
2536               'pounds', 'pound sterling',
2537               #'pounds', '&pound;'
2538               'ordf'         => 'a',
2539               'ordm'         => 'o',
2540               'comma'        => ',',
2541               'euro'         => 'Euro',
2542               'tie'          => ' ',
2543            );
2544
2545# taken from
2546#Latin extended additionnal
2547#http://www.alanwood.net/unicode/latin_extended_additional.html
2548#C1 Controls and Latin-1 Supplement
2549#http://www.alanwood.net/unicode/latin_1_supplement.html
2550#Latin Extended-A
2551#http://www.alanwood.net/unicode/latin_extended_a.html
2552#Latin Extended-B
2553#http://www.alanwood.net/unicode/latin_extended_b.html
2554#dotless i: 0131
2555
2556#http://www.alanwood.net/unicode/arrows.html 21**
2557#http://www.alanwood.net/unicode/general_punctuation.html 20**
2558#http://www.alanwood.net/unicode/mathematical_operators.html 22**
2559
2560%unicode_map = (
2561               'bullet'       => '2022',
2562               'copyright'    => '00A9',
2563               'registeredsymbol'   => '00AE',
2564               'dots'         => '2026',
2565               'enddots'      => '',
2566               'equiv'        => '2261',
2567               'error'        => '',
2568               'expansion'    => '2192',
2569               'minus'        => '2212', # in mathematical operators
2570#               'minus'        => '002D', # in latin1
2571               'point'        => '2605',
2572               'print'        => '22A3',
2573               'result'       => '21D2',
2574               'today'        => '',
2575               'aa'           => '00E5',
2576               'AA'           => '00C5',
2577               'ae'           => '00E6',
2578               'oe'           => '0153',
2579               'AE'           => '00C6',
2580               'OE'           => '0152',
2581               'o'            => '00F8',
2582               'O'            => '00D8',
2583               'ss'           => '00DF',
2584               'l'            => '0142',
2585               'L'            => '0141',
2586               'exclamdown'   => '00A1',
2587               'questiondown' => '00BF',
2588               'pounds'       => '00A3',
2589               'ordf'         => '00AA',
2590               'ordm'         => '00BA',
2591               'comma'        => '002C',
2592               'euro'         => '20AC',
2593               'tie'          => '',
2594#               'tie'          => '0020',
2595             );
2596
2597%transliterate_map = (
2598               '00C5'  => 'AA',
2599               '00E5'  => 'aa',
2600               '00D8'  => 'OE',
2601               '00F8'  => 'oe',
2602               '00E6' => 'ae',
2603               '0153' => 'oe',
2604               '00C6' => 'AE',
2605               '0152' => 'OE',
2606               '00DF' => 'ss',
2607               '0141' => 'L',
2608               '0142' => 'l',
2609               '00D0'  => 'DH',
2610               '0415'  => 'E',
2611               '0435'  => 'e',
2612               '0426'  => 'C',
2613               '042A'  => 'W',
2614               '044A'  => 'w',
2615               '042C'  => 'X',
2616               '044C'  => 'x',
2617               '042E'  => 'yu',
2618               '042F'  => 'YA',
2619               '044F'  => 'ya',
2620               '0433'  => 'g',
2621               '0446'  => 'c',
2622               '04D7'  => 'IO',
2623               '00DD'  => 'Y', # unidecode gets this wrong ?
2624          );
2625
2626foreach my $symbol(keys(%unicode_map))
2627{
2628    if ($unicode_map{$symbol} ne '' and !exists($transliterate_map{$symbol}))
2629    {
2630         $no_transliterate_map{$unicode_map{$symbol}} = 1;
2631    }
2632}
2633
2634%ascii_character_map = (
2635            ' ' => '0020',
2636            '!' => '0021',
2637            '"' => '0022',
2638            '#' => '0023',
2639            '$' => '0024',
2640            '%' => '0025',
2641            '&' => '0026',
2642            "'" => '0027',
2643            '(' => '0028',
2644            ')' => '0029',
2645            '*' => '002A',
2646            '+' => '002B',
2647            ',' => '002C',
2648            '-' => '002D',
2649            '.' => '002E',
2650            '/' => '002F',
2651            ':' => '003A',
2652            ';' => '003B',
2653            '<' => '003C',
2654            '=' => '003D',
2655            '>' => '003E',
2656            '?' => '003F',
2657            '@' => '0040',
2658            '[' => '005B',
2659            '\\' => '005C',
2660            ']' => '005D',
2661            '^' => '005E',
2662            '_' => '005F',
2663            '`' => '0060',
2664            '{' => '007B',
2665            '|' => '007C',
2666            '}' => '007D',
2667            '~' => '007E',
2668);
2669
2670%perl_charset_to_html = (
2671              'utf8'       => 'utf-8',
2672              'utf-8-strict'       => 'utf-8',
2673              'ascii'      => 'us-ascii',
2674);
2675
2676# symbols used for the commands if $USE_ISO is true.
2677%iso_symbols = (
2678         'equiv'     => '&equiv;',
2679         'dots'      => '&hellip;',
2680         'bullet'    => '&bull;',
2681         'result'    => '&rArr;',
2682         'expansion' => '&rarr;',
2683         'point'     => '&lowast;',
2684         "'"         => '&rsquo;',
2685         '`'         => '&lsquo;',
2686        );
2687
2688# not used currently for html, but used in chm.init
2689%numeric_entity_map = ();
2690
2691foreach my $symbol (keys(%unicode_map))
2692{
2693    if ($symbol ne '')
2694    {
2695        $numeric_entity_map{$symbol} = '&#' . hex($unicode_map{$symbol}) . ';';
2696    }
2697}
2698
2699# When the value begins with & the function with that name is used to do the
2700# html. The first argument is the text enclosed within {}, the second is the
2701# style name (which is also the key of the hash)
2702#
2703# Otherwithe the value is the html element used to enclose the text, and if
2704# there is a " the resulting text is also enclosed within `'
2705my %old_style_map = (
2706      'acronym',    '',
2707      'asis',       '',
2708      'b',          'b',
2709      'cite',       'cite',
2710      'code',       'code',
2711      'command',    'code',
2712      'ctrl',       '&default_ctrl',
2713      'dfn',        'em',
2714      'dmn',        '',
2715      'email',      '&default_email',
2716      'emph',       'em',
2717      'env',        'code',
2718      'file',       '"tt',
2719      'i',          'i',
2720      'kbd',        'kbd',
2721      'key',        'kbd',
2722      'math',       'em',
2723      'option',     '"samp',
2724      'r',          '',
2725      'samp',       '"samp',
2726      'sc',         '&default_sc',
2727      'strong',     'strong',
2728      't',          'tt',
2729      'uref',       '&default_uref',
2730      'url',        '&default_url',
2731      'var',        'var',
2732      'verb',       'tt',
2733      'titlefont',  '&default_titlefont',
2734      'w',          '',
2735     );
2736
2737# default is {'args' => ['normal'], 'attribute' => ''},
2738%style_map = (
2739      'asis',       {},
2740      'b',          {'attribute' => 'b'},
2741      'cite',       {'attribute' => 'cite'},
2742      'code',       {'args' => ['code'], 'attribute' => 'code'},
2743      'command',    {'args' => ['code'], 'attribute' => 'code'},
2744      'ctrl',       {'function' => \&t2h_default_ctrl,'type' => 'simple_type'},
2745      'dfn',        {'attribute' => 'em'},
2746      'dmn',        {},
2747      'email',      {'args' => ['code', 'normal'],
2748                       'function' => \&t2h_default_email,
2749                       'type' => 'simple_type'},
2750      #'email',      {'args' => ['normal', 'normal'],
2751      #                 'function' => \&t2h_default_email},
2752      'emph',       {'attribute' => 'em'},
2753      'env',        {'args' => ['code'], 'attribute' => 'code'},
2754      'file',       {'args' => ['code'], 'attribute' => 'tt', 'quote' => '"'},
2755      'i',          {'attribute' => 'i'},
2756      'slanted',    {'attribute' => 'i'},
2757      'sansserif',  {'attribute' => 'span class="sansserif"'},
2758      'kbd',        {'args' => ['code'], 'attribute' => 'kbd'},
2759      'key',        {'begin' => '&lt;', 'end' => '&gt;'},
2760      'math',       {'attribute' => 'em'},
2761      'option',     {'args' => ['code'], 'attribute' => 'samp', 'quote' => '"'},
2762      'r',          {'attribute' => 'span class="roman"'},
2763      'samp',       {'args' => ['code'], 'attribute' => 'samp', 'quote' => '"'},
2764#      'sc',         {'function' => \&t2h_default_sc},
2765      'sc',         {'attribute' => 'small'},
2766      'strong',     {'attribute' => 'strong'},
2767      't',          {'attribute' => 'tt'},
2768      'uref',       {'function' => \&t2h_default_uref,
2769                      'args' => ['code', 'normal', 'normal'],
2770                      'type' => 'simple_type' },
2771      #'uref',       {'function' => \&t2h_default_uref,
2772      #                'args' => ['normal', 'normal', 'normal']},
2773      'url',        {'function' => \&t2h_default_uref,
2774                      'args' => ['code', 'normal', 'normal'],
2775                      'type' => 'simple_type'},
2776      'indicateurl', {'args' => ['code'], 'begin' => '&lt;<code>', 'end' => '</code>&gt;','type' => 'simple_type'},
2777      'var',        {'attribute' => 'var'},
2778      'verb',       {'args' => ['code'], 'attribute' => 'tt'},
2779      'titlefont',  {'function' => \&t2h_default_titlefont,
2780            'type' => 'simple_type'},
2781      'w',          {'type' => 'simple_type'},
2782     );
2783
2784%command_type = ();
2785
2786foreach my $style (keys(%style_map))
2787{
2788   if (exists($style_map{$style}->{'type'}))
2789   {
2790       $command_type{$style} = $style_map{$style}->{'type'};
2791   }
2792   else
2793   {
2794       $command_type{$style} = 'style';
2795   }
2796}
2797
2798%unicode_diacritical = (
2799       'H'          => '030B',
2800       'ringaccent' => '030A',
2801       "'"          => '0301',
2802       'v'          => '030C',
2803       ','          => '0327',
2804       '^'          => '0302',
2805       'dotaccent'  => '0307',
2806       '`'          => '0300',
2807       '='          => '0304',
2808       '~'          => '0303',
2809       '"'          => '0308',
2810       'udotaccent' => '0323',
2811       'ubaraccent' => '0332',
2812       'u'          => '0306',
2813       'tieaccent'  => '0361'
2814);
2815
2816%unicode_accents = (
2817    'dotaccent' => { # dot above
2818        'A' => '0226', #C moz-1.2
2819        'a' => '0227', #c moz-1.2
2820        'B' => '1E02',
2821        'b' => '1E03',
2822        'C' => '010A',
2823        'c' => '010B',
2824        'D' => '1E0A',
2825        'd' => '1E0B',
2826        'E' => '0116',
2827        'e' => '0117',
2828        'F' => '1E1E',
2829        'f' => '1E1F',
2830        'G' => '0120',
2831        'g' => '0121',
2832        'H' => '1E22',
2833        'h' => '1E23',
2834        'i' => '0069',
2835        'I' => '0130',
2836        'N' => '1E44',
2837        'n' => '1E45',
2838        'O' => '022E', #Y moz-1.2
2839        'o' => '022F', #v moz-1.2
2840        'P' => '1E56',
2841        'p' => '1E57',
2842        'R' => '1E58',
2843        'r' => '1E59',
2844        'S' => '1E60',
2845        's' => '1E61',
2846        'T' => '1E6A',
2847        't' => '1E6B',
2848        'W' => '1E86',
2849        'w' => '1E87',
2850        'X' => '1E8A',
2851        'x' => '1E8B',
2852        'Y' => '1E8E',
2853        'y' => '1E8F',
2854        'Z' => '017B',
2855        'z' => '017C',
2856    },
2857    'udotaccent' => { # dot below
2858        'A' => '1EA0',
2859        'a' => '1EA1',
2860        'B' => '1E04',
2861        'b' => '1E05',
2862        'D' => '1E0C',
2863        'd' => '1E0D',
2864        'E' => '1EB8',
2865        'e' => '1EB9',
2866        'H' => '1E24',
2867        'h' => '1E25',
2868        'I' => '1ECA',
2869        'i' => '1ECB',
2870        'K' => '1E32',
2871        'k' => '1E33',
2872        'L' => '1E36',
2873        'l' => '1E37',
2874        'M' => '1E42',
2875        'm' => '1E43',
2876        'N' => '1E46',
2877        'n' => '1E47',
2878        'O' => '1ECC',
2879        'o' => '1ECD',
2880        'R' => '1E5A',
2881        'r' => '1E5B',
2882        'S' => '1E62',
2883        's' => '1E63',
2884        'T' => '1E6C',
2885        't' => '1E6D',
2886        'U' => '1EE4',
2887        'u' => '1EE5',
2888        'V' => '1E7E',
2889        'v' => '1E7F',
2890        'W' => '1E88',
2891        'w' => '1E89',
2892        'Y' => '1EF4',
2893        'y' => '1EF5',
2894        'Z' => '1E92',
2895        'z' => '1E93',
2896    },
2897    'ubaraccent' => { # line below
2898        'B' => '1E06',
2899        'b' => '1E07',
2900        'D' => '1E0E',
2901        'd' => '1E0F',
2902        'h' => '1E96',
2903        'K' => '1E34',
2904        'k' => '1E35',
2905        'L' => '1E3A',
2906        'l' => '1E3B',
2907        'N' => '1E48',
2908        'n' => '1E49',
2909        'R' => '1E5E',
2910        'r' => '1E5F',
2911        'T' => '1E6E',
2912        't' => '1E6F',
2913        'Z' => '1E94',
2914        'z' => '1E95',
2915    },
2916    ',' => { # cedilla
2917        'C' => '00C7',
2918        'c' => '00E7',
2919        'D' => '1E10',
2920        'd' => '1E11',
2921        'E' => '0228', #C moz-1.2
2922        'e' => '0229', #c moz-1.2
2923        'G' => '0122',
2924        'g' => '0123',
2925        'H' => '1E28',
2926        'h' => '1E29',
2927        'K' => '0136',
2928        'k' => '0137',
2929        'L' => '013B',
2930        'l' => '013C',
2931        'N' => '0145',
2932        'n' => '0146',
2933        'R' => '0156',
2934        'r' => '0157',
2935        'S' => '015E',
2936        's' => '015F',
2937        'T' => '0162',
2938        't' => '0163',
2939    },
2940    '=' => { # macron
2941        'A' => '0100',
2942        'a' => '0101',
2943        'E' => '0112',
2944        'e' => '0113',
2945        'I' => '012A',
2946        'i' => '012B',
2947        'G' => '1E20',
2948        'g' => '1E21',
2949        'O' => '014C',
2950        'o' => '014D',
2951        'U' => '016A',
2952        'u' => '016B',
2953        'Y' => '0232', #? moz-1.2
2954        'y' => '0233', #? moz-1.2
2955    },
2956    '"' => { # diaeresis
2957        'A' => '00C4',
2958        'a' => '00E4',
2959        'E' => '00CB',
2960        'e' => '00EB',
2961        'H' => '1E26',
2962        'h' => '1E27',
2963        'I' => '00CF',
2964        'i' => '00EF',
2965        'O' => '00D6',
2966        'o' => '00F6',
2967        't' => '1E97',
2968        'U' => '00DC',
2969        'u' => '00FC',
2970        'W' => '1E84',
2971        'w' => '1E85',
2972        'X' => '1E8C',
2973        'x' => '1E8D',
2974        'y' => '00FF',
2975        'Y' => '0178',
2976    },
2977    'u' => { # breve
2978        'A' => '0102',
2979        'a' => '0103',
2980        'E' => '0114',
2981        'e' => '0115',
2982        'G' => '011E',
2983        'g' => '011F',
2984        'I' => '012C',
2985        'i' => '012D',
2986        'O' => '014E',
2987        'o' => '014F',
2988        'U' => '016C',
2989        'u' => '016D',
2990    },
2991    "'" => { # acute
2992        'A' => '00C1',
2993        'a' => '00E1',
2994        'C' => '0106',
2995        'c' => '0107',
2996        'E' => '00C9',
2997        'e' => '00E9',
2998        'G' => '01F4',
2999        'g' => '01F5',
3000        'I' => '00CD',
3001        'i' => '00ED',
3002        'K' => '1E30',
3003        'k' => '1E31',
3004        'L' => '0139',
3005        'l' => '013A',
3006        'M' => '1E3E',
3007        'm' => '1E3F',
3008        'N' => '0143',
3009        'n' => '0144',
3010        'O' => '00D3',
3011        'o' => '00F3',
3012        'P' => '1E54',
3013        'p' => '1E55',
3014        'R' => '0154',
3015        'r' => '0155',
3016        'S' => '015A',
3017        's' => '015B',
3018        'U' => '00DA',
3019        'u' => '00FA',
3020        'W' => '1E82',
3021        'w' => '1E83',
3022        'Y' => '00DD',
3023        'y' => '00FD',
3024        'Z' => '0179',
3025        'z' => '018A',
3026    },
3027    '~' => { # tilde
3028        'A' => '00C3',
3029        'a' => '00E3',
3030        'E' => '1EBC',
3031        'e' => '1EBD',
3032        'I' => '0128',
3033        'i' => '0129',
3034        'N' => '00D1',
3035        'n' => '00F1',
3036        'O' => '00D5',
3037        'o' => '00F5',
3038        'U' => '0168',
3039        'u' => '0169',
3040        'V' => '1E7C',
3041        'v' => '1E7D',
3042        'Y' => '1EF8',
3043        'y' => '1EF9',
3044    },
3045    '`' => { # grave
3046        'A' => '00C0',
3047        'a' => '00E0',
3048        'E' => '00C8',
3049        'e' => '00E8',
3050        'I' => '00CC',
3051        'i' => '00EC',
3052        'N' => '01F8',
3053        'n' => '01F9',
3054        'O' => '00D2',
3055        'o' => '00F2',
3056        'U' => '00D9',
3057        'u' => '00F9',
3058        'W' => '1E80',
3059        'w' => '1E81',
3060        'Y' => '1EF2',
3061        'y' => '1EF3',
3062    },
3063    '^' => { # circumflex
3064        'A' => '00C2',
3065        'a' => '00E2',
3066        'C' => '0108',
3067        'c' => '0109',
3068        'E' => '00CA',
3069        'e' => '00EA',
3070        'G' => '011C',
3071        'g' => '011D',
3072        'H' => '0124',
3073        'h' => '0125',
3074        'I' => '00CE',
3075        'i' => '00EE',
3076        'J' => '0134',
3077        'j' => '0135',
3078        'O' => '00D4',
3079        'o' => '00F4',
3080        'S' => '015C',
3081        's' => '015D',
3082        'U' => '00DB',
3083        'u' => '00FB',
3084        'W' => '0174',
3085        'w' => '0175',
3086        'Y' => '0176',
3087        'y' => '0177',
3088        'Z' => '1E90',
3089        'z' => '1E91',
3090    },
3091    'ringaccent' => { # ring
3092        'A' => '00C5',
3093        'a' => '00E5',
3094        'U' => '016E',
3095        'u' => '016F',
3096        'w' => '1E98',
3097        'y' => '1E99',
3098    },
3099    'v' => { # caron
3100        'A' => '01CD',
3101        'a' => '01CE',
3102        'C' => '010C',
3103        'c' => '010D',
3104        'D' => '010E',
3105        'd' => '010F',
3106        'E' => '011A',
3107        'e' => '011B',
3108        'G' => '01E6',
3109        'g' => '01E7',
3110        'H' => '021E', #K with moz-1.2
3111        'h' => '021F', #k with moz-1.2
3112        'I' => '01CF',
3113        'i' => '01D0',
3114        'K' => '01E8',
3115        'k' => '01E9',
3116        'L' => '013D', #L' with moz-1.2
3117        'l' => '013E', #l' with moz-1.2
3118        'N' => '0147',
3119        'n' => '0148',
3120        'O' => '01D1',
3121        'o' => '01D2',
3122        'R' => '0158',
3123        'r' => '0159',
3124        'S' => '0160',
3125        's' => '0161',
3126        'T' => '0164',
3127        't' => '0165',
3128        'U' => '01D3',
3129        'u' => '01D4',
3130        'Z' => '017D',
3131        'z' => '017E',
3132    },
3133    'H' => { # double acute
3134        'O' => '0150',
3135        'o' => '0151',
3136        'U' => '0170',
3137        'u' => '0171',
3138    },
3139);
3140
3141%transliterate_accent_map = ();
3142foreach my $command (keys(%unicode_accents))
3143{
3144    foreach my $letter(keys (%{$unicode_accents{$command}}))
3145    {
3146        $transliterate_accent_map{$unicode_accents{$command}->{$letter}}
3147            = $letter
3148          unless (exists($transliterate_map{$unicode_accents{$command}->{$letter}}));
3149    }
3150}
3151
3152%special_accents = (
3153      'ringaccent' => 'aA',
3154      "'"          => 'aeiouyAEIOUY',
3155      ','          => 'cC',
3156      '^'          => 'aeiouAEIOU',
3157      '`'          => 'aeiouAEIOU',
3158      '~'          => 'nNaoAO',
3159      '"'          => 'aeiouyAEIOU',
3160);
3161
3162foreach my $accent_command ('tieaccent', 'dotless', keys(%unicode_accents))
3163{
3164     $style_map{$accent_command} = { 'function' => \&t2h_default_accent };
3165     $old_style_map{$accent_command} = '&default_accent';
3166     $style_map_texi{$accent_command} = { 'function' => \&t2h_default_ascii_accent };
3167}
3168
3169sub default_accent($$)
3170{
3171    my $text = shift;
3172    my $accent = shift;
3173    return "&${text}$accent_map{$accent};" if (defined($accent_map{$accent}) and defined($special_accents{$accent}) and ($text =~ /^[$special_accents{$accent}]$/));
3174    return '&' . $text . 'ring;' if (($accent eq 'ringaccent') and (defined($special_accents{$accent})) and ($text =~ /^[$special_accents{$accent}]$/));
3175    return $text . '&lt;' if ($accent eq 'v');
3176    return "&${text}cedil;" if (($accent eq ',') and (defined($special_accents{$accent})) and ($text =~ /^[$special_accents{$accent}]$/));
3177    return ascii_accents($text, $accent);
3178}
3179
3180sub t2h_default_accent($$)
3181{
3182    my $accent = shift;
3183    my $args = shift;
3184
3185    my $text = $args->[0];
3186
3187    return "&${text}$accent_map{$accent};" if (defined($accent_map{$accent}) and defined($special_accents{$accent}) and ($text =~ /^[$special_accents{$accent}]$/));
3188    return '&' . $text . 'ring;' if (($accent eq 'ringaccent') and (defined($special_accents{$accent})) and ($text =~ /^[$special_accents{$accent}]$/));
3189    return $text . '&lt;' if ($accent eq 'v');
3190    return "&${text}cedil;" if (($accent eq ',') and (defined($special_accents{$accent})) and ($text =~ /^[$special_accents{$accent}]$/));
3191# FIXME here there could be a conversion to the character in the right
3192# encoding, like
3193#    if ($USE_UNICODE and defined($OUT_ENCODING) and $OUT_ENCODING ne ''
3194#        and exists($unicode_accents{$accent}) and  exists($unicode_accents{$accent}->{$text}))
3195#    {
3196#          my $encoded_char =  Encode::encode($OUT_ENCODING, chr(hex($unicode_map{$thing})), Encode::FB_QUIET);
3197#          return $encoded_char if ($encoded_char ne '');
3198#    }
3199    if ($USE_NUMERIC_ENTITY)
3200    {
3201        if (exists($unicode_accents{$accent}) and exists($unicode_accents{$accent}->{$text}))
3202        {
3203             return ('&#' . hex($unicode_accents{$accent}->{$text}) . ';');
3204        }
3205    }
3206    return ascii_accents($text, $accent);
3207}
3208
3209sub ascii_accents($$)
3210{
3211    my $text = shift;
3212    my $accent = shift;
3213    return $text if ($accent eq 'dotless');
3214    return $text . $accent if (defined($accent_map{$accent}));
3215    return $text . "''" if ($accent eq 'H');
3216    return $text . '.' if ($accent eq 'dotaccent');
3217    return $text . '*' if ($accent eq 'ringaccent');
3218    return $text . '[' if ($accent eq 'tieaccent');
3219    return $text . '(' if ($accent eq 'u');
3220    return $text . '_' if ($accent eq 'ubaraccent');
3221    return '.' . $text  if ($accent eq 'udotaccent');
3222    return $text . '<' if ($accent eq 'v');
3223    return $text . ',' if ($accent eq ',');
3224}
3225
3226sub default_sc($$)
3227{
3228    return '<small>' . uc($_[0]) . '</small>';
3229}
3230
3231# now unused, upcasing is done in normal_text
3232sub t2h_default_sc($$$)
3233{
3234    shift;
3235    my $args = shift;
3236    return '<small>' . uc($args->[0]) . '</small>';
3237}
3238
3239sub default_ctrl($$)
3240{
3241   return "^$_[0]";
3242}
3243
3244sub t2h_default_ctrl($$$)
3245{
3246    shift;
3247    my $args = shift;
3248   return "^$args->[0]";
3249}
3250
3251sub default_sc_pre($$)
3252{
3253    return uc($_[0]);
3254}
3255
3256# now unused, upcasing is done in normal_text
3257sub t2h_default_sc_pre($$$)
3258{
3259    shift;
3260    my $args = shift;
3261    return uc($args->[0]);
3262}
3263
3264sub default_titlefont($$)
3265{
3266    return "<h1 class=\"titlefont\">$_[0]</h1>" if ($_[0] =~ /\S/);
3267    return '';
3268}
3269
3270# Avoid adding h1 if the text is empty
3271sub t2h_default_titlefont($$$)
3272{
3273    shift;
3274    my $args = shift;
3275    return "<h1 class=\"titlefont\">$args->[0]</h1>" if ($args->[0] =~ /\S/);
3276    return '';
3277}
3278
3279# At some point in time (before 4.7?) according to the texinfo
3280# manual, url shouldn't lead to a link but rather be formatted
3281# like text. It is now what indicateurl do, url is the same that
3282# uref with one arg. If we did like makeinfo did it would have been
3283#sub url($$)
3284#{
3285#    return '&lt;<code>' . $_[0] . '</code>&gt;';
3286#}
3287#
3288# This is unused, t2h_default_uref is used instead
3289sub t2h_default_url ($$)
3290{
3291    shift;
3292    my $args = shift;
3293    my $url = shift @$args;
3294    #$url =~ s/\s*$//;
3295    #$url =~ s/^\s*//;
3296    $url = main::normalise_space($url);
3297    return '' unless ($url =~ /\S/);
3298    return &$anchor('', $url, $url);
3299}
3300
3301sub default_url ($$)
3302{
3303    my $url = shift;
3304    my $command = shift;
3305    $url =~ s/\s*$//;
3306    $url =~ s/^\s*//;
3307    return '' unless ($url =~ /\S/);
3308    return &$anchor('', $url, $url);
3309}
3310
3311sub default_uref($$)
3312{
3313    my $arg = shift;
3314    my $command = shift;
3315    my ($url, $text, $replacement);
3316    ($url, $text, $replacement) = split /,\s*/, $arg;
3317    $url =~ s/\s*$//;
3318    $url =~ s/^\s*//;
3319    $text = $replacement if (defined($replacement));
3320    $text = $url unless ($text);
3321    return $text if ($url eq '');
3322    return &$anchor('', $url, $text);
3323}
3324
3325sub t2h_default_uref($$)
3326{
3327    shift;
3328    my $args = shift;
3329    my $url = shift @$args;
3330    my $text = shift @$args;
3331    my $replacement = shift @$args;
3332    #$url =~ s/\s*$//;
3333    #$url =~ s/^\s*//;
3334    $url = main::normalise_space($url);
3335    $replacement = '' if (!defined($replacement));
3336    $replacement = main::normalise_space($replacement);
3337    $text = '' if (!defined($text));
3338    $text = main::normalise_space($text);
3339    $text = $replacement if ($replacement ne '');
3340    $text = $url unless ($text ne '');
3341    return $text if ($url eq '');
3342    return &$anchor('', $url, $text);
3343}
3344
3345sub default_email($$)
3346{
3347    my $arg = shift;
3348    my $command = shift;
3349    my ($mail, $text);
3350    ($mail, $text) = split /,\s*/, $arg;
3351    $mail =~ s/\s*$//;
3352    $mail =~ s/^\s*//;
3353    $text = $mail unless ($text);
3354    return $text if ($mail eq '');
3355    return &$anchor('', "mailto:$mail", $text);
3356}
3357
3358sub t2h_default_email($$)
3359{
3360    my $command = shift;
3361    my $args = shift;
3362    my $mail = shift @$args;
3363    my $text = shift @$args;
3364    $mail = main::normalise_space($mail);
3365    #$mail =~ s/\s*$//;
3366    #$mail =~ s/^\s*//;
3367    $text = $mail unless (defined($text) and ($text ne ''));
3368    $text = main::normalise_space($text);
3369    return $text if ($mail eq '');
3370    return &$anchor('', "mailto:$mail", $text);
3371}
3372
3373sub t2h_default_ascii_accent($$$$)
3374{
3375    my $accent = shift;
3376    my $args = shift;
3377
3378    my $text = $args->[0];
3379    return ascii_accents($text, $accent);
3380}
3381
3382sub t2h_default_no_texi_email
3383{
3384    my $command = shift;
3385    my $args = shift;
3386    my $mail = shift @$args;
3387    my $text = shift @$args;
3388    $mail = main::normalise_space($mail);
3389    #$mail =~ s/\s*$//;
3390    #$mail =~ s/^\s*//;
3391    return $text if (defined($text) and ($text ne ''));
3392    return $mail;
3393}
3394
3395sub t2h_default_no_texi_image($$$$)
3396{
3397    my $command = shift;
3398    my $args = shift;
3399    my $text = $args->[0];
3400    $text = main::normalise_space($text);
3401    my @args = split (/\s*,\s*/, $text);
3402    return $args[0];
3403}
3404
3405sub t2h_default_no_texi_acronym_like($$)
3406{
3407    my $command = shift;
3408    my $args = shift;
3409    my $acronym_texi = $args->[0];
3410    return (main::remove_texi($acronym_texi));
3411}
3412
3413sub t2h_remove_command($$$$)
3414{
3415    return '';
3416}
3417
3418# This is used for style in preformatted sections
3419my %old_style_map_pre = %old_style_map;
3420$old_style_map_pre{'sc'} = '&default_sc_pre';
3421$old_style_map_pre{'titlefont'} = '';
3422
3423foreach my $command (keys(%style_map))
3424{
3425    $style_map_pre{$command} = {};
3426    $style_map_texi{$command} = {} if (!exists($style_map_texi{$command}));
3427    $style_map_texi{$command}->{'args'} = $style_map{$command}->{'args'}
3428        if (exists($style_map{$command}->{'args'}));
3429 #print STDERR "COMMAND $command";
3430
3431    foreach my $key (keys(%{$style_map{$command}}))
3432    {
3433        $style_map_pre{$command}->{$key} = $style_map{$command}->{$key};
3434    }
3435}
3436
3437#$style_map_pre{'sc'}->{'function'} = \&t2h_default_sc_pre;
3438$style_map_pre{'sc'} = {};
3439$style_map_pre{'titlefont'} = {};
3440
3441#$style_map_texi{'sc'}->{'function'} = \&t2h_default_sc_pre;
3442$style_map_texi{'sc'} = {};
3443$style_map_texi{'email'}->{'function'} = \&t2h_default_no_texi_email;
3444
3445####### special styles. You shouldn't need to change them
3446my %special_style = (
3447           #'xref'      => ['keep','normal','normal','keep','normal'],
3448           'xref'         => { 'args' => ['keep','keep','keep','keep','keep'],
3449               'function' => \&main::do_xref },
3450           'ref'         => { 'args' => ['keep','keep','keep','keep','keep'],
3451               'function' => \&main::do_xref },
3452           'pxref'         => { 'args' => ['keep','keep','keep','keep','keep'],
3453               'function' => \&main::do_xref },
3454           'inforef'      => { 'args' => ['keep','keep','keep'],
3455               'function' => \&main::do_xref },
3456           'image'        => { 'args' => ['keep'], 'function' => \&main::do_image },
3457           'anchor'       => { 'args' => ['keep'], 'function' => \&main::do_anchor_label },
3458           'footnote'     => { 'args' => ['keep'], 'function' => \&main::do_footnote },
3459           'shortcaption' => { 'args' => ['keep'], 'function' => \&main::do_caption_shortcaption },
3460           'caption' => { 'args' => ['keep'], 'function' => \&main::do_caption_shortcaption },
3461           'acronym',    {'args' => ['keep','keep'], 'function' => \&main::do_acronym_like},
3462           'abbr',    {'args' => ['keep','keep'], 'function' => \&main::do_acronym_like},
3463);
3464
3465# @image is replaced by the first arg in strings
3466$style_map_texi{'image'} = { 'args' => ['keep'],
3467       'function' => \&t2h_default_no_texi_image };
3468
3469$style_map_texi{'acronym'} = { 'args' => ['keep','keep'],
3470       'function' => \&t2h_default_no_texi_acronym_like };
3471$style_map_texi{'abbr'} = { 'args' => ['keep','keep'],
3472       'function' => \&t2h_default_no_texi_acronym_like };
3473
3474foreach my $special (keys(%special_style))
3475{
3476    $style_map{$special} = $special_style{$special}
3477          unless (defined($style_map{$special}));
3478    $style_map_pre{$special} = $special_style{$special}
3479          unless (defined($style_map_pre{$special}));
3480    $style_map_texi{$special} = { 'args' => ['keep'],
3481        'function' => \&t2h_remove_command }
3482          unless (defined($style_map_texi{$special}));
3483}
3484####### end special styles.
3485
3486
3487#foreach my $command (keys(%style_map))
3488#{
3489#    print STDERR "STYLE_MAP_TEXI $command($style_map_texi{$command}) ";
3490#    print STDERR "ARGS $style_map_texi{$command}->{'args'} " if (defined($style_map_texi{$command}->{'args'}));
3491#    print STDERR "FUN $style_map_texi{$command}->{'function'} " if (defined($style_map_texi{$command}->{'function'}));
3492#    print STDERR "\n";
3493#}
3494
3495# uncomment to use the old interface
3496#%style_map = %old_style_map;
3497#%style_map_pre = %old_style_map_pre;
3498
3499%simple_format_simple_map_texi = %simple_map_pre;
3500%simple_format_texi_map = %pre_map;
3501%simple_format_style_map_texi = ();
3502
3503foreach my $command (keys(%style_map_texi))
3504{
3505    #$simple_format_style_map_texi{$command} = {};
3506    foreach my $key (keys (%{$style_map_texi{$command}}))
3507    {
3508    #print STDERR "$command, $key, $style_map_texi{$command}->{$key}\n";
3509        $simple_format_style_map_texi{$command}->{$key} =
3510             $style_map_texi{$command}->{$key};
3511    }
3512    $simple_format_style_map_texi{$command} = {} if (!defined($simple_format_style_map_texi{$command}));
3513}
3514
3515foreach my $accent_command ('tieaccent', 'dotless', keys(%unicode_accents))
3516{
3517#    $simple_format_style_map_texi{$accent_command}->{'args'} = ['normal'];
3518    $simple_format_style_map_texi{$accent_command}->{'function'} = \&t2h_default_accent;
3519}
3520
3521%format_map = (
3522#       'quotation'   =>  'blockquote',
3523       # lists
3524#       'itemize'     =>  'ul',
3525       'enumerate'   =>  'ol',
3526       'multitable'  =>  'table',
3527       'table'       =>  'dl compact="compact"',
3528       'vtable'      =>  'dl compact="compact"',
3529       'ftable'      =>  'dl compact="compact"',
3530       'group'       =>  '',
3531       );
3532
3533%special_list_commands = (
3534       'table'        =>  {},
3535       'vtable'       =>  {},
3536       'ftable'       =>  {},
3537       'itemize'      =>  { 'bullet'  => '' }
3538       );
3539#
3540# texinfo format to align attribute of paragraphs
3541#
3542
3543%paragraph_style = (
3544      'center'     => 'center',
3545      'flushleft'  => 'left',
3546      'flushright' => 'right',
3547      );
3548
3549# an eval of these $complex_format_map->{what}->{'begin'} yields beginning
3550# an eval of these $complex_format_map->{what}->{'end'} yields end
3551# $EXAMPLE_INDENT_CELL and SMALL_EXAMPLE_INDENT_CELL can be usefull here
3552$complex_format_map =
3553{
3554 'example' =>
3555 {
3556  'begin' => q{"<table><tr>$EXAMPLE_INDENT_CELL<td>"},
3557  'end' => q{"</td></tr></table>\n"},
3558 },
3559 'smallexample' =>
3560 {
3561  'begin' => q{"<table><tr>$SMALL_EXAMPLE_INDENT_CELL<td>"},
3562  'end' => q{"</td></tr></table>\n"},
3563 },
3564 'display' =>
3565 {
3566  'begin' => q{"<table><tr>$EXAMPLE_INDENT_CELL<td>"},
3567  'end' => q{"</td></tr></table>\n"},
3568 },
3569 'smalldisplay' =>
3570 {
3571  'begin' => q{"<table><tr>$SMALL_EXAMPLE_INDENT_CELL<td>"},
3572  'end' => q{"</td></tr></table>\n"},
3573 }
3574};
3575
3576# format shouldn't narrow the margins
3577
3578$complex_format_map->{'lisp'} =  $complex_format_map->{'example'};
3579$complex_format_map->{'smalllisp'} = $complex_format_map->{'smallexample'};
3580$complex_format_map->{'format'} = $complex_format_map->{'display'};
3581$complex_format_map->{'smallformat'} = $complex_format_map->{'smalldisplay'};
3582
3583%def_map = (
3584    # basic commands
3585    'deffn', [ 'f', 'category', 'name', 'arg' ],
3586    'defvr', [ 'v', 'category', 'name' ],
3587    'deftypefn', [ 'f', 'category', 'type', 'name', 'arg' ],
3588    'deftypeop', [ 'f', 'category', 'class' , 'type', 'name', 'arg' ],
3589    'deftypevr', [ 'v', 'category', 'type', 'name' ],
3590    'defcv', [ 'v', 'category', 'class' , 'name' ],
3591    'deftypecv', [ 'v', 'category', 'class' , 'type', 'name' ],
3592    'defop', [ 'f', 'category', 'class' , 'name', 'arg' ],
3593    'deftp', [ 't', 'category', 'name', 'arg' ],
3594    # shortcuts
3595    # FIXME i18n
3596    'defun', 'deffn Function',
3597    'defmac', 'deffn Macro',
3598    'defspec', 'deffn {Special Form}',
3599    'defvar', 'defvr Variable',
3600    'defopt', 'defvr {User Option}',
3601    'deftypefun', 'deftypefn {Function}',
3602    'deftypevar', 'deftypevr Variable',
3603    'defivar', 'defcv {Instance Variable}',
3604    'deftypeivar', 'deftypecv {Instance Variable}',
3605    'defmethod', 'defop Method',
3606    'deftypemethod', 'deftypeop Method',
3607         );
3608
3609# basic x commands
3610foreach my $key (keys(%def_map))
3611{
3612    $def_map{$key . 'x'} = $def_map{$key};
3613}
3614
3615#
3616# miscalleneous commands
3617#
3618# Depending on the value, the command arg or spaces following the command
3619#     are handled differently:
3620#
3621# the value is a reference on a hash.
3622# the hash keys are
3623#    'arg'  if the value is 'line' then the remaining of the line is the arg
3624#           if it is a number it is the number of args (separated by spaces)
3625#    'skip' if the value is 'line' then the remaining of the line is skipped
3626#           if the value is 'space' space but no newline is skipped
3627#           if the value is 'whitespace' space is skipped
3628#           if the value is 'linewhitespace' space is skipped if there are
3629#                 only spaces remaining on the line
3630#           if the value is 'linespace' space but no newline is skipped if
3631#                 there are only spaces remaining on the line
3632#    'texi' if true it is some texinfo code and @value and @macros are expanded
3633#    'keep' if true the args and the macro are kept, otherwise the macro
3634#          args and skipped stuffs are removed
3635%misc_command = (
3636        # not needed for formatting
3637        'raisesections' => {'skip' => 'line'},  # no arg
3638        'lowersections' => {'skip' => 'line'}, # no arg
3639        'contents' => {}, # no arg
3640        'shortcontents' => {}, # no arg
3641        'summarycontents'=> {}, # no arg
3642        'setcontentsaftertitlepage' => {}, # no arg
3643        'setshortcontentsaftertitlepage' => {}, # no arg
3644        'detailmenu' => {'skip' => 'whitespace'}, # no arg
3645        'end detailmenu' => {'skip' => 'space'}, # no arg
3646        'bye' => {'skip' => 'line'}, # no arg
3647        # comments
3648        'comment' => {'arg' => 'line'},
3649        'c' => {'arg' => 'line'},
3650        # in preamble
3651        'novalidate' => {}, # no arg
3652        'dircategory'=> {'skip' => 'line'}, # line. Position with regard
3653                         # with direntry is significant
3654        'pagesizes' => {'skip' => 'line', 'arg' => 2}, # can have 2 args
3655                                 # or one? 200mm,150mm 11.5in
3656        'finalout' => {}, # no arg
3657        'paragraphindent' => {'skip' => 'line', 'arg' => 1}, # arg none asis
3658                             # or a number and forbids anything else on the line
3659        'firstparagraphindent' => {'skip' => 'line', 'arg' => 1}, # none insert
3660        'frenchspacing' => {'arg' => 1}, # on off
3661        'exampleindent' => {'skip' => 'line', 'arg' => 1}, # asis or a number
3662        'footnotestyle'=> {'skip' => 'line', 'arg' => 1}, # end and separate
3663                                 # and nothing else on the line
3664        'afourpaper' => {'skip' => 'line'}, # no arg
3665        'afourlatex' => {'skip' => 'line'}, # no arg
3666        'afourwide' => {'skip' => 'line'}, # no arg
3667        'headings'=> {'skip' => 'line', 'arg' => 1},
3668                    #off on single double singleafter doubleafter
3669                    # interacts with setchapternewpage
3670        'setchapternewpage' => {'skip' => 'line', 'arg' => 1}, # off on odd
3671        'everyheading' => {'arg' => 'line'},
3672        'everyfooting' => {'arg' => 'line'},
3673        'evenheading' => {'arg' => 'line'},
3674        'evenfooting' => {'arg' => 'line'},
3675        'oddheading' => {'arg' => 'line'},
3676        'oddfooting' => {'arg' => 'line'},
3677        'smallbook' => {'skip' => 'line'}, # no arg
3678        'setfilename' => {'arg' => 'line'},
3679        'shorttitle' => {'arg' => 'line', 'texi' => 1},
3680        'shorttitlepage' => {'arg' => 'line', 'texi' => 1},
3681        'settitle' => {'arg' => 'line', 'texi' => 1},
3682        'author' => {'arg' => 'line', 'texi' => 1},
3683        'subtitle' => {'arg' => 'line', 'texi' => 1},
3684        'title' => {'arg' => 'line', 'texi' => 1},
3685        'syncodeindex' => {'skip' => 'linespace', 'arg' => 2},
3686                          # args are index identifiers
3687        'synindex' => {'skip' => 'linespace', 'arg' => 2},
3688        'defindex' => {'skip' => 'line', 'arg' => 1}, # one identifier arg
3689        'defcodeindex' => {'skip' => 'line', 'arg' => 1}, # one identifier arg
3690        'documentlanguage' => {'skip' => 'whitespace', 'arg' => 1},
3691                                                       # language code arg
3692        'kbdinputstyle' => {'skip' => 'whitespace', 'arg' => 1}, # code
3693                                                        #example distinct
3694        'sp' => {'skip' => 'whitespace', 'arg' => 1}, # no arg
3695                                    # at the end of line or a numerical arg
3696        # formatting
3697        'page' => {}, # no arg (pagebreak)
3698        'refill' => {}, # no arg (obsolete, to be ignored)
3699        'noindent' => {'skip' => 'whitespace'}, # no arg
3700        'indent' => {'skip' => 'whitespace'},
3701        'need' => {'skip' => 'line', 'arg' => 1}, # one numerical/real arg
3702        'exdent' => {'skip' => 'space'},
3703        # not valid for info (should be in @iftex)
3704        'vskip' => {'arg' => 'line'}, # arg line in TeX
3705        'cropmarks' => {}, # no arg
3706        # miscalleneous
3707        'verbatiminclude'=> {'skip' => 'line'},
3708        'documentencoding' => {'arg' => 1}, # makeinfo ignore the whole line
3709        # ???
3710        'filbreak' => {},
3711        # obsolete @-commands
3712        'quote-arg' => {},
3713        'allow-recursion' => {},
3714     );
3715my %misc_command_old = (
3716        # not needed for formatting
3717        'raisesections', 'line',  # no arg
3718        'lowersections', 'line', # no arg
3719        'contents', 1, # no arg
3720        'shortcontents', 1, # no arg
3721        'summarycontents', 1, # no arg
3722        'detailmenu', 'whitespace', # no arg
3723        'end detailmenu', 'space', # no arg
3724        #'end detailmenu', 1, # no arg
3725        'novalidate', 1, # no arg
3726        'bye', 'line', # no arg
3727        # comments
3728        'comment', 'line',
3729        'c', 'line',
3730        # in preamble
3731        'dircategory', 'line', # line. Position with regard with direntry is
3732                               # significant
3733        'pagesizes', 'line arg2', # can have 2 args
3734        'finalout', 1, # no arg
3735        'paragraphindent', 'line arg1', # in fact accepts only none asis
3736                             # or a number and forbids anything else on the line
3737        'firstparagraphindent', 'line arg1', # in fact accepts only none insert
3738        'exampleindent', 'line arg1', # in fact accepts only asis or a number
3739        'footnotestyle', 'line arg1', # in fact accepts only end and separate
3740                                 # and nothing else on the line
3741        'afourpaper', 'line', # no arg
3742        'afourlatex', 'line', # no arg
3743        'afourwide', 'line',  # no arg
3744        'headings', 'line', # one arg, possibilities are
3745                    #off on single double singleafter doubleafter
3746                    # interacts with setchapternewpage
3747        'setchapternewpage', 'line', # no arg
3748        'everyheading', 'line',
3749        'everyfooting', 'line',
3750        'evenheading', 'line',
3751        'evenfooting', 'line',
3752        'oddheading', 'line',
3753        'oddfooting', 'line',
3754        'smallbook', 'line', # no arg
3755        'setfilename', 'line',
3756        'shorttitle', 'linetexi',
3757        'shorttitlepage', 'linetexi',
3758        'settitle', 'linetexi',
3759        'author', 'linetexi',
3760        'subtitle', 'linetexi',
3761        'title','linetexi',
3762        'syncodeindex','linespace arg2', # args are
3763        'synindex','linespace arg2',
3764        'defindex', 'line arg1', # one identifier arg
3765        'defcodeindex', 'line arg1', # one identifier arg
3766        'documentlanguage', 'whitespace arg1', # one language code arg
3767        'kbdinputstyle', 'whitespace arg1', # one arg within
3768                                 #code example distnct
3769        'sp', 'whitespace arg1', # no arg at the en of line or a numerical arg
3770        # formatting
3771        'page', 1, # no arg (pagebreak)
3772        'refill', 1, # no arg (obsolete, to be ignored))
3773        'noindent', 'space', # no arg
3774        'need', 'line arg1', # one numerical/real arg
3775        'exdent', 'space',
3776        # not valid for info (should be in @iftex)
3777        'vskip', 'line', # arg line in TeX
3778        'cropmarks', 1, # no arg
3779        # miscalleneous
3780        'verbatiminclude', 'line',
3781        'documentencoding', 'arg1',
3782        # ???
3783        'filbreak', 1,
3784     );
3785
3786%format_in_paragraph = (
3787        'group' => 1,
3788        'html'  => 1,
3789);
3790# map mapping css specification to style
3791
3792%css_map =
3793     (
3794         'ul.toc'                 => "$TOC_LIST_STYLE",
3795         'pre.menu-comment'       => "$MENU_PRE_STYLE",
3796         'pre.menu-preformatted'  => "$MENU_PRE_STYLE",
3797         'a.summary-letter'       => 'text-decoration: none',
3798         'pre.display'            => 'font-family: serif',
3799         'pre.smalldisplay'       => 'font-family: serif; font-size: smaller',
3800         'pre.smallexample'       => 'font-size: smaller',
3801         'span.sansserif'         => 'font-family:sans-serif; font-weight:normal;',
3802         'span.roman'         => 'font-family:serif; font-weight:normal;'
3803     );
3804
3805$css_map{'pre.format'} = $css_map{'pre.display'};
3806$css_map{'pre.smallformat'} = $css_map{'pre.smalldisplay'};
3807$css_map{'pre.smalllisp'} = $css_map{'pre.smallexample'};
3808
3809# The command_handler arrays are for commands formatted externally.
3810# The function references in @command_handler_init are called
3811# before the second pass, before the @-commands text collection.
3812# Those in @command_handler_process are called between the second pass
3813# and the third pass, after collection of @-commands text and before their
3814# expansion.
3815# Those in @command_handler_process are called after the third pass,
3816# after the document generation.
3817@command_handler_init = ();
3818@command_handler_process = ();
3819@command_handler_finish = ();
3820
3821# the keys of %command_handler are @-command names and the value
3822# is a hash reference with the following keys:
3823# 'init'          function reference used to collect the @-command text
3824# 'expand'        function reference used when expanding the @-command text
3825%command_handler = ();
3826
3827# formatting functions
3828
3829$anchor            = \&t2h_default_anchor;
3830$def_item          = \&t2h_default_def_item;
3831$def               = \&t2h_default_def;
3832$menu              = \&t2h_default_menu;
3833$menu_link         = \&t2h_default_menu_link;
3834$menu_comment      = \&t2h_default_menu_comment;
3835$menu_description  = \&t2h_default_menu_description;
3836$simple_menu_link  = \&t2h_default_simple_menu_link;
3837$external_ref      = \&t2h_default_external_ref;
3838$external_href     = \&t2h_default_external_href;
3839$internal_ref      = \&t2h_default_internal_ref;
3840$table_item        = \&t2h_default_table_item;
3841$table_line        = \&t2h_default_table_line;
3842$table_list        = \&t2h_default_table_list;
3843$row               = \&t2h_default_row;
3844$cell              = \&t2h_default_cell;
3845$list_item         = \&t2h_default_list_item;
3846$comment           = \&t2h_default_comment;
3847$def_line          = \&t2h_default_def_line;
3848$def_line_no_texi  = \&t2h_default_def_line_no_texi;
3849$raw               = \&t2h_default_raw;
3850$raw_no_texi       = \&t2h_default_raw_no_texi;
3851$heading           = \&t2h_default_heading;
3852$paragraph         = \&t2h_default_paragraph;
3853$preformatted      = \&t2h_default_preformatted;
3854$foot_line_and_ref = \&t2h_default_foot_line_and_ref;
3855$foot_section      = \&t2h_default_foot_section;
3856$image_files       = \&t2h_default_image_files;
3857$image             = \&t2h_default_image;
3858$address           = \&t2h_default_address;
3859$index_entry_label = \&t2h_default_index_entry_label;
3860$index_summary     = \&t2h_default_index_summary;
3861$summary_letter    = \&t2h_default_summary_letter;
3862$index_entry       = \&t2h_default_index_entry;
3863$index_letter      = \&t2h_default_index_letter;
3864$print_index       = \&t2h_default_print_index;
3865$protect_text      = \&t2h_default_protect_text;
3866$normal_text       = \&t2h_default_normal_text;
3867$complex_format    = \&t2h_default_complex_format;
3868$cartouche         = \&t2h_default_cartouche;
3869$sp                = \&t2h_default_sp;
3870$definition_category      = \&t2h_default_definition_category;
3871$copying_comment          = \&t2h_default_copying_comment;
3872$index_summary_file_entry = \&t2h_default_index_summary_file_entry;
3873$index_summary_file_end   = \&t2h_default_index_summary_file_end;
3874$index_summary_file_begin = \&t2h_default_index_summary_file_begin;
3875$empty_line               = \&t2h_default_empty_line;
3876$unknown                  = \&t2h_default_unknown;
3877$unknown_style            = \&t2h_default_unknown_style;
3878$caption_shortcaption     = \&t2h_caption_shortcaption;
3879$float                     = \&t2h_default_float;
3880$listoffloats             = \&t2h_default_listoffloats;
3881$listoffloats_entry       = \&t2h_default_listoffloats_entry;
3882$listoffloats_caption     = \&t2h_default_listoffloats_caption;
3883$listoffloats_float_style = \&t2h_default_listoffloats_float_style;
3884$listoffloats_style       = \&t2h_default_listoffloats_style;
3885$acronym_like             = \&t2h_default_acronym_like;
3886$quotation                = \&t2h_default_quotation;
3887$quotation_prepend_text   = \&t2h_default_quotation_prepend_text;
3888$paragraph_style_command  = \&t2h_default_paragraph_style_command;
3889$heading_texi             = \&t2h_default_heading_texi;
3890$index_element_heading_texi = \&t2h_default_index_element_heading_texi;
3891
3892# This function is called whenever a complex format is processed
3893#
3894# arguments:
3895# name of the format
3896# text appearing inside the format
3897#
3898# an eval of $complex_format->{format name}->{'begin'} should lead to the
3899# beginning of the complex format, an eval of
3900# $complex_format->{format name}->{'end'}  should lead to the end of the
3901# complex format.
3902sub t2h_default_complex_format($$)
3903{
3904    my $name = shift;
3905    my $text = shift;
3906    return '' if ($text eq '');
3907    my $beginning = eval "$complex_format_map->{$name}->{'begin'}";
3908    if ($@ ne '')
3909    {
3910        print STDERR "$ERROR Evaluation of $complex_format_map->{$name}->{'begin'}: $@";
3911        $beginning = '';
3912
3913    }
3914    my $end = eval "$complex_format_map->{$name}->{'end'}";
3915    if ($@ ne '')
3916    {
3917        print STDERR "$ERROR Evaluation of $complex_format_map->{$name}->{'end'}: $@";
3918        $end = '';
3919
3920    }
3921    return $beginning . $text . $end;
3922}
3923
3924sub t2h_default_empty_line($$)
3925{
3926    my $text = shift;
3927    my $state = shift;
3928    #ignore the line if it just follows a deff
3929    return '' if ($state->{'deff_line'});
3930    return $text;
3931}
3932
3933sub t2h_default_unknown($$$$)
3934{
3935    my $macro = shift;
3936    my $line = shift;
3937    my $stack = shift;
3938    my $state = shift;
3939
3940    my ($result_line, $result, $result_text, $message);
3941    return ($line, 0, undef, undef);
3942}
3943
3944sub t2h_default_unknown_style($$$$)
3945{
3946    my $command = shift;
3947    my $text = shift;
3948    my $state = shift;
3949
3950    my ($result, $result_text, $message);
3951    return (0, undef, undef);
3952}
3953
3954sub t2h_caption_shortcaption($)
3955{
3956    my $float = shift;
3957    my $caption_lines;
3958    my $shortcaption_lines;
3959    my $style = $float->{'style_texi'};
3960    if (defined($float->{'nr'}))
3961    {
3962        my $nr = $float->{'nr'};
3963        if ($style ne '')
3964        {
3965            $style = &$I('%{style} %{number}', { 'style' => $style, 'number' => $nr});
3966        }
3967        else
3968        {
3969            $style = $nr;
3970        }
3971    }
3972
3973    if (defined($float->{'caption_texi'}))
3974    {
3975        @$caption_lines = @{$float->{'caption_texi'}};
3976        if (defined($style))
3977        {
3978            $caption_lines->[0] = '@strong{' . &$I('%{style}: %{caption_first_line}', { 'style' => $style, 'caption_first_line' => $caption_lines->[0] });
3979        }
3980        else
3981        {
3982            $caption_lines->[0] = '@strong{' .  $caption_lines->[0];
3983        }
3984        push @$caption_lines, "}\n";
3985    }
3986    elsif (defined($style))
3987    {
3988        $caption_lines->[0] = '@strong{' . $style . '}' . "\n";
3989    }
3990    if (defined($float->{'shortcaption_texi'}))
3991    {
3992         @$shortcaption_lines = @{$float->{'shortcaption_texi'}};
3993         if (defined($style))
3994         {
3995              $shortcaption_lines->[0] = '@strong{' . &$I('%{style}: %{shortcaption_first_line}', { 'style' => $style, 'shortcaption_first_line' => $shortcaption_lines->[0] });
3996         }
3997         else
3998         {
3999              $shortcaption_lines->[0] = '@strong{' .  $shortcaption_lines->[0];
4000         }
4001         push @$shortcaption_lines, "}\n";
4002    }
4003    elsif (defined($style))
4004    {
4005         $shortcaption_lines->[0] = '@strong{' . $style . '}' . "\n";
4006    }
4007    return ($caption_lines, $shortcaption_lines);
4008}
4009
4010sub t2h_default_float($$$$$)
4011{
4012    my $text = shift;
4013    my $float = shift;
4014    my $caption = shift;
4015    my $shortcaption = shift;
4016
4017    my $label = '';
4018    if (exists($float->{'id'}))
4019    {
4020        $label = &$anchor($float->{'id'});
4021    }
4022    my $caption_text = '';
4023
4024    if (defined($float->{'caption_texi'}))
4025    {
4026        $caption_text = $caption;
4027    }
4028    elsif (defined($float->{'shortcaption_texi'}))
4029    {
4030        $caption_text = $shortcaption;
4031    }
4032    elsif (defined($caption))
4033    {
4034        $caption_text = $caption;
4035    }
4036
4037    return '<div class="float">' . "$label\n" . $text . '</div>' . $caption_text;
4038}
4039
4040sub t2h_default_listoffloats_style($)
4041{
4042    my $style_texi = shift;
4043    return ($style_texi);
4044}
4045
4046sub t2h_default_listoffloats_float_style($$)
4047{
4048    my $style_texi = shift;
4049    my $float = shift;
4050
4051    my $style = $float->{'style_texi'};
4052    if (defined($float->{'nr'}))
4053    {
4054         my $nr = $float->{'nr'};
4055         if ($style ne '')
4056         {
4057              $style = &$I('%{style} %{number}', { 'style' => $style, 'number' => $nr});
4058         }
4059         else
4060         {
4061              $style = $nr;
4062         }
4063    }
4064    return $style;
4065}
4066
4067sub t2h_default_listoffloats_caption($)
4068{
4069    my $float = shift;
4070    if (defined($float->{'shortcaption_texi'}))
4071    {
4072         return [ @{$float->{'shortcaption_texi'}} ];
4073    }
4074    elsif (defined($float->{'caption_texi'}))
4075    {
4076         return [ @{$float->{'caption_texi'}} ];
4077    }
4078    return [ ];
4079}
4080
4081sub t2h_default_listoffloats_entry($$$$)
4082{
4083    my $style_texi = shift;
4084    my $float = shift;
4085    my $float_style = shift;
4086    my $caption = shift;
4087    my $href = shift;
4088
4089    return '<dt>' . &$anchor('', $href, $float_style) . '</dt><dd>' . $caption
4090. '</dd>' . "\n";
4091}
4092
4093sub t2h_default_listoffloats($$$)
4094{
4095    my $style_texi = shift;
4096    my $style = shift;
4097    my $float_entries = shift;
4098
4099    my $result = "<dl class=\"listoffloats\">\n" ;
4100    foreach my $float_entry (@$float_entries)
4101    {
4102         $result .= $float_entry;
4103    }
4104    return $result . "</dl>\n";
4105}
4106
4107# This function is used to protect characters which are special in html
4108# in inline text:  &, ", <, and >.
4109#
4110# argument:
4111# text to be protected
4112sub t2h_default_protect_text($)
4113{
4114   my $text = shift;
4115   $text =~ s/&/&amp;/g;
4116   $text =~ s/</&lt;/g;
4117   $text =~ s/>/&gt;/g;
4118   $text =~ s/\"/&quot;/g;
4119   return $text;
4120}
4121
4122
4123sub in_small_caps($)
4124{
4125   my $style_stack = shift;
4126   my $in_sc = 0;
4127   if ($style_stack and scalar(@{$style_stack}))
4128   {
4129       my $level = $#$style_stack;
4130       #print STDERR ":::$level ::@{$style_stack}\n";
4131       while ($level >= 0)
4132       {
4133           if ($style_stack->[$level] eq 'sc')
4134           {
4135               $in_sc = 1;
4136               last;
4137           }
4138           $level--;
4139       }
4140   }
4141   return $in_sc;
4142}
4143#
4144#
4145sub t2h_default_normal_text($$$$$)
4146{
4147   my $text = shift;
4148   my $in_raw_text = shift;
4149   my $in_preformatted = shift;
4150   my $in_code = shift;
4151   my $style_stack = shift;
4152   $text = uc($text) if (in_small_caps($style_stack));
4153   $text = &$protect_text($text) unless($in_raw_text);
4154   if (! $in_code and !$in_preformatted)
4155   {
4156       if ($USE_ISO and !$in_raw_text)
4157       {
4158           $text =~ s/---/\&mdash\;/g;
4159           $text =~ s/--/\&ndash\;/g;
4160           $text =~ s/``/\&ldquo\;/g;
4161           $text =~ s/''/\&rdquo\;/g;
4162       }
4163       else
4164       {
4165            if ($in_raw_text) #FIXME really do that ?
4166            {
4167                 $text =~ s/``/"/g;
4168                 $text =~ s/''/"/g;
4169            }
4170            else
4171            {
4172                $text =~ s/``/&quot;/g;
4173                $text =~ s/''/&quot;/g;
4174            }
4175            # temporary reuse '' to store --- !....
4176            # FIXME won't '---' be handled wrongly?
4177            # FIXME really do that in raw text?
4178            $text =~ s/---/''/g;
4179            $text =~ s/--/-/g;
4180            $text =~ s/''/--/g;
4181       }
4182   }
4183   return $text;
4184}
4185
4186# This function produces an anchor
4187#
4188# arguments:
4189# $name           :   anchor name
4190# $href           :   anchor href
4191# text            :   text displayed
4192# extra_attribs   :   added to anchor attributes list
4193sub t2h_default_anchor($;$$$)
4194{
4195    my $name = shift;
4196    my $href = shift;
4197    my $text = shift;
4198    my $attributes = shift;
4199#print STDERR "!$name!$href!$text!$attributes!\n";
4200    if (!defined($attributes) or ($attributes !~ /\S/))
4201    {
4202        $attributes = '';
4203    }
4204    else
4205    {
4206        $attributes = ' ' . $attributes;
4207    }
4208    $name = '' if (!defined($name) or ($name !~ /\S/));
4209    $href = '' if (!defined($href) or ($href !~ /\S/));
4210    $text = '' if (!defined($text));
4211    return $text if (($name eq '') and ($href eq ''));
4212    $name = "name=\"$name\"" if ($name ne '');
4213    $href = "href=\"$href\"" if ($href ne '');
4214    $href = ' ' . $href if (($name ne '') and ($href ne ''));
4215#print STDERR "!!!$name!$href!$text!$attributes!\n";
4216    return "<a ${name}${href}${attributes}>$text</a>";
4217}
4218
4219# This function is used to format the text associated with a @deff/@end deff
4220#
4221# argument:
4222# text
4223#
4224# $DEF_TABLE should be used to distinguish between @def formatted as table
4225# and as definition lists.
4226sub t2h_default_def_item($)
4227{
4228    my $text = shift;
4229    if ($text =~ /\S/)
4230    {
4231        if (! $DEF_TABLE)
4232        {
4233            return '<dd>' . $text . '</dd>';
4234        }
4235        else
4236        {
4237            return '<tr><td colspan="2">' . $text . '</td></tr>';
4238        }
4239    }
4240    return '';
4241}
4242
4243sub t2h_default_definition_category($$$)
4244{
4245    my $name = shift;
4246    my $class = shift;
4247    my $style = shift;
4248    return ($name) if (!defined($class) or $class =~ /^\s*$/);
4249    if ($style eq 'f')
4250    {
4251        return &$I('%{name} on %{class}', { 'name' => $name, 'class' => $class });
4252    }
4253    elsif ($style eq 'v')
4254    {
4255        return &$I('%{name} of %{class}', { 'name' => $name, 'class' => $class });
4256    }
4257    else
4258    {
4259        return $name;
4260    }
4261}
4262
4263# format the container for the @deffn line and text
4264#
4265# argument
4266# text of the whole @def, line and associated text.
4267#
4268# $DEF_TABLE should be used.
4269sub t2h_default_def($)
4270{
4271    my $text = shift;
4272    if ($text =~ /\S/)
4273    {
4274        if (! $DEF_TABLE)
4275        {
4276            return "<dl>\n" . $text . "</dl>\n";
4277        }
4278        else
4279        {
4280            return "<table width=\"100%\">\n" . $text . "</table>\n";
4281        }
4282    }
4283    return '';
4284
4285}
4286
4287# a whole menu
4288#
4289# argument:
4290# the whole menu text (entries and menu comments)
4291#
4292# argument:
4293# whole menu text.
4294sub t2h_default_menu($)
4295{
4296    my $text = shift;
4297    if ($text =~ /\S/)
4298    {
4299        return "<table class=\"menu\" border=\"0\" cellspacing=\"0\">\n"
4300        . $text . "</table>\n";
4301    }
4302}
4303
4304# a simple menu entry ref in case we aren't in a standard menu context
4305sub t2h_default_simple_menu_link($$$$$$)
4306{
4307    my $entry = shift;
4308    my $preformatted = shift;
4309    my $href = shift;
4310    my $node = shift;
4311    my $name = shift;
4312    my $ending = shift;
4313    $ending = '' if (!defined($ending));
4314    if (($entry eq '') or $NODE_NAME_IN_MENU or $preformatted)
4315    {
4316        $name .= ':' if ($name ne '');
4317        $entry = "$MENU_SYMBOL$name$node";
4318    }
4319    $entry = &$anchor('', $href, $entry) if ($href);
4320    $entry .= $ending if ($preformatted);
4321    $entry .= '&nbsp;' unless $preformatted;
4322    return $entry;
4323}
4324
4325# formats a menu entry link pointing to a node or section
4326#
4327# arguments:
4328# the entry text
4329# the state, a hash reference holding informations about the context, with a
4330#     usefull entry, 'preformatted', true if we are in a preformatted format
4331#     (a format keeping space between words). In that case a function
4332#     of the main program, main::do_preformatted($text, $state) might
4333#     be used to format the text with the current format style.
4334# href is optionnal. It is the reference to the section or the node anchor
4335#     which should be used to make the link (typically it is the argument
4336#     of a href= attribute in a <a> element).
4337sub t2h_default_menu_link($$$$$$)
4338{
4339    my $entry = shift;
4340    my $state = shift;
4341    my $href = shift;
4342    my $node = shift;
4343    my $name = shift;
4344    my $ending = shift;
4345#print STDERR  "MENU_LINK\n";
4346    if (($entry eq '') or $NODE_NAME_IN_MENU or $state->{'preformatted'})
4347    {
4348        $name .= ':' if ($name ne '');
4349        $entry = "$MENU_SYMBOL$name$node";
4350    }
4351    $entry = &$anchor ('', $href, $entry) if (defined($href));
4352    return $entry if ($SIMPLE_MENU);
4353    if ($state->{'preformatted'})
4354    {
4355        return '<tr><td>' . main::do_preformatted($entry . $ending, $state);
4356    }
4357    return "<tr><td align=\"left\" valign=\"top\">$entry</td><td>&nbsp;&nbsp;</td>";
4358}
4359
4360sub simplify_text($)
4361{
4362    my $text = shift;
4363    $text =~ s/[^\w]//og;
4364    return $text;
4365}
4366
4367# formats a menu entry description, ie the text appearing after the node
4368# specification in a menu entry an spanning until there is another
4369# menu entry, an empty line or some text at the very beginning of the line
4370# (we consider that text at the beginning of the line begins a menu comment)
4371#
4372# arguments:
4373# the description text
4374# the state. See menu_entry.
4375# the heading of the element associated with the node.
4376sub t2h_default_menu_description($$$)
4377{
4378    my $text = shift;
4379    my $state = shift;
4380    my $element_text = shift;
4381    return $text if ($SIMPLE_MENU);
4382#print STDERR  "MENU_DESCRIPTION element_text!$element_text, text!$text\n";
4383    if ($state->{'preformatted'})
4384    {
4385        return main::do_preformatted($text, $state) . '</td></tr>';
4386    }
4387    elsif ($AVOID_MENU_REDUNDANCY)
4388    {
4389        $text = '' if (simplify_text($element_text) eq simplify_text($text));
4390    }
4391    return "<td align=\"left\" valign=\"top\">$text</td></tr>\n";
4392}
4393
4394# a menu comment (between menu lines)
4395# formats the container of a menu comment. A menu comment is any text
4396# appearing between menu lines, either separated by an empty line from
4397# the preceding menu entry, or a text beginning at the first character
4398# of the line (text not at the very beginning of the line is considered to
4399# be the continuation of a menu entry description text).
4400#
4401# The text itself is considered to be in a preformatted environment
4402# with name 'menu-commment' and with style $MENU_PRE_STYLE.
4403#
4404# argument
4405# text contained in the menu comment.
4406sub t2h_default_menu_comment($)
4407{
4408   my $text = shift;
4409   return $text if ($SIMPLE_MENU);
4410   if ($text =~ /\S/)
4411   {
4412       return "<tr><th colspan=\"3\" align=\"left\" valign=\"top\">$text</th></tr>";
4413   }
4414   return '';
4415}
4416
4417# Construct a href to an external source of information.
4418# node is the node with texinfo @-commands
4419# node_id is the node transliterated and transformed as explained in the
4420#         texinfo manual
4421# node_xhtml_id is the node transformed such that it is unique and can
4422#     be used to make an html cross ref as explained in the texinfo manual
4423# file is the file in '(file)node'
4424sub t2h_default_external_href($$$)
4425{
4426    my $node = shift;
4427    my $node_id = shift;
4428    my $node_xhtml_id = shift;
4429    my $file = shift;
4430    $file = '' if (!defined($file));
4431    my $default_target_split = $EXTERNAL_CROSSREF_SPLIT;
4432    my $target_split;
4433    my $target_mono;
4434    my $href_split;
4435    my $href_mono;
4436    if ($file ne '')
4437    {
4438         if ($NEW_CROSSREF_STYLE)
4439         {
4440             $file =~ s/\.[^\.]*$//;
4441             $file =~ s/^.*\///;
4442             my $href;
4443             if (exists($Texi2HTML::THISDOC{'htmlxref'}->{$file}))
4444             {
4445                  if (exists($Texi2HTML::THISDOC{'htmlxref'}->{$file}->{'split'}))
4446                  {
4447                       $target_split = 1;
4448                       $href_split =  $Texi2HTML::THISDOC{'htmlxref'}->{$file}->{'split'}->{'href'};
4449                  }
4450                  if (exists($Texi2HTML::THISDOC{'htmlxref'}->{$file}->{'mono'}))
4451                  {
4452                       $target_mono = 1;
4453                       $href_mono =  $Texi2HTML::THISDOC{'htmlxref'}->{$file}->{'mono'}->{'href'};
4454                  }
4455             }
4456
4457             if ((not $target_mono) and (not $target_split))
4458             { # nothing specified for that manual, use default
4459                  $target_split = $default_target_split;
4460             }
4461             elsif ($target_split and $target_mono)
4462             { # depends on the splitting of the manual
4463                  $target_split = $SPLIT;
4464             }
4465             elsif ($target_mono)
4466             { # only mono specified
4467                  $target_split = 0;
4468             }
4469
4470             if ($target_split)
4471             {
4472                  if (defined($href_split))
4473                  {
4474                       $file = "$href_split";
4475                  }
4476                  elsif (defined($EXTERNAL_DIR))
4477                  {
4478                       $file = "$EXTERNAL_DIR/$file";
4479                  }
4480                  elsif ($SPLIT)
4481                  {
4482                       $file = "../$file";
4483                  }
4484                  $file .= "/";
4485             }
4486             else
4487             {# target not split
4488                  if (defined($href_mono))
4489                  {
4490                       $file = "$href_mono";
4491                  }
4492                  else
4493                  {
4494                       if (defined($EXTERNAL_DIR))
4495                       {
4496                            $file = "$EXTERNAL_DIR/$file";
4497                       }
4498                       elsif ($SPLIT)
4499                       {
4500                           $file = "../$file";
4501                       }
4502                       $file .= "." . $NODE_FILE_EXTENSION;
4503                  }
4504             }
4505         }
4506         else
4507         {
4508             $file .= "/";
4509             if (defined($EXTERNAL_DIR))
4510             {
4511                 $file = $EXTERNAL_DIR . $file;
4512             }
4513             else
4514             {
4515                 $file = '../' . $file;
4516             }
4517         }
4518    }
4519    else
4520    {
4521        $target_split = $default_target_split;
4522    }
4523    if ($node eq '')
4524    {
4525         if ($NEW_CROSSREF_STYLE)
4526         {
4527             if ($target_split)
4528             {
4529                 return $file . $TOP_NODE_FILE . '.' . $NODE_FILE_EXTENSION . '#Top';
4530                 # or ?
4531                 #return $file . '#Top';
4532             }
4533             else
4534             {
4535                  return $file . '#Top';
4536             }
4537         }
4538         else
4539         {
4540             return $file;
4541         }
4542    }
4543    my $target;
4544    if ($NEW_CROSSREF_STYLE)
4545    {
4546         $node = $node_id;
4547         $target = $node_xhtml_id;
4548    }
4549    else
4550    {
4551         $node = main::remove_texi($node);
4552         $node =~ s/[^\w\.\-]/-/g;
4553    }
4554    my $file_basename = $node;
4555    $file_basename = $TOP_NODE_FILE if ($node =~ /^top$/i);
4556    if ($NEW_CROSSREF_STYLE)
4557    {
4558        if ($target_split)
4559        {
4560            return $file . $file_basename . ".$NODE_FILE_EXTENSION" . '#' . $target;
4561        }
4562        else
4563        {
4564            return $file . '#' . $target;
4565        }
4566    }
4567    else
4568    {
4569        return $file . $file_basename . ".$NODE_FILE_EXTENSION";
4570    }
4571}
4572
4573# format a reference external to the generated manual. This produces a full
4574# reference with introductive words and the reference itself.
4575#
4576# arguments:
4577# type of the reference: xref (reference at the beginning of a sentence),
4578#     pxref (reference in a parenthesis),
4579# section in the book. This might be undef.
4580# book name.
4581# node and file name formatted according to the convention used in info
4582#     '(file)node' and no node means the Top node.
4583# href linking to the html page containing the referenced node. A typical
4584#     use for this href is a href attribute in an <a> element
4585# an optionnal cross reference name
4586sub t2h_default_external_ref($$$$$$)
4587{
4588    my $type = shift;
4589    my $section = shift;
4590    my $book = shift;
4591    my $file_node = shift;
4592    my $href = shift;
4593    my $cross_ref = shift;
4594
4595    $file_node = "$cross_ref: $file_node" if (($file_node ne '') and ($cross_ref ne ''));
4596    $file_node = &$anchor('', $href, $file_node) if ($file_node ne '');
4597
4598    # Yes, this is ugly, but this helps internationalization
4599    if ($type eq 'pxref')
4600    {
4601         if (($book ne '') and ($file_node ne ''))
4602         {
4603              return &$I('see %{node_file_href} section `%{section}\' in @cite{%{book}}', { 'node_file_href' => $file_node, 'book' => $book, 'section' => $section }) if ($section ne '');
4604              return &$I('see %{node_file_href} @cite{%{book}}', { 'node_file_href' => $file_node, 'book' => $book });
4605         }
4606         elsif ($book ne '')
4607         {
4608              return &$I('see section `%{section}\' in @cite{%{book}}', { 'book' => $book, 'section' => $section }) if ($section ne '');
4609              return &$I('see @cite{%{book}}', { 'book' => $book });
4610         }
4611         elsif ($file_node ne '')
4612         {
4613              return &$I('see %{node_file_href}', { 'node_file_href' => $file_node });
4614         }
4615    }
4616    if ($type eq 'xref')
4617    {
4618         if (($book ne '') and ($file_node ne ''))
4619         {
4620              return &$I('See %{node_file_href} section `%{section}\' in @cite{%{book}}', { 'node_file_href' => $file_node, 'book' => $book, 'section' => $section }) if ($section ne '');
4621              return &$I('See %{node_file_href} @cite{%{book}}', { 'node_file_href' => $file_node, 'book' => $book });
4622         }
4623         elsif ($book ne '')
4624         {
4625              return &$I('See section `%{section}\' in @cite{%{book}}', { 'book' => $book, 'section' => $section }) if ($section ne '');
4626              return &$I('See @cite{%{book}}', { 'book' => $book });
4627         }
4628         elsif ($file_node ne '')
4629         {
4630              return &$I('See %{node_file_href}', { 'node_file_href' => $file_node });
4631         }
4632    }
4633    if ($type eq 'ref')
4634    {
4635         if (($book ne '') and ($file_node ne ''))
4636         {
4637              return &$I('%{node_file_href} section `%{section}\' in @cite{%{book}}', { 'node_file_href' => $file_node, 'book' => $book, 'section' => $section }) if ($section ne '');
4638              return &$I('%{node_file_href} @cite{%{book}}', { 'node_file_href' => $file_node, 'book' => $book });
4639         }
4640         elsif ($book ne '')
4641         {
4642              return &$I('section `%{section}\' in @cite{%{book}}', { 'book' => $book, 'section' => $section }) if ($section ne '');
4643              return &$I('@cite{%{book}}', { 'book' => $book });
4644         }
4645         elsif ($file_node ne '')
4646         {
4647              return &$I('%{node_file_href}', { 'node_file_href' => $file_node });
4648         }
4649    }
4650    return '';
4651}
4652
4653# format a reference to a node or a section in the generated manual. This
4654# produces a full reference with introductive words and the reference itself.
4655#
4656# arguments:
4657# type of the reference: xref (reference at the beginning of a sentence),
4658#     pxref (reference in a parenthesis),
4659# href linking to the html page containing the node or the section. A typical
4660#     use for this href is a href attribute in an <a> element
4661# short name for this reference
4662# name for this reference
4663# boolean true if the reference is a reference to a section
4664#
4665# $SHORT_REF should be used.
4666sub t2h_default_internal_ref($$$$$)
4667{
4668    my $type = shift;
4669    my $href = shift;
4670    my $short_name = shift;
4671    my $name = shift;
4672    my $is_section = shift;
4673
4674    if (! $SHORT_REF)
4675    {
4676        $name = &$anchor('', $href, $name);
4677        if ($type eq 'pxref')
4678        {
4679            return &$I('see section %{reference_name}', { 'reference_name' => $name }) if ($is_section);
4680            return &$I('see %{reference_name}', { 'reference_name' => $name });
4681        }
4682        elsif ($type eq 'xref')
4683        {
4684            return &$I('See section %{reference_name}', { 'reference_name' => $name }) if ($is_section);
4685            return &$I('See %{reference_name}', { 'reference_name' => $name });
4686        }
4687        elsif ($type eq 'ref')
4688        {
4689            return &$I('%{reference_name}', { 'reference_name' => $name });
4690        }
4691    }
4692    else
4693    {
4694        $name = &$anchor('', $href, $short_name);
4695        if ($type eq 'pxref')
4696        {
4697            return &$I('see %{reference_name}', { 'reference_name' => $name });
4698        }
4699        elsif ($type eq 'xref')
4700        {
4701            return &$I('See %{reference_name}', { 'reference_name' => $name });
4702        }
4703        elsif ($type eq 'ref')
4704        {
4705            return &$I('%{reference_name}', { 'reference_name' => $name });
4706        }
4707    }
4708    return '';
4709}
4710
4711sub teletyped_in_stack($)
4712{
4713    my $stack = shift;
4714    foreach my $element(reverse(@$stack))
4715    {
4716        if ($complex_format_map->{$element})
4717        {
4718            if (!$complex_format_map->{$element}->{'pre_style'})
4719            {
4720                return 1;
4721            }
4722            else
4723            {
4724                return 0;
4725            }
4726        }
4727    }
4728    return 0;
4729}
4730
4731# text after @item in table, vtable and ftable
4732sub t2h_default_table_item($$$$$$)
4733{
4734    my $text = shift;
4735    my $index_label = shift;
4736    my $format = shift;
4737    my $command = shift;
4738    my $formatted_command = shift;
4739    my $style_stack = shift;
4740    #print STDERR "-> $format (@$style_stack)\n";
4741    $formatted_command = '' if (!defined($formatted_command) or
4742          exists($special_list_commands{$format}->{$command}));
4743    if (teletyped_in_stack($style_stack))
4744    {
4745       $text .= '</tt>';
4746       $formatted_command = '<tt>' . $formatted_command;
4747    }
4748    $text .= "\n" . $index_label  if (defined($index_label));
4749    return '<dt>' . $formatted_command . $text . '</dt>' . "\n";
4750}
4751
4752# format text on the line following the @item line (in table, vtable and ftable)
4753sub t2h_default_table_line($)
4754{
4755    my $text = shift;
4756
4757    if ($text =~ /\S/)
4758    {
4759         return '<dd>' . $text . '</dd>' . "\n";
4760    }
4761    return '';
4762}
4763
4764# row in multitable
4765sub t2h_default_row($$)
4766{
4767    my $text = shift;
4768    my $macro = shift;
4769
4770    if ($text =~ /\S/)
4771    {
4772         if ($macro eq 'headitem')
4773         {
4774              return '<thead><tr>' . $text . '</tr></thead>' . "\n";
4775         }
4776         return '<tr>' . $text . '</tr>' . "\n";
4777    }
4778    return '';
4779}
4780
4781# cell in multitable
4782sub t2h_default_cell($$)
4783{
4784    my $text = shift;
4785    my $row_macro = shift;
4786
4787    if ($row_macro eq 'headitem')
4788    {
4789        return '<th>' . $text . '</th>';
4790    }
4791    return '<td>' . $text . '</td>';
4792}
4793
4794# format an item in a list
4795#
4796# argument:
4797# text of the item
4798# format of the list (itemize or enumerate)
4799# command passed as argument to the format
4800# formatted_command leading command formatted, if it is a thing command
4801sub t2h_default_list_item($$$$$$$)
4802{
4803    my $text = shift;
4804    my $format = shift;
4805    my $command = shift;
4806    my $formatted_command = shift;
4807    my $item_nr = shift;
4808    my $enumerate_style = shift;
4809    my $number = shift;
4810
4811    $formatted_command = '' if (!defined($formatted_command) or
4812          exists($special_list_commands{$format}->{$command}));
4813    if ($text =~ /\S/)
4814    {
4815        return '<li>' . $formatted_command . $text . '</li>';
4816    }
4817    return '';
4818}
4819
4820sub t2h_default_table_list($$$$$$)
4821{
4822    my $format = shift;
4823    my $text = shift;
4824    my $command = shift;
4825    my $formatted_command = shift;
4826    my $item_nr = shift;
4827    my $enumerate_style = shift;
4828    my $number = shift;
4829    $formatted_command = '' if (!defined($formatted_command) or
4830          exists($special_list_commands{$format}->{$command}));
4831    if ($format eq 'itemize')
4832    {
4833        return "<ul>\n" . $text . "</ul>\n" if ($command eq 'bullet');
4834        return "<ul$TOC_LIST_ATTRIBUTE>\n" . $text . "</ul>\n";
4835    }
4836}
4837
4838# an html comment
4839sub t2h_default_comment($)
4840{
4841    my $text = shift;
4842    $text =~ s/--+/-/go;
4843    return '<!-- ' . $text . ' -->' . "\n";
4844}
4845
4846sub t2h_collect_styles($)
4847{
4848    my $stack = shift;
4849    my @result = ();
4850    foreach my $style (reverse(@$stack))
4851    {
4852#        last unless (defined($command_type{$style}) and $command_type{$style} eq 'style');
4853        push @result, $style if (defined($command_type{$style}) and $command_type{$style} eq 'style');
4854    }
4855    return @result;
4856}
4857
4858sub t2h_get_attribute($;$)
4859{
4860    my $command = shift;
4861    my $map_ref = shift;
4862    $map_ref = \%style_map if (!defined($map_ref));
4863    return '' unless (defined($map_ref->{$command}));
4864    if ((ref($map_ref->{$command}) eq 'HASH')
4865       and exists($map_ref->{$command}->{'attribute'}))
4866    {
4867        return $map_ref->{$command}->{'attribute'};
4868    }
4869    elsif ($map_ref->{$command} !~ /^&/)
4870    {
4871        my $attribute = $map_ref->{$command};
4872        $attribute =~ s/^\"//;
4873        return $attribute;
4874    }
4875    return '';
4876}
4877
4878sub t2h_begin_style($$;$)
4879{
4880    my $command = shift;
4881    my $text = shift;
4882    my $map_ref = shift;
4883    my $attribute = t2h_get_attribute($command,$map_ref);
4884    $attribute = "<$attribute>" if ($attribute ne '');
4885    return $attribute.$text;
4886}
4887
4888sub t2h_end_style($$;$)
4889{
4890    my $command = shift;
4891    my $text = shift;
4892    my $map_ref = shift;
4893    my $attribute = t2h_get_attribute($command,$map_ref);
4894    if ($attribute =~ /^(\w+)/)
4895    {
4896        $attribute = $1;
4897    }
4898    $attribute = "</$attribute>" if ($attribute ne '');
4899    return $text.$attribute;
4900}
4901
4902# a paragraph
4903# arguments:
4904# $text of the paragraph
4905# $align for the alignement
4906# $indent for the indent style (indent or noindent)
4907# The following is usefull if the paragraph is in an itemize.
4908# $paragraph_command is the leading formatting command (like @minus)
4909# $paragraph_command_formatted is the leading formatting command formatted
4910# $paragraph_number is a reference on the number of paragraphs appearing
4911#    in the format. The value should be increased if a paragraph is done
4912# $format is the format name (@itemize)
4913sub t2h_default_paragraph($$$$$$$$$$$$)
4914{
4915    my $text = shift;
4916    my $align = shift;
4917    my $indent = shift;
4918    my $paragraph_command = shift;
4919    my $paragraph_command_formatted = shift;
4920    my $paragraph_number = shift;
4921    my $format = shift;
4922    my $item_nr = shift;
4923    my $enumerate_style = shift;
4924    my $number = shift;
4925    my $command_stack_at_end = shift;
4926    my $command_stack_at_begin = shift;
4927#print STDERR "format: $format\n" if (defined($format));
4928#print STDERR "paragraph @$command_stack_at_end; @$command_stack_at_begin\n";
4929    $paragraph_command_formatted = '' if (!defined($paragraph_command_formatted) or
4930          exists($special_list_commands{$format}->{$paragraph_command}));
4931    return '' if ($text =~ /^\s*$/);
4932    foreach my $style(t2h_collect_styles($command_stack_at_begin))
4933    {
4934       $text = t2h_begin_style($style, $text);
4935    }
4936    foreach my $style(t2h_collect_styles($command_stack_at_end))
4937    {
4938       $text = t2h_end_style($style, $text);
4939    }
4940    if (defined($paragraph_number) and defined($$paragraph_number))
4941    {
4942         $$paragraph_number++;
4943         return $text  if (($format eq 'itemize' or $format eq 'enumerate') and
4944            ($$paragraph_number == 1));
4945    }
4946    my $open = '<p>';
4947    if ($align)
4948    {
4949        $open = "<p align=\"$paragraph_style{$align}\">";
4950    }
4951    return $open.$text.'</p>';
4952}
4953
4954# a preformatted region
4955# arguments:
4956# $text of the preformatted region
4957# $pre_style css style
4958# $class identifier for the preformatted region (example, menu-comment)
4959# The following is usefull if the preformatted is in an itemize.
4960# $leading_command is the leading formatting command (like @minus)
4961# $leading_command_formatted is the leading formatting command formatted
4962# $preformatted_number is a reference on the number of preformatteds appearing
4963#    in the format. The value should be increased if a preformatted is done
4964sub t2h_default_preformatted($$$$$$$$$$$$)
4965{
4966    my $text = shift;
4967    my $pre_style = shift;
4968    my $class = shift;
4969    my $leading_command = shift;
4970    my $leading_command_formatted = shift;
4971    my $preformatted_number = shift;
4972    my $format = shift;
4973    my $item_nr = shift;
4974    my $enumerate_style = shift;
4975    my $number = shift;
4976    my $command_stack_at_end = shift;
4977    my $command_stack_at_begin = shift;
4978
4979#print STDERR "preformatted @$command_stack_at_end; @$command_stack_at_begin\n";
4980    return '' if ($text eq '');
4981    $leading_command_formatted = '' if (!defined($leading_command_formatted) or
4982          exists($special_list_commands{$format}->{$leading_command}));
4983    if (defined($preformatted_number) and defined($$preformatted_number))
4984    {
4985        $$preformatted_number++;
4986    }
4987    foreach my $style(t2h_collect_styles($command_stack_at_begin))
4988    {
4989       $text = t2h_begin_style($style, $text, \%style_map_pre);
4990    }
4991    foreach my $style(t2h_collect_styles($command_stack_at_end))
4992    {
4993       $text = t2h_end_style($style, $text, \%style_map_pre);
4994    }
4995    return "<pre class=\"$class\">".$text."</pre>";
4996}
4997
4998# This function formats a heading for an element
4999#
5000# argument:
5001# an element. It is a hash reference for a node or a sectionning command.
5002# The interesting keys are:
5003# 'text': the heading text
5004# 'text_nonumber': the heading text without section number
5005# 'node': true if it is a node
5006# 'level': level of the element. 0 for @top, 1 for chapter, heading,
5007#      appendix..., 2 for section and so on...
5008# 'tag_level': the sectionning element name, raisesections and lowersections
5009#      taken into account
5010sub t2h_default_heading($)
5011{
5012    my $element = shift;
5013    my $level = 3;
5014    if (!$element->{'node'})
5015    {
5016        $level = $element->{'level'};
5017    }
5018    $level = 1 if ($level == 0);
5019    my $text = $element->{'text'};
5020    return '' if ($text !~ /\S/);
5021    my $class = $element->{'tag_level'};
5022    $class = 'unnumbered' if ($class eq 'top');
5023    if (defined($element->{'tocid'}) and $TOC_LINKS)
5024    {
5025         $text = &$anchor ('', "$Texi2HTML::THISDOC{'toc_file'}#$element->{'tocid'}", $text);
5026    }
5027    my $align = '';
5028    $align = ' align="center"' if ($element->{'tag'} eq 'centerchap');
5029    return "<h$level class=\"$class\"$align> $text </h$level>\n";
5030}
5031
5032# formatting of raw regions
5033# if L2H is true another mechanism is used for tex
5034sub t2h_default_raw($$)
5035{
5036    my $style = shift;
5037    my $text = shift;
5038    if ($style eq 'verbatim' or $style eq 'tex')
5039    {
5040        return "<pre class=\"$style\">" . &$protect_text($text) . '</pre>';
5041    }
5042    elsif ($style eq 'html')
5043    {
5044        return $text;
5045    }
5046    else
5047    {
5048        warn "$WARN (bug) unknown style $style\n";
5049        return &$protect_text($text);
5050    }
5051}
5052
5053# raw environment when removing texi (in comments)
5054sub t2h_default_raw_no_texi($$)
5055{
5056    my $style = shift;
5057    my $text = shift;
5058    return $text;
5059}
5060
5061# This function formats a footnote reference and the footnote text associated
5062# with a given footnote.
5063# The footnote reference is the text appearing in the main document pointing
5064# to the footnote text.
5065#
5066# arguments:
5067# absolute number of the footnote (in the document)
5068# relative number of the footnote (in the page)
5069# identifier for the footnote
5070# identifier for the footnote reference in the main document
5071# main document file
5072# footnote text file
5073# array with the footnote text lines
5074# the state. See menu entry.
5075#
5076# returns:
5077# reference on an array containing the footnote text lines which should
5078#     have been updated
5079# the text for the reference pointing on the footnote text
5080sub t2h_default_foot_line_and_ref($$$$$$$)
5081{
5082    my $number_in_doc = shift;
5083    my $number_in_page = shift;
5084    my $footnote_id = shift;
5085    my $place_id = shift;
5086    my $document_file = shift;
5087    my $footnote_file = shift;
5088    my $lines = shift;
5089    my $state = shift;
5090
5091    unshift (@$lines, '<h3>' .
5092          &$anchor($footnote_id, $document_file . "#$place_id",
5093                   "($number_in_doc)")
5094          . "</h3>\n");
5095    return ($lines, &$anchor($place_id,  $footnote_file . "#$footnote_id",
5096           "($number_in_doc)"));
5097}
5098
5099# formats a group of footnotes.
5100#
5101# argument:
5102# array reference on the footnotes texts lines
5103#
5104# returns an array reference on the group of footnotes lines
5105sub t2h_default_foot_section($)
5106{
5107    my $lines = shift;
5108    unshift (@$lines, "<div class=\"footnote\">\n" ,"$DEFAULT_RULE\n", "<h3>" . &$I('Footnotes') . "</h3>\n");
5109    push (@$lines, "</div>\n");
5110    return $lines;
5111}
5112
5113sub t2h_default_image_files($$)
5114{
5115    my $base = shift;
5116    my $extension = shift;
5117    my @files = ();
5118    return @files if (!defined($base) or ($base eq ''));
5119    push @files,"$base.$extension" if (defined($extension) and ($extension ne ''));
5120    foreach my $ext (@IMAGE_EXTENSIONS)
5121    {
5122        push @files, "$base.$ext";
5123    }
5124    return @files;
5125}
5126
5127# format an image
5128#
5129# arguments:
5130# image file name with path
5131# image basename
5132# a boolean true if we are in a preformatted format
5133# image file name without path
5134# alt text
5135# width
5136# height
5137# raw alt
5138# extension
5139# path to working dir
5140# path to file relative from working dir
5141sub t2h_default_image($$$$$$$$$$$)
5142{
5143    my $file = shift;
5144    my $base = shift;
5145    my $preformatted = shift;
5146    my $file_name = shift;
5147    my $alt = shift;
5148    my $width = shift;
5149    my $height = shift;
5150    my $raw_alt = shift;
5151    my $extension = shift;
5152    my $working_dir = shift;
5153    my $file_path = shift;
5154
5155    if (!defined($file_path) or $file_path eq '')
5156    {
5157        if (defined($extension) and $extension ne '')
5158        {
5159            $file = "$base.$extension";
5160        }
5161        else
5162        {
5163            $file = "$base.jpg";
5164        }
5165        main::echo_warn ("no image file for $base, (using $file)");
5166    }
5167    $alt = &$protect_text($base) if (!defined($alt) or ($alt eq ''));
5168    return "[ $alt ]" if ($preformatted);
5169    # it is possible that $file_name is more correct as it allows the user
5170    # to chose the relative path.
5171    $file = &$protect_text($file);
5172    return "<img src=\"$file\" alt=\"$alt\">";
5173}
5174
5175# address put in footer describing when was generated and who did the manual
5176sub t2h_default_address($$)
5177{
5178    my $user = shift;
5179    my $date = shift;
5180    $user = '' if (!defined($user));
5181    $date = '' if (!defined($date));
5182    if (($user ne '') and ($date ne ''))
5183    {
5184        return &$I('by @emph{%{user}} on @emph{%{date}}', { 'user' => $user,
5185            'date' => $date });
5186    }
5187    elsif ($user ne '')
5188    {
5189        return &$I('by @emph{%{user}}', { 'user' => $user });
5190    }
5191    elsif ($date ne '')
5192    {
5193        return &$I('on @emph{%{date}}', { 'date' => $date });
5194    }
5195    return '';
5196}
5197
5198# format a target in the main document for an index entry.
5199#
5200# arguments:
5201# target identifier
5202# boolean true if in preformatted format
5203# FIXME document the remaining
5204sub t2h_default_index_entry_label($$)
5205{
5206    my $identifier = shift;
5207    my $preformatted = shift;
5208
5209    return '' if (!defined($identifier) or ($identifier !~ /\S/));
5210    my $label = &$anchor($identifier);
5211    return $label . "\n" if (!$preformatted);
5212    return $label;
5213}
5214
5215# process definition commands line @deffn for example
5216sub t2h_default_def_line($$$$$)
5217{
5218   my $category = shift;
5219   my $name = shift;
5220   my $type = shift;
5221   my $arguments = shift;
5222   my $index_label = shift;
5223   $index_label = '' if (!defined($index_label));
5224   $category = '' if (!defined($category) or ($category =~ /^\s*$/));
5225   $name = '' if (!defined($name) or ($name =~ /^\s*$/));
5226   $type = '' if (!defined($type) or $type =~ /^\s*$/);
5227   if (!defined($arguments) or $arguments =~ /^\s*$/)
5228   {
5229       $arguments = '';
5230   }
5231   else
5232   {
5233       chomp ($arguments);
5234       $arguments = '<i>' . $arguments . '</i>';
5235   }
5236   my $type_name = '';
5237   $type_name = " $type" if ($type ne '');
5238   $type_name .= ' <b>' . $name . '</b>' if ($name ne '');
5239   $type_name .= $arguments . "\n";
5240   if (! $DEF_TABLE)
5241   {
5242       return '<dt>'. '<u>' . $category . ':</u>' . $type_name . $index_label . "</dt>\n";
5243   }
5244   else
5245   {
5246
5247       return "<tr>\n<td align=\"left\">" . $type_name .
5248       "</td>\n<td align=\"right\">" . $category . $index_label . "</td>\n" . "</tr>\n";
5249   }
5250}
5251
5252# process definition commands line @deffn for example while removing texi
5253# commands
5254sub t2h_default_def_line_no_texi($$$$$)
5255{
5256   my $category = shift;
5257   my $name = shift;
5258   my $type = shift;
5259   my $arguments = shift;
5260   $name = '' if (!defined($name) or ($name =~ /^\s*$/));
5261   $type = '' if (!defined($type) or $type =~ /^\s*$/);
5262   if (!defined($arguments) or $arguments =~ /^\s*$/)
5263   {
5264       $arguments = '';
5265   }
5266   my $type_name = '';
5267   $type_name = " $type" if ($type ne '');
5268   $type_name .= ' ' . $name if ($name ne '');
5269   $type_name .= $arguments;
5270   if (! $DEF_TABLE)
5271   {
5272       return $category . ':' . $type_name . "\n";
5273   }
5274   else
5275   {
5276
5277       return $type_name . "    " . $category . "\n";
5278   }
5279}
5280
5281# a cartouche
5282sub t2h_default_cartouche($$)
5283{
5284    my $text = shift;
5285
5286    if ($text =~ /\S/)
5287    {
5288        return "<table class=\"cartouche\" border=\"1\"><tr><td>\n" . $text . "</td></tr></table>\n";
5289    }
5290    return '';
5291}
5292
5293# key:
5294# origin_href:
5295# entry:
5296# texi entry:
5297# element_href:
5298# element_text:
5299sub t2h_default_index_summary_file_entry ($$$$$$$$)
5300{
5301    my $index_name = shift;
5302    my $key = shift;
5303    my $origin_href = shift;
5304    my $entry = shift;
5305    my $texi_entry = shift;
5306    my $element_href = shift;
5307    my $element_text = shift;
5308    my $is_printed = shift;
5309    print IDXFILE "key: $key\n  origin_href: $origin_href\n  entry: $entry\n"
5310      . "  texi_entry: $texi_entry\n"
5311      . "  element_href: $element_href\n  element_text: $element_text\n";
5312}
5313
5314sub t2h_default_index_summary_file_begin($$)
5315{
5316    my $name = shift;
5317    my $is_printed = shift;
5318    open(IDXFILE, ">$Texi2HTML::THISDOC{'destination_directory'}$Texi2HTML::THISDOC{'file_base_name'}" . "_$name.idx")
5319       || die "Can't open >$Texi2HTML::THISDOC{'destination_directory'}$Texi2HTML::THISDOC{'file_base_name'}" . "_$name.idx for writing: $!\n";
5320}
5321
5322sub t2h_default_index_summary_file_end($$)
5323{
5324    my $name = shift;
5325    my $is_printed = shift;
5326    close (IDXFILE);
5327}
5328
5329sub t2h_default_sp($$)
5330{
5331   my $number = shift;
5332   my $preformatted = shift;
5333   return "<br>\n" x $number if (!$preformatted);
5334   return "\n" x $number;
5335}
5336
5337sub t2h_default_acronym_like($$$$$$)
5338{
5339    my $command = shift;
5340    my $acronym_texi = shift;
5341    my $acronym_text = shift;
5342    my $with_explanation = shift;
5343    my $explanation_lines = shift;
5344    my $explanation_text = shift;
5345    my $explanation_simply_formatted = shift;
5346
5347    my $attribute = $command;
5348    my $opening = "<$attribute>";
5349    if (defined($explanation_simply_formatted))
5350    {
5351        $opening = "<$attribute title=\"$explanation_simply_formatted\">";
5352    }
5353    if ($with_explanation)
5354    {
5355        return &$I('%{acronym_like} (%{explanation})', {'acronym_like' => $opening . $acronym_text . "</$attribute>", 'explanation' => $explanation_text})
5356    }
5357    else
5358    {
5359        return  $opening . $acronym_text . "</$attribute>";
5360    }
5361}
5362
5363sub t2h_default_quotation_prepend_text($)
5364{
5365    my $text = shift;
5366    return undef if (!defined($text) or $text =~ /^$/);
5367# FIXME if there is a @ protecting the end of line the result is
5368# @b{some text @:}
5369# It is likely not to be what was intended
5370    chomp($text);
5371    return &$I('@b{%{quotation_arg}:} ', {'quotation_arg' => $text}, {'keep_texi' => 1});
5372}
5373
5374sub t2h_default_quotation($$$)
5375{
5376    my $text = shift;
5377    my $argument_text = shift;
5378    my $argument_text_texi = shift;
5379#    my $argument_style_texi = shift;
5380#    my $argument_style_id = shift;
5381#    if (defined($argument_text))
5382#    {
5383#         return '<blockquote>' . &$I('%{style}:%{quotation}',
5384#          {'style' => $argument_text, 'quotation' => $text}) . '</blockquote>' ;
5385#    }
5386    return '<blockquote>' . $text . "</blockquote>\n";
5387}
5388
5389# format the text within a paragraph style format,
5390#
5391# argument:
5392# format name
5393# text within the format
5394sub t2h_default_paragraph_style_command($$)
5395{
5396    my $format = shift;
5397    my $text = shift;
5398    return $text;
5399}
5400
5401# format a whole index
5402#
5403# argument:
5404# index text
5405# index name
5406sub t2h_default_print_index($$)
5407{
5408    my $text = shift;
5409    my $name = shift;
5410    return "<table border=\"0\" class=\"index-$name\">\n" .
5411    "<tr><td></td><th align=\"left\">" . &$I('Index Entry') . "</th><th align=\"left\"> " . &$I('Section') . "</th></tr>\n"
5412    . "<tr><td colspan=\"3\"> $DEFAULT_RULE</td></tr>\n" . $text .
5413    "</table>\n";
5414}
5415
5416# format a letter entry in an index page. The letter entry contains
5417# the index entries for the words beginning with that letter. It is
5418# a target for links pointing from the summary of the index.
5419#
5420# arguments:
5421# the letter
5422# identifier for the letter entry. This should be used to make the target
5423#     identifier
5424# text of the index entries
5425sub t2h_default_index_letter($$$)
5426{
5427     my $letter = shift;
5428     my $id = shift;
5429     my $text = shift;
5430     return '<tr><th>' . &$anchor($id,'',&$protect_text($letter)) .
5431     "</th><td></td><td></td></tr>\n" . $text .
5432     "<tr><td colspan=\"3\"> $DEFAULT_RULE</td></tr>\n";
5433}
5434
5435# format an index entry (in a letter entry).
5436#
5437# arguments:
5438# href to the main text, linking to the place where the index entry appears
5439# entry text
5440# href to the main text, linking to the section or node where the index
5441#      entry appears
5442# section or node heading
5443sub t2h_default_index_entry($$$$)
5444{
5445    my $text_href = shift;
5446    my $entry = shift;
5447    my $element_href = shift;
5448    my $element_text = shift;
5449
5450    return '<tr><td></td><td valign="top">' . &$anchor('', $text_href, $entry)
5451    . '</td><td valign="top">' .  &$anchor('', $element_href, $element_text)
5452    . "</td></tr>\n";
5453}
5454
5455
5456sub t2h_default_copying_comment($)
5457{
5458    my $copying_lines = shift;
5459    my $text = &$comment(main::remove_texi(@$copying_lines));
5460    return $text;
5461}
5462# format a letter appearing in a summary for an index. The letter links to
5463# the place where the index elements beginning with this letter are (called
5464# a letter entry).
5465#
5466# arguments:
5467# letter
5468# file where the target letter entry is
5469# identifier for the target letter entry
5470sub t2h_default_summary_letter($$$)
5471{
5472   my $letter = shift;
5473   my $file = shift;
5474   my $identifier = shift;
5475   return &$anchor('', $file . '#' . $identifier, '<b>' . &$protect_text($letter) . '</b>', 'class="summary-letter"');
5476}
5477
5478# format an index summary. This is a list of letters linking to the letter
5479# entries.
5480#
5481# arguments:
5482# array reference containing the formatted alphabetical letters
5483# array reference containing the formatted non lphabetical letters
5484sub t2h_default_index_summary($$)
5485{
5486    my $alpha = shift;
5487    my $nonalpha = shift;
5488    my $join = '';
5489    my $nonalpha_text = '';
5490    my $alpha_text = '';
5491    $join = " &nbsp; \n<br>\n" if (@$nonalpha and @$alpha);
5492    if (@$nonalpha)
5493    {
5494       $nonalpha_text = join("\n &nbsp; \n", @$nonalpha) . "\n";
5495    }
5496    if (@$alpha)
5497    {
5498       $alpha_text = join("\n &nbsp; \n", @$alpha) . "\n &nbsp; \n";
5499    }
5500    return "<table><tr><th valign=\"top\">" . &$I('Jump to') .": &nbsp; </th><td>" .
5501    $nonalpha_text . $join . $alpha_text . "</td></tr></table>\n";
5502}
5503
5504# return the heading with number texinfo text
5505# also called for nodes.
5506sub t2h_default_heading_texi($$$)
5507{
5508    my $tag = shift;
5509    my $texi = shift;
5510    my $number = shift;
5511    $texi =~ s/\s*$//;
5512    $texi =~ s/^\s*//;
5513    return "$number $texi" if ($NUMBER_SECTIONS and defined($number) and ($number !~ /^\s*$/)) ;
5514    return $texi;
5515}
5516
5517# return the heading texinfo text for split index sections
5518sub t2h_default_index_element_heading_texi($$$)
5519{ # FIXME i18n
5520    my $heading_texi = shift;
5521    my $tag = shift;
5522    my $texi = shift;
5523    my $number = shift;
5524    my $first_letter = shift;
5525    my $last_letter = shift;
5526    return "$heading_texi: $first_letter -- $last_letter" if ($last_letter ne $first_letter);
5527    return "$heading_texi: $first_letter";
5528}
5529
55301;
5531
5532require "$ENV{T2H_HOME}/texi2html.init"
5533    if ($0 =~ /\.pl$/ &&
5534        -e "$ENV{T2H_HOME}/texi2html.init" && -r "$ENV{T2H_HOME}/texi2html.init");
5535
5536my $translation_file = 'translations.pl'; # file containing all the translations
5537my $T2H_OBSOLETE_STRINGS;
5538
5539# leave this within comments, and keep the require statement
5540# This way, you can directly run texi2html.pl,
5541# if $ENV{T2H_HOME}/translations.pl exists.
5542#
5543# @T2H_TRANSLATIONS_FILE@
5544$LANGUAGES->{'de'} = {
5545                       '  The buttons in the navigation panels have the following meaning:' => '',
5546                       '  where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '',
5547                       ' Up ' => '',
5548                       '%{acronym_like} (%{explanation})' => '',
5549                       '%{month}, %{day} %{year}' => '',
5550                       '%{name} of %{class}' => '',
5551                       '%{name} on %{class}' => '',
5552                       '%{node_file_href}' => '',
5553                       '%{node_file_href} @cite{%{book}}' => '',
5554                       '%{node_file_href} section `%{section}\' in @cite{%{book}}' => '',
5555                       '%{reference_name}' => '',
5556                       '%{style} %{number}' => '',
5557                       '%{style}: %{caption_first_line}' => '',
5558                       '%{style}: %{shortcaption_first_line}' => '',
5559                       '@b{%{quotation_arg}:} ' => '',
5560                       '@cite{%{book}}' => '',
5561                       'About' => '',
5562                       'About (help)' => '',
5563                       'About This Document' => '@"Uber dieses Dokument',
5564                       'April' => 'April',
5565                       'August' => 'August',
5566                       'Back' => '',
5567                       'Beginning of this chapter or previous chapter' => '',
5568                       'Button' => '',
5569                       'Contents' => '',
5570                       'Cover (top) of document' => '',
5571                       'Current Position' => '',
5572                       'Current section' => '',
5573                       'December' => 'Dezember',
5574                       'FastBack' => '',
5575                       'FastForward' => '',
5576                       'February' => 'Februar',
5577                       'First' => '',
5578                       'First section in reading order' => '',
5579                       'Following' => '',
5580                       'Following node' => '',
5581                       'Footnotes' => 'Fu@ss{}noten',
5582                       'Forward' => '',
5583                       'From 1.2.3 go to' => '',
5584                       'Go to' => '',
5585                       'Index' => 'Index',
5586                       'Index Entry' => '',
5587                       'January' => 'Januar',
5588                       'July' => 'Juli',
5589                       'Jump to' => '',
5590                       'June' => 'Juni',
5591                       'Last' => '',
5592                       'Last section in reading order' => '',
5593                       'March' => 'M@"arz',
5594                       'May' => 'Mai',
5595                       'Menu:' => '',
5596                       'Name' => '',
5597                       'Next' => '',
5598                       'Next chapter' => '',
5599                       'Next node' => '',
5600                       'Next section in reading order' => '',
5601                       'Next section on same level' => '',
5602                       'Node following in node reading order' => '',
5603                       'Node up' => '',
5604                       'NodeNext' => '',
5605                       'NodePrev' => '',
5606                       'NodeUp' => '',
5607                       'November' => 'November',
5608                       'October' => 'Oktober',
5609                       'Overview' => '',
5610                       'Overview:' => '',
5611                       'Prev' => '',
5612                       'Previous node' => '',
5613                       'Previous section in reading order' => '',
5614                       'Previous section on same level' => '',
5615                       'Section' => '',
5616                       'Section One' => '',
5617                       'See %{node_file_href}' => '',
5618                       'See %{node_file_href} @cite{%{book}}' => '',
5619                       'See %{node_file_href} section `%{section}\' in @cite{%{book}}' => '',
5620                       'See %{reference_name}' => '',
5621                       'See @cite{%{book}}' => '',
5622                       'See section %{reference_name}' => '',
5623                       'See section `%{section}\' in @cite{%{book}}' => '',
5624                       'September' => 'September',
5625                       'Short Table of Contents' => 'Kurzes Inhaltsverzeichniss',
5626                       'Short table of contents' => '',
5627                       'Subsection One-Four' => '',
5628                       'Subsection One-One' => '',
5629                       'Subsection One-Three' => '',
5630                       'Subsection One-Two' => '',
5631                       'Subsubsection One-Two-Four' => '',
5632                       'Subsubsection One-Two-One' => '',
5633                       'Subsubsection One-Two-Three' => '',
5634                       'Subsubsection One-Two-Two' => '',
5635                       'T2H_today' => '',
5636                       'Table of Contents' => 'Inhaltsverzeichniss',
5637                       'Table of contents' => '',
5638                       'The node you are looking for is at %{href}.' => '',
5639                       'This' => '',
5640                       'This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '',
5641                       'This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '',
5642                       'This document was generated on @i{%{date}} using @uref{%{program_homepage}, @i{%{program}}}.' => '',
5643                       'This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.' => '',
5644                       'Top' => '',
5645                       'Untitled Document' => '',
5646                       'Up' => '',
5647                       'Up node' => '',
5648                       'Up section' => '',
5649                       'by @emph{%{user}}' => '',
5650                       'by @emph{%{user}} on @emph{%{date}}' => '',
5651                       'current' => '',
5652                       'on @emph{%{date}}' => '',
5653                       'section `%{section}\' in @cite{%{book}}' => '',
5654                       'see %{node_file_href}' => '',
5655                       'see %{node_file_href} @cite{%{book}}' => '',
5656                       'see %{node_file_href} section `%{section}\' in @cite{%{book}}' => '',
5657                       'see %{reference_name}' => '',
5658                       'see @cite{%{book}}' => '',
5659                       'see section %{reference_name}' => '',
5660                       'see section `%{section}\' in @cite{%{book}}' => '',
5661                       'unknown' => ''
5662                     };
5663
5664$T2H_OBSOLETE_STRINGS->{'de'} = {
5665                                  'See' => 'Siehe',
5666                                  'section' => 'Abschnitt',
5667                                  'see' => 'siehe'
5668                                };
5669
5670
5671$LANGUAGES->{'en'} = {
5672                       '  The buttons in the navigation panels have the following meaning:' => '',
5673                       '  where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '',
5674                       ' Up ' => '',
5675                       '%{acronym_like} (%{explanation})' => '',
5676                       '%{month}, %{day} %{year}' => '',
5677                       '%{name} of %{class}' => '',
5678                       '%{name} on %{class}' => '',
5679                       '%{node_file_href}' => '',
5680                       '%{node_file_href} @cite{%{book}}' => '',
5681                       '%{node_file_href} section `%{section}\' in @cite{%{book}}' => '',
5682                       '%{reference_name}' => '',
5683                       '%{style} %{number}' => '',
5684                       '%{style}: %{caption_first_line}' => '',
5685                       '%{style}: %{shortcaption_first_line}' => '',
5686                       '@b{%{quotation_arg}:} ' => '',
5687                       '@cite{%{book}}' => '',
5688                       'About' => '',
5689                       'About (help)' => '',
5690                       'About This Document' => '',
5691                       'April' => '',
5692                       'August' => '',
5693                       'Back' => '',
5694                       'Beginning of this chapter or previous chapter' => '',
5695                       'Button' => '',
5696                       'Contents' => '',
5697                       'Cover (top) of document' => '',
5698                       'Current Position' => '',
5699                       'Current section' => '',
5700                       'December' => '',
5701                       'FastBack' => '',
5702                       'FastForward' => '',
5703                       'February' => '',
5704                       'First' => '',
5705                       'First section in reading order' => '',
5706                       'Following' => '',
5707                       'Following node' => '',
5708                       'Footnotes' => '',
5709                       'Forward' => '',
5710                       'From 1.2.3 go to' => '',
5711                       'Go to' => '',
5712                       'Index' => '',
5713                       'Index Entry' => '',
5714                       'January' => '',
5715                       'July' => '',
5716                       'Jump to' => '',
5717                       'June' => '',
5718                       'Last' => '',
5719                       'Last section in reading order' => '',
5720                       'March' => '',
5721                       'May' => '',
5722                       'Menu:' => '',
5723                       'Name' => '',
5724                       'Next' => '',
5725                       'Next chapter' => '',
5726                       'Next node' => '',
5727                       'Next section in reading order' => '',
5728                       'Next section on same level' => '',
5729                       'Node following in node reading order' => '',
5730                       'Node up' => '',
5731                       'NodeNext' => '',
5732                       'NodePrev' => '',
5733                       'NodeUp' => '',
5734                       'November' => '',
5735                       'October' => '',
5736                       'Overview' => '',
5737                       'Overview:' => '',
5738                       'Prev' => '',
5739                       'Previous node' => '',
5740                       'Previous section in reading order' => '',
5741                       'Previous section on same level' => '',
5742                       'Section' => '',
5743                       'Section One' => '',
5744                       'See %{node_file_href}' => '',
5745                       'See %{node_file_href} @cite{%{book}}' => '',
5746                       'See %{node_file_href} section `%{section}\' in @cite{%{book}}' => '',
5747                       'See %{reference_name}' => '',
5748                       'See @cite{%{book}}' => '',
5749                       'See section %{reference_name}' => '',
5750                       'See section `%{section}\' in @cite{%{book}}' => '',
5751                       'September' => '',
5752                       'Short Table of Contents' => '',
5753                       'Short table of contents' => '',
5754                       'Subsection One-Four' => '',
5755                       'Subsection One-One' => '',
5756                       'Subsection One-Three' => '',
5757                       'Subsection One-Two' => '',
5758                       'Subsubsection One-Two-Four' => '',
5759                       'Subsubsection One-Two-One' => '',
5760                       'Subsubsection One-Two-Three' => '',
5761                       'Subsubsection One-Two-Two' => '',
5762                       'T2H_today' => '%s, %d %d',
5763                       'Table of Contents' => '',
5764                       'Table of contents' => '',
5765                       'The node you are looking for is at %{href}.' => '',
5766                       'This' => '',
5767                       'This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '',
5768                       'This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '',
5769                       'This document was generated on @i{%{date}} using @uref{%{program_homepage}, @i{%{program}}}.' => '',
5770                       'This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.' => '',
5771                       'Top' => '',
5772                       'Untitled Document' => '',
5773                       'Up' => '',
5774                       'Up node' => '',
5775                       'Up section' => '',
5776                       'by @emph{%{user}}' => '',
5777                       'by @emph{%{user}} on @emph{%{date}}' => '',
5778                       'current' => '',
5779                       'on @emph{%{date}}' => '',
5780                       'section `%{section}\' in @cite{%{book}}' => '',
5781                       'see %{node_file_href}' => '',
5782                       'see %{node_file_href} @cite{%{book}}' => '',
5783                       'see %{node_file_href} section `%{section}\' in @cite{%{book}}' => '',
5784                       'see %{reference_name}' => '',
5785                       'see @cite{%{book}}' => '',
5786                       'see section %{reference_name}' => '',
5787                       'see section `%{section}\' in @cite{%{book}}' => '',
5788                       'unknown' => ''
5789                     };
5790
5791$T2H_OBSOLETE_STRINGS->{'en'} = {};
5792
5793
5794$LANGUAGES->{'es'} = {
5795                       '  The buttons in the navigation panels have the following meaning:' => '',
5796                       '  where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '',
5797                       ' Up ' => '',
5798                       '%{acronym_like} (%{explanation})' => '',
5799                       '%{month}, %{day} %{year}' => '',
5800                       '%{name} of %{class}' => '',
5801                       '%{name} on %{class}' => '',
5802                       '%{node_file_href}' => '',
5803                       '%{node_file_href} @cite{%{book}}' => '',
5804                       '%{node_file_href} section `%{section}\' in @cite{%{book}}' => '',
5805                       '%{reference_name}' => '',
5806                       '%{style} %{number}' => '',
5807                       '%{style}: %{caption_first_line}' => '',
5808                       '%{style}: %{shortcaption_first_line}' => '',
5809                       '@b{%{quotation_arg}:} ' => '',
5810                       '@cite{%{book}}' => '',
5811                       'About' => '',
5812                       'About (help)' => '',
5813                       'About This Document' => '',
5814                       'April' => 'abril',
5815                       'August' => 'agosto',
5816                       'Back' => '',
5817                       'Beginning of this chapter or previous chapter' => '',
5818                       'Button' => '',
5819                       'Contents' => '',
5820                       'Cover (top) of document' => '',
5821                       'Current Position' => '',
5822                       'Current section' => '',
5823                       'December' => 'diciembre',
5824                       'FastBack' => '',
5825                       'FastForward' => '',
5826                       'February' => 'febrero',
5827                       'First' => '',
5828                       'First section in reading order' => '',
5829                       'Following' => '',
5830                       'Following node' => '',
5831                       'Footnotes' => '',
5832                       'Forward' => '',
5833                       'From 1.2.3 go to' => '',
5834                       'Go to' => '',
5835                       'Index' => 'Index',
5836                       'Index Entry' => '',
5837                       'January' => 'enero',
5838                       'July' => 'julio',
5839                       'Jump to' => '',
5840                       'June' => 'junio',
5841                       'Last' => '',
5842                       'Last section in reading order' => '',
5843                       'March' => 'marzo',
5844                       'May' => 'mayo',
5845                       'Menu:' => '',
5846                       'Name' => '',
5847                       'Next' => '',
5848                       'Next chapter' => '',
5849                       'Next node' => '',
5850                       'Next section in reading order' => '',
5851                       'Next section on same level' => '',
5852                       'Node following in node reading order' => '',
5853                       'Node up' => '',
5854                       'NodeNext' => '',
5855                       'NodePrev' => '',
5856                       'NodeUp' => '',
5857                       'November' => 'noviembre',
5858                       'October' => 'octubre',
5859                       'Overview' => '',
5860                       'Overview:' => '',
5861                       'Prev' => '',
5862                       'Previous node' => '',
5863                       'Previous section in reading order' => '',
5864                       'Previous section on same level' => '',
5865                       'Section' => '',
5866                       'Section One' => '',
5867                       'See %{node_file_href}' => '',
5868                       'See %{node_file_href} @cite{%{book}}' => '',
5869                       'See %{node_file_href} section `%{section}\' in @cite{%{book}}' => '',
5870                       'See %{reference_name}' => '',
5871                       'See @cite{%{book}}' => '',
5872                       'See section %{reference_name}' => '',
5873                       'See section `%{section}\' in @cite{%{book}}' => '',
5874                       'September' => 'septiembre',
5875                       'Short Table of Contents' => 'Resumen del Contenido',
5876                       'Short table of contents' => '',
5877                       'Subsection One-Four' => '',
5878                       'Subsection One-One' => '',
5879                       'Subsection One-Three' => '',
5880                       'Subsection One-Two' => '',
5881                       'Subsubsection One-Two-Four' => '',
5882                       'Subsubsection One-Two-One' => '',
5883                       'Subsubsection One-Two-Three' => '',
5884                       'Subsubsection One-Two-Two' => '',
5885                       'T2H_today' => '',
5886                       'Table of Contents' => '@\'{@dotless{I}}ndice General',
5887                       'Table of contents' => '',
5888                       'The node you are looking for is at %{href}.' => '',
5889                       'This' => '',
5890                       'This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '',
5891                       'This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '',
5892                       'This document was generated on @i{%{date}} using @uref{%{program_homepage}, @i{%{program}}}.' => '',
5893                       'This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.' => '',
5894                       'Top' => '',
5895                       'Untitled Document' => '',
5896                       'Up' => '',
5897                       'Up node' => '',
5898                       'Up section' => '',
5899                       'by @emph{%{user}}' => '',
5900                       'by @emph{%{user}} on @emph{%{date}}' => '',
5901                       'current' => '',
5902                       'on @emph{%{date}}' => '',
5903                       'section `%{section}\' in @cite{%{book}}' => '',
5904                       'see %{node_file_href}' => '',
5905                       'see %{node_file_href} @cite{%{book}}' => '',
5906                       'see %{node_file_href} section `%{section}\' in @cite{%{book}}' => '',
5907                       'see %{reference_name}' => '',
5908                       'see @cite{%{book}}' => '',
5909                       'see section %{reference_name}' => '',
5910                       'see section `%{section}\' in @cite{%{book}}' => '',
5911                       'unknown' => ''
5912                     };
5913
5914$T2H_OBSOLETE_STRINGS->{'es'} = {
5915                                  'See' => 'V@\'ease',
5916                                  'section' => 'secci@\'on',
5917                                  'see' => 'v@\'ase'
5918                                };
5919
5920
5921$LANGUAGES->{'fr'} = {
5922                       '  The buttons in the navigation panels have the following meaning:' => '  Les boutons de navigation ont la signification suivante :',
5923                       '  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 section un-deux-trois } dans un document dont la structure est :',
5924                       ' Up ' => 'Plus haut',
5925                       '%{acronym_like} (%{explanation})' => '',
5926                       '%{month}, %{day} %{year}' => 'le %{day} %{month} %{year}',
5927                       '%{name} of %{class}' => '%{name} de %{class}',
5928                       '%{name} on %{class}' => '%{name} de %{class}',
5929                       '%{node_file_href}' => '',
5930                       '%{node_file_href} @cite{%{book}}' => '',
5931                       '%{node_file_href} section `%{section}\' in @cite{%{book}}' => '%{node_file_href} section `%{section}\' dans @cite{%{book}}',
5932                       '%{reference_name}' => '',
5933                       '%{style} %{number}' => '',
5934                       '%{style}: %{caption_first_line}' => '',
5935                       '%{style}: %{shortcaption_first_line}' => '',
5936                       '@b{%{quotation_arg}:} ' => '',
5937                       '@cite{%{book}}' => '',
5938                       'About' => 'A propos',
5939                       'About (help)' => 'A propos (page d\'aide)',
5940                       'About This Document' => 'A propos de ce document',
5941                       'April' => 'Avril',
5942                       'August' => 'Ao@^ut',
5943                       'Back' => 'Retour',
5944                       'Beginning of this chapter or previous chapter' => 'D@\'ebut de ce chapitre ou chapitre pr@\'ec@\'edent',
5945                       'Button' => 'Bouton',
5946                       'Contents' => 'Table des mati@`eres',
5947                       'Cover (top) of document' => 'Couverture (top) du document',
5948                       'Current Position' => 'Position',
5949                       'Current section' => 'Section actuelle',
5950                       'December' => 'D@\'ecembre',
5951                       'FastBack' => 'RetourRapide',
5952                       'FastForward' => 'AvanceRapide',
5953                       'February' => 'F@\'evrier',
5954                       'First' => 'Premier',
5955                       'First section in reading order' => 'Premi@`e section dans l\'ordre de lecture',
5956                       'Following' => 'Suivant',
5957                       'Following node' => 'N@oe{}ud suivant',
5958                       'Footnotes' => 'Notes de bas de page',
5959                       'Forward' => 'Avant',
5960                       'From 1.2.3 go to' => 'Depuis 1.2.3 aller @`a',
5961                       'Go to' => 'Aller @`a',
5962                       'Index' => 'Index',
5963                       'Index Entry' => 'Entr@\'ee d\'index',
5964                       'January' => 'Janvier',
5965                       'July' => 'Juillet',
5966                       'Jump to' => 'Aller @`a',
5967                       'June' => 'Juin',
5968                       'Last' => 'Dernier',
5969                       'Last section in reading order' => 'Derni@`ere section dans l\'ordre de lecture',
5970                       'March' => 'Mars',
5971                       'May' => 'Mai',
5972                       'Menu:' => 'Menu@ :',
5973                       'Name' => 'Nom',
5974                       'Next' => 'Suivant',
5975                       'Next chapter' => 'Chapitre suivant',
5976                       'Next node' => 'N@oe{}ud suivant',
5977                       'Next section in reading order' => 'Section suivante dans l\'ordre de lecture',
5978                       'Next section on same level' => 'Section suivante au m@^eme niveau',
5979                       'Node following in node reading order' => 'N@oe{}ud suivant dans l\'ordre de lecture',
5980                       'Node up' => 'N@oe{}ud au dessus',
5981                       'NodeNext' => 'N@oe{}udSuivant',
5982                       'NodePrev' => 'N@oe{}udPr@\'ec@\'edent',
5983                       'NodeUp' => 'N@oe{}udMonter',
5984                       'November' => 'Novembre',
5985                       'October' => 'Octobre',
5986                       'Overview' => 'Vue d\'ensemble',
5987                       'Overview:' => 'Vue d\'ensemble@ :',
5988                       'Prev' => 'Pr@\'ec@\'edent',
5989                       'Previous node' => 'N@oe{}ud pr@\'ec@\'edent',
5990                       'Previous section in reading order' => 'Section pr@\'ec@\'edente dans l\'ordre de lecture',
5991                       'Previous section on same level' => 'Section pr@\'ec@\'edente au m@^eme niveau',
5992                       'Section' => '',
5993                       'Section One' => 'Section un',
5994                       'See %{node_file_href}' => 'Voir %{node_file_href}',
5995                       'See %{node_file_href} @cite{%{book}}' => 'Voir %{node_file_href} @cite{%{book}}',
5996                       'See %{node_file_href} section `%{section}\' in @cite{%{book}}' => 'Voir %{node_file_href} section `%{section}\' dans @cite{%{book}}',
5997                       'See %{reference_name}' => 'Voir %{reference_name}',
5998                       'See @cite{%{book}}' => 'Voir @cite{%{book}}',
5999                       'See section %{reference_name}' => 'Voir la section %{reference_name}',
6000                       'See section `%{section}\' in @cite{%{book}}' => 'Voir la section `%{section}\' dans @cite{%{book}}',
6001                       'September' => 'Septembre',
6002                       'Short Table of Contents' => 'R@\'esum@\'e du contenu',
6003                       'Short table of contents' => 'R@\'esum@\'e du contenu',
6004                       'Subsection One-Four' => 'Sous section un-quatre',
6005                       'Subsection One-One' => 'Sous section un-un',
6006                       'Subsection One-Three' => 'Sous section un-trois',
6007                       'Subsection One-Two' => 'Sous section un-deux',
6008                       'Subsubsection One-Two-Four' => 'Sous sous section un-deux-quatre',
6009                       'Subsubsection One-Two-One' => 'Sous sous section un-deux-un',
6010                       'Subsubsection One-Two-Three' => 'Sous sous section un-deux-trois',
6011                       'Subsubsection One-Two-Two' => 'Sous sous section un-deux-deux',
6012                       'T2H_today' => 'le %2$d %1$s %3$d',
6013                       'Table of Contents' => 'Table des mati@`eres',
6014                       'Table of contents' => 'Table des mati@`eres',
6015                       'The node you are looking for is at %{href}.' => 'Le n@oe{}ud que vous recherchez est ici@ : %{href}.',
6016                       'This' => 'Ici',
6017                       'This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e par @emph{%{user}} @emph{%{date}} en utilisant @uref{%{program_homepage}, @emph{%{program}}}.',
6018                       'This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e par @emph{%{user}} en utilisant @uref{%{program_homepage}, @emph{%{program}}}.',
6019                       'This document was generated on @i{%{date}} using @uref{%{program_homepage}, @i{%{program}}}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e @emph{%{date}} en utilisant @uref{%{program_homepage}, @emph{%{program}}}',
6020                       '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}}}.',
6021                       'Top' => '',
6022                       'Untitled Document' => 'Document sans titre',
6023                       'Up' => 'Monter',
6024                       'Up node' => 'N@oe{}ud au dessus',
6025                       'Up section' => 'Section sup@\'erieure',
6026                       'by @emph{%{user}}' => 'par @emph{%{user}}',
6027                       'by @emph{%{user}} on @emph{%{date}}' => 'par @emph{%{user}} @emph{%{date}}',
6028                       'current' => 'courante',
6029                       'on @emph{%{date}}' => '@emph{%{date}}',
6030                       'section `%{section}\' in @cite{%{book}}' => 'section `%{section}\' dans @cite{%{book}}',
6031                       'see %{node_file_href}' => 'voir %{node_file_href}',
6032                       'see %{node_file_href} @cite{%{book}}' => 'voir %{node_file_href} @cite{%{book}}',
6033                       'see %{node_file_href} section `%{section}\' in @cite{%{book}}' => 'voir %{node_file_href} section `%{section}\' dans @cite{%{book}}',
6034                       'see %{reference_name}' => 'voir %{reference_name}',
6035                       'see @cite{%{book}}' => 'voir @cite{%{book}}',
6036                       'see section %{reference_name}' => 'voir la section %{reference_name}',
6037                       'see section `%{section}\' in @cite{%{book}}' => 'voir la section `%{section}\' dans @cite{{book}}',
6038                       'unknown' => 'inconnu'
6039                     };
6040
6041$T2H_OBSOLETE_STRINGS->{'fr'} = {
6042                                  '  This document was generated %{who_and_when_generated} using %{program_homepage_href}.' => '  Ce document a &eacute;t&eacute; g&eacute;n&eacute;r&eacute; %{who_and_when_generated} en utilisant %{program_homepage_href}.',
6043                                  '  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:' => '  Dans cet exemple on est &agrave; <strong> Sous section un-deux-trois </strong> dans un document dont la structure est :',
6044                                  '%{node_file_href} section `%{section}\' in <cite>%{book}</cite>' => '%{node_file_href} section `%{section}\' dans <cite>%{book}</cite>',
6045                                  'See' => 'Voir',
6046                                  'See %{node_file_href} <cite>%{book}</cite>' => 'Voir %{node_file_href} <cite>%{book}</cite>',
6047                                  'See %{node_file_href} section `%{section}\' in <cite>%{book}</cite>' => 'Voir %{node_file_href} section `%{section}\' dans <cite>%{book}</cite>',
6048                                  'See <cite>%{book}</cite>' => 'Voir <cite>%{book}</cite>',
6049                                  'See section `%{section}\' in <cite>%{book}</cite>' => 'Voir la section `%{section}\' dans <cite>%{book}</cite>',
6050                                  'This document was generated by <i>%{user}</i> on <i>%{date}</i> using %{program_homepage_href}.' => 'Ce document a &eacute;t&eacute; g&eacute;n&eacute;r&eacute; par <i>%{user}</i> <i>%{date}</i> en utilisant %{program_homepage_href}.',
6051                                  'This document was generated by <i>%{user}</i> using %{program_homepage_href}.' => 'Ce document a &eacute;t&eacute; g&eacute;n&eacute;r&eacute; par <i>%{user}</i> en utilisant %{program_homepage_href}.',
6052                                  'This document was generated by @emph{%{user}} on @emph{%{date}} using %{program_homepage_href}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e par @emph{%{user}} @emph{%{date}} en utilisant %{program_homepage_href}.',
6053                                  'This document was generated by @emph{%{user}} using %{program_homepage_href}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e par @emph{%{user}} en utilisant %{program_homepage_href}.',
6054                                  'This document was generated on <i>%{date}</i> using %{program_homepage_href}.' => 'Ce document a &eacute;t&eacute; g&eacute;n&eacute;r&eacute; <i>%{date}</i> en utilisant %{program_homepage_href}.',
6055                                  'This document was generated on @emph{%{date}} using %{program_homepage_href}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e @emph{%{date}} en utilisant %{program_homepage_href}.',
6056                                  'This document was generated on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e @emph{%{date}} en utilisant @uref{%{program_homepage}, @emph{%{program}}}.',
6057                                  'This document was generated using %{program_homepage_href}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e en utilisant %{program_homepage_href}.',
6058                                  'about (help)' => '@`a propos (page d\'aide)',
6059                                  'about (this page)' => 'a propos (cette page)',
6060                                  'beginning of this chapter or previous chapter' => 'd@\'ebut de ce chapitre ou chapitre pr@\'ec@\'edent',
6061                                  'by <i>%{user}</i>' => 'par <i>%{user}</i>',
6062                                  'by <i>%{user}</i> on <i>%{date}</i>' => 'par <i>%{user}</i> <i>%{date}</i>',
6063                                  'concept index' => 'index',
6064                                  'cover (top) of document' => 'couverture (top) du document',
6065                                  'current section' => 'section actuelle',
6066                                  'first section in reading order' => 'premi@`e section dans l\'ordre de lecture',
6067                                  'following node' => 'node suivant',
6068                                  'index' => 'index',
6069                                  'last section in reading order' => 'derni@`ere section dans l\'ordre de lecture',
6070                                  'next chapter' => 'chapitre suivant',
6071                                  'next node' => 'node suivant',
6072                                  'next section in reading order' => 'section suivante dans l\'ordre de lecture',
6073                                  'next section on same level' => 'section suivante au m@^eme niveau',
6074                                  'node following in node reading order' => 'node suivant dans l\'ordre des nodes',
6075                                  'node up' => 'node au dessus',
6076                                  'on <i>%{date}</i>' => '<i>%{date}</i>',
6077                                  'previous node' => 'node pr@\'ec@\'edent',
6078                                  'previous section in reading order' => 'section pr@\'ec@\'edente dans l\'ordre de lecture',
6079                                  'previous section on same level' => 'section pr@\'ec@\'edente au m@^eme niveau',
6080                                  'section' => 'section',
6081                                  'section `%{section}\' in <cite>%{book}</cite>' => 'section `%{section}\' dans <cite>%{book}</cite>',
6082                                  'see' => 'voir',
6083                                  'see %{node_file_href} <cite>%{book}</cite>' => 'voir %{node_file_href} <cite>%{book}</cite>',
6084                                  'see %{node_file_href} section `%{section}\' in <cite>%{book}</cite>' => 'voir %{node_file_href} section `%{section}\' dans <cite>%{book}</cite>',
6085                                  'see <cite>%{book}</cite>' => 'voir <cite>%{book}</cite>',
6086                                  'see section `%{section}\' in <cite>%{book}</cite>' => 'voir la section `%{section}\' dans <cite>%{book}</cite>',
6087                                  'short table of contents' => 'table des mati@`eres r@\'esum@\'ee',
6088                                  'table of contents' => 'table des mati@`eres',
6089                                  'up node' => 'node au dessus',
6090                                  'up section' => 'section sup@\'erieure'
6091                                };
6092
6093
6094$LANGUAGES->{'ja'} = {
6095                       '  The buttons in the navigation panels have the following meaning:' => 'ナビゲーションパネル中のボタンには以下の意味があります。',
6096                       '  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項}を現在位置に仮定しています。',
6097                       ' Up ' => '上',
6098                       '%{acronym_like} (%{explanation})' => '',
6099                       '%{month}, %{day} %{year}' => '%{year}年%{month}月%{day}日',
6100                       '%{name} of %{class}' => '',
6101                       '%{name} on %{class}' => '',
6102                       '%{node_file_href}' => '',
6103                       '%{node_file_href} @cite{%{book}}' => '',
6104                       '%{node_file_href} section `%{section}\' in @cite{%{book}}' => '',
6105                       '%{reference_name}' => '',
6106                       '%{style} %{number}' => '',
6107                       '%{style}: %{caption_first_line}' => '',
6108                       '%{style}: %{shortcaption_first_line}' => '',
6109                       '@b{%{quotation_arg}:} ' => '',
6110                       '@cite{%{book}}' => '',
6111                       'About' => '',
6112                       'About (help)' => '',
6113                       'About This Document' => 'この文書について',
6114                       'April' => '4月',
6115                       'August' => '8月',
6116                       'Back' => '',
6117                       'Beginning of this chapter or previous chapter' => '',
6118                       'Button' => 'ボタン',
6119                       'Contents' => '目次',
6120                       'Cover (top) of document' => '',
6121                       'Current Position' => '現在位置',
6122                       'Current section' => '',
6123                       'December' => '12月',
6124                       'FastBack' => '',
6125                       'FastForward' => '',
6126                       'February' => '2月',
6127                       'First' => '',
6128                       'First section in reading order' => '',
6129                       'Following' => '',
6130                       'Following node' => '',
6131                       'Footnotes' => '脚注',
6132                       'Forward' => '',
6133                       'From 1.2.3 go to' => '1.2.3項からの移動先',
6134                       'Go to' => '移動先',
6135                       'Index' => '見出し',
6136                       'Index Entry' => '見出し一覧',
6137                       'January' => '1月',
6138                       'July' => '7月',
6139                       'Jump to' => '移動',
6140                       'June' => '6月',
6141                       'Last' => '',
6142                       'Last section in reading order' => '',
6143                       'March' => '3月',
6144                       'May' => '5月',
6145                       'Menu:' => 'メニュー',
6146                       'Name' => '名称',
6147                       'Next' => '次',
6148                       'Next chapter' => '',
6149                       'Next node' => '',
6150                       'Next section in reading order' => '',
6151                       'Next section on same level' => '',
6152                       'Node following in node reading order' => '',
6153                       'Node up' => '',
6154                       'NodeNext' => '',
6155                       'NodePrev' => '',
6156                       'NodeUp' => '',
6157                       'November' => '11月',
6158                       'October' => '10月',
6159                       'Overview' => '概要',
6160                       'Overview:' => '概要:',
6161                       'Prev' => '前',
6162                       'Previous node' => '',
6163                       'Previous section in reading order' => '',
6164                       'Previous section on same level' => '',
6165                       'Section' => '項',
6166                       'Section One' => '第1項',
6167                       'See %{node_file_href}' => '',
6168                       'See %{node_file_href} @cite{%{book}}' => '',
6169                       'See %{node_file_href} section `%{section}\' in @cite{%{book}}' => '',
6170                       'See %{reference_name}' => '',
6171                       'See @cite{%{book}}' => '',
6172                       'See section %{reference_name}' => '',
6173                       'See section `%{section}\' in @cite{%{book}}' => '',
6174                       'September' => '9月',
6175                       'Short Table of Contents' => '簡略化した目次',
6176                       'Short table of contents' => '',
6177                       'Subsection One-Four' => '第1.4項',
6178                       'Subsection One-One' => '第1.1項',
6179                       'Subsection One-Three' => '第1.3項',
6180                       'Subsection One-Two' => '第1.2項',
6181                       'Subsubsection One-Two-Four' => '第1.2.4項',
6182                       'Subsubsection One-Two-One' => '第1.2.1項',
6183                       'Subsubsection One-Two-Three' => '第1.2.3項',
6184                       'Subsubsection One-Two-Two' => '第1.2.2項',
6185                       'T2H_today' => '%s, %d %d',
6186                       'Table of Contents' => '目次',
6187                       'Table of contents' => '',
6188                       'The node you are looking for is at %{href}.' => '',
6189                       'This' => '',
6190                       'This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => 'この文書は@emph{%{user}}によって@emph{%{date}}に@uref{%{program_homepage}, @emph{%{program}}}を用いて生成されました。',
6191                       'This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.' => 'この文書は@emph{%{user}}によって@uref{%{program_homepage}, @emph{%{program}}}を用いて生成されました。',
6192                       'This document was generated on @i{%{date}} using @uref{%{program_homepage}, @i{%{program}}}.' => 'この文書は@emph{%{date}}に@uref{%{program_homepage}, @emph{%{program}}}を用いて生成されました。',
6193                       'This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.' => 'この文書は@uref{%{program_homepage}, @emph{%{program}}}を用いて生成されました。',
6194                       'Top' => '冒頭',
6195                       'Untitled Document' => '無題の文書',
6196                       'Up' => '',
6197                       'Up node' => '',
6198                       'Up section' => '',
6199                       'by @emph{%{user}}' => '@emph{%{user}}',
6200                       'by @emph{%{user}} on @emph{%{date}}' => '@emph{%{user}}, @emph{%{date}',
6201                       'current' => '現在位置',
6202                       'on @emph{%{date}}' => '@emph{%{date}}',
6203                       'section `%{section}\' in @cite{%{book}}' => '@cite{%{book}}の `%{section}\' ',
6204                       'see %{node_file_href}' => '%{node_file_href}参照',
6205                       'see %{node_file_href} @cite{%{book}}' => '%{node_file_href} @cite{%{book}}参照',
6206                       'see %{node_file_href} section `%{section}\' in @cite{%{book}}' => '',
6207                       'see %{reference_name}' => '',
6208                       'see @cite{%{book}}' => '',
6209                       'see section %{reference_name}' => '',
6210                       'see section `%{section}\' in @cite{%{book}}' => '',
6211                       'unknown' => '不明'
6212                     };
6213
6214$T2H_OBSOLETE_STRINGS->{'ja'} = {
6215                                  'about (help)' => '使用法 (ヘルプ)',
6216                                  'beginning of this chapter or previous chapter' => 'この章または前の章の冒頭',
6217                                  'cover (top) of document' => '文書の表紙 (トップ)',
6218                                  'current section' => '現在の節',
6219                                  'first section in reading order' => '文書順で前の項',
6220                                  'following node' => '次の節',
6221                                  'index' => '見出し',
6222                                  'last section in reading order' => '文書順で最後の項',
6223                                  'next chapter' => '次の章',
6224                                  'next node' => '次の節',
6225                                  'next section in reading order' => '文書順で次の項',
6226                                  'next section on same level' => '同じ階層にある次の項',
6227                                  'node following in node reading order' => '文書順で次の節',
6228                                  'node up' => '上の節へ',
6229                                  'previous node' => '前の節',
6230                                  'previous section in reading order' => '文書順で前の節',
6231                                  'previous section on same level' => '同じ階層にある前の項',
6232                                  'short table of contents' => '簡略化した目次',
6233                                  'table of contents' => '文書の目次',
6234                                  'up node' => '上の節',
6235                                  'up section' => '上の項'
6236                                };
6237
6238
6239$LANGUAGES->{'nl'} = {
6240                       '  The buttons in the navigation panels have the following meaning:' => '',
6241                       '  where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '',
6242                       ' Up ' => '',
6243                       '%{acronym_like} (%{explanation})' => '',
6244                       '%{month}, %{day} %{year}' => '',
6245                       '%{name} of %{class}' => '',
6246                       '%{name} on %{class}' => '',
6247                       '%{node_file_href}' => '',
6248                       '%{node_file_href} @cite{%{book}}' => '',
6249                       '%{node_file_href} section `%{section}\' in @cite{%{book}}' => '',
6250                       '%{reference_name}' => '',
6251                       '%{style} %{number}' => '',
6252                       '%{style}: %{caption_first_line}' => '',
6253                       '%{style}: %{shortcaption_first_line}' => '',
6254                       '@b{%{quotation_arg}:} ' => '',
6255                       '@cite{%{book}}' => '',
6256                       'About' => '',
6257                       'About (help)' => '',
6258                       'About This Document' => 'No translation available!',
6259                       'April' => 'April',
6260                       'August' => 'Augustus',
6261                       'Back' => '',
6262                       'Beginning of this chapter or previous chapter' => '',
6263                       'Button' => '',
6264                       'Contents' => '',
6265                       'Cover (top) of document' => '',
6266                       'Current Position' => '',
6267                       'Current section' => '',
6268                       'December' => 'December',
6269                       'FastBack' => '',
6270                       'FastForward' => '',
6271                       'February' => 'Februari',
6272                       'First' => '',
6273                       'First section in reading order' => '',
6274                       'Following' => '',
6275                       'Following node' => '',
6276                       'Footnotes' => 'No translation available!',
6277                       'Forward' => '',
6278                       'From 1.2.3 go to' => '',
6279                       'Go to' => '',
6280                       'Index' => 'Index',
6281                       'Index Entry' => '',
6282                       'January' => 'Januari',
6283                       'July' => 'Juli',
6284                       'Jump to' => '',
6285                       'June' => 'Juni',
6286                       'Last' => '',
6287                       'Last section in reading order' => '',
6288                       'March' => 'Maart',
6289                       'May' => 'Mei',
6290                       'Menu:' => '',
6291                       'Name' => '',
6292                       'Next' => '',
6293                       'Next chapter' => '',
6294                       'Next node' => '',
6295                       'Next section in reading order' => '',
6296                       'Next section on same level' => '',
6297                       'Node following in node reading order' => '',
6298                       'Node up' => '',
6299                       'NodeNext' => '',
6300                       'NodePrev' => '',
6301                       'NodeUp' => '',
6302                       'November' => 'November',
6303                       'October' => 'Oktober',
6304                       'Overview' => '',
6305                       'Overview:' => '',
6306                       'Prev' => '',
6307                       'Previous node' => '',
6308                       'Previous section in reading order' => '',
6309                       'Previous section on same level' => '',
6310                       'Section' => '',
6311                       'Section One' => '',
6312                       'See %{node_file_href}' => '',
6313                       'See %{node_file_href} @cite{%{book}}' => '',
6314                       'See %{node_file_href} section `%{section}\' in @cite{%{book}}' => '',
6315                       'See %{reference_name}' => '',
6316                       'See @cite{%{book}}' => '',
6317                       'See section %{reference_name}' => '',
6318                       'See section `%{section}\' in @cite{%{book}}' => '',
6319                       'September' => 'September',
6320                       'Short Table of Contents' => 'Korte inhoudsopgave',
6321                       'Short table of contents' => '',
6322                       'Subsection One-Four' => '',
6323                       'Subsection One-One' => '',
6324                       'Subsection One-Three' => '',
6325                       'Subsection One-Two' => '',
6326                       'Subsubsection One-Two-Four' => '',
6327                       'Subsubsection One-Two-One' => '',
6328                       'Subsubsection One-Two-Three' => '',
6329                       'Subsubsection One-Two-Two' => '',
6330                       'T2H_today' => '',
6331                       'Table of Contents' => 'Inhoudsopgave',
6332                       'Table of contents' => '',
6333                       'The node you are looking for is at %{href}.' => '',
6334                       'This' => '',
6335                       'This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '',
6336                       'This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '',
6337                       'This document was generated on @i{%{date}} using @uref{%{program_homepage}, @i{%{program}}}.' => '',
6338                       'This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.' => '',
6339                       'Top' => '',
6340                       'Untitled Document' => '',
6341                       'Up' => '',
6342                       'Up node' => '',
6343                       'Up section' => '',
6344                       'by @emph{%{user}}' => '',
6345                       'by @emph{%{user}} on @emph{%{date}}' => '',
6346                       'current' => '',
6347                       'on @emph{%{date}}' => '',
6348                       'section `%{section}\' in @cite{%{book}}' => '',
6349                       'see %{node_file_href}' => '',
6350                       'see %{node_file_href} @cite{%{book}}' => '',
6351                       'see %{node_file_href} section `%{section}\' in @cite{%{book}}' => '',
6352                       'see %{reference_name}' => '',
6353                       'see @cite{%{book}}' => '',
6354                       'see section %{reference_name}' => '',
6355                       'see section `%{section}\' in @cite{%{book}}' => '',
6356                       'unknown' => ''
6357                     };
6358
6359$T2H_OBSOLETE_STRINGS->{'nl'} = {
6360                                  'See' => 'Zie',
6361                                  'section' => 'sectie',
6362                                  'see' => 'zie'
6363                                };
6364
6365
6366$LANGUAGES->{'no'} = {
6367                       '  The buttons in the navigation panels have the following meaning:' => '',
6368                       '  where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '',
6369                       ' Up ' => '',
6370                       '%{acronym_like} (%{explanation})' => '',
6371                       '%{month}, %{day} %{year}' => '',
6372                       '%{name} of %{class}' => '',
6373                       '%{name} on %{class}' => '',
6374                       '%{node_file_href}' => '',
6375                       '%{node_file_href} @cite{%{book}}' => '',
6376                       '%{node_file_href} section `%{section}\' in @cite{%{book}}' => '',
6377                       '%{reference_name}' => '',
6378                       '%{style} %{number}' => '',
6379                       '%{style}: %{caption_first_line}' => '',
6380                       '%{style}: %{shortcaption_first_line}' => '',
6381                       '@b{%{quotation_arg}:} ' => '',
6382                       '@cite{%{book}}' => '',
6383                       'About' => '',
6384                       'About (help)' => '',
6385                       'About This Document' => 'No translation available!',
6386                       'April' => 'april',
6387                       'August' => 'august',
6388                       'Back' => '',
6389                       'Beginning of this chapter or previous chapter' => '',
6390                       'Button' => '',
6391                       'Contents' => '',
6392                       'Cover (top) of document' => '',
6393                       'Current Position' => '',
6394                       'Current section' => '',
6395                       'December' => 'desember',
6396                       'FastBack' => '',
6397                       'FastForward' => '',
6398                       'February' => 'februar',
6399                       'First' => '',
6400                       'First section in reading order' => '',
6401                       'Following' => '',
6402                       'Following node' => '',
6403                       'Footnotes' => 'No translation available!',
6404                       'Forward' => '',
6405                       'From 1.2.3 go to' => '',
6406                       'Go to' => '',
6407                       'Index' => 'Indeks',
6408                       'Index Entry' => '',
6409                       'January' => 'januar',
6410                       'July' => 'juli',
6411                       'Jump to' => '',
6412                       'June' => 'juni',
6413                       'Last' => '',
6414                       'Last section in reading order' => '',
6415                       'March' => 'mars',
6416                       'May' => 'mai',
6417                       'Menu:' => '',
6418                       'Name' => '',
6419                       'Next' => '',
6420                       'Next chapter' => '',
6421                       'Next node' => '',
6422                       'Next section in reading order' => '',
6423                       'Next section on same level' => '',
6424                       'Node following in node reading order' => '',
6425                       'Node up' => '',
6426                       'NodeNext' => '',
6427                       'NodePrev' => '',
6428                       'NodeUp' => '',
6429                       'November' => 'november',
6430                       'October' => 'oktober',
6431                       'Overview' => '',
6432                       'Overview:' => '',
6433                       'Prev' => '',
6434                       'Previous node' => '',
6435                       'Previous section in reading order' => '',
6436                       'Previous section on same level' => '',
6437                       'Section' => '',
6438                       'Section One' => '',
6439                       'See %{node_file_href}' => '',
6440                       'See %{node_file_href} @cite{%{book}}' => '',
6441                       'See %{node_file_href} section `%{section}\' in @cite{%{book}}' => '',
6442                       'See %{reference_name}' => '',
6443                       'See @cite{%{book}}' => '',
6444                       'See section %{reference_name}' => '',
6445                       'See section `%{section}\' in @cite{%{book}}' => '',
6446                       'September' => 'september',
6447                       'Short Table of Contents' => 'Kort innholdsfortegnelse',
6448                       'Short table of contents' => '',
6449                       'Subsection One-Four' => '',
6450                       'Subsection One-One' => '',
6451                       'Subsection One-Three' => '',
6452                       'Subsection One-Two' => '',
6453                       'Subsubsection One-Two-Four' => '',
6454                       'Subsubsection One-Two-One' => '',
6455                       'Subsubsection One-Two-Three' => '',
6456                       'Subsubsection One-Two-Two' => '',
6457                       'T2H_today' => '',
6458                       'Table of Contents' => 'Innholdsfortegnelse',
6459                       'Table of contents' => '',
6460                       'The node you are looking for is at %{href}.' => '',
6461                       'This' => '',
6462                       'This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '',
6463                       'This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '',
6464                       'This document was generated on @i{%{date}} using @uref{%{program_homepage}, @i{%{program}}}.' => '',
6465                       'This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.' => '',
6466                       'Top' => '',
6467                       'Untitled Document' => '',
6468                       'Up' => '',
6469                       'Up node' => '',
6470                       'Up section' => '',
6471                       'by @emph{%{user}}' => '',
6472                       'by @emph{%{user}} on @emph{%{date}}' => '',
6473                       'current' => '',
6474                       'on @emph{%{date}}' => '',
6475                       'section `%{section}\' in @cite{%{book}}' => '',
6476                       'see %{node_file_href}' => '',
6477                       'see %{node_file_href} @cite{%{book}}' => '',
6478                       'see %{node_file_href} section `%{section}\' in @cite{%{book}}' => '',
6479                       'see %{reference_name}' => '',
6480                       'see @cite{%{book}}' => '',
6481                       'see section %{reference_name}' => '',
6482                       'see section `%{section}\' in @cite{%{book}}' => '',
6483                       'unknown' => ''
6484                     };
6485
6486$T2H_OBSOLETE_STRINGS->{'no'} = {
6487                                  'See' => 'Se',
6488                                  'section' => 'avsnitt',
6489                                  'see' => 'se'
6490                                };
6491
6492
6493$LANGUAGES->{'pt'} = {
6494                       '  The buttons in the navigation panels have the following meaning:' => '  Os bot@~oes nos pain@\'eis de navega@,{c}@~ao possuem os seguintes significados:',
6495                       '  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:',
6496                       ' Up ' => ' Acima ',
6497                       '%{acronym_like} (%{explanation})' => '',
6498                       '%{month}, %{day} %{year}' => '%{day} de %{month} de %{year}',
6499                       '%{name} of %{class}' => '%{name} da %{class}',
6500                       '%{name} on %{class}' => '%{name} na %{class}',
6501                       '%{node_file_href}' => '',
6502                       '%{node_file_href} @cite{%{book}}' => '',
6503                       '%{node_file_href} section `%{section}\' in @cite{%{book}}' => '%{node_file_href} se@,{c}@~ao `%{section}\' em @cite{%{book}}',
6504                       '%{reference_name}' => '',
6505                       '%{style} %{number}' => '',
6506                       '%{style}: %{caption_first_line}' => '',
6507                       '%{style}: %{shortcaption_first_line}' => '',
6508                       '@b{%{quotation_arg}:} ' => '',
6509                       '@cite{%{book}}' => '',
6510                       'About' => 'Sobre',
6511                       'About (help)' => 'Sobre (ajuda)',
6512                       'About This Document' => 'Sobre Esse Documento',
6513                       'April' => 'Abril',
6514                       'August' => 'Agosto',
6515                       'Back' => 'Volta',
6516                       'Beginning of this chapter or previous chapter' => 'Come@,{c}o desse cap@\'itulo ou cap@\'itulo anterior',
6517                       'Button' => 'Bot@~ao',
6518                       'Contents' => 'Conte@\'udo',
6519                       'Cover (top) of document' => 'In@\'icio (topo) do documento',
6520                       'Current Position' => 'Posi@,{c}@~ao Atual',
6521                       'Current section' => 'Se@,{c}@~ao atual',
6522                       'December' => 'Dezembro',
6523                       'FastBack' => 'Voltar R@\'apido',
6524                       'FastForward' => 'Avan@,{c}ar R@\'apido',
6525                       'February' => 'Fevereiro',
6526                       'First' => 'Primeiro',
6527                       'First section in reading order' => 'Primeira se@,{c}@~ao na ordem de leitura',
6528                       'Following' => 'Seguinte',
6529                       'Following node' => 'Nodo seguinte',
6530                       'Footnotes' => 'Notas de Rodap@\'e',
6531                       'Forward' => 'Avan@,{c}ar',
6532                       'From 1.2.3 go to' => 'De 1.2.3 v@\'a para',
6533                       'Go to' => 'V@\'a para',
6534                       'Index' => '@\'Indice',
6535                       'Index Entry' => 'Entrada de @\'Indice',
6536                       'January' => 'Janeiro',
6537                       'July' => 'Julho',
6538                       'Jump to' => 'Pular para',
6539                       'June' => 'Junho',
6540                       'Last' => '@\'Ultimo',
6541                       'Last section in reading order' => '@\'Ultima se@,{c}@~ao na ordem de leitura',
6542                       'March' => 'Mar@,{c}o',
6543                       'May' => 'Maio',
6544                       'Menu:' => '',
6545                       'Name' => 'Nome',
6546                       'Next' => 'Pr@\'oximo',
6547                       'Next chapter' => 'Pr@\'oximo cap@\'itulo',
6548                       'Next node' => 'Pr@\'oximo nodo',
6549                       'Next section in reading order' => 'Pr@\'oxima se@,{c}@~ao na ordem de leitura',
6550                       'Next section on same level' => 'Pr@\'oxima se@,{c}@~ao no mesmo n@\'ivel',
6551                       'Node following in node reading order' => 'Nodo seguinte na ordem de leitura de nodos',
6552                       'Node up' => 'Nodo acima',
6553                       'NodeNext' => 'Pr@\'oximo Nodo',
6554                       'NodePrev' => 'Nodo Anterior',
6555                       'NodeUp' => 'Nodo Acima',
6556                       'November' => 'Novembro',
6557                       'October' => 'Outubro',
6558                       'Overview' => 'Vis@~ao geral',
6559                       'Overview:' => 'Vis@~ao geral:',
6560                       'Prev' => 'Pr@\'evio',
6561                       'Previous node' => 'Nodo anterior',
6562                       'Previous section in reading order' => 'Se@,{c}@~ao anterior na ordem de leitura',
6563                       'Previous section on same level' => 'Se@,{c}@~ao anterior no mesmo n@\'ivel',
6564                       'Section' => 'Se@,{c}@~ao',
6565                       'Section One' => 'Se@,{c}@~ao Um',
6566                       'See %{node_file_href}' => 'Veja %{node_file_href}',
6567                       'See %{node_file_href} @cite{%{book}}' => 'Veja %{node_file_href} @cite{%{book}}',
6568                       'See %{node_file_href} section `%{section}\' in @cite{%{book}}' => 'Veja %{node_file_href} se@,{c}@~ao `%{section}\' em @cite{%{book}}',
6569                       'See %{reference_name}' => 'Veja %{reference_name}',
6570                       'See @cite{%{book}}' => 'Veja @cite{%{book}}',
6571                       'See section %{reference_name}' => 'Veja se@,{c}@~ao %{reference_name}',
6572                       'See section `%{section}\' in @cite{%{book}}' => 'Veja se@,{c}@~ao `%{section}\' em @cite{%{book}}',
6573                       'September' => 'Setembro',
6574                       'Short Table of Contents' => 'Breve Sum@\'ario',
6575                       'Short table of contents' => 'Breve sum@\'ario',
6576                       'Subsection One-Four' => 'Subse@,{c}@~ao Um-Quatro',
6577                       'Subsection One-One' => 'Subse@,{c}@~ao Um-Um',
6578                       'Subsection One-Three' => 'Subse@,{c}@~ao Um-Tr@^es',
6579                       'Subsection One-Two' => 'Subse@,{c}@~ao Um-Dois',
6580                       'Subsubsection One-Two-Four' => 'Subse@,{c}@~ao Um-Dois-Quatro',
6581                       'Subsubsection One-Two-One' => 'Subse@,{c}@~ao Um-Dois-Um',
6582                       'Subsubsection One-Two-Three' => 'Subse@,{c}@~ao Um-Dois-Tr@^es',
6583                       'Subsubsection One-Two-Two' => 'Subse@,{c}@~ao Um-Dois-Dois',
6584                       'T2H_today' => '',
6585                       'Table of Contents' => 'Sum@\'ario',
6586                       'Table of contents' => 'Sum@\'ario',
6587                       'The node you are looking for is at %{href}.' => 'O nodo que vo@^e est@\'a olhando est@\'a em %{href}.',
6588                       'This' => 'Esse',
6589                       'This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Esse documento foi gereado por @emph{%{user}} em @emph{%{date}} usando @uref{%{program_homepage}, @emph{%{program}}}.',
6590                       'This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Esse documento foi gerado por @emph{%{user}} usando @uref{%{program_homepage}, @emph{%{program}}}.',
6591                       '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}}}.',
6592                       'This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Esse documento foi gerado usando @uref{%{program_homepage}, @emph{%{program}}}.',
6593                       'Top' => 'Topo',
6594                       'Untitled Document' => 'Documento Sem Nome',
6595                       'Up' => 'Acima',
6596                       'Up node' => 'Nodo acima',
6597                       'Up section' => 'Se@,{c}@~ao acima',
6598                       'by @emph{%{user}}' => 'por  @emph{%{user}}',
6599                       'by @emph{%{user}} on @emph{%{date}}' => 'por @emph{%{user}} em @emph{%{date}}',
6600                       'current' => 'atual',
6601                       'on @emph{%{date}}' => 'em @emph{%{date}}',
6602                       'section `%{section}\' in @cite{%{book}}' => 'se@,{c}@~ao `%{section}\' em @cite{%{book}}',
6603                       'see %{node_file_href}' => 'veja %{node_file_href}',
6604                       'see %{node_file_href} @cite{%{book}}' => 'veja %{node_file_href} @cite{%{book}}',
6605                       'see %{node_file_href} section `%{section}\' in @cite{%{book}}' => 'veja %{node_file_href} se@,{c}@~ao `%{section}\' em @cite{%{book}}',
6606                       'see %{reference_name}' => 'veja %{reference_name}',
6607                       'see @cite{%{book}}' => 'veja @cite{%{book}}',
6608                       'see section %{reference_name}' => 'veja se@,{c}@~ao %{reference_name}',
6609                       'see section `%{section}\' in @cite{%{book}}' => 'veja se@,{c}@~ao `%{section}\' em @cite{%{book}}',
6610                       'unknown' => 'desconhecido'
6611                     };
6612
6613$T2H_OBSOLETE_STRINGS->{'pt'} = {
6614                                  'See' => 'Veja',
6615                                  'about (help)' => 'sobre (ajuda)',
6616                                  'beginning of this chapter or previous chapter' => 'come@,{c}o desse cap@\'itulo ou cap@\'itulo anterior',
6617                                  'cover (top) of document' => 'in@\'icio (topo) do documento',
6618                                  'current section' => 'se@,{c}@~ao atual',
6619                                  'first section in reading order' => 'primeira se@,{c}@~ao na ordem de leitura',
6620                                  'following node' => 'nodo seguinte',
6621                                  'index' => '@\'indice',
6622                                  'last section in reading order' => '@\'ultima se@,{c}@~ao na ordem de leitura',
6623                                  'next chapter' => 'pr@\'oximo cap@\'itulo',
6624                                  'next node' => 'pr@\'oximo nodo',
6625                                  'next section in reading order' => 'pr@\'oxima se@,{c}@~ao na ordem de leitura',
6626                                  'next section on same level' => 'pr@\'oxima se@,{c}@~ao no mesmo n@\'ivel',
6627                                  'node following in node reading order' => 'nodo seguinte na ordem de leitura de nodos',
6628                                  'node up' => 'nodo acima',
6629                                  'previous node' => 'nodo anterior',
6630                                  'previous section in reading order' => 'se@,{c}@~ao anterior na ordem de leitura',
6631                                  'previous section on same level' => 'se@,{c}@~ao anterior no mesmo n@\'ivel',
6632                                  'section' => 'Se@,{c}@~ao',
6633                                  'see' => 'veja',
6634                                  'short table of contents' => 'breve sum@\'ario',
6635                                  'table of contents' => 'sum@\'ario',
6636                                  'up node' => 'nodo acima',
6637                                  'up section' => 'se@,{c}@~ao acima'
6638                                };
6639
6640
6641$LANGUAGES->{'pt_BR'} = {
6642                          '  The buttons in the navigation panels have the following meaning:' => '  Os bot@~oes nos pain@\'eis de navega@,{c}@~ao possuem os seguintes significados:',
6643                          '  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:',
6644                          ' Up ' => ' Acima ',
6645                          '%{acronym_like} (%{explanation})' => '',
6646                          '%{month}, %{day} %{year}' => '%{day} de %{month} de %{year}',
6647                          '%{name} of %{class}' => '%{name} da %{class}',
6648                          '%{name} on %{class}' => '%{name} na %{class}',
6649                          '%{node_file_href}' => '',
6650                          '%{node_file_href} @cite{%{book}}' => '',
6651                          '%{node_file_href} section `%{section}\' in @cite{%{book}}' => '%{node_file_href} se@,{c}@~ao `%{section}\' em @cite{%{book}}',
6652                          '%{reference_name}' => '',
6653                          '%{style} %{number}' => '',
6654                          '%{style}: %{caption_first_line}' => '',
6655                          '%{style}: %{shortcaption_first_line}' => '',
6656                          '@b{%{quotation_arg}:} ' => '',
6657                          '@cite{%{book}}' => '',
6658                          'About' => 'Sobre',
6659                          'About (help)' => 'Sobre (ajuda)',
6660                          'About This Document' => 'Sobre Esse Documento',
6661                          'April' => 'Abril',
6662                          'August' => 'Agosto',
6663                          'Back' => 'Volta',
6664                          'Beginning of this chapter or previous chapter' => 'Come@,{c}o desse cap@\'itulo ou cap@\'itulo anterior',
6665                          'Button' => 'Bot@~ao',
6666                          'Contents' => 'Conte@\'udo',
6667                          'Cover (top) of document' => 'In@\'icio (topo) do documento',
6668                          'Current Position' => 'Posi@,{c}@~ao Atual',
6669                          'Current section' => 'Se@,{c}@~ao atual',
6670                          'December' => 'Dezembro',
6671                          'FastBack' => 'Voltar R@\'apido',
6672                          'FastForward' => 'Avan@,{c}ar R@\'apido',
6673                          'February' => 'Fevereiro',
6674                          'First' => 'Primeiro',
6675                          'First section in reading order' => 'Primeira se@,{c}@~ao na ordem de leitura',
6676                          'Following' => 'Seguinte',
6677                          'Following node' => 'Nodo seguinte',
6678                          'Footnotes' => 'Notas de Rodap@\'e',
6679                          'Forward' => 'Avan@,{c}ar',
6680                          'From 1.2.3 go to' => 'De 1.2.3 v@\'a para',
6681                          'Go to' => 'V@\'a para',
6682                          'Index' => '@\'Indice',
6683                          'Index Entry' => 'Entrada de @\'Indice',
6684                          'January' => 'Janeiro',
6685                          'July' => 'Julho',
6686                          'Jump to' => 'Pular para',
6687                          'June' => 'Junho',
6688                          'Last' => '@\'Ultimo',
6689                          'Last section in reading order' => '@\'Ultima se@,{c}@~ao na ordem de leitura',
6690                          'March' => 'Mar@,{c}o',
6691                          'May' => 'Maio',
6692                          'Menu:' => '',
6693                          'Name' => 'Nome',
6694                          'Next' => 'Pr@\'oximo',
6695                          'Next chapter' => 'Pr@\'oximo cap@\'itulo',
6696                          'Next node' => 'Pr@\'oximo nodo',
6697                          'Next section in reading order' => 'Pr@\'oxima se@,{c}@~ao na ordem de leitura',
6698                          'Next section on same level' => 'Pr@\'oxima se@,{c}@~ao no mesmo n@\'ivel',
6699                          'Node following in node reading order' => 'Nodo seguinte na ordem de leitura de nodos',
6700                          'Node up' => 'Nodo acima',
6701                          'NodeNext' => 'Pr@\'oximo Nodo',
6702                          'NodePrev' => 'Nodo Anterior',
6703                          'NodeUp' => 'Nodo Acima',
6704                          'November' => 'Novembro',
6705                          'October' => 'Outubro',
6706                          'Overview' => 'Vis@~ao geral',
6707                          'Overview:' => 'Vis@~ao geral:',
6708                          'Prev' => 'Pr@\'evio',
6709                          'Previous node' => 'Nodo anterior',
6710                          'Previous section in reading order' => 'Se@,{c}@~ao anterior na ordem de leitura',
6711                          'Previous section on same level' => 'Se@,{c}@~ao anterior no mesmo n@\'ivel',
6712                          'Section' => 'Se@,{c}@~ao',
6713                          'Section One' => 'Se@,{c}@~ao Um',
6714                          'See %{node_file_href}' => 'Veja %{node_file_href}',
6715                          'See %{node_file_href} @cite{%{book}}' => 'Veja %{node_file_href} @cite{%{book}}',
6716                          'See %{node_file_href} section `%{section}\' in @cite{%{book}}' => 'Veja %{node_file_href} se@,{c}@~ao `%{section}\' em @cite{%{book}}',
6717                          'See %{reference_name}' => 'Veja %{reference_name}',
6718                          'See @cite{%{book}}' => 'Veja @cite{%{book}}',
6719                          'See section %{reference_name}' => 'Veja se@,{c}@~ao %{reference_name}',
6720                          'See section `%{section}\' in @cite{%{book}}' => 'Veja se@,{c}@~ao `%{section}\' em @cite{%{book}}',
6721                          'September' => 'Setembro',
6722                          'Short Table of Contents' => 'Breve Sum@\'ario',
6723                          'Short table of contents' => 'Breve sum@\'ario',
6724                          'Subsection One-Four' => 'Subse@,{c}@~ao Um-Quatro',
6725                          'Subsection One-One' => 'Subse@,{c}@~ao Um-Um',
6726                          'Subsection One-Three' => 'Subse@,{c}@~ao Um-Tr@^es',
6727                          'Subsection One-Two' => 'Subse@,{c}@~ao Um-Dois',
6728                          'Subsubsection One-Two-Four' => 'Subse@,{c}@~ao Um-Dois-Quatro',
6729                          'Subsubsection One-Two-One' => 'Subse@,{c}@~ao Um-Dois-Um',
6730                          'Subsubsection One-Two-Three' => 'Subse@,{c}@~ao Um-Dois-Tr@^es',
6731                          'Subsubsection One-Two-Two' => 'Subse@,{c}@~ao Um-Dois-Dois',
6732                          'T2H_today' => '',
6733                          'Table of Contents' => 'Sum@\'ario',
6734                          'Table of contents' => 'Sum@\'ario',
6735                          'The node you are looking for is at %{href}.' => 'O nodo que vo@^e est@\'a olhando est@\'a em %{href}.',
6736                          'This' => 'Esse',
6737                          'This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Esse documento foi gereado por @emph{%{user}} em @emph{%{date}} usando @uref{%{program_homepage}, @emph{%{program}}}.',
6738                          'This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Esse documento foi gerado por @emph{%{user}} usando @uref{%{program_homepage}, @emph{%{program}}}.',
6739                          '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}}}.',
6740                          'This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Esse documento foi gerado usando @uref{%{program_homepage}, @emph{%{program}}}.',
6741                          'Top' => 'Topo',
6742                          'Untitled Document' => 'Documento Sem Nome',
6743                          'Up' => 'Acima',
6744                          'Up node' => 'Nodo acima',
6745                          'Up section' => 'Se@,{c}@~ao acima',
6746                          'by @emph{%{user}}' => 'por  @emph{%{user}}',
6747                          'by @emph{%{user}} on @emph{%{date}}' => 'por @emph{%{user}} em @emph{%{date}}',
6748                          'current' => 'atual',
6749                          'on @emph{%{date}}' => 'em @emph{%{date}}',
6750                          'section `%{section}\' in @cite{%{book}}' => 'se@,{c}@~ao `%{section}\' em @cite{%{book}}',
6751                          'see %{node_file_href}' => 'veja %{node_file_href}',
6752                          'see %{node_file_href} @cite{%{book}}' => 'veja %{node_file_href} @cite{%{book}}',
6753                          'see %{node_file_href} section `%{section}\' in @cite{%{book}}' => 'veja %{node_file_href} se@,{c}@~ao `%{section}\' em @cite{%{book}}',
6754                          'see %{reference_name}' => 'veja %{reference_name}',
6755                          'see @cite{%{book}}' => 'veja @cite{%{book}}',
6756                          'see section %{reference_name}' => 'veja se@,{c}@~ao %{reference_name}',
6757                          'see section `%{section}\' in @cite{%{book}}' => 'veja se@,{c}@~ao `%{section}\' em @cite{%{book}}',
6758                          'unknown' => 'desconhecido'
6759                        };
6760
6761$T2H_OBSOLETE_STRINGS->{'pt_BR'} = {
6762                                     'See' => 'Veja',
6763                                     'about (help)' => 'sobre (ajuda)',
6764                                     'beginning of this chapter or previous chapter' => 'come@,{c}o desse cap@\'itulo ou cap@\'itulo anterior',
6765                                     'cover (top) of document' => 'in@\'icio (topo) do documento',
6766                                     'current section' => 'se@,{c}@~ao atual',
6767                                     'first section in reading order' => 'primeira se@,{c}@~ao na ordem de leitura',
6768                                     'following node' => 'nodo seguinte',
6769                                     'index' => '@\'indice',
6770                                     'last section in reading order' => '@\'ultima se@,{c}@~ao na ordem de leitura',
6771                                     'next chapter' => 'pr@\'oximo cap@\'itulo',
6772                                     'next node' => 'pr@\'oximo nodo',
6773                                     'next section in reading order' => 'pr@\'oxima se@,{c}@~ao na ordem de leitura',
6774                                     'next section on same level' => 'pr@\'oxima se@,{c}@~ao no mesmo n@\'ivel',
6775                                     'node following in node reading order' => 'nodo seguinte na ordem de leitura de nodos',
6776                                     'node up' => 'nodo acima',
6777                                     'previous node' => 'nodo anterior',
6778                                     'previous section in reading order' => 'se@,{c}@~ao anterior na ordem de leitura',
6779                                     'previous section on same level' => 'se@,{c}@~ao anterior no mesmo n@\'ivel',
6780                                     'section' => 'Se@,{c}@~ao',
6781                                     'see' => 'veja',
6782                                     'short table of contents' => 'breve sum@\'ario',
6783                                     'table of contents' => 'sum@\'ario',
6784                                     'up node' => 'nodo acima',
6785                                     'up section' => 'se@,{c}@~ao acima'
6786                                   };
6787
6788
6789
6790require "$ENV{T2H_HOME}/$translation_file"
6791    if ($0 =~ /\.pl$/ &&
6792        -e "$ENV{T2H_HOME}/$translation_file" && -r "$ENV{T2H_HOME}/$translation_file");
6793
6794# set the default 'args' entry to normal for each style hash (and each command
6795# within)
6796my $name_index = -1;
6797my @hash_names = ('style_map', 'style_map_pre', 'style_map_texi', 'simple_format_style_map_texi');
6798foreach my $hash (\%style_map, \%style_map_pre, \%style_map_texi, \%simple_format_style_map_texi)
6799{
6800    $name_index++;
6801    my $name = $hash_names[$name_index]; # name associated with hash ref
6802    foreach my $style (keys(%{$hash}))
6803    {
6804        next unless (ref($hash->{$style}) eq 'HASH');
6805        $hash->{$style}->{'args'} = ['normal'] if (!exists($hash->{$style}->{'args'}));
6806        die "Bug: args not defined, but existing, for $style in $name" if (!defined($hash->{$style}->{'args'}));
6807#print STDERR "DEFAULT($name, $hash) add normal as arg for $style ($hash->{$style}), $hash->{$style}->{'args'}\n";
6808    }
6809}
6810
6811#
6812# Some functions used to override normal formatting functions in specific
6813# cases. The user shouldn't want to change them, but can use them.
6814#
6815
6816# used to utf8 encode the result
6817sub t2h_utf8_accent($$$)
6818{
6819    my $accent = shift;
6820    my $args = shift;
6821    my $style_stack = shift;
6822
6823    my $text = $args->[0];
6824    #print STDERR "$accent\[".scalar(@$style_stack) ."\] (@$style_stack)\n";
6825
6826    # special handling of @dotless{i}
6827    if ($accent eq 'dotless')
6828    {
6829        if (($text eq 'i') and (!defined($style_stack->[-1]) or (!defined($unicode_accents{$style_stack->[-1]})) or ($style_stack->[-1] eq 'tieaccent')))
6830        {
6831             return "\x{0131}";
6832        }
6833        #return "\x{}" if ($text eq 'j'); # not found !
6834        return $text;
6835    }
6836
6837    # FIXME \x{0131}\x{0308} for @dotless{i} @" doesn't lead to NFC 00ef.
6838    return Unicode::Normalize::NFC($text . chr(hex($unicode_diacritical{$accent})))
6839        if (defined($unicode_diacritical{$accent}));
6840    return ascii_accents($text, $accent);
6841}
6842
6843sub t2h_utf8_normal_text($$$$$)
6844{
6845    my $text = shift;
6846    my $in_raw_text = shift;
6847    my $in_preformatted = shift;
6848    my $in_code =shift;
6849    my $style_stack = shift;
6850    $text = &$protect_text($text) unless($in_raw_text);
6851    $text = uc($text) if (in_small_caps($style_stack));
6852
6853    if (!$in_code and !$in_preformatted)
6854    {
6855        $text =~ s/---/\x{2014}/g;
6856        $text =~ s/--/\x{2013}/g;
6857        $text =~ s/``/\x{201C}/g;
6858        $text =~ s/''/\x{201D}/g;
6859    }
6860    return Unicode::Normalize::NFC($text);
6861}
6862
6863# these are unlikely to be used by users, as they are essentially
6864# used to follow the html external refs specification in texinfo
6865sub t2h_cross_manual_normal_text($$$$$)
6866{
6867    my $text = shift;
6868    my $in_raw_text = shift;
6869    my $in_preformatted = shift;
6870    my $in_code =shift;
6871    my $style_stack = shift;
6872
6873    $text = uc($text) if (in_small_caps($style_stack));
6874    return $text if ($USE_UNICODE);
6875
6876    # if there is no unicode support, we do all the transformations here
6877    my $result = '';
6878    while ($text ne '')
6879    {
6880        if ($text =~ s/^([A-Za-z0-9]+)//o)
6881        {
6882             $result .= $1;
6883        }
6884        elsif ($text =~ s/^ //o)
6885        {
6886             $result .= '-';
6887        }
6888        elsif ($text =~ s/^(.)//o)
6889        {
6890             if (exists($ascii_character_map{$1}))
6891             {
6892                 $result .= '_' . lc($ascii_character_map{$1});
6893             }
6894             else
6895             { # wild guess that should work for latin1
6896                  $result .= '_' . '00' . lc(sprintf("%02x",ord($1)));
6897             }
6898        }
6899        else
6900        {
6901             print STDERR "Bug: unknown character in cross ref (likely in infinite loop)\n";
6902             sleep 1;
6903        }
6904    }
6905
6906    return $result;
6907}
6908
6909sub t2h_nounicode_cross_manual_accent($$$)
6910{
6911    my $accent = shift;
6912    my $args = shift;
6913    my $style_stack = shift;
6914
6915    my $text = $args->[0];
6916
6917    if ($accent eq 'dotless')
6918    {
6919        if (($text eq 'i') and (!defined($style_stack->[-1]) or (!defined($unicode_accents{$style_stack->[-1]})) or ($style_stack->[-1] eq 'tieaccent')))
6920        {
6921             return "_0131";
6922        }
6923        #return "\x{}" if ($text eq 'j'); # not found !
6924        return $text;
6925    }
6926    return '_' . lc($unicode_accents{$accent}->{$text})
6927        if (defined($unicode_accents{$accent}->{$text}));
6928    return ($text . '_' . lc($unicode_diacritical{$accent}))
6929        if (defined($unicode_diacritical{$accent}));
6930    return ascii_accents($text, $accent);
6931}
6932
6933sub t2h_transliterate_cross_manual_accent($$)
6934{
6935    my $accent = shift;
6936    my $args = shift;
6937
6938    my $text = $args->[0];
6939
6940    if (exists($unicode_accents{$accent}->{$text}) and
6941        exists ($transliterate_map{$unicode_accents{$accent}->{$text}}))
6942    {
6943         return $transliterate_map{$unicode_accents{$accent}->{$text}};
6944    }
6945    return $text;
6946}
6947
6948
6949} # end package Texi2HTML::Config
6950
6951use vars qw(
6952%value
6953);
6954
6955# variables which might be redefined by the user but aren't likely to be
6956# they seem to be in the main namespace
6957use vars qw(
6958%index_names
6959%predefined_index
6960%valid_index
6961%sec2level
6962%code_style_map
6963%region_lines
6964%forbidden_index_name
6965);
6966
6967# Some global variables are set in the script, and used in the subroutines
6968# they are in the Texi2HTML namespace, thus prefixed with Texi2HTML::.
6969# see texi2html.init for details.
6970
6971#+++############################################################################
6972#                                                                              #
6973# Initialization                                                               #
6974# Pasted content of File $(srcdir)/MySimple.pm: Command-line processing        #
6975#                                                                              #
6976#---############################################################################
6977
6978# leave this within comments, and keep the require statement
6979# This way, you can directly run texi2html.pl, if $ENV{T2H_HOME}/texi2html.init
6980# exists.
6981
6982# @MYSIMPLE@
6983package Getopt::MySimple;
6984
6985# Name:
6986#	Getopt::MySimple.
6987#
6988# Documentation:
6989#	POD-style (incomplete) documentation is in file MySimple.pod
6990#
6991# Tabs:
6992#	4 spaces || die.
6993#
6994# Author:
6995#	Ron Savage	rpsavage@ozemail.com.au.
6996#	1.00	19-Aug-97	Initial version.
6997#	1.10	13-Oct-97	Add arrays of switches (eg '=s@').
6998#	1.20	 3-Dec-97	Add 'Help' on a per-switch basis.
6999#	1.30	11-Dec-97	Change 'Help' to 'verbose'. Make all hash keys lowercase.
7000#	1.40	10-Nov-98	Change width of help report. Restructure tests.
7001#               1-Jul-00        Modifications for Texi2html
7002
7003# --------------------------------------------------------------------------
7004# Locally modified by obachman (Display type instead of env, order by cmp)
7005# $Id: MySimple.pm,v 1.5 2006/04/17 23:11:09 pertusus Exp $
7006
7007# use strict;
7008# no strict 'refs';
7009
7010use vars qw(@EXPORT @EXPORT_OK @ISA);
7011use vars qw($fieldWidth $opt $VERSION);
7012
7013use Exporter();
7014use Getopt::Long;
7015
7016@ISA		= qw(Exporter);
7017@EXPORT		= qw();
7018@EXPORT_OK	= qw($opt);	# An alias for $self -> {'opt'}.
7019
7020# --------------------------------------------------------------------------
7021
7022$fieldWidth	= 20;
7023$VERSION	= '1.41';
7024
7025# --------------------------------------------------------------------------
7026
7027sub byOrder
7028{
7029	my($self) = @_;
7030
7031	return uc($a) cmp (uc($b));
7032}
7033
7034# --------------------------------------------------------------------------
7035
7036sub dumpOptions
7037{
7038	my($self) = @_;
7039
7040	print 'Option', ' ' x ($fieldWidth - length('Option') ), "Value\n";
7041
7042	for (sort byOrder keys(%{$self -> {'opt'} }) )
7043	{
7044	  print "-$_", ' ' x ($fieldWidth - (1 + length) ), "${$self->{'opt'} }{$_}\n";
7045	}
7046
7047	print "\n";
7048
7049}	# End of dumpOptions.
7050
7051# --------------------------------------------------------------------------
7052# Return:
7053#	0 -> Error.
7054#	1 -> Ok.
7055
7056sub getOptions
7057{
7058	push(@_, 0) if ($#_ == 2);	# Default for $ignoreCase is 0.
7059	push(@_, 1) if ($#_ == 3);	# Default for $helpThenExit is 1.
7060
7061	my($self, $default, $helpText, $versionText,
7062	   $helpThenExit, $versionThenExit, $ignoreCase) = @_;
7063
7064	$helpThenExit = 1 unless (defined($helpThenExit));
7065	$versionThenExit = 1 unless (defined($versionThenExit));
7066	$ignoreCase = 0 unless (defined($ignoreCase));
7067
7068	$self -> {'default'}		= $default;
7069	$self -> {'helpText'}		= $helpText;
7070	$self -> {'versionText'}        = $versionText;
7071	$Getopt::Long::ignorecase	= $ignoreCase;
7072
7073	unless (defined($self -> {'default'}{'help'}))
7074	{
7075	  $self -> {'default'}{'help'} =
7076	  {
7077	   type => ':i',
7078	   default => '',
7079	   linkage => sub {$self->helpOptions($_[1]); sleep 5;exit (0) if $helpThenExit;},
7080	   verbose => "print help and exit"
7081	  };
7082	}
7083
7084	unless (defined($self -> {'default'}{'version'}))
7085	{
7086	  $self -> {'default'}{'version'} =
7087	  {
7088	   type => '',
7089	   default => '',
7090	   linkage => sub {print $self->{'versionText'};  exit (0) if $versionThenExit;},
7091	   verbose => "print version and exit"
7092	  };
7093	}
7094
7095	for (keys(%{$self -> {'default'} }) )
7096	{
7097	  next unless (ref(${$self -> {'default'} }{$_}) eq 'HASH');
7098	  my $type = ${$self -> {'default'} }{$_}{'type'};
7099	  push(@{$self -> {'type'} }, "$_$type");
7100	  $self->{'opt'}->{$_} =  ${$self -> {'default'} }{$_}{'linkage'}
7101            if ${$self -> {'default'} }{$_}{'linkage'};
7102	}
7103
7104	my($result) = &GetOptions($self -> {'opt'}, @{$self -> {'type'} });
7105
7106        return $result unless $result;
7107
7108	for (keys(%{$self -> {'default'} }) )
7109	{
7110 	   if (! defined(${$self -> {'opt'} }{$_})) #{
7111            {
7112 	     ${$self -> {'opt'} }{$_} = ${$self -> {'default'} }{$_}{'default'};
7113            }
7114	}
7115
7116	$result;
7117}	# End of getOptions.
7118
7119# --------------------------------------------------------------------------
7120
7121sub helpOptions
7122{
7123	my($self) = shift;
7124	my($noHelp) = shift;
7125	$noHelp = 0 unless $noHelp;
7126	my($optwidth, $typewidth, $defaultwidth, $maxlinewidth, $valind, $valwidth)
7127	  = (10, 5, 9, 78, 4, 11);
7128
7129	print "$self->{'helpText'}" if ($self -> {'helpText'});
7130
7131	print ' Option', ' ' x ($optwidth - length('Option') -1 ),
7132		'Type', ' ' x ($typewidth - length('Type') + 1),
7133		'Default', ' ' x ($defaultwidth - length('Default') ),
7134	        "Description\n";
7135
7136	for (sort byOrder keys(%{$self -> {'default'} }) )
7137	{
7138	  my($line, $help, $option, $val);
7139	  $option = $_;
7140	  next if ${$self->{'default'} }{$_}{'noHelp'} && ${$self->{'default'} }{$_}{'noHelp'} > $noHelp;
7141          #$line = " -$_" . ' ' x ($optwidth - (2 + length) ) .
7142          #      	"${$self->{'default'} }{$_}{'type'} ".
7143          #      	' ' x ($typewidth - (1+length(${$self -> {'default'} }{$_}{'type'}) ));
7144		$line = " --$_" . "${$self->{'default'} }{$_}{'type'}".
7145			' ' x ($typewidth - (1+length(${$self -> {'default'} }{$_}{'type'}) ));
7146
7147                 $val = ${$self->{'default'} }{$_}{'linkage'};
7148                if ($val)
7149                {
7150                  if ((ref($val) eq 'SCALAR') and (defined($$val)))
7151		  {
7152		    $val = $$val;
7153		  }
7154		  else
7155		  {
7156		    $val = '';
7157		  }
7158                }
7159		elsif (defined(${$self->{'default'} }{$_}{'default'}))
7160		{
7161		  $val = ${$self->{'default'} }{$_}{'default'};
7162		}
7163		else
7164		{
7165		  $val = '';
7166		}
7167	        $line .= "$val  ";
7168		$line .= ' ' x ($optwidth + $typewidth + $defaultwidth + 1 - length($line));
7169
7170		if (defined(${$self -> {'default'} }{$_}{'verbose'}) &&
7171		  ${$self -> {'default'} }{$_}{'verbose'} ne '')
7172	      {
7173		$help = "${$self->{'default'} }{$_}{'verbose'}";
7174	      }
7175	      else
7176	      {
7177		$help = ' ';
7178	      }
7179	      if ((length("$line") + length($help)) < $maxlinewidth)
7180	      {
7181		print $line , $help, "\n";
7182	      }
7183	      else
7184	      {
7185		print $line, "\n", ' ' x $valind, $help, "\n";
7186	      }
7187	      for $val (sort byOrder keys(%{${$self->{'default'}}{$option}{'values'}}))
7188	      {
7189	        print ' ' x ($valind + 2);
7190                print $val, '  ', ' ' x ($valwidth - length($val) - 2);
7191	        print ${$self->{'default'}}{$option}{'values'}{$val}, "\n";
7192	      }
7193	}
7194
7195	print <<EOT;
7196Note: 'Options' may be abbreviated. 'Type' specifications mean:
7197 <none>| !    no argument: variable is set to 1 on -foo (or, to 0 on -nofoo)
7198    =s | :s   mandatory (or, optional)  string argument
7199    =i | :i   mandatory (or, optional)  integer argument
7200EOT
7201}	# End of helpOptions.
7202
7203#-------------------------------------------------------------------
7204
7205sub new
7206{
7207	my($class)				= @_;
7208	my($self)				= {};
7209	$self -> {'default'}	= {};
7210	$self -> {'helpText'}	= '';
7211	$self -> {'opt'}		= {};
7212	$opt					= $self -> {'opt'};	 # An alias for $self -> {'opt'}.
7213	$self -> {'type'}		= ();
7214
7215	return bless $self, $class;
7216
7217}	# End of new.
7218
7219# --------------------------------------------------------------------------
7220
72211;
7222
7223# End MySimple.pm
7224
7225require "$ENV{T2H_HOME}/MySimple.pm"
7226    if ($0 =~ /\.pl$/ &&
7227        -e "$ENV{T2H_HOME}/MySimple.pm" && -r "$ENV{T2H_HOME}/MySimple.pm");
7228
7229#+++########################################################################
7230#                                                                          #
7231# Initialization                                                           #
7232# Pasted content of File $(srcdir)/T2h_i18n.pm: Internationalisation       #
7233#                                                                          #
7234#---########################################################################
7235
7236# leave this within comments, and keep the require statement
7237# This way, you can directly run texi2html.pl, if $ENV{T2H_HOME}/T2h_i18n.pm
7238# exists.
7239
7240# @T2H_I18N@
7241#+##############################################################################
7242#
7243# T2h_i18n.pm: Internationalization for texi2html
7244#
7245#    Copyright (C) 1999-2005  Patrice Dumas <dumas@centre-cired.fr>,
7246#                             Derek Price <derek@ximbiot.com>,
7247#                             Adrian Aichner <adrian@xemacs.org>,
7248#                           & others.
7249#
7250#    This program is free software; you can redistribute it and/or modify
7251#    it under the terms of the GNU General Public License as published by
7252#    the Free Software Foundation; either version 2 of the License, or
7253#    (at your option) any later version.
7254#
7255#    This program is distributed in the hope that it will be useful,
7256#    but WITHOUT ANY WARRANTY; without even the implied warranty of
7257#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
7258#    GNU General Public License for more details.
7259#
7260#    You should have received a copy of the GNU General Public License
7261#    along with this program; if not, write to the Free Software
7262#    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
7263#
7264#-##############################################################################
7265
7266# This requires perl version 5 or higher
7267require 5.0;
7268
7269package Texi2HTML::I18n;
7270
7271use strict;
7272
7273use vars qw(
7274@ISA
7275@EXPORT
7276);
7277
7278use Exporter;
7279@ISA = qw(Exporter);
7280@EXPORT = qw(pretty_date);
7281
7282my $language;
7283my $i18n_dir = 'i18n'; # name of the directory containing the per language files
7284#my $translation_file = 'translations.pl'; # file containing all the translations
7285#my @known_languages = ('de', 'nl', 'es', 'no', 'pt', 'fr'); # The supported
7286                                               # languages
7287
7288########################################################################
7289# Language dependencies:
7290# To add a new language extend the WORDS hash and create $T2H_<...>_WORDS hash
7291# To redefine one word, simply do:
7292# $T2h_i18n::T2H_LANGUAGES->{<language>}->{<word>} = 'whatever' in your personal init file.
7293#
7294
7295# Those hashes are obsolete but retained here for reference
7296
7297my $T2H_WORDS_EN =
7298{
7299 # titles  of pages
7300 #'Table of Contents'       => 'Table of Contents',
7301 #'Short Table of Contents'  => 'Short Table of Contents',
7302 #'Index'     => 'Index',
7303 #'About This Document'     => 'About This Document',
7304 #'Footnotes' => 'Footnotes',
7305 #'See'             => 'See',
7306 #'see'             => 'see',
7307 #'section'         => 'section',
7308 'About This Document'       => '',
7309 'Table of Contents'         => '',
7310 'Short Table of Contents',  => '',
7311 'Index'                     => '',
7312 'Footnotes'                 => '',
7313 'See'                       => '',
7314 'see'                       => '',
7315 'section'                   => '',
7316 'Top'                       => '',
7317 'Untitled Document'         => '',
7318 # If necessary, we could extend this as follows:
7319 #  # text for buttons
7320 #  'Top_Button' => 'Top',
7321 #  'ToC_Button' => 'Contents',
7322 #  'Overview_Button' => 'Overview',
7323 #  'Index_button' => 'Index',
7324 #  'Back_Button' => 'Back',
7325 #  'FastBack_Button' => 'FastBack',
7326 #  'Prev_Button' => 'Prev',
7327 #  'Up_Button' => 'Up',
7328 #  'Next_Button' => 'Next',
7329 #  'Forward_Button' =>'Forward',
7330 #  'FastWorward_Button' => 'FastForward',
7331 #  'First_Button' => 'First',
7332 #  'Last_Button' => 'Last',
7333 #  'About_Button' => 'About'
7334 'January' => '',
7335 'February' => '',
7336 'March' => '',
7337 'April' => '',
7338 'May' => '',
7339 'June' => '',
7340 'July' => '',
7341 'August' => '',
7342 'September' => '',
7343 'October' => '',
7344 'November' => '',
7345 'December' => '',
7346 'T2H_today' => '%s, %d %d',
7347};
7348
7349my $T2H_WORDS_DE =
7350{
7351 'Table of Contents'       => 'Inhaltsverzeichniss',
7352 'Short Table of Contents'  => 'Kurzes Inhaltsverzeichniss',
7353 'Index'     => 'Index',
7354 'About This Document'     => '&Uuml;ber dieses Dokument',
7355 'Footnotes' => 'Fu&szlig;noten',
7356 'See'             => 'Siehe',
7357 'see'             => 'siehe',
7358 'section'         => 'Abschnitt',
7359 'January' => 'Januar',
7360 'February' => 'Februar',
7361 'March' => 'M&auml;rz',
7362 'April' => 'April',
7363 'May' => 'Mai',
7364 'June' => 'Juni',
7365 'July' => 'Juli',
7366 'August' => 'August',
7367 'September' => 'September',
7368 'October' => 'Oktober',
7369 'November' => 'November',
7370 'December' => 'Dezember',
7371};
7372
7373my $T2H_WORDS_NL =
7374{
7375 'Table of Contents'       => 'Inhoudsopgave',
7376 'Short Table of Contents'  => 'Korte inhoudsopgave',
7377 'Index'     => 'Index',      #Not sure ;-)
7378 'About This Document'     => 'No translation available!', #No translation available!
7379 'Footnotes' => 'No translation available!', #No translation available!
7380 'See'             => 'Zie',
7381 'see'             => 'zie',
7382 'section'         => 'sectie',
7383 'January' => 'Januari',
7384 'February' => 'Februari',
7385 'March' => 'Maart',
7386 'April' => 'April',
7387 'May' => 'Mei',
7388 'June' => 'Juni',
7389 'July' => 'Juli',
7390 'August' => 'Augustus',
7391 'September' => 'September',
7392 'October' => 'Oktober',
7393 'November' => 'November',
7394 'December' => 'December',
7395};
7396
7397my $T2H_WORDS_ES =
7398{
7399 'Table of Contents'       => '&iacute;ndice General',
7400 'Short Table of Contents'  => 'Resumen del Contenido',
7401 'Index'     => 'Index',      #Not sure ;-)
7402 'About This Document'     => 'No translation available!', #No translation available!
7403 'Footnotes' => 'Fu&szlig;noten',
7404 'See'             => 'V&eacute;ase',
7405 'see'             => 'v&eacute;ase',
7406 'section'         => 'secci&oacute;n',
7407 'January' => 'enero',
7408 'February' => 'febrero',
7409 'March' => 'marzo',
7410 'April' => 'abril',
7411 'May' => 'mayo',
7412 'June' => 'junio',
7413 'July' => 'julio',
7414 'August' => 'agosto',
7415 'September' => 'septiembre',
7416 'October' => 'octubre',
7417 'November' => 'noviembre',
7418 'December' => 'diciembre',
7419};
7420
7421my $T2H_WORDS_NO =
7422{
7423 'Table of Contents'       => 'Innholdsfortegnelse',
7424 'Short Table of Contents'  => 'Kort innholdsfortegnelse',
7425 'Index'     => 'Indeks',     #Not sure ;-)
7426 'About This Document'     => 'No translation available!', #No translation available!
7427 'Footnotes' => 'No translation available!',
7428 'See'             => 'Se',
7429 'see'             => 'se',
7430 'section'         => 'avsnitt',
7431 'January' => 'januar',
7432 'February' => 'februar',
7433 'March' => 'mars',
7434 'April' => 'april',
7435 'May' => 'mai',
7436 'June' => 'juni',
7437 'July' => 'juli',
7438 'August' => 'august',
7439 'September' => 'september',
7440 'October' => 'oktober',
7441 'November' => 'november',
7442 'December' => 'desember',
7443};
7444
7445my $T2H_WORDS_PT =
7446{
7447 'Table of Contents'       => 'Sum&aacute;rio',
7448 'Short Table of Contents'  => 'Breve Sum&aacute;rio',
7449 'Index'     => '&Iacute;ndice', #Not sure ;-)
7450 'About This Document'     => 'No translation available!', #No translation available!
7451 'Footnotes' => 'No translation available!',
7452 'See'             => 'Veja',
7453 'see'             => 'veja',
7454 'section'         => 'Se&ccedil;&atilde;o',
7455 'January' => 'Janeiro',
7456 'February' => 'Fevereiro',
7457 'March' => 'Mar&ccedil;o',
7458 'April' => 'Abril',
7459 'May' => 'Maio',
7460 'June' => 'Junho',
7461 'July' => 'Julho',
7462 'August' => 'Agosto',
7463 'September' => 'Setembro',
7464 'October' => 'Outubro',
7465 'November' => 'Novembro',
7466 'December' => 'Dezembro',
7467};
7468
7469my $T2H_WORDS_FR =
7470{
7471 'Table of Contents'       => 'Table des mati&egrave;res',
7472 'Short Table of Contents'  => 'R&eacute;sum&eacute;e du contenu',
7473 'Index'     => 'Index',
7474 'About This Document'     => 'A propos de ce document',
7475 'Footnotes' => 'Notes de bas de page',
7476 'See'             => 'Voir',
7477 'see'             => 'voir',
7478 'section'         => 'section',
7479 'January' => 'Janvier',
7480 'February' => 'F&eacute;vrier',
7481 'March' => 'Mars',
7482 'April' => 'Avril',
7483 'May' => 'Mai',
7484 'June' => 'Juin',
7485 'July' => 'Juillet',
7486 'August' => 'Ao&ucirc;t',
7487 'September' => 'Septembre',
7488 'October' => 'Octobre',
7489 'November' => 'Novembre',
7490 'December' => 'D&eacute;cembre',
7491 'T2H_today' => 'le %2$d %1$s %3$d'
7492};
7493
7494#$T2H_LANGUAGES =
7495#{
7496# 'en' => $T2H_WORDS_EN,
7497# 'de' => $T2H_WORDS_DE,
7498# 'nl' => $T2H_WORDS_NL,
7499# 'es' => $T2H_WORDS_ES,
7500# 'no' => $T2H_WORDS_NO,
7501# 'pt' => $T2H_WORDS_PT,
7502# 'fr' => $T2H_WORDS_FR,
7503#};
7504
7505sub set_language($)
7506{
7507    my $lang = shift;
7508    if (defined($lang) && exists($Texi2HTML::Config::LANGUAGES->{$lang}) && defined($Texi2HTML::Config::LANGUAGES->{$lang}))
7509    {
7510         $language = $lang;
7511         return 1;
7512    }
7513    else
7514    {
7515         return 0;
7516    }
7517}
7518
7519
7520my @MONTH_NAMES =
7521    (
7522     'January', 'February', 'March', 'April', 'May',
7523     'June', 'July', 'August', 'September', 'October',
7524     'November', 'December'
7525    );
7526
7527my $I = \&get_string;
7528
7529sub pretty_date($)
7530{
7531    my $lang = shift;
7532    my($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);
7533
7534    ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
7535    $year += ($year < 70) ? 2000 : 1900;
7536    # obachman: Let's do it as the Americans do
7537    #return($MONTH_NAMES->{$lang}[$mon] . ", " . $mday . " " . $year);
7538	#return(sprintf(&$I('T2H_today'), (get_string($MONTH_NAMES[$mon]), $mday, $year)));
7539	return &$I('%{month}, %{day} %{year}', { 'month' => get_string($MONTH_NAMES[$mon]),
7540          'day' => $mday, 'year' => $year });
7541}
7542
7543my $error_no_en = 0;
7544sub get_string($;$$)
7545{
7546    my $string = shift;
7547    my $arguments = shift;
7548    my $state = shift;
7549    my $T2H_LANGUAGES = $Texi2HTML::Config::LANGUAGES;
7550    if (! exists($T2H_LANGUAGES->{'en'}))
7551    {
7552        unless($error_no_en)
7553        {
7554            print STDERR "i18n: no LANGUAGES->{'en'} hash\n";
7555            $error_no_en = 1;
7556        }
7557    }
7558    else
7559    {
7560        print STDERR "i18n: missing string $string\n" unless (exists ($T2H_LANGUAGES->{'en'}->{$string}));
7561        if (defined ($T2H_LANGUAGES->{$language}->{$string}) and
7562           ($T2H_LANGUAGES->{$language}->{$string} ne ''))
7563        {
7564            $string = $T2H_LANGUAGES->{$language}->{$string};
7565        }
7566        elsif (defined ($T2H_LANGUAGES->{'en'}->{$string}) and
7567            ($T2H_LANGUAGES->{'en'}->{$string} ne ''))
7568        {
7569            $string = $T2H_LANGUAGES->{'en'}->{$string};
7570        }
7571    }
7572    return main::substitute_line($string, $state) unless (defined($arguments) or !keys(%$arguments));
7573    # if there are arguments, we must protect the %{arg} constructs before
7574    # doing substitute_line. So there is a first pass here to change %{arg}
7575    # to %@{arg@}
7576    my $result = '';
7577    if (!$state->{'keep_texi'})
7578    {
7579        while ($string)
7580        {
7581            if ($string =~ s/^([^%]*)%//)
7582            {
7583                $result .= $1 if (defined($1));
7584                $result .= '%';
7585                if ($string =~ s/^%//)
7586                {
7587                     $result .= '%';
7588                }
7589                elsif ($string =~ /^\{(\w+)\}/ and exists($arguments->{$1}))
7590                {
7591                     $string =~ s/^\{(\w+)\}//;
7592                     $result .= "\@\{$1\@\}";
7593                }
7594                else
7595                {
7596                     $result .= '%';
7597                }
7598                next;
7599            }
7600            else
7601            {
7602                $result .= $string;
7603                last;
7604            }
7605        }
7606        $string = main::substitute_line($result, $state);
7607    }
7608    # now we substitute the arguments
7609    $result = '';
7610    while ($string)
7611    {
7612        if ($string =~ s/^([^%]*)%//)
7613        {
7614            $result .= $1 if (defined($1));
7615            if ($string =~ s/^%//)
7616            {
7617                 $result .= '%';
7618            }
7619            elsif ($string =~ /^\{(\w+)\}/ and exists($arguments->{$1}))
7620            {
7621                 $string =~ s/^\{(\w+)\}//;
7622                 $result .= $arguments->{$1};
7623            }
7624            else
7625            {
7626                 $result .= '%';
7627            }
7628            next;
7629        }
7630        else
7631        {
7632            $result .= $string;
7633            last;
7634        }
7635    }
7636    return $result;
7637}
7638
76391;
7640require "$ENV{T2H_HOME}/T2h_i18n.pm"
7641    if ($0 =~ /\.pl$/ &&
7642        -e "$ENV{T2H_HOME}/T2h_i18n.pm" && -r "$ENV{T2H_HOME}/T2h_i18n.pm");
7643
7644
7645#########################################################################
7646#
7647# latex2html stuff
7648#
7649#---######################################################################
7650
7651{
7652# leave this within comments, and keep the require statement
7653# This way, you can directly run texi2html.pl, if $ENV{T2H_HOME}/T2h_l2h.pm
7654# exists.
7655
7656# @T2H_L2H@
7657#+##############################################################################
7658#
7659# T2h_l2h.pm: interface to LaTeX2HTML
7660#
7661#    Copyright (C) 1999-2005  Patrice Dumas <dumas@centre-cired.fr>,
7662#                             Derek Price <derek@ximbiot.com>,
7663#                             Adrian Aichner <adrian@xemacs.org>,
7664#                           & others.
7665#
7666#    This program is free software; you can redistribute it and/or modify
7667#    it under the terms of the GNU General Public License as published by
7668#    the Free Software Foundation; either version 2 of the License, or
7669#    (at your option) any later version.
7670#
7671#    This program is distributed in the hope that it will be useful,
7672#    but WITHOUT ANY WARRANTY; without even the implied warranty of
7673#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
7674#    GNU General Public License for more details.
7675#
7676#    You should have received a copy of the GNU General Public License
7677#    along with this program; if not, write to the Free Software
7678#    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
7679#    02110-1301  USA
7680#
7681#-##############################################################################
7682
7683require 5.0;
7684use strict;
7685
7686package Texi2HTML::LaTeX2HTML;
7687use Cwd;
7688
7689
7690# latex2html conversions consist of three stages:
7691# 1) ToLatex: Put "latex" code into a latex file
7692# 2) ToHtml: Use latex2html to generate corresponding html code and images
7693# 3) FromHtml: Extract generated code and images from latex2html run
7694#
7695
7696# init l2h defaults for files and names
7697
7698# global variable used for caching
7699use vars qw(
7700            %l2h_cache
7701           );
7702
7703my ($l2h_name, $l2h_latex_file, $l2h_cache_file, $l2h_html_file, $l2h_prefix);
7704
7705# holds the status of latex2html operations. If 0 it means that there was
7706# an error
7707my $status = 0;
7708
7709my $debug;
7710my $verbose;
7711my $docu_rdir;
7712my $docu_name;
7713my $docu_ext;
7714my $ERROR = '***';
7715
7716##########################
7717#
7718# First stage: Generation of Latex file
7719# Initialize with: init
7720# Add content with: to_latex ($text) --> HTML placeholder comment
7721# Finish with: finish_to_latex
7722#
7723
7724my $l2h_latex_preamble = <<EOT;
7725% This document was automatically generated by the l2h extenstion of texi2html
7726% DO NOT EDIT !!!
7727\\documentclass{article}
7728\\usepackage{html}
7729\\begin{document}
7730EOT
7731
7732my $l2h_latex_closing = <<EOT;
7733\\end{document}
7734EOT
7735
7736my %l2h_to_latex = ();         # associate a latex text with the index in the
7737                               # html result array.
7738my @l2h_to_latex = ();         # array used to associate the index with
7739                               # the original latex text.
7740my $latex_count = 0;           # number of latex texts really stored
7741my $latex_converted_count = 0; # number of latex texts passed through latex2html
7742my $to_latex_count = 0;        # total number of latex texts processed
7743my $cached_count = 0;          # number of cached latex texts
7744%l2h_cache = ();               # the cache hash. Associate latex text with
7745                               # html from the previous run
7746my @l2h_from_html;             # array of resulting html
7747
7748my %global_count = ();         # associate a command name and the
7749                               # corresponding counter to the index in the
7750                               # html result array
7751
7752# set $status to 1, if l2h could be initalized properly, to 0 otherwise
7753sub init()
7754{
7755    $docu_name = $Texi2HTML::THISDOC{'file_base_name'};
7756    $docu_rdir = $Texi2HTML::THISDOC{'out_dir'};
7757    $docu_ext = $Texi2HTML::THISDOC{'extension'};
7758    $l2h_name =  "${docu_name}_l2h";
7759    $l2h_latex_file = "$docu_rdir${l2h_name}.tex";
7760    $l2h_cache_file = "${docu_rdir}${docu_name}-l2h_cache.pm";
7761    # destination dir -- generated images are put there, should be the same
7762    # as dir of enclosing html document --
7763    $l2h_html_file = "$docu_rdir${l2h_name}.html";
7764    $l2h_prefix = "${l2h_name}_";
7765    $debug = $Texi2HTML::THISDOC{'debug_l2h'};
7766    $verbose = $Texi2HTML::Config::VERBOSE;
7767
7768    unless ($Texi2HTML::Config::L2H_SKIP)
7769    {
7770        unless (open(L2H_LATEX, ">$l2h_latex_file"))
7771        {
7772            warn "$ERROR l2h: Can't open latex file '$l2h_latex_file' for writing: $!\n";
7773            $status = 0;
7774            return;
7775        }
7776        warn "# l2h: use ${l2h_latex_file} as latex file\n" if ($verbose);
7777        print L2H_LATEX $l2h_latex_preamble;
7778    }
7779    # open the database that holds cached text
7780    init_cache();
7781    $status = 1;
7782}
7783
7784
7785# print text (2nd arg) into latex file (if not already there nor in cache)
7786# which can be later on replaced by the latex2html generated text.
7787#
7788sub to_latex($$$)
7789{
7790    my $command = shift;
7791    my $text = shift;
7792    my $counter = shift;
7793    if ($command eq 'tex')
7794    {
7795        $text .= ' ';
7796    }
7797    elsif ($command eq 'math')
7798    {
7799        $text = "\$".$text."\$";
7800    }
7801    $to_latex_count++;
7802    $text =~ s/(\s*)$//;
7803    # try whether we have text already on things to do
7804    my $count = $l2h_to_latex{$text};
7805    unless ($count)
7806    {
7807        $latex_count++;
7808        $count = $latex_count;
7809        # try whether we can get it from cache
7810        my $cached_text = from_cache($text);
7811        if (defined($cached_text))
7812        {
7813             $cached_count++;
7814             # put the cached result in the html result array
7815             $l2h_from_html[$count] = $cached_text;
7816        }
7817        else
7818        {
7819             $latex_converted_count++;
7820             unless ($Texi2HTML::Config::L2H_SKIP)
7821             {
7822                 print L2H_LATEX "\\begin{rawhtml}\n";
7823                 print L2H_LATEX "<!-- l2h_begin $l2h_name $count -->\n";
7824                 print L2H_LATEX "\\end{rawhtml}\n";
7825
7826                 print L2H_LATEX "$text\n";
7827
7828                 print L2H_LATEX "\\begin{rawhtml}\n";
7829                 print L2H_LATEX "<!-- l2h_end $l2h_name $count -->\n";
7830                 print L2H_LATEX "\\end{rawhtml}\n";
7831            }
7832        }
7833        $l2h_to_latex[$count] = $text;
7834        $l2h_to_latex{$text} = $count;
7835    }
7836    $global_count{"${command}_$counter"} = $count;
7837    return 1;
7838}
7839
7840# print closing into latex file and close it
7841sub finish_to_latex()
7842{
7843    my $reused = $to_latex_count - $latex_converted_count - $cached_count;
7844    unless ($Texi2HTML::Config::L2H_SKIP)
7845    {
7846        print L2H_LATEX $l2h_latex_closing;
7847        close (L2H_LATEX);
7848    }
7849    warn "# l2h: finished to latex ($cached_count cached, $reused reused, $latex_converted_count to process)\n" if ($verbose);
7850    unless ($latex_count)
7851    {
7852        # no @tex nor @math
7853        finish();
7854        return 0;
7855    }
7856    return 1;
7857}
7858
7859###################################
7860# Second stage: Use latex2html to generate corresponding html code and images
7861#
7862# to_html([$l2h_latex_file, [$l2h_html_dir]]):
7863#   Call latex2html on $l2h_latex_file
7864#   Put images (prefixed with $l2h_name."_") and html file(s) in $l2h_html_dir
7865#   Return 1, on success
7866#          0, otherwise
7867#
7868sub to_html()
7869{
7870    my ($call, $dotbug);
7871    # when there are no tex constructs to convert (happens in case everything
7872    # comes from the cache), there is no latex2html run
7873    if ($Texi2HTML::Config::L2H_SKIP or ($latex_converted_count == 0))
7874    {
7875        warn "# l2h: skipping latex2html run\n" if ($verbose);
7876        return 1;
7877    }
7878    # Check for dot in directory where dvips will work
7879    if ($Texi2HTML::Config::L2H_TMP)
7880    {
7881        if ($Texi2HTML::Config::L2H_TMP =~ /\./)
7882        {
7883            warn "$ERROR Warning l2h: l2h_tmp dir contains a dot. Use /tmp, instead\n";
7884            $dotbug = 1;
7885        }
7886    }
7887    else
7888    {
7889        if (cwd() =~ /\./)
7890        {
7891            warn "$ERROR Warning l2h: current dir contains a dot. Use /tmp as l2h_tmp dir \n";
7892            $dotbug = 1;
7893        }
7894    }
7895    # fix it, if necessary and hope that it works
7896    $Texi2HTML::Config::L2H_TMP = "/tmp" if ($dotbug);
7897
7898    $call = $Texi2HTML::Config::L2H_L2H;
7899    # use init file, if specified
7900    my $init_file = main::locate_init_file($Texi2HTML::Config::L2H_FILE);
7901    $call = $call . " -init_file " . $init_file if ($init_file);
7902    # set output dir
7903    $call .=  ($docu_rdir ? " -dir $docu_rdir" : " -no_subdir");
7904    # use l2h_tmp, if specified
7905    $call .= " -tmp $Texi2HTML::Config::L2H_TMP" if ($Texi2HTML::Config::L2H_TMP);
7906    # use a given html version if specified
7907    $call .= " -html_version $Texi2HTML::Config::L2H_HTML_VERSION" if ($Texi2HTML::Config::L2H_HTML_VERSION);
7908    # options we want to be sure of
7909    $call .= " -address 0 -info 0 -split 0 -no_navigation -no_auto_link";
7910    $call .= " -prefix $l2h_prefix $l2h_latex_file";
7911
7912    warn "# l2h: executing '$call'\n" if ($verbose);
7913    if (system($call))
7914    {
7915        warn "$ERROR l2h: '${call}' did not succeed\n";
7916        return 0;
7917    }
7918    else
7919    {
7920        warn "# l2h: latex2html finished successfully\n" if ($verbose);
7921        return 1;
7922    }
7923}
7924
7925##########################
7926# Third stage: Extract generated contents from latex2html run
7927# Initialize with: init_from_html
7928#   open $l2h_html_file for reading
7929#   reads in contents into array indexed by numbers
7930#   return 1,  on success -- 0, otherwise
7931# Finish with: finish
7932#   closes $l2h_html_dir/$l2h_name.".$docu_ext"
7933
7934# the images generated by latex2html have names like ${docu_name}_l2h_img?.png
7935# they are copied to ${docu_name}_?.png, and html is changed accordingly.
7936my %l2h_img;            # associate src file to destination file
7937                        # such that files are not copied twice
7938my $image_count = 1;
7939sub change_image_file_names($)
7940{
7941    my $content = shift;
7942    my @images = ($content =~ /SRC="(.*?)"/g);
7943    my ($src, $dest);
7944
7945    for $src (@images)
7946    {
7947        $dest = $l2h_img{$src};
7948        unless ($dest)
7949        {
7950            my $ext = '';
7951            if ($src =~ /.*\.(.*)$/ && $1 ne $docu_ext)
7952            {
7953                $ext = ".$1";
7954            }
7955            else
7956            {
7957                warn "$ERROR: L2h image $src has invalid extension\n";
7958                next;
7959            }
7960            while (-e "$docu_rdir${docu_name}_${image_count}$ext")
7961            {
7962                $image_count++;
7963            }
7964            $dest = "${docu_name}_${image_count}$ext";
7965# FIXME this isn't portable. + error condition not checked.
7966            system("cp -f $docu_rdir$src $docu_rdir$dest");
7967            $l2h_img{$src} = $dest;
7968# FIXME error condition not checked
7969            unlink "$docu_rdir$src" unless ($debug);
7970        }
7971        $content =~ s/SRC="$src"/SRC="$dest"/g;
7972    }
7973    return $content;
7974}
7975
7976my $extract_error_count = 0;
7977my $invalid_counter_count = 0;
7978
7979sub init_from_html()
7980{
7981    # when there are no tex constructs to convert (happens in case everything
7982    # comes from the cache), the html file that was generated by previous
7983    # latex2html runs isn't reused.
7984    if ($latex_converted_count == 0)
7985    {
7986        return 1;
7987    }
7988
7989    if (! open(L2H_HTML, "<$l2h_html_file"))
7990    {
7991        warn "$ERROR l2h: Can't open $l2h_html_file for reading\n";
7992        return 0;
7993    }
7994    warn "# l2h: use $l2h_html_file as html file\n" if ($verbose);
7995
7996    my $html_converted_count = 0;   # number of html resulting texts
7997                                    # retrieved in the file
7998
7999    my ($count, $h_line);
8000    while ($h_line = <L2H_HTML>)
8001    {
8002        if ($h_line =~ /^<!-- l2h_begin $l2h_name ([0-9]+) -->/)
8003        {
8004            $count = $1;
8005            my $h_content = '';
8006            my $h_end_found = 0;
8007            while ($h_line = <L2H_HTML>)
8008            {
8009                if ($h_line =~ /^<!-- l2h_end $l2h_name $count -->/)
8010                {
8011                    $h_end_found = 1;
8012                    chomp $h_content;
8013                    chomp $h_content;
8014                    $html_converted_count++;
8015                    # transform image file names and copy image files
8016                    $h_content = change_image_file_names($h_content);
8017                    # store result in the html result array
8018                    $l2h_from_html[$count] = $h_content;
8019                    # also add the result in cache hash
8020                    $l2h_cache{$l2h_to_latex[$count]} = $h_content;
8021                    last;
8022                }
8023                $h_content = $h_content.$h_line;
8024            }
8025            unless ($h_end_found)
8026            { # couldn't found the closing comment. Certainly  a bug.
8027                warn "$ERROR l2h(BUG): l2h_end $l2h_name $count not found\n";
8028                close(L2H_HTML);
8029                return 0;
8030            }
8031        }
8032    }
8033
8034    # Not the same number of converted elements and retrieved elements
8035    if ($latex_converted_count != $html_converted_count)
8036    {
8037        warn "$ERROR l2h(BUG): waiting for $latex_converted_count elements found $html_converted_count\n";
8038    }
8039
8040    warn "# l2h: Got $html_converted_count of $latex_count html contents\n"
8041        if ($verbose);
8042
8043    close(L2H_HTML);
8044    return 1;
8045}
8046
8047my $html_output_count = 0;   # html text outputed in html result file
8048
8049# called each time a construct handled by latex2html is encountered, should
8050# output the corresponding html
8051sub do_tex($$$$)
8052{
8053    my $style = shift;
8054    my $counter = shift;
8055    my $state = shift;
8056    my $count = $global_count{"${style}_$counter"};
8057    ################################## begin debug section (incorrect counts)
8058    if (!defined($count))
8059    {
8060         # counter is undefined
8061         $invalid_counter_count++;
8062         warn "$ERROR l2h(BUG): undefined count for ${style}_$counter\n";
8063         return ("<!-- l2h: ". __LINE__ . " undef count for ${style}_$counter -->")
8064                if ($debug);
8065         return '';
8066    }
8067    elsif(($count <= 0) or ($count > $latex_count))
8068    {
8069        # counter out of range
8070        $invalid_counter_count++;
8071        warn "$ERROR l2h(BUG): Request of $count content which is out of valide range [0,$latex_count)\n";
8072         return ("<!-- l2h: ". __LINE__ . " out of range count $count -->")
8073                if ($debug);
8074         return '';
8075    }
8076    ################################## end debug section (incorrect counts)
8077
8078    # this seems to be a valid counter
8079    my $result = '';
8080    $result = "<!-- l2h_begin $l2h_name $count -->" if ($debug);
8081    if (defined($l2h_from_html[$count]))
8082    {
8083         $html_output_count++;
8084         # maybe we could also have something if simple_format
8085         # with Texi2HTML::Config::protect_text, once simple_format
8086         # may happen for anything else than lines
8087         if ($state->{'remove_texi'})
8088         {# don't protect anything
8089             $result .= $l2h_to_latex[$count];
8090         }
8091         else
8092         {
8093             $result .= $l2h_from_html[$count];
8094         }
8095    }
8096    else
8097    {
8098    # if the result is not in @l2h_from_html, there is an error somewhere.
8099        $extract_error_count++;
8100        warn "$ERROR l2h(BUG): can't extract content $count from html\n";
8101        # try simple (ordinary) substitution (without l2h)
8102        $result .= "<!-- l2h: ". __LINE__ . " use texi2html -->" if ($debug);
8103        $result .= main::substitute_text({}, $l2h_to_latex[$count]);
8104    }
8105    $result .= "<!-- l2h_end $l2h_name $count -->" if ($debug);
8106    return $result;
8107}
8108
8109# store results in the cache and remove temporary files.
8110sub finish()
8111{
8112    return unless($status);
8113    if ($verbose)
8114    {
8115        if ($extract_error_count + $invalid_counter_count)
8116        {
8117            warn "# l2h: finished from html ($extract_error_count extract and $invalid_counter_count invalid counter errors)\n";
8118        }
8119        else
8120        {
8121            warn "# l2h: finished from html (no error)\n";
8122        }
8123        if ($html_output_count != $latex_converted_count)
8124        { # this may happen if @-commands are collected at some places
8125          # but @-command at those places are not expanded later. For
8126          # example @math on @multitable lines.
8127             warn "# l2h: $html_output_count html outputed for $latex_converted_count converted\n";
8128        }
8129    }
8130    store_cache();
8131    if ($Texi2HTML::Config::L2H_CLEAN)
8132    {
8133        local ($_);
8134        warn "# l2h: removing temporary files generated by l2h extension\n"
8135            if $verbose;
8136        while (<"$docu_rdir$l2h_name"*>)
8137        {
8138# FIXME error condition not checked
8139            unlink $_;
8140        }
8141    }
8142    warn "# l2h: Finished\n" if $verbose;
8143    return 1;
8144}
8145
8146# the driver of end of first pass, second pass and beginning of third pass
8147#
8148sub latex2html()
8149{
8150    return unless($status);
8151    return unless ($status = finish_to_latex());
8152    return unless ($status = to_html());
8153    return unless ($status = init_from_html());
8154}
8155
8156
8157##############################
8158# stuff for l2h caching
8159#
8160
8161# I tried doing this with a dbm data base, but it did not store all
8162# keys/values. Hence, I did as latex2html does it
8163sub init_cache
8164{
8165    if (-r "$l2h_cache_file")
8166    {
8167        my $rdo = do "$l2h_cache_file";
8168        warn("$ERROR l2h Error: could not load $docu_rdir$l2h_cache_file: $@\n")
8169            unless ($rdo);
8170    }
8171}
8172
8173# store all the text obtained through latex2html
8174sub store_cache
8175{
8176    return unless $latex_count;
8177    my ($key, $value);
8178    unless (open(FH, ">$l2h_cache_file"))
8179    {
8180        warn "$ERROR l2h Error: could not open $docu_rdir$l2h_cache_file for writing: $!\n";
8181        return;
8182    }
8183    while (($key, $value) = each %l2h_cache)
8184    {
8185        # escape stuff
8186        $key =~ s|/|\\/|g;
8187        $key =~ s|\\\\/|\\/|g;
8188        # weird, a \ at the end of the key results in an error
8189        # maybe this also broke the dbm database stuff
8190        $key =~ s|\\$|\\\\|;
8191        $value =~ s/\|/\\\|/go;
8192        $value =~ s/\\\\\|/\\\|/go;
8193        $value =~ s|\\\\|\\\\\\\\|g;
8194        print FH "\n\$l2h_cache_key = q/$key/;\n";
8195        print FH "\$l2h_cache{\$l2h_cache_key} = q|$value|;\n";
8196    }
8197    print FH "1;";
8198    close (FH);
8199}
8200
8201# return cached html, if it exists for text, and if all pictures
8202# are there, as well
8203sub from_cache($)
8204{
8205    my $text = shift;
8206    my $cached = $l2h_cache{$text};
8207    if (defined($cached))
8208    {
8209        while ($cached =~ m/SRC="(.*?)"/g)
8210        {
8211            unless (-e "$docu_rdir$1")
8212            {
8213                return undef;
8214            }
8215        }
8216        return $cached;
8217    }
8218    return undef;
8219}
8220
82211;
8222
8223
8224require "$ENV{T2H_HOME}/T2h_l2h.pm"
8225    if ($0 =~ /\.pl$/ &&
8226        -e "$ENV{T2H_HOME}/T2h_l2h.pm" && -r "$ENV{T2H_HOME}/T2h_l2h.pm");
8227
8228}
8229
8230{
8231package Texi2HTML::LaTeX2HTML::Config;
8232
8233# latex2html variables
8234# These variables are not used. They are here for information only, and
8235# an example of config file for latex2html file is included.
8236my $ADDRESS;
8237my $ANTI_ALIAS;
8238my $ANTI_ALIAS_TEXT;
8239my $ASCII_MODE;
8240my $AUTO_LINK;
8241my $AUTO_PREFIX;
8242my $CHILDLINE;
8243my $DEBUG;
8244my $DESTDIR;
8245my $ERROR;
8246my $EXTERNAL_FILE;
8247my $EXTERNAL_IMAGES;
8248my $EXTERNAL_UP_LINK;
8249my $EXTERNAL_UP_TITLE;
8250my $FIGURE_SCALE_FACTOR;
8251my $HTML_VERSION;
8252my $IMAGES_ONLY;
8253my $INFO;
8254my $LINE_WIDTH;
8255my $LOCAL_ICONS;
8256my $LONG_TITLES;
8257my $MATH_SCALE_FACTOR;
8258my $MAX_LINK_DEPTH;
8259my $MAX_SPLIT_DEPTH;
8260my $NETSCAPE_HTML;
8261my $NOLATEX;
8262my $NO_FOOTNODE;
8263my $NO_IMAGES;
8264my $NO_NAVIGATION;
8265my $NO_SIMPLE_MATH;
8266my $NO_SUBDIR;
8267my $PAPERSIZE;
8268my $PREFIX;
8269my $PS_IMAGES;
8270my $REUSE;
8271my $SCALABLE_FONTS;
8272my $SHORTEXTN;
8273my $SHORT_INDEX;
8274my $SHOW_SECTION_NUMBERS;
8275my $SPLIT;
8276my $TEXDEFS;
8277my $TITLE;
8278my $TITLES_LANGUAGE;
8279my $TMP;
8280my $VERBOSE;
8281my $WORDS_IN_NAVIGATION_PANEL_TITLES;
8282my $WORDS_IN_PAGE;
8283
8284# @T2H_L2H_INIT@
8285
8286######################################################################
8287# from here on, its l2h init stuff
8288#
8289
8290## initialization for latex2html as for Singular manual generation
8291## obachman 3/99
8292
8293#
8294# Options controlling Titles, File-Names, Tracing and Sectioning
8295#
8296$TITLE = '';
8297
8298$SHORTEXTN = 0;
8299
8300$LONG_TITLES = 0;
8301
8302$DESTDIR = '';
8303
8304$NO_SUBDIR = 1;
8305
8306$PREFIX = '';
8307
8308$AUTO_PREFIX = 0;
8309
8310$AUTO_LINK = 0;
8311
8312$SPLIT = 0;
8313
8314$MAX_LINK_DEPTH = 0;
8315
8316$TMP = '';
8317
8318$DEBUG = 0;
8319
8320$VERBOSE = 1;
8321
8322#
8323# Options controlling Extensions and Special Features
8324#
8325#$HTML_VERSION = "3.2";         # set by command line
8326
8327$TEXDEFS = 1;                   # we absolutely need that
8328
8329$EXTERNAL_FILE = '';
8330
8331$SCALABLE_FONTS = 1;
8332
8333$NO_SIMPLE_MATH = 1;
8334
8335$LOCAL_ICONS = 1;
8336
8337$SHORT_INDEX = 0;
8338
8339$NO_FOOTNODE = 1;
8340
8341$ADDRESS = '';
8342
8343$INFO = '';
8344
8345#
8346# Switches controlling Image Generation
8347#
8348$ASCII_MODE = 0;
8349
8350$NOLATEX = 0;
8351
8352$EXTERNAL_IMAGES = 0;
8353
8354$PS_IMAGES = 0;
8355
8356$NO_IMAGES = 0;
8357
8358$IMAGES_ONLY = 0;
8359
8360$REUSE = 2;
8361
8362$ANTI_ALIAS = 1;
8363
8364$ANTI_ALIAS_TEXT = 1;
8365
8366#
8367#Switches controlling Navigation Panels
8368#
8369$NO_NAVIGATION = 1;
8370$ADDRESS = '';
8371$INFO = 0;                      # 0 = do not make a "About this document..." section
8372
8373#
8374#Switches for Linking to other documents
8375#
8376# currently -- we don't care
8377
8378$MAX_SPLIT_DEPTH = 0;           # Stop making separate files at this depth
8379
8380$MAX_LINK_DEPTH = 0;            # Stop showing child nodes at this depth
8381
8382$NOLATEX = 0;                   # 1 = do not pass unknown environments to Latex
8383
8384$EXTERNAL_IMAGES = 0;           # 1 = leave the images outside the document
8385
8386$ASCII_MODE = 0;                # 1 = do not use any icons or internal images
8387
8388# 1 =  use links to external postscript images rather than inlined bitmap
8389# images.
8390$PS_IMAGES = 0;
8391$SHOW_SECTION_NUMBERS = 0;
8392
8393### Other global variables ###############################################
8394$CHILDLINE = "";
8395
8396# This is the line width measured in pixels and it is used to right justify
8397# equations and equation arrays;
8398$LINE_WIDTH = 500;
8399
8400# Used in conjunction with AUTO_NAVIGATION
8401$WORDS_IN_PAGE = 300;
8402
8403# The value of this variable determines how many words to use in each
8404# title that is added to the navigation panel (see below)
8405#
8406$WORDS_IN_NAVIGATION_PANEL_TITLES = 0;
8407
8408# This number will determine the size of the equations, special characters,
8409# and anything which will be converted into an inlined image
8410# *except* "image generating environments" such as "figure", "table"
8411# or "minipage".
8412# Effective values are those greater than 0.
8413# Sensible values are between 0.1 - 4.
8414$MATH_SCALE_FACTOR = 1.5;
8415
8416# This number will determine the size of
8417# image generating environments such as "figure", "table" or "minipage".
8418# Effective values are those greater than 0.
8419# Sensible values are between 0.1 - 4.
8420$FIGURE_SCALE_FACTOR = 1.6;
8421
8422
8423#  If both of the following two variables are set then the "Up" button
8424#  of the navigation panel in the first node/page of a converted document
8425#  will point to $EXTERNAL_UP_LINK. $EXTERNAL_UP_TITLE should be set
8426#  to some text which describes this external link.
8427$EXTERNAL_UP_LINK = "";
8428$EXTERNAL_UP_TITLE = "";
8429
8430# If this is set then the resulting HTML will look marginally better if viewed
8431# with Netscape.
8432$NETSCAPE_HTML = 1;
8433
8434# Valid paper sizes are "letter", "legal", "a4","a3","a2" and "a0"
8435# Paper sizes has no effect other than in the time it takes to create inlined
8436# images and in whether large images can be created at all ie
8437#  - larger paper sizes *MAY* help with large image problems
8438#  - smaller paper sizes are quicker to handle
8439$PAPERSIZE = "a4";
8440
8441# Replace "english" with another language in order to tell LaTeX2HTML that you
8442# want some generated section titles (eg "Table of Contents" or "References")
8443# to appear in a different language. Currently only "english" and "french"
8444# is supported but it is very easy to add your own. See the example in the
8445# file "latex2html.config"
8446$TITLES_LANGUAGE = "english";
8447
84481;                              # This must be the last non-comment line
8449
8450# End File l2h.init
8451######################################################################
8452
8453}
8454
8455package main;
8456
8457#
8458# pre-defined indices
8459#
8460
8461my %index_prefix_to_name = ();
8462
8463%index_names =
8464(
8465 'cp' => { 'prefix' => ['cp','c']},
8466 'fn' => { 'prefix' => ['fn', 'f'], code => 1},
8467 'vr' => { 'prefix' => ['vr', 'v'], code => 1},
8468 'ky' => { 'prefix' => ['ky', 'k'], code => 1},
8469 'pg' => { 'prefix' => ['pg', 'p'], code => 1},
8470 'tp' => { 'prefix' => ['tp', 't'], code => 1}
8471);
8472
8473foreach my $name(keys(%index_names))
8474{
8475    foreach my $prefix (@{$index_names{$name}->{'prefix'}})
8476    {
8477        $forbidden_index_name{$prefix} = 1;
8478        $index_prefix_to_name{$prefix} = $name;
8479    }
8480}
8481
8482foreach my $other_forbidden_index_name ('info','ps','pdf','htm',
8483   'log','aux','dvi','texi','txi','texinfo','tex','bib')
8484{
8485    $forbidden_index_name{$other_forbidden_index_name} = 1;
8486}
8487
8488# commands with ---, -- '' and `` preserved
8489# usefull with the old interface
8490
8491%code_style_map = (
8492           'code'    => 1,
8493           'command' => 1,
8494           'env'     => 1,
8495           'file'    => 1,
8496           'kbd'     => 1,
8497           'option'  => 1,
8498           'samp'    => 1,
8499           'verb'    => 1,
8500);
8501
8502my @element_directions = ('Up', 'Forward', 'Back', 'Next', 'Prev',
8503'SectionNext', 'SectionPrev', 'SectionUp', 'FastForward', 'FastBack',
8504'This', 'NodeUp', 'NodePrev', 'NodeNext', 'Following' );
8505$::simple_map_ref = \%Texi2HTML::Config::simple_map;
8506$::simple_map_pre_ref = \%Texi2HTML::Config::simple_map_pre;
8507$::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi;
8508$::style_map_ref = \%Texi2HTML::Config::style_map;
8509$::style_map_pre_ref = \%Texi2HTML::Config::style_map_pre;
8510$::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi;
8511$::things_map_ref = \%Texi2HTML::Config::things_map;
8512$::pre_map_ref = \%Texi2HTML::Config::pre_map;
8513$::texi_map_ref = \%Texi2HTML::Config::texi_map;
8514
8515# delete from hash if we are using the new interface
8516foreach my $code (keys(%code_style_map))
8517{
8518    delete ($code_style_map{$code})
8519       if (ref($::style_map_ref->{$code}) eq 'HASH');
8520}
8521
8522# no paragraph in these commands
8523my %no_paragraph_macro = (
8524           'xref'         => 1,
8525           'ref'          => 1,
8526           'pxref'        => 1,
8527           'inforef'      => 1,
8528           'anchor'       => 1,
8529);
8530
8531
8532#
8533# texinfo section names to level
8534#
8535%sec2level = (
8536	      'top', 0,
8537	      'chapter', 1,
8538	      'unnumbered', 1,
8539	      'chapheading', 1,
8540	      'appendix', 1,
8541	      'section', 2,
8542	      'unnumberedsec', 2,
8543	      'heading', 2,
8544	      'appendixsec', 2,
8545	      'subsection', 3,
8546	      'unnumberedsubsec', 3,
8547	      'subheading', 3,
8548	      'appendixsubsec', 3,
8549	      'subsubsection', 4,
8550	      'unnumberedsubsubsec', 4,
8551	      'subsubheading', 4,
8552	      'appendixsubsubsec', 4,
8553         );
8554
8555# the reverse mapping. There is an entry for each sectionning command.
8556# The value is a ref on an array containing at each index the corresponding
8557# sectionning command name.
8558my %level2sec;
8559{
8560    my $sections = [ ];
8561    my $appendices = [ ];
8562    my $unnumbered = [ ];
8563    my $headings = [ ];
8564    foreach my $command (keys (%sec2level))
8565    {
8566        if ($command =~ /^appendix/)
8567        {
8568            $level2sec{$command} = $appendices;
8569        }
8570        elsif ($command =~ /^unnumbered/ or $command eq 'top')
8571        {
8572            $level2sec{$command} = $unnumbered;
8573        }
8574        elsif ($command =~ /section$/ or $command eq 'chapter')
8575        {
8576            $level2sec{$command} = $sections;
8577        }
8578        else
8579        {
8580            $level2sec{$command} = $headings;
8581        }
8582        $level2sec{$command}->[$sec2level{$command}] = $command;
8583    }
8584}
8585
8586# this are synonyms
8587$sec2level{'appendixsection'} = 2;
8588# sec2level{'majorheading'} is also 1 and not 0
8589$sec2level{'majorheading'} = 1;
8590$sec2level{'chapheading'} = 1;
8591$sec2level{'centerchap'} = 1;
8592
8593# sction to level hash not taking into account raise and lower sections
8594my %reference_sec2level = %sec2level;
8595
8596# regions treated especially. The text for these regions is collected in the
8597# corresponding array
8598%region_lines = (
8599          'titlepage'            => [ ],
8600          'documentdescription'  => [ ],
8601          'copying'              => [ ],
8602);
8603
8604# those macros aren't considered as beginning a paragraph
8605my %no_line_macros = (
8606    'macro' => 1,
8607    'unmacro' => 1,
8608    'rmacro' => 1,
8609    'set' => 1,
8610    'clear' => 1,
8611    'titlefont' => 1,
8612    'include' => 1,
8613    'copying' => 1,
8614    'end copying' => 1,
8615    'tab' => 1,
8616    'item' => 1,
8617    'itemx' => 1,
8618    '*' => 1,
8619    'float' => 1,
8620    'end float' => 1,
8621    'caption' => 1,
8622    'shortcaption' => 1,
8623);
8624
8625foreach my $key (keys(%Texi2HTML::Config::misc_command))
8626{
8627    $no_line_macros{$key} = 1;
8628}
8629
8630# a hash associating a format @thing / @end thing with the type of the format
8631# 'complex_format' 'simple_format' 'deff' 'list' 'menu' 'paragraph_format'
8632my %format_type = ();
8633
8634foreach my $simple_format (keys(%Texi2HTML::Config::format_map))
8635{
8636   $format_type{$simple_format} = 'simple_format';
8637}
8638foreach my $paragraph_style (keys(%Texi2HTML::Config::paragraph_style))
8639{
8640   $format_type{$paragraph_style} = 'paragraph_format';
8641}
8642foreach my $complex_format (keys(%$Texi2HTML::Config::complex_format_map))
8643{
8644   $format_type{$complex_format} = 'complex_format';
8645}
8646foreach my $table (('table', 'ftable', 'vtable', 'multitable'))
8647{
8648   $format_type{$table} = 'table';
8649}
8650foreach my $def_format (keys(%Texi2HTML::Config::def_map))
8651{
8652   $format_type{$def_format} = 'deff';
8653}
8654$format_type{'itemize'} = 'list';
8655$format_type{'enumerate'} = 'list';
8656
8657$format_type{'menu'} = 'menu';
8658
8659$format_type{'cartouche'} = 'cartouche';
8660
8661$format_type{'float'} = 'float';
8662
8663$format_type{'quotation'} = 'quotation';
8664
8665$format_type{'group'} = 'group';
8666
8667foreach my $key (keys(%format_type))
8668{
8669   $no_line_macros{$key} = 1;
8670   $no_line_macros{"end $key"} = 1;
8671}
8672
8673foreach my $macro (keys(%Texi2HTML::Config::format_in_paragraph))
8674{
8675   $no_line_macros{$macro} = 1;
8676   $no_line_macros{"end $macro"} = 1;
8677}
8678
8679# fake format at the bottom of the stack
8680$format_type{'noformat'} = '';
8681
8682# fake formats are formats used internally within other formats
8683# we associate them with a real format, for the error messages
8684my %fake_format = (
8685     'line' => 'table',
8686     'term' => 'table',
8687     'item' => 'list or table',
8688     'row' => 'multitable row',
8689     'cell' => 'multitable cell',
8690     'deff_item' => 'definition command',
8691     'menu_comment' => 'menu',
8692     'menu_description' => 'menu',
8693     'menu_preformatted' => 'menu',
8694  );
8695
8696foreach my $key (keys(%fake_format))
8697{
8698    $format_type{$key} = 'fake';
8699}
8700
8701# raw formats which are expanded especially
8702my @raw_regions = ('html', 'verbatim', 'tex', 'xml', 'docbook');
8703
8704# regions expanded or not depending on the value of this hash
8705my %text_macros = (
8706     'iftex' => 0,
8707     'ignore' => 0,
8708     'menu' => 0,
8709     'ifplaintext' => 0,
8710     'ifinfo' => 0,
8711     'ifxml' => 0,
8712     'ifhtml' => 0,
8713     'ifdocbook' => 0,
8714     'html' => 0,
8715     'tex' => 0,
8716     'xml' => 0,
8717     'titlepage' => 1,
8718     'documentdescription' => 1,
8719     'copying' => 1,
8720     'ifnothtml' => 1,
8721     'ifnottex' => 1,
8722     'ifnotplaintext' => 1,
8723     'ifnotinfo' => 1,
8724     'ifnotxml' => 1,
8725     'ifnotdocbook' => 1,
8726     'direntry' => 0,
8727     'verbatim' => 'raw',
8728     'ifclear' => 'value',
8729     'ifset' => 'value' ,
8730     );
8731
8732foreach my $key (keys(%text_macros))
8733{
8734    unless ($text_macros{$key} eq 'raw')
8735    {
8736        $no_line_macros{$key} = 1;
8737        $no_line_macros{"end $key"} = 1;
8738    }
8739}
8740
8741# The css formats are associated with complex format commands, and associated
8742# with the 'pre_style' key
8743foreach my $complex_format (keys(%$Texi2HTML::Config::complex_format_map))
8744{
8745    next if (defined($Texi2HTML::Config::complex_format_map->{$complex_format}->{'pre_style'}));
8746    $Texi2HTML::Config::complex_format_map->{$complex_format}->{'pre_style'} = '';
8747    $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"}));
8748}
8749
8750#+++############################################################################
8751#                                                                              #
8752# Argument parsing, initialisation                                             #
8753#                                                                              #
8754#---############################################################################
8755
8756#
8757# flush stdout and stderr after every write
8758#
8759select(STDERR);
8760$| = 1;
8761select(STDOUT);
8762$| = 1;
8763
8764my $I = \&Texi2HTML::I18n::get_string;
8765
8766my $T2H_USER; # user running the script
8767my $documentdescription; # text in @documentdescription
8768
8769# shorthand for Texi2HTML::Config::VERBOSE
8770my $T2H_VERBOSE;
8771my $T2H_DEBUG;
8772
8773sub echo_warn($;$);
8774#print STDERR "" . &$I('test i18n: \' , \a \\ %% %{unknown}a %known % %{known}  \\', { 'known' => 'a known string', 'no' => 'nope'}); exit 0;
8775
8776# file:        file name to locate. It can be a file path.
8777# all_files:   if true collect all the files with that name, otherwise stop
8778#              at first match.
8779# directories: a reference on a array containing a list of directories to
8780#              search the file in. default is \@texi2html_config_dirs.
8781sub locate_init_file($;$$)
8782{
8783    my $file = shift;
8784    my $all_files = shift;
8785    my $directories = shift;
8786
8787    $directories = \@texi2html_config_dirs if !defined($directories);
8788
8789    if ($file =~ /^\//)
8790    {
8791         return $file if (-e $file and -r $file);
8792    }
8793    else
8794    {
8795         my @files;
8796         foreach my $dir (@$directories)
8797         {
8798              next unless (-d "$dir");
8799              if ($all_files)
8800              {
8801                  push (@files, "$dir/$file") if (-e "$dir/$file" and -r "$dir/$file");
8802              }
8803              else
8804              {
8805                  return "$dir/$file" if (-e "$dir/$file" and -r "$dir/$file");
8806              }
8807         }
8808         return @files if ($all_files);
8809    }
8810    return undef;
8811}
8812
8813# called on -init-file
8814sub load_init_file
8815{
8816    # First argument is option
8817    shift;
8818    # second argument is value of options
8819    my $init_file = shift;
8820    my $file;
8821    if ($file = locate_init_file($init_file))
8822    {
8823        print STDERR "# reading initialization file from $file\n"
8824            if ($T2H_VERBOSE);
8825        return (Texi2HTML::Config::load($file));
8826    }
8827    else
8828    {
8829        print STDERR "$ERROR Error: can't read init file $init_file\n";
8830        return 0;
8831    }
8832}
8833
8834my $cmd_line_lang = 0; # 1 if lang was succesfully set by the command line
8835                       # in that case @documentlanguage is ignored.
8836my $lang_set = 0; # 1 if lang was set
8837
8838#
8839# called on -lang
8840sub set_document_language ($;$$)
8841{
8842    my $lang = shift;
8843    my $from_command_line = shift;
8844    my $line_nr = shift;
8845    my @files = locate_init_file("$i18n_dir/$lang", 1);
8846    foreach  my $file (@files)
8847    {
8848        Texi2HTML::Config::load($file);
8849    }
8850    if (Texi2HTML::I18n::set_language($lang))
8851    {
8852        print STDERR "# using '$lang' as document language\n" if ($T2H_VERBOSE);
8853        $Texi2HTML::Config::LANG = $lang;
8854        $lang_set = 1;
8855        $cmd_line_lang = 1 if ($from_command_line);
8856        if (!$Texi2HTML::Config::TEST)
8857        {
8858            print STDERR "# Setting date in $Texi2HTML::Config::LANG\n" if ($T2H_DEBUG);
8859            $Texi2HTML::THISDOC{'today'} = Texi2HTML::I18n::pretty_date($Texi2HTML::Config::LANG);  # like "20 September 1993";
8860        }
8861        else
8862        {
8863            $Texi2HTML::THISDOC{'today'} = 'a sunny day';
8864        }
8865        $Texi2HTML::THISDOC{'today'} = $Texi2HTML::Config::DATE
8866            if (defined($Texi2HTML::Config::DATE));
8867        $::things_map_ref->{'today'} = $Texi2HTML::THISDOC{'today'};
8868        $::pre_map_ref->{'today'} = $Texi2HTML::THISDOC{'today'};
8869        $::texi_map_ref->{'today'} = $Texi2HTML::THISDOC{'today'};
8870    }
8871    else
8872    {
8873        echo_error ("Language specs for '$lang' do not exists. Reverting to '$Texi2HTML::Config::LANG'", $line_nr);
8874    }
8875}
8876
8877# used to manage expanded sections from the command line
8878sub set_expansion($$)
8879{
8880    my $region = shift;
8881    my $set = shift;
8882    $set = 1 if (!defined($set));
8883    if ($set)
8884    {
8885         push (@Texi2HTML::Config::EXPAND, $region) unless (grep {$_ eq $region} @Texi2HTML::Config::EXPAND);
8886    }
8887    else
8888    {
8889         @Texi2HTML::Config::EXPAND = grep {$_ ne $region} @Texi2HTML::Config::EXPAND;
8890    }
8891}
8892
8893
8894# find the encoding alias.
8895# with encoding support (USE_UNICODE), may return undef if no alias was found
8896sub encoding_alias($)
8897{
8898    my $encoding = shift;
8899    return $encoding if (!defined($encoding) or $encoding eq '');
8900    if ($Texi2HTML::Config::USE_UNICODE)
8901    {
8902         if (! Encode::resolve_alias($encoding))
8903         {
8904              echo_warn("Encoding $encoding unknown");
8905              return undef;
8906         }
8907         print STDERR "# Using encoding " . Encode::resolve_alias($encoding) . "\n"
8908             if ($T2H_VERBOSE);
8909         return Encode::resolve_alias($encoding);
8910    }
8911    else
8912    {
8913         echo_warn("No alias searched for encoding");
8914         return $encoding;
8915    }
8916}
8917
8918# setup hashes used for html manual cross references in texinfo
8919my %cross_ref_texi_map = %Texi2HTML::Config::texi_map;
8920
8921$cross_ref_texi_map{'enddots'} = '...';
8922
8923my %cross_ref_simple_map_texi = %Texi2HTML::Config::simple_map_texi;
8924my %cross_ref_style_map_texi = ();
8925my %cross_transliterate_style_map_texi = ();
8926
8927my %cross_transliterate_texi_map = %cross_ref_texi_map;
8928
8929foreach my $command (keys(%Texi2HTML::Config::style_map_texi))
8930{
8931    $cross_ref_style_map_texi{$command} = {};
8932    $cross_transliterate_style_map_texi{$command} = {};
8933    foreach my $key (keys (%{$Texi2HTML::Config::style_map_texi{$command}}))
8934    {
8935#print STDERR "$command, $key, $style_map_texi{$command}->{$key}\n";
8936         $cross_ref_style_map_texi{$command}->{$key} =
8937              $Texi2HTML::Config::style_map_texi{$command}->{$key};
8938         $cross_transliterate_style_map_texi{$command}->{$key} =
8939              $Texi2HTML::Config::style_map_texi{$command}->{$key};
8940    }
8941}
8942
8943$cross_ref_simple_map_texi{"\n"} = ' ';
8944$cross_ref_simple_map_texi{"*"} = ' ';
8945
8946my %nodes = ();             # nodes hash. The key is the texi node name
8947my %cross_reference_nodes = ();  # normalized node names arrays
8948
8949# This function is used to construct link names from node names as
8950# specified for texinfo
8951sub cross_manual_links()
8952{
8953    print STDERR "# Doing ".scalar(keys(%nodes))." cross manual links\n"
8954       if ($T2H_DEBUG);
8955    my $normal_text_kept = $Texi2HTML::Config::normal_text;
8956    $::simple_map_texi_ref = \%cross_ref_simple_map_texi;
8957    $::style_map_texi_ref = \%cross_ref_style_map_texi;
8958    $::texi_map_ref = \%cross_ref_texi_map;
8959    $Texi2HTML::Config::normal_text = \&Texi2HTML::Config::t2h_cross_manual_normal_text;
8960
8961    foreach my $key (keys(%nodes))
8962    {
8963        my $node = $nodes{$key};
8964        #print STDERR "CROSS_MANUAL:$key,$node\n";
8965        next if ($node->{'index_page'});
8966        if (!defined($node->{'texi'}))
8967        {
8968            ###################### debug section
8969            foreach my $key (keys(%$node))
8970            {
8971                #print STDERR "$key:$node->{$key}!!!\n";
8972            }
8973            ###################### end debug section
8974        }
8975        else
8976        {
8977            $node->{'cross_manual_target'} = remove_texi($node->{'texi'});
8978            if ($Texi2HTML::Config::USE_UNICODE)
8979            {
8980                $node->{'cross_manual_target'} = Unicode::Normalize::NFC($node->{'cross_manual_target'});
8981                if ($Texi2HTML::Config::TRANSLITERATE_NODE and  $Texi2HTML::Config::USE_UNIDECODE)
8982                {
8983                     $node->{'cross_manual_file'} =
8984                       unicode_to_protected(unicode_to_transliterate($node->{'cross_manual_target'}));
8985                }
8986                $node->{'cross_manual_target'} =
8987                    unicode_to_protected($node->{'cross_manual_target'});
8988            }
8989#print STDERR "CROSS_MANUAL_TARGET $node->{'cross_manual_target'}\n";
8990            unless ($node->{'external_node'})
8991            {
8992                if (exists($cross_reference_nodes{$node->{'cross_manual_target'}}))
8993                {
8994                    my $other_node_array = $cross_reference_nodes{$node->{'cross_manual_target'}};
8995                    my $node_seen;
8996                    foreach my $other_node (@{$other_node_array})
8997                    {
8998                        $node_seen = $other_node;
8999                        last if ($nodes{$other_node}->{'seen'})
9000                    }
9001                    echo_error("Node equivalent with `$node->{'texi'}' allready used `$node_seen'");
9002                    push @{$other_node_array}, $node->{'texi'};
9003                }
9004                else
9005                {
9006                    push @{$cross_reference_nodes{$node->{'cross_manual_target'}}}, $node->{'texi'};
9007                }
9008            }
9009        }
9010    }
9011
9012
9013    if ($Texi2HTML::Config::TRANSLITERATE_NODE and
9014         (!$Texi2HTML::Config::USE_UNICODE or !$Texi2HTML::Config::USE_UNIDECODE))
9015    {
9016         $::style_map_texi_ref = \%cross_transliterate_style_map_texi;
9017         $::texi_map_ref = \%cross_transliterate_texi_map;
9018
9019         foreach my $key (keys(%nodes))
9020         {
9021             my $node = $nodes{$key};
9022             next if ($node->{'index_page'});
9023             if (defined($node->{'texi'}))
9024             {
9025                  $node->{'cross_manual_file'} = remove_texi($node->{'texi'});
9026                  $node->{'cross_manual_file'} = unicode_to_protected(unicode_to_transliterate($node->{'cross_manual_file'})) if ($Texi2HTML::Config::USE_UNICODE);
9027             }
9028         }
9029    }
9030
9031    $Texi2HTML::Config::normal_text = $normal_text_kept;
9032    $::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi;
9033    $::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi;
9034    $::texi_map_ref = \%Texi2HTML::Config::texi_map;
9035}
9036
9037sub unicode_to_protected($)
9038{
9039    my $text = shift;
9040    my $result = '';
9041    while ($text ne '')
9042    {
9043        if ($text =~ s/^([A-Za-z0-9]+)//o)
9044        {
9045             $result .= $1;
9046        }
9047        elsif ($text =~ s/^ //o)
9048        {
9049             $result .= '-';
9050        }
9051        elsif ($text =~ s/^(.)//o)
9052        {
9053             if (exists($Texi2HTML::Config::ascii_character_map{$1}))
9054             {
9055                 $result .= '_' . lc($Texi2HTML::Config::ascii_character_map{$1});
9056             }
9057             else
9058             {
9059                 $result .= '_' . lc(sprintf("%04x",ord($1)));
9060             }
9061        }
9062        else
9063        {
9064             print STDERR "Bug: unknown character in a cross ref (likely in infinite loop)\n";
9065             print STDERR "Text: !!$text!!\n";
9066             sleep 1;
9067        }
9068    }
9069    return $result;
9070}
9071
9072sub unicode_to_transliterate($)
9073{
9074    my $text = shift;
9075    my $result = '';
9076    while ($text ne '')
9077    {
9078        if ($text =~ s/^([A-Za-z0-9 ]+)//o)
9079        {
9080             $result .= $1;
9081        }
9082        elsif ($text =~ s/^(.)//o)
9083        {
9084             if (exists($Texi2HTML::Config::ascii_character_map{$1}))
9085             {
9086                 $result .= $1;
9087             }
9088             elsif (exists($Texi2HTML::Config::transliterate_map{uc(sprintf("%04x",ord($1)))}))
9089             {
9090                 $result .= $Texi2HTML::Config::transliterate_map{uc(sprintf("%04x",ord($1)))};
9091             }
9092             elsif (exists($Texi2HTML::Config::unicode_diacritical{uc(sprintf("%04x",ord($1)))}))
9093             {
9094                 $result .= '';
9095             }
9096             else
9097             {
9098                 if ($Texi2HTML::Config::USE_UNIDECODE)
9099                 {
9100                      $result .= unidecode($1);
9101                 }
9102                 else
9103                 {
9104                      $result .= $1;
9105                 }
9106             }
9107        }
9108        else
9109        {
9110             print STDERR "Bug: unknown character in cross ref transliteration (likely in infinite loop)\n";
9111             sleep 1;
9112        }
9113    }
9114    return $result;
9115}
9116
9117# This function is used to construct a link name from a node name as
9118# specified for texinfo
9119sub cross_manual_line($;$)
9120{
9121    my $text = shift;
9122    my $transliterate = shift;
9123#print STDERR "cross_manual_line $text\n";
9124#print STDERR "remove_texi text ". remove_texi($text)."\n\n\n";
9125    $::simple_map_texi_ref = \%cross_ref_simple_map_texi;
9126    $::style_map_texi_ref = \%cross_ref_style_map_texi;
9127    $::texi_map_ref = \%cross_ref_texi_map;
9128    my $normal_text_kept = $Texi2HTML::Config::normal_text;
9129    $Texi2HTML::Config::normal_text = \&Texi2HTML::Config::t2h_cross_manual_normal_text;
9130
9131    my ($cross_ref_target, $cross_ref_file);
9132    if ($Texi2HTML::Config::USE_UNICODE)
9133    {
9134         $cross_ref_target = Unicode::Normalize::NFC(remove_texi($text));
9135         if ($transliterate and $Texi2HTML::Config::USE_UNIDECODE)
9136         {
9137             $cross_ref_file =
9138                unicode_to_protected(unicode_to_transliterate($cross_ref_target));
9139         }
9140         $cross_ref_target = unicode_to_protected($cross_ref_target);
9141    }
9142    else
9143    {
9144         $cross_ref_target = remove_texi($text);
9145    }
9146
9147    if ($transliterate and
9148         (!$Texi2HTML::Config::USE_UNICODE or !$Texi2HTML::Config::USE_UNIDECODE))
9149    {
9150         $::style_map_texi_ref = \%cross_transliterate_style_map_texi;
9151         $::texi_map_ref = \%cross_transliterate_texi_map;
9152         $cross_ref_file = remove_texi($text);
9153         $cross_ref_file = unicode_to_protected(unicode_to_transliterate($cross_ref_file))
9154               if ($Texi2HTML::Config::USE_UNICODE);
9155    }
9156
9157    $Texi2HTML::Config::normal_text = $normal_text_kept;
9158    $::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi;
9159    $::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi;
9160    $::texi_map_ref = \%Texi2HTML::Config::texi_map;
9161#print STDERR "\n\ncross_ref $cross_ref\n";
9162    unless ($transliterate)
9163    {
9164        return $cross_ref_target;
9165    }
9166#    print STDERR "$text|$cross_ref_target|$cross_ref_file\n";
9167    return ($cross_ref_target, $cross_ref_file);
9168}
9169
9170# T2H_OPTIONS is a hash whose keys are the (long) names of valid
9171# command-line options and whose values are a hash with the following keys:
9172# type    ==> one of !|=i|:i|=s|:s (see GetOpt::Long for more info)
9173# linkage ==> ref to scalar, array, or subroutine (see GetOpt::Long for more info)
9174# verbose ==> short description of option (displayed by -h)
9175# noHelp  ==> if 1 -> for "not so important options": only print description on -h 1
9176#                2 -> for obsolete options: only print description on -h 2
9177my $T2H_OPTIONS;
9178$T2H_OPTIONS -> {'debug'} =
9179{
9180 type => '=i',
9181 linkage => \$Texi2HTML::Config::DEBUG,
9182 verbose => 'output HTML with debuging information',
9183};
9184
9185$T2H_OPTIONS -> {'doctype'} =
9186{
9187 type => '=s',
9188 linkage => \$Texi2HTML::Config::DOCTYPE,
9189 verbose => 'document type which is output in header of HTML files',
9190 noHelp => 1
9191};
9192
9193$T2H_OPTIONS -> {'frameset-doctype'} =
9194{
9195 type => '=s',
9196 linkage => \$Texi2HTML::Config::FRAMESET_DOCTYPE,
9197 verbose => 'document type for HTML frameset documents',
9198 noHelp => 1
9199};
9200
9201$T2H_OPTIONS -> {'test'} =
9202{
9203 type => '!',
9204 linkage => \$Texi2HTML::Config::TEST,
9205 verbose => 'use predefined information to avoid differences with reference files',
9206 noHelp => 1
9207};
9208
9209$T2H_OPTIONS -> {'dump-texi'} =
9210{
9211 type => '!',
9212 linkage => \$Texi2HTML::Config::DUMP_TEXI,
9213 verbose => 'dump the output of first pass into a file with extension passfirst and exit',
9214 noHelp => 1
9215};
9216
9217$T2H_OPTIONS -> {'macro-expand'} =
9218{
9219 type => '=s',
9220 linkage => \$Texi2HTML::Config::MACRO_EXPAND,
9221 verbose => 'output macro expanded source in <file>',
9222};
9223
9224$T2H_OPTIONS -> {'expand'} =
9225{
9226 type => '=s',
9227 linkage => sub {set_expansion($_[1], 1);},
9228 verbose => 'Expand info|tex|none section of texinfo source',
9229 noHelp => 1,
9230};
9231
9232$T2H_OPTIONS -> {'no-expand'} =
9233{
9234 type => '=s',
9235 linkage => sub {set_expansion ($_[1], 0);},
9236 verbose => 'Don\'t expand the given section of texinfo source',
9237};
9238
9239$T2H_OPTIONS -> {'noexpand'} =
9240{
9241 type => '=s',
9242 linkage => $T2H_OPTIONS->{'no-expand'}->{'linkage'},
9243 verbose => $T2H_OPTIONS->{'no-expand'}->{'verbose'},
9244 noHelp  => 1,
9245};
9246
9247$T2H_OPTIONS -> {'ifhtml'} =
9248{
9249 type => '!',
9250 linkage => sub { set_expansion('html', $_[1]); },
9251 verbose => "expand ifhtml and html sections",
9252};
9253
9254$T2H_OPTIONS -> {'ifinfo'} =
9255{
9256 type => '!',
9257 linkage => sub { set_expansion('info', $_[1]); },
9258 verbose => "expand ifinfo",
9259};
9260
9261$T2H_OPTIONS -> {'ifxml'} =
9262{
9263 type => '!',
9264 linkage => sub { set_expansion('xml', $_[1]); },
9265 verbose => "expand ifxml and xml sections",
9266};
9267
9268$T2H_OPTIONS -> {'ifdocbook'} =
9269{
9270 type => '!',
9271 linkage => sub { set_expansion('docbook', $_[1]); },
9272 verbose => "expand ifdocbook and docbook sections",
9273};
9274
9275$T2H_OPTIONS -> {'iftex'} =
9276{
9277 type => '!',
9278 linkage => sub { set_expansion('tex', $_[1]); },
9279 verbose => "expand iftex and tex sections",
9280};
9281
9282$T2H_OPTIONS -> {'ifplaintext'} =
9283{
9284 type => '!',
9285 linkage => sub { set_expansion('plaintext', $_[1]); },
9286 verbose => "expand ifplaintext sections",
9287};
9288
9289$T2H_OPTIONS -> {'invisible'} =
9290{
9291 type => '=s',
9292 linkage => \$Texi2HTML::Config::INVISIBLE_MARK,
9293 verbose => 'use text in invisble anchor',
9294 noHelp  => 1,
9295};
9296
9297$T2H_OPTIONS -> {'iso'} =
9298{
9299 type => 'iso',
9300 linkage => \$Texi2HTML::Config::USE_ISO,
9301 verbose => 'if set, ISO8859 characters are used for special symbols (like copyright, etc)',
9302 noHelp => 1,
9303};
9304
9305$T2H_OPTIONS -> {'I'} =
9306{
9307 type => '=s',
9308 linkage => \@Texi2HTML::Config::INCLUDE_DIRS,
9309 verbose => 'append $s to the @include search path',
9310};
9311
9312$T2H_OPTIONS -> {'conf-dir'} =
9313{
9314 type => '=s',
9315 linkage => \@Texi2HTML::Config::CONF_DIRS,
9316 verbose => 'append $s to the init file directories',
9317};
9318
9319$T2H_OPTIONS -> {'P'} =
9320{
9321 type => '=s',
9322 linkage => sub {unshift (@Texi2HTML::Config::PREPEND_DIRS, $_[1]);},
9323 verbose => 'prepend $s to the @include search path',
9324};
9325
9326$T2H_OPTIONS -> {'top-file'} =
9327{
9328 type => '=s',
9329 linkage => \$Texi2HTML::Config::TOP_FILE,
9330 verbose => 'use $s as top file, instead of <docname>.html',
9331};
9332
9333$T2H_OPTIONS -> {'toc-file'} =
9334{
9335 type => '=s',
9336 linkage => \$Texi2HTML::Config::TOC_FILE,
9337 verbose => 'use $s as ToC file, instead of <docname>_toc.html',
9338};
9339
9340$T2H_OPTIONS -> {'frames'} =
9341{
9342 type => '!',
9343 linkage => \$Texi2HTML::Config::FRAMES,
9344 verbose => 'output files which use HTML 4.0 frames (experimental)',
9345 noHelp => 1,
9346};
9347
9348$T2H_OPTIONS -> {'menu'} =
9349{
9350 type => '!',
9351 linkage => \$Texi2HTML::Config::SHOW_MENU,
9352 verbose => 'output Texinfo menus',
9353};
9354
9355$T2H_OPTIONS -> {'number'} =
9356{
9357 type => '!',
9358 linkage => \$Texi2HTML::Config::NUMBER_SECTIONS,
9359 verbose => 'use numbered sections',
9360};
9361
9362$T2H_OPTIONS -> {'use-nodes'} =
9363{
9364 type => '!',
9365 linkage => \$Texi2HTML::Config::USE_NODES,
9366 verbose => 'use nodes for sectionning',
9367};
9368
9369$T2H_OPTIONS -> {'node-files'} =
9370{
9371 type => '!',
9372 linkage => \$Texi2HTML::Config::NODE_FILES,
9373 verbose => 'produce one file per node for cross references'
9374};
9375
9376$T2H_OPTIONS -> {'separated-footnotes'} =
9377{
9378 type => '!',
9379 linkage => \$Texi2HTML::Config::SEPARATED_FOOTNOTES,
9380 verbose => 'footnotes on a separated page',
9381 noHelp => 1,
9382};
9383
9384$T2H_OPTIONS -> {'toc-links'} =
9385{
9386 type => '!',
9387 linkage => \$Texi2HTML::Config::TOC_LINKS,
9388 verbose => 'create links from headings to toc entries'
9389};
9390
9391$T2H_OPTIONS -> {'split'} =
9392{
9393 type => '=s',
9394 linkage => \$Texi2HTML::Config::SPLIT,
9395 verbose => 'split document on section|chapter|node else no splitting',
9396};
9397
9398$T2H_OPTIONS -> {'sec-nav'} =
9399{
9400 type => '!',
9401 linkage => \$Texi2HTML::Config::SECTION_NAVIGATION,
9402 verbose => 'output navigation panels for each section',
9403};
9404
9405$T2H_OPTIONS -> {'subdir'} =
9406{
9407 type => '=s',
9408 linkage => \$Texi2HTML::Config::SUBDIR,
9409 verbose => 'put files in directory $s, not $cwd',
9410 noHelp => 1,
9411};
9412
9413$T2H_OPTIONS -> {'short-ext'} =
9414{
9415 type => '!',
9416 linkage => \$Texi2HTML::Config::SHORTEXTN,
9417 verbose => 'use "htm" extension for output HTML files',
9418};
9419
9420$T2H_OPTIONS -> {'prefix'} =
9421{
9422 type => '=s',
9423 linkage => \$Texi2HTML::Config::PREFIX,
9424 verbose => 'use as prefix for output files, instead of <docname>',
9425};
9426
9427$T2H_OPTIONS -> {'output'} =
9428{
9429 type => '=s',
9430 linkage => \$Texi2HTML::Config::OUT,
9431 verbose => 'output goes to $s (directory if split)',
9432};
9433
9434$T2H_OPTIONS -> {'no-validate'} =
9435{
9436 type => '!',
9437 linkage => \$Texi2HTML::Config::NOVALIDATE,
9438 verbose => 'suppress node cross-reference validation',
9439};
9440
9441$T2H_OPTIONS -> {'short-ref'} =
9442{
9443 type => '!',
9444 linkage => \$Texi2HTML::Config::SHORT_REF,
9445 verbose => 'if set, references are without section numbers',
9446};
9447
9448$T2H_OPTIONS -> {'idx-sum'} =
9449{
9450 type => '!',
9451 linkage => \$Texi2HTML::Config::IDX_SUMMARY,
9452 verbose => 'if set, also output index summary',
9453 noHelp  => 1,
9454};
9455
9456$T2H_OPTIONS -> {'def-table'} =
9457{
9458 type => '!',
9459 linkage => \$Texi2HTML::Config::DEF_TABLE,
9460 verbose => 'if set, \@def.. are converted using tables.',
9461 noHelp  => 1,
9462};
9463
9464$T2H_OPTIONS -> {'Verbose'} =
9465{
9466 type => '!',
9467 linkage=> \$Texi2HTML::Config::VERBOSE,
9468 verbose => 'print progress info to stdout',
9469};
9470
9471$T2H_OPTIONS -> {'lang'} =
9472{
9473 type => '=s',
9474 linkage => sub {set_document_language($_[1], 1)},
9475 verbose => 'use $s as document language (ISO 639 encoding)',
9476};
9477
9478$T2H_OPTIONS -> {'ignore-preamble-text'} =
9479{
9480  type => '!',
9481  linkage => \$Texi2HTML::Config::IGNORE_PREAMBLE_TEXT,
9482  verbose => 'if set, ignore the text before @node and sectionning commands',
9483  noHelp => 1,
9484};
9485
9486$T2H_OPTIONS -> {'html-xref-prefix'} =
9487{
9488 type => '=s',
9489 linkage => \$Texi2HTML::Config::EXTERNAL_DIR,
9490 verbose => '$s is the base dir for external manual references',
9491 noHelp => 1,
9492};
9493
9494$T2H_OPTIONS -> {'l2h'} =
9495{
9496 type => '!',
9497 linkage => \$Texi2HTML::Config::L2H,
9498 verbose => 'if set, uses latex2html for @math and @tex',
9499};
9500
9501$T2H_OPTIONS -> {'l2h-l2h'} =
9502{
9503 type => '=s',
9504 linkage => \$Texi2HTML::Config::L2H_L2H,
9505 verbose => 'program to use for latex2html translation',
9506 noHelp => 1,
9507};
9508
9509$T2H_OPTIONS -> {'l2h-skip'} =
9510{
9511 type => '!',
9512 linkage => \$Texi2HTML::Config::L2H_SKIP,
9513 verbose => 'if set, tries to reuse previously latex2html output',
9514 noHelp => 1,
9515};
9516
9517$T2H_OPTIONS -> {'l2h-tmp'} =
9518{
9519 type => '=s',
9520 linkage => \$Texi2HTML::Config::L2H_TMP,
9521 verbose => 'if set, uses $s as temporary latex2html directory',
9522 noHelp => 1,
9523};
9524
9525$T2H_OPTIONS -> {'l2h-file'} =
9526{
9527 type => '=s',
9528 linkage => \$Texi2HTML::Config::L2H_FILE,
9529 verbose => 'if set, uses $s as latex2html init file',
9530 noHelp => 1,
9531};
9532
9533
9534$T2H_OPTIONS -> {'l2h-clean'} =
9535{
9536 type => '!',
9537 linkage => \$Texi2HTML::Config::L2H_CLEAN,
9538 verbose => 'if set, do not keep intermediate latex2html files for later reuse',
9539 noHelp => 1,
9540};
9541
9542$T2H_OPTIONS -> {'D'} =
9543{
9544 type => '=s',
9545 linkage => sub {$value{$_[1]} = 1;},
9546 verbose => 'equivalent to Texinfo "@set $s 1"',
9547 noHelp => 1,
9548};
9549
9550$T2H_OPTIONS -> {'U'} =
9551{
9552 type => '=s',
9553 linkage => sub {delete $value{$_[1]};},
9554 verbose => 'equivalent to Texinfo "@clear $s"',
9555 noHelp => 1,
9556};
9557
9558$T2H_OPTIONS -> {'init-file'} =
9559{
9560 type => '=s',
9561 linkage => \&load_init_file,
9562 verbose => 'load init file $s'
9563};
9564
9565$T2H_OPTIONS -> {'css-include'} =
9566{
9567 type => '=s',
9568 linkage => \@Texi2HTML::Config::CSS_FILES,
9569 verbose => 'use css file $s'
9570};
9571
9572##
9573## obsolete cmd line options
9574##
9575my $T2H_OBSOLETE_OPTIONS;
9576
9577$T2H_OBSOLETE_OPTIONS -> {'out-file'} =
9578{
9579 type => '=s',
9580 linkage => sub {$Texi2HTML::Config::OUT = $_[1]; $Texi2HTML::Config::SPLIT = '';},
9581 verbose => 'if set, all HTML output goes into file $s, obsoleted by "-output" with different semantics',
9582 noHelp => 2
9583};
9584
9585$T2H_OBSOLETE_OPTIONS -> {init_file} =
9586{
9587 type => '=s',
9588 linkage => \&load_init_file,
9589 verbose => 'obsolete, use "-init-file" instead',
9590 noHelp => 2
9591};
9592
9593$T2H_OBSOLETE_OPTIONS -> {l2h_clean} =
9594{
9595 type => '!',
9596 linkage => \$Texi2HTML::Config::L2H_CLEAN,
9597 verbose => 'obsolete, use "-l2h-clean" instead',
9598 noHelp => 2,
9599};
9600
9601$T2H_OBSOLETE_OPTIONS -> {l2h_l2h} =
9602{
9603 type => '=s',
9604 linkage => \$Texi2HTML::Config::L2H_L2H,
9605 verbose => 'obsolete, use "-l2h-l2h" instead',
9606 noHelp => 2
9607};
9608
9609$T2H_OBSOLETE_OPTIONS -> {l2h_skip} =
9610{
9611 type => '!',
9612 linkage => \$Texi2HTML::Config::L2H_SKIP,
9613 verbose => 'obsolete, use "-l2h-skip" instead',
9614 noHelp => 2
9615};
9616
9617$T2H_OBSOLETE_OPTIONS -> {l2h_tmp} =
9618{
9619 type => '=s',
9620 linkage => \$Texi2HTML::Config::L2H_TMP,
9621 verbose => 'obsolete, use "-l2h-tmp" instead',
9622 noHelp => 2
9623};
9624
9625$T2H_OBSOLETE_OPTIONS -> {out_file} =
9626{
9627 type => '=s',
9628 linkage => sub {$Texi2HTML::Config::OUT = $_[1]; $Texi2HTML::Config::SPLIT = '';},
9629 verbose => 'obsolete, use "-out-file" instead',
9630 noHelp => 2
9631};
9632
9633$T2H_OBSOLETE_OPTIONS -> {short_ref} =
9634{
9635 type => '!',
9636 linkage => \$Texi2HTML::Config::SHORT_REF,
9637 verbose => 'obsolete, use "-short-ref" instead',
9638 noHelp => 2
9639};
9640
9641$T2H_OBSOLETE_OPTIONS -> {idx_sum} =
9642{
9643 type => '!',
9644 linkage => \$Texi2HTML::Config::IDX_SUMMARY,
9645 verbose => 'obsolete, use "-idx-sum" instead',
9646 noHelp  => 2
9647};
9648
9649$T2H_OBSOLETE_OPTIONS -> {def_table} =
9650{
9651 type => '!',
9652 linkage => \$Texi2HTML::Config::DEF_TABLE,
9653 verbose => 'obsolete, use "-def-table" instead',
9654 noHelp  => 2
9655};
9656
9657$T2H_OBSOLETE_OPTIONS -> {short_ext} =
9658{
9659 type => '!',
9660 linkage => \$Texi2HTML::Config::SHORTEXTN,
9661 verbose => 'obsolete, use "-short-ext" instead',
9662 noHelp  => 2
9663};
9664
9665$T2H_OBSOLETE_OPTIONS -> {sec_nav} =
9666{
9667 type => '!',
9668 linkage => \$Texi2HTML::Config::SECTION_NAVIGATION,
9669 verbose => 'obsolete, use "-sec-nav" instead',
9670 noHelp  => 2
9671};
9672
9673$T2H_OBSOLETE_OPTIONS -> {top_file} =
9674{
9675 type => '=s',
9676 linkage => \$Texi2HTML::Config::TOP_FILE,
9677 verbose => 'obsolete, use "-top-file" instead',
9678 noHelp  => 2
9679};
9680
9681$T2H_OBSOLETE_OPTIONS -> {toc_file} =
9682{
9683 type => '=s',
9684 linkage => \$Texi2HTML::Config::TOC_FILE,
9685 verbose => 'obsolete, use "-toc-file" instead',
9686 noHelp  => 2
9687};
9688
9689$T2H_OBSOLETE_OPTIONS -> {glossary} =
9690{
9691 type => '!',
9692 linkage => \$Texi2HTML::Config::USE_GLOSSARY,
9693 verbose => "this does nothing",
9694 noHelp  => 2,
9695};
9696
9697$T2H_OBSOLETE_OPTIONS -> {check} =
9698{
9699 type => '!',
9700 linkage => sub {exit 0;},
9701 verbose => "exit without doing anything",
9702 noHelp  => 2,
9703};
9704
9705$T2H_OBSOLETE_OPTIONS -> {dump_texi} =
9706{
9707 type => '!',
9708 linkage => \$Texi2HTML::Config::DUMP_TEXI,
9709 verbose => 'obsolete, use "-dump-texi" instead',
9710 noHelp => 1
9711};
9712
9713$T2H_OBSOLETE_OPTIONS -> {frameset_doctype} =
9714{
9715 type => '=s',
9716 linkage => \$Texi2HTML::Config::FRAMESET_DOCTYPE,
9717 verbose => 'obsolete, use "-frameset-doctype" instead',
9718 noHelp => 2
9719};
9720
9721$T2H_OBSOLETE_OPTIONS -> {'no-section_navigation'} =
9722{
9723 type => '!',
9724 linkage => sub {$Texi2HTML::Config::SECTION_NAVIGATION = 0;},
9725 verbose => 'obsolete, use -nosec_nav',
9726 noHelp => 2,
9727};
9728my $use_acc; # not used
9729$T2H_OBSOLETE_OPTIONS -> {use_acc} =
9730{
9731 type => '!',
9732 linkage => \$use_acc,
9733 verbose => 'obsolete, set to true unconditionnaly',
9734 noHelp => 2
9735};
9736$T2H_OBSOLETE_OPTIONS -> {expandinfo} =
9737{
9738 type => '!',
9739 linkage => sub {push @Texi2HTML::Config::EXPAND, 'info';},
9740 verbose => 'obsolete, use "-expand info" instead',
9741 noHelp => 2,
9742};
9743$T2H_OBSOLETE_OPTIONS -> {expandtex} =
9744{
9745 type => '!',
9746 linkage => sub {push @Texi2HTML::Config::EXPAND, 'tex';},
9747 verbose => 'obsolete, use "-expand tex" instead',
9748 noHelp => 2,
9749};
9750$T2H_OBSOLETE_OPTIONS -> {monolithic} =
9751{
9752 type => '!',
9753 linkage => sub {$Texi2HTML::Config::SPLIT = '';},
9754 verbose => 'obsolete, use "-split no" instead',
9755 noHelp => 2
9756};
9757$T2H_OBSOLETE_OPTIONS -> {split_node} =
9758{
9759 type => '!',
9760 linkage => sub{$Texi2HTML::Config::SPLIT = 'section';},
9761 verbose => 'obsolete, use "-split section" instead',
9762 noHelp => 2,
9763};
9764$T2H_OBSOLETE_OPTIONS -> {split_chapter} =
9765{
9766 type => '!',
9767 linkage => sub{$Texi2HTML::Config::SPLIT = 'chapter';},
9768 verbose => 'obsolete, use "-split chapter" instead',
9769 noHelp => 2,
9770};
9771$T2H_OBSOLETE_OPTIONS -> {no_verbose} =
9772{
9773 type => '!',
9774 linkage => sub {$Texi2HTML::Config::VERBOSE = 0;},
9775 verbose => 'obsolete, use -noverbose instead',
9776 noHelp => 2,
9777};
9778$T2H_OBSOLETE_OPTIONS -> {output_file} =
9779{
9780 type => '=s',
9781 linkage => sub {$Texi2HTML::Config::OUT = $_[1]; $Texi2HTML::Config::SPLIT = '';},
9782 verbose => 'obsolete, use --out-file instead',
9783 noHelp => 2
9784};
9785
9786$T2H_OBSOLETE_OPTIONS -> {section_navigation} =
9787{
9788 type => '!',
9789 linkage => \$Texi2HTML::Config::SECTION_NAVIGATION,
9790 verbose => 'obsolete, use --sec-nav instead',
9791 noHelp => 2,
9792};
9793
9794$T2H_OBSOLETE_OPTIONS -> {verbose} =
9795{
9796 type => '!',
9797 linkage=> \$Texi2HTML::Config::VERBOSE,
9798 verbose => 'obsolete, use -Verbose instead',
9799 noHelp => 2
9800};
9801
9802# read initialzation from $sysconfdir/texi2htmlrc or $HOME/.texi2htmlrc
9803# (this is obsolete)
9804my @rc_files = ();
9805push @rc_files, "$sysconfdir/texi2htmlrc" if defined($sysconfdir);
9806push @rc_files, "$ENV{'HOME'}/.texi2htmlrc" if (defined($ENV{HOME}));
9807foreach my $i (@rc_files)
9808{
9809    if (-e $i and -r $i)
9810    {
9811        print STDERR "# reading initialization file from $i\n"
9812	    if ($T2H_VERBOSE);
9813        print STDERR "Reading config from $i is obsolete, use texi2html/$conf_file_name instead\n";
9814        Texi2HTML::Config::load($i);
9815    }
9816}
9817
9818# read initialization files
9819foreach my $file (locate_init_file($conf_file_name, 1))
9820{
9821    print STDERR "# reading initialization file from $file\n" if ($T2H_VERBOSE);
9822    Texi2HTML::Config::load($file);
9823}
9824
9825#
9826# %value hold texinfo variables, see also -D, -U, @set and @clear.
9827# we predefine html (the output format) and texi2html (the translator)
9828%value =
9829      (
9830          'html' => 1,
9831          'texi2html' => $THISVERSION,
9832      );
9833
9834#+++############################################################################
9835#                                                                              #
9836# parse command-line options
9837#                                                                              #
9838#---############################################################################
9839
9840
9841my $T2H_USAGE_TEXT = <<EOT;
9842Usage: texi2html  [OPTIONS] TEXINFO-FILE
9843Translates Texinfo source documentation to HTML.
9844EOT
9845my $T2H_FAILURE_TEXT = <<EOT;
9846Try 'texi2html --help' for usage instructions.
9847EOT
9848
9849my $options = new Getopt::MySimple;
9850
9851$T2H_OPTIONS -> {'help'} =
9852{
9853 type => ':i',
9854 default => '',
9855 linkage => sub {$options->helpOptions($_[1]);
9856    print "\nSend bugs and suggestions to <texi2html-bug\@nongnu.org>\n";
9857    exit (0);},
9858 verbose => "print help and exit"
9859};
9860
9861# this avoids getOptions defining twice 'help' and 'version'.
9862$T2H_OBSOLETE_OPTIONS -> {'help'} = 0;
9863$T2H_OBSOLETE_OPTIONS -> {'version'} = 0;
9864
9865# some older version of GetOpt::Long don't have
9866# Getopt::Long::Configure("pass_through")
9867eval {Getopt::Long::Configure("pass_through");};
9868my $Configure_failed = $@ && <<EOT;
9869**WARNING: Parsing of obsolete command-line options could have failed.
9870           Consider to use only documented command-line options (run
9871           'texi2html --help 2' for a complete list) or upgrade to perl
9872           version 5.005 or higher.
9873EOT
9874if (! $options->getOptions($T2H_OPTIONS, $T2H_USAGE_TEXT, "$THISVERSION\n"))
9875{
9876    print STDERR "$Configure_failed" if $Configure_failed;
9877    die $T2H_FAILURE_TEXT;
9878}
9879if (@ARGV > 1)
9880{
9881    eval {Getopt::Long::Configure("no_pass_through");};
9882    if (! $options->getOptions($T2H_OBSOLETE_OPTIONS, $T2H_USAGE_TEXT, "$THISVERSION\n"))
9883    {
9884        print STDERR "$Configure_failed" if $Configure_failed;
9885        die $T2H_FAILURE_TEXT;
9886    }
9887}
9888
9889#
9890# read texi2html extensions (if any)
9891# It is obsolete (obsoleted by -init-file). we keep it for backward
9892# compatibility.
9893my $extensions = 'texi2html.ext';  # extensions in working directory
9894if (-f $extensions)
9895{
9896    print STDERR "# reading extensions from $extensions\n" if $T2H_VERBOSE;
9897    require($extensions);
9898}
9899my $progdir;
9900($progdir = $0) =~ s/[^\/]+$//;
9901if ($progdir && ($progdir ne './'))
9902{
9903    $extensions = "${progdir}texi2html.ext"; # extensions in texi2html directory
9904    if (-f $extensions)
9905    {
9906	print STDERR "# reading extensions from $extensions\n" if $T2H_VERBOSE;
9907	require($extensions);
9908    }
9909}
9910
9911# $T2H_DEBUG and $T2H_VERBOSE are shorthands
9912$T2H_DEBUG = $Texi2HTML::Config::DEBUG;
9913$T2H_VERBOSE = $Texi2HTML::Config::VERBOSE;
9914
9915$Texi2HTML::THISDOC{'debug_l2h'} = 0;
9916$Texi2HTML::THISDOC{'debug_l2h'} = 1 if ($T2H_DEBUG & $DEBUG_L2H);
9917
9918
9919#+++############################################################################
9920#                                                                              #
9921# evaluation of cmd line options
9922#                                                                              #
9923#---############################################################################
9924
9925# Fill in the %style_type hash, a hash associating style @-comand with
9926# the type, 'accent', real 'style', simple' style, or 'special'.
9927# 'simple_style' styles don't extend accross lines.
9928my %style_type = ();
9929my @simple_styles = ('ctrl', 'w', 'url','uref','indicateurl','email',
9930    'titlefont');
9931foreach my $style (keys(%Texi2HTML::Config::style_map))
9932{
9933    if (exists $Texi2HTML::Config::command_type{$style})
9934    {
9935        $style_type{$style} = $Texi2HTML::Config::command_type{$style};
9936        next;
9937    }
9938    if (ref($Texi2HTML::Config::style_map{$style} eq 'HASH'))
9939    {
9940        $style_type{$style} = $Texi2HTML::Config::style_map{$style}->{'type'}
9941          if (exists($Texi2HTML::Config::style_map{$style}->{'type'}));
9942    }
9943    else
9944    {
9945        $style_type{$style} = 'simple_style' if (grep {$_ eq $style} @simple_styles);
9946    }
9947    $style_type{$style} = 'style' unless (defined($style_type{$style}));
9948}
9949foreach my $accent (keys(%Texi2HTML::Config::unicode_accents), 'tieaccent', 'dotless')
9950{
9951    if (exists $Texi2HTML::Config::command_type{$accent})
9952    {
9953        $style_type{$accent} = $Texi2HTML::Config::command_type{$accent};
9954        next;
9955    }
9956    $style_type{$accent} = 'accent';
9957}
9958#foreach my $simple ('ctrl', 'w', 'url','uref','indicateurl','email')
9959#{
9960#    $style_type{$simple} = 'simple_style';
9961#}
9962foreach my $special ('footnote', 'ref', 'xref', 'pxref', 'inforef', 'anchor', 'image')
9963{
9964    if (exists $Texi2HTML::Config::command_type{$special})
9965    {
9966        $style_type{$special} = $Texi2HTML::Config::command_type{$special};
9967        next;
9968    }
9969    $style_type{$special} = 'special';
9970}
9971
9972# retro compatibility for $Texi2HTML::Config::EXPAND
9973push (@Texi2HTML::Config::EXPAND, $Texi2HTML::Config::EXPAND) if ($Texi2HTML::Config::EXPAND);
9974
9975unshift @texi2html_config_dirs, @Texi2HTML::Config::CONF_DIRS;
9976# correct %text_macros based on command line and init
9977# variables
9978$text_macros{'menu'} = 1 if ($Texi2HTML::Config::SHOW_MENU);
9979
9980foreach my $expanded (@Texi2HTML::Config::EXPAND)
9981{
9982    $text_macros{"if$expanded"} = 1 if (exists($text_macros{"if$expanded"}));
9983    next unless (exists($text_macros{$expanded}));
9984    if (grep {$_ eq $expanded} @raw_regions)
9985    {
9986         $text_macros{$expanded} = 'raw';
9987    }
9988    else
9989    {
9990         $text_macros{$expanded} = 1;
9991    }
9992}
9993
9994# handle ifnot regions
9995foreach my $region (keys (%text_macros))
9996{
9997    next if ($region =~ /^ifnot/);
9998    if ($text_macros{$region} and $region =~ /^if(\w+)$/)
9999    {
10000        $text_macros{"ifnot$1"} = 0;
10001    }
10002}
10003
10004if ($T2H_VERBOSE)
10005{
10006    print STDERR "# Expanded: ";
10007    foreach my $text_macro (keys(%text_macros))
10008    {
10009        print STDERR "$text_macro " if ($text_macros{$text_macro});
10010    }
10011    print STDERR "\n";
10012}
10013
10014# This is kept in that file although it is html formatting as it seems to
10015# be rather obsolete
10016$Texi2HTML::Config::INVISIBLE_MARK = '<img src="invisible.xbm" alt="">' if $Texi2HTML::Config::INVISIBLE_MARK eq 'xbm';
10017
10018$T2H_DEBUG |= $DEBUG_TEXI if ($Texi2HTML::Config::DUMP_TEXI);
10019
10020# no user provided USE_UNICODE, use configure provided
10021if (!defined($Texi2HTML::Config::USE_UNICODE))
10022{
10023    $Texi2HTML::Config::USE_UNICODE = '1';
10024}
10025
10026# no user provided nor configured, run time test
10027if ($Texi2HTML::Config::USE_UNICODE eq '@' .'USE_UNICODE@')
10028{
10029    $Texi2HTML::Config::USE_UNICODE = 1;
10030    eval {
10031        require Encode;
10032        require Unicode::Normalize;
10033        Encode->import('encode');
10034    };
10035    $Texi2HTML::Config::USE_UNICODE = 0 if ($@);
10036}
10037elsif ($Texi2HTML::Config::USE_UNICODE)
10038{# user provided or set by configure
10039    require Encode;
10040    require Unicode::Normalize;
10041    Encode->import('encode');
10042}
10043
10044# no user provided USE_UNIDECODE, use configure provided
10045if (!defined($Texi2HTML::Config::USE_UNIDECODE))
10046{
10047    $Texi2HTML::Config::USE_UNIDECODE = '0';
10048}
10049
10050# no user provided nor configured, run time test
10051if ($Texi2HTML::Config::USE_UNIDECODE eq '@' .'USE_UNIDECODE@')
10052{
10053    $Texi2HTML::Config::USE_UNIDECODE = 1;
10054    eval {
10055        require Text::Unidecode;
10056        Text::Unidecode->import('unidecode');
10057    };
10058    $Texi2HTML::Config::USE_UNIDECODE = 0 if ($@);
10059}
10060elsif ($Texi2HTML::Config::USE_UNIDECODE)
10061{# user provided or set by configure
10062    require Text::Unidecode;
10063    Text::Unidecode->import('unidecode');
10064}
10065
10066print STDERR "# USE_UNICODE $Texi2HTML::Config::USE_UNICODE, USE_UNIDECODE $Texi2HTML::Config::USE_UNIDECODE \n"
10067  if ($T2H_VERBOSE);
10068
10069# Construct hashes used for cross references generation
10070# Do it now as the user may have changed $USE_UNICODE
10071
10072foreach my $key (keys(%Texi2HTML::Config::unicode_map))
10073{
10074    if ($Texi2HTML::Config::unicode_map{$key} ne '')
10075    {
10076        if ($Texi2HTML::Config::USE_UNICODE)
10077        {
10078            $cross_ref_texi_map{$key} = chr(hex($Texi2HTML::Config::unicode_map{$key}));
10079            if (($Texi2HTML::Config::TRANSLITERATE_NODE and !$Texi2HTML::Config::USE_UNIDECODE)
10080                and (exists ($Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}})))
10081            {
10082                $cross_transliterate_texi_map{$key} = $Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}};
10083
10084            }
10085        }
10086        else
10087        {
10088            $cross_ref_texi_map{$key} = '_' . lc($Texi2HTML::Config::unicode_map{$key});
10089            if ($Texi2HTML::Config::TRANSLITERATE_NODE)
10090            {
10091                if (exists ($Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}}))
10092                {
10093                    $cross_transliterate_texi_map{$key} = $Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}};
10094                }
10095                else
10096                {
10097                     $cross_transliterate_texi_map{$key} = '_' . lc($Texi2HTML::Config::unicode_map{$key});
10098                }
10099            }
10100        }
10101    }
10102}
10103if ($Texi2HTML::Config::USE_UNICODE and $Texi2HTML::Config::TRANSLITERATE_NODE
10104     and ! $Texi2HTML::Config::USE_UNIDECODE)
10105{
10106    foreach my $key (keys (%Texi2HTML::Config::transliterate_accent_map))
10107    {
10108        $Texi2HTML::Config::transliterate_map{$key} = $Texi2HTML::Config::transliterate_accent_map{$key};
10109    }
10110}
10111
10112foreach my $key (keys(%cross_ref_style_map_texi))
10113{
10114    if ($style_type{$key} eq 'accent'
10115        and (ref($cross_ref_style_map_texi{$key}) eq 'HASH'))
10116    {
10117        if ($Texi2HTML::Config::USE_UNICODE)
10118        {
10119             $cross_ref_style_map_texi{$key}->{'function'} = \&Texi2HTML::Config::t2h_utf8_accent;
10120        }
10121        else
10122        {
10123             $cross_ref_style_map_texi{$key}->{'function'} = \&Texi2HTML::Config::t2h_nounicode_cross_manual_accent;
10124        }
10125        if ($Texi2HTML::Config::TRANSLITERATE_NODE and
10126           !($Texi2HTML::Config::USE_UNICODE and $Texi2HTML::Config::USE_UNIDECODE))
10127        {
10128             $cross_transliterate_style_map_texi{$key}->{'function'} = \&Texi2HTML::Config::t2h_transliterate_cross_manual_accent;
10129        }
10130    }
10131}
10132
10133#
10134# file name business
10135#
10136
10137
10138my $docu_dir;            # directory of the document
10139my $docu_name;           # basename of the document
10140my $docu_rdir;           # directory for the output
10141my $docu_ext = $Texi2HTML::Config::EXTENSION;   # extension
10142my $docu_toc;            # document's table of contents
10143my $docu_stoc;           # document's short toc
10144my $docu_foot;           # document's footnotes
10145my $docu_about;          # about this document
10146my $docu_top;            # document top
10147my $docu_doc;            # document (or document top of split)
10148
10149die "Need exactly one file to translate\n$T2H_FAILURE_TEXT" unless @ARGV == 1;
10150my $docu = shift(@ARGV);
10151if ($docu =~ /(.*\/)/)
10152{
10153    chop($docu_dir = $1);
10154    $docu_name = $docu;
10155    $docu_name =~ s/.*\///;
10156}
10157else
10158{
10159    $docu_dir = '.';
10160    $docu_name = $docu;
10161}
10162unshift(@Texi2HTML::Config::INCLUDE_DIRS, $docu_dir);
10163unshift(@Texi2HTML::Config::INCLUDE_DIRS, @Texi2HTML::Config::PREPEND_DIRS);
10164$docu_name =~ s/\.te?x(i|info)?$//;
10165$docu_name = $Texi2HTML::Config::PREFIX if $Texi2HTML::Config::PREFIX;
10166
10167# resulting files splitting
10168if ($Texi2HTML::Config::SPLIT =~ /section/i)
10169{
10170    $Texi2HTML::Config::SPLIT = 'section';
10171}
10172elsif ($Texi2HTML::Config::SPLIT =~ /node/i)
10173{
10174    $Texi2HTML::Config::SPLIT = 'node';
10175}
10176elsif ($Texi2HTML::Config::SPLIT =~ /chapter/i)
10177{
10178    $Texi2HTML::Config::SPLIT = 'chapter';
10179}
10180else
10181{
10182    $Texi2HTML::Config::SPLIT = '';
10183}
10184
10185# Something like backward compatibility
10186if ($Texi2HTML::Config::SPLIT and $Texi2HTML::Config::SUBDIR)
10187{
10188    $Texi2HTML::Config::OUT = $Texi2HTML::Config::SUBDIR;
10189}
10190
10191# subdir
10192
10193die "output to STDOUT and split or frames incompatible\n"
10194    if (($Texi2HTML::Config::SPLIT or $Texi2HTML::Config::FRAMES) and ($Texi2HTML::Config::OUT eq '-'));
10195
10196if ($Texi2HTML::Config::SPLIT and ($Texi2HTML::Config::OUT eq ''))
10197{
10198    $Texi2HTML::Config::OUT = $docu_name;
10199}
10200
10201if ($Texi2HTML::Config::SPLIT and ($Texi2HTML::Config::OUT eq '.'))
10202{# This is to avoid trouble with latex2html
10203    $Texi2HTML::Config::OUT = '';
10204}
10205
10206$docu_rdir = '';
10207
10208if ($Texi2HTML::Config::SPLIT and ($Texi2HTML::Config::OUT ne ''))
10209{
10210    $Texi2HTML::Config::OUT =~ s|/*$||;
10211    $docu_rdir = "$Texi2HTML::Config::OUT/";
10212    unless (-d $Texi2HTML::Config::OUT)
10213    {
10214        if ( mkdir($Texi2HTML::Config::OUT, oct(755)))
10215        {
10216            print STDERR "# created directory $Texi2HTML::Config::OUT\n" if ($T2H_VERBOSE);
10217        }
10218        else
10219        {
10220            die "$ERROR can't create directory $Texi2HTML::Config::OUT\n";
10221        }
10222    }
10223    print STDERR "# putting result files into directory $docu_rdir\n" if ($T2H_VERBOSE);
10224}
10225elsif (! $Texi2HTML::Config::SPLIT and ($Texi2HTML::Config::OUT ne ''))
10226{
10227    if ($Texi2HTML::Config::OUT =~ m|(.*)/|)
10228    {# there is a leading directories
10229        $docu_rdir = "$1/";
10230        unless (-d $docu_rdir)
10231        {
10232            if ( mkdir($docu_rdir, oct(755)))
10233            {
10234                 print STDERR "# created directory $docu_rdir\n" if ($T2H_VERBOSE);
10235            }
10236            else
10237            {
10238                die "$ERROR can't create directory $docu_rdir\n";
10239            }
10240        }
10241        print STDERR "# putting result files into directory $docu_rdir\n" if ($T2H_VERBOSE);
10242    }
10243    else
10244    {
10245        print STDERR "# putting result files into current directory \n" if ($T2H_VERBOSE);
10246        $docu_rdir = '';
10247    }
10248}
10249
10250# We don't use "./" as $docu_rdir when $docu_rdir is the current directory
10251# because it is problematic for latex2html. To test writability with -w,
10252# however we need a real directory.
10253my $result_rdir = $docu_rdir;
10254$result_rdir = "." if ($docu_rdir eq '');
10255unless (-w $result_rdir)
10256{
10257    $docu_rdir = 'current directory' if ($docu_rdir eq '');
10258    die "$ERROR $docu_rdir not writable\n";
10259}
10260
10261# relative path leading to the working directory from the document directory
10262my $path_to_working_dir = $docu_rdir;
10263if ($docu_rdir ne '')
10264{
10265    my $cwd = cwd;
10266    my $docu_path = $docu_rdir;
10267    $docu_path = $cwd . '/' . $docu_path unless ($docu_path =~ /^\//);
10268    my @result = ();
10269    foreach my $element (split /\//, File::Spec->canonpath($docu_path))
10270    {
10271        if ($element eq '')
10272        {
10273            push @result, '';
10274        }
10275        elsif ($element eq '..')
10276        {
10277            if (@result and ($result[-1] eq ''))
10278            {
10279                print STDERR "Too much .. in absolute file name\n";
10280            }
10281            elsif (@result and ($result[-1] ne '..'))
10282            {
10283                pop @result;
10284            }
10285            else
10286            {
10287                push @result, $element;
10288            }
10289        }
10290        else
10291        {
10292            push @result, $element;
10293        }
10294    }
10295    $path_to_working_dir = File::Spec->abs2rel($cwd, join ('/', @result));
10296    $path_to_working_dir =~ s|.*/||;
10297    $path_to_working_dir .= '/' unless($path_to_working_dir eq '');
10298}
10299
10300# extension
10301if ($Texi2HTML::Config::SHORTEXTN)
10302{
10303    $docu_ext = "htm";
10304}
10305
10306$docu_doc = $docu_name . ($docu_ext ? ".$docu_ext" : ""); # document's contents
10307if ($Texi2HTML::Config::SPLIT)
10308{
10309    $docu_top   = $Texi2HTML::Config::TOP_FILE || $docu_doc;
10310
10311    if (defined $Texi2HTML::Config::element_file_name)
10312    {
10313        $docu_toc = &$Texi2HTML::Config::element_file_name
10314            (undef, "toc", $docu_name);
10315        $docu_stoc = &$Texi2HTML::Config::element_file_name
10316            (undef, "stoc", $docu_name);
10317        $docu_foot = &$Texi2HTML::Config::element_file_name
10318            (undef, "foot", $docu_name);
10319        $docu_about = &$Texi2HTML::Config::element_file_name
10320            (undef, "about", $docu_name);
10321	# $docu_top may be overwritten later.
10322    }
10323    if (!defined($docu_toc))
10324    {
10325        my $default_toc = "${docu_name}_toc";
10326        $default_toc .= ".$docu_ext" if (defined($docu_ext));
10327        $docu_toc   = $Texi2HTML::Config::TOC_FILE || $default_toc;
10328    }
10329    if (!defined($docu_stoc))
10330    {
10331        $docu_stoc  = "${docu_name}_ovr";
10332        $docu_stoc .= ".$docu_ext" if (defined($docu_ext));
10333    }
10334    if (!defined($docu_foot))
10335    {
10336        $docu_foot  = "${docu_name}_fot";
10337        $docu_foot .= ".$docu_ext" if (defined($docu_ext));
10338    }
10339    if (!defined($docu_about))
10340    {
10341        $docu_about = "${docu_name}_abt";
10342        $docu_about .= ".$docu_ext" if (defined($docu_ext));
10343    }
10344}
10345else
10346{
10347    if ($Texi2HTML::Config::OUT)
10348    {
10349        $docu_doc = $Texi2HTML::Config::OUT;
10350        $docu_doc =~ s|.*/||;
10351    }
10352    if (defined $Texi2HTML::Config::element_file_name)
10353    {
10354        my $docu_name = &$Texi2HTML::Config::element_file_name
10355           (undef, "doc", $docu_name);
10356        $docu_top = $docu_name if (defined($docu_name));
10357    }
10358    $docu_toc = $docu_foot = $docu_stoc = $docu_about = $docu_top = $docu_doc;
10359}
10360
10361# Note that file extension has already been added here.
10362
10363# For use in init files
10364$Texi2HTML::THISDOC{'filename'}->{'top'} = $docu_top;
10365$Texi2HTML::THISDOC{'filename'}->{'foot'} = $docu_foot;
10366$Texi2HTML::THISDOC{'filename'}->{'stoc'} = $docu_stoc;
10367$Texi2HTML::THISDOC{'filename'}->{'about'} = $docu_about;
10368$Texi2HTML::THISDOC{'filename'}->{'toc'} = $docu_toc;
10369$Texi2HTML::THISDOC{'extension'} = $docu_ext;
10370# FIXME document that
10371$Texi2HTML::THISDOC{'out_dir'} = $docu_rdir;
10372$Texi2HTML::THISDOC{'file_base_name'} = $docu_name;
10373
10374
10375my $docu_doc_file = "$docu_rdir$docu_doc";
10376my $docu_toc_file  = "$docu_rdir$docu_toc";
10377my $docu_stoc_file = "$docu_rdir$docu_stoc";
10378my $docu_foot_file = "$docu_rdir$docu_foot";
10379my $docu_about_file = "$docu_rdir$docu_about";
10380my $docu_top_file  = "$docu_rdir$docu_top";
10381
10382my $docu_frame_file =     "$docu_rdir${docu_name}_frame";
10383$docu_frame_file .= ".$docu_ext" if $docu_ext;
10384my $docu_toc_frame_file = "$docu_rdir${docu_name}_toc_frame";
10385$docu_toc_frame_file .= ".$docu_ext" if $docu_ext;
10386
10387#
10388# _foo: internal variables to track @foo
10389#
10390foreach my $key ('_author', '_title', '_subtitle', '_shorttitlepage',
10391	 '_settitle', '_setfilename', '_shorttitle', '_titlefont')
10392{
10393    $value{$key} = '';            # prevent -w warnings
10394}
10395my $index;                         # ref on a hash for the index entries
10396my %indices = ();                  # hash of indices names containing
10397                                   #[ $pages, $entries ] (page indices and
10398                                   # raw index entries)
10399my @index_labels = ();             # array corresponding with @?index commands
10400                                   # constructed during pass_texi, used to
10401                                   # put labels in pass_text
10402#
10403# initial counters
10404#
10405my $foot_num = 0;
10406my $relative_foot_num = 0;
10407my $idx_num = 0;
10408my $sec_num = 0;
10409my $anchor_num = 0;
10410
10411#
10412# can I use ISO8859 characters? (HTML+)
10413#
10414if ($Texi2HTML::Config::USE_ISO)
10415{
10416    foreach my $thing (keys(%Texi2HTML::Config::iso_symbols))
10417    {
10418         next unless exists ($::things_map_ref->{$thing});
10419         $::things_map_ref->{$thing} = $Texi2HTML::Config::iso_symbols{$thing};
10420         $::pre_map_ref->{$thing} = $Texi2HTML::Config::iso_symbols{$thing};
10421         $Texi2HTML::Config::simple_format_texi_map{$thing} = $Texi2HTML::Config::iso_symbols{$thing};
10422    }
10423    # we don't override the user defined quote, but beware that this works
10424    # only if the hardcoded defaults, '`' and "'" match with the defaults
10425    # in the default init file
10426    $Texi2HTML::Config::OPEN_QUOTE_SYMBOL = $Texi2HTML::Config::iso_symbols{'`'}
10427        if (exists($Texi2HTML::Config::iso_symbols{'`'}) and ($Texi2HTML::Config::OPEN_QUOTE_SYMBOL eq '`'));
10428    $Texi2HTML::Config::CLOSE_QUOTE_SYMBOL = $Texi2HTML::Config::iso_symbols{"'"}
10429       if (exists($Texi2HTML::Config::iso_symbols{"'"}) and ($Texi2HTML::Config::CLOSE_QUOTE_SYMBOL eq "'"));
10430}
10431
10432
10433
10434# process a css file
10435sub process_css_file ($$)
10436{
10437    my $fh =shift;
10438    my $file = shift;
10439    my $in_rules = 0;
10440    my $in_comment = 0;
10441    my $in_import = 0;
10442    my $in_string = 0;
10443    my $rules = [];
10444    my $imports = [];
10445    while (<$fh>)
10446    {
10447	    #print STDERR "Line: $_";
10448        if ($in_rules)
10449        {
10450            push @$rules, $_;
10451            next;
10452        }
10453        my $text = '';
10454        while (1)
10455        {
10456		#sleep 1;
10457		#print STDERR "${text}!in_comment $in_comment in_rules $in_rules in_import $in_import in_string $in_string: $_";
10458             if ($in_comment)
10459             {
10460                 if (s/^(.*?\*\/)//)
10461                 {
10462                     $text .= $1;
10463                     $in_comment = 0;
10464                 }
10465                 else
10466                 {
10467                     push @$imports, $text . $_;
10468                     last;
10469                 }
10470             }
10471             elsif (!$in_string and s/^\///)
10472             { # what do '\' do here ?
10473                 if (s/^\*//)
10474                 {
10475                     $text .= '/*';
10476                     $in_comment = 1;
10477                 }
10478                 else
10479                 {
10480                     push (@$imports, $text. "\n") if ($text ne '');
10481                     push (@$rules, '/' . $_);
10482                     $in_rules = 1;
10483                     last;
10484                 }
10485             }
10486             elsif (!$in_string and $in_import and s/^([\"\'])//)
10487             { # strings outside of import start rules
10488                 $text .= "$1";
10489                 $in_string = quotemeta("$1");
10490             }
10491             elsif ($in_string and s/^(\\$in_string)//)
10492             {
10493                 $text .= $1;
10494             }
10495             elsif ($in_string and s/^($in_string)//)
10496             {
10497                 $text .= $1;
10498                 $in_string = 0;
10499             }
10500             elsif ((! $in_string and !$in_import) and (s/^([\\]?\@import)$// or s/^([\\]?\@import\s+)//))
10501             {
10502                 $text .= $1;
10503                 $in_import = 1;
10504             }
10505             elsif (!$in_string and $in_import and s/^\;//)
10506             {
10507                 $text .= ';';
10508                 $in_import = 0;
10509             }
10510             elsif (($in_import or $in_string) and s/^(.)//)
10511             {
10512                  $text .= $1;
10513             }
10514             elsif (!$in_import and s/^([^\s])//)
10515             {
10516                  push (@$imports, $text. "\n") if ($text ne '');
10517                  push (@$rules, $1 . $_);
10518                  $in_rules = 1;
10519                  last;
10520             }
10521             elsif (s/^(\s)//)
10522             {
10523                  $text .= $1;
10524             }
10525             elsif ($_ eq '')
10526             {
10527                  push (@$imports, $text);
10528                  last;
10529             }
10530        }
10531    }
10532    warn "$WARN string not closed in css file $file\n" if ($in_string);
10533    warn "$WARN comment not closed in css file $file\n" if ($in_comment);
10534    warn "$WARN \@import not finished in css file $file\n"  if ($in_import and !$in_comment and !$in_string);
10535    return ($imports, $rules);
10536}
10537
10538
10539
10540# parse texinfo cnf file for external manual specifications. This was
10541# discussed on texinfo list but not in makeinfo for now.
10542my @texinfo_htmlxref_files = locate_init_file ($texinfo_htmlxref, 1, \@texinfo_config_dirs);
10543foreach my $file (@texinfo_htmlxref_files)
10544{
10545    print STDERR "html refs config file: $file\n" if ($T2H_DEBUG);
10546    unless (open (HTMLXREF, $file))
10547    {
10548         warn "Cannot open html refs config file ${file}: $!";
10549         next;
10550    }
10551    while (<HTMLXREF>)
10552    {
10553        my $line = $_;
10554        s/[#]\s.*//;
10555        s/^\s*//;
10556        next if /^\s*$/;
10557        my @htmlxref = split /\s+/;
10558        my $manual = shift @htmlxref;
10559        my $split_or_mono = shift @htmlxref;
10560        if (!defined($split_or_mono) or ($split_or_mono ne 'split' and $split_or_mono ne 'mono'))
10561        {
10562            echo_warn("Bad line in $file: $line");
10563            next;
10564        }
10565        my $href = shift @htmlxref;
10566        next if (exists($Texi2HTML::THISDOC{'htmlxref'}->{$manual}->{$split_or_mono}) and exists($Texi2HTML::THISDOC{'htmlxref'}->{$manual}->{$split_or_mono}->{'href'}));
10567
10568        if (defined($href))
10569        {
10570            $href =~ s/\/*$// if ($split_or_mono eq 'split');
10571            $Texi2HTML::THISDOC{'htmlxref'}->{$manual}->{$split_or_mono}->{'href'} = $href;
10572        }
10573        else
10574        {
10575            $Texi2HTML::THISDOC{'htmlxref'}->{$manual}->{$split_or_mono} = {};
10576        }
10577    }
10578    close (HTMLXREF);
10579}
10580
10581if ($T2H_DEBUG)
10582{
10583    foreach my $manual (keys(%{$Texi2HTML::THISDOC{'htmlxref'}}))
10584    {
10585         foreach my $split ('split', 'mono')
10586         {
10587              my $href = 'NO';
10588              next unless (exists($Texi2HTML::THISDOC{'htmlxref'}->{$manual}->{$split}));
10589              $href = $Texi2HTML::THISDOC{'htmlxref'}->{$manual}->{$split}->{'href'} if
10590                  exists($Texi2HTML::THISDOC{'htmlxref'}->{$manual}->{$split}->{'href'});
10591              print STDERR "$manual: $split, href: $href\n";
10592         }
10593    }
10594}
10595
10596print STDERR "# reading from $docu\n" if $T2H_VERBOSE;
10597
10598#+++###########################################################################
10599#                                                                             #
10600# Pass texi: read source, handle variable, ignored text,                      #
10601#                                                                             #
10602#---###########################################################################
10603
10604my @fhs = ();			# hold the file handles to read
10605my $input_spool;		# spooled lines to read
10606my @lines = ();             # whole document
10607my @lines_numbers = ();     # line number, originating file associated with
10608                            # whole document
10609my $macros;                 # macros. reference on a hash
10610my %info_enclose;           # macros defined with definfoenclose
10611my $texi_line_number = { 'file_name' => '', 'line_nr' => 0, 'macro' => '' };
10612my @floats = ();            # floats list
10613my %floats = ();            # floats by style
10614
10615sub initialise_state_texi($)
10616{
10617    my $state = shift;
10618    $state->{'texi'} = 1;           # for substitute_text and close_stack:
10619                                    # 1 if pass_texi/scan_texi is to be used
10620    $state->{'macro_inside'} = 0 unless(defined($state->{'macro_inside'}));
10621    $state->{'ifvalue_inside'} = 0 unless(defined($state->{'ifvalue_inside'}));
10622    $state->{'arg_expansion'} = 0 unless(defined($state->{'arg_expansion'}));
10623}
10624
10625my @first_lines = ();
10626
10627sub pass_texi()
10628{
10629    my $first_lines = 1;        # is it the first lines
10630    my $state = {};
10631                                # holds the informations about the context
10632                                # to pass it down to the functions
10633    initialise_state_texi($state);
10634    my @stack;
10635    my $text;
10636 INPUT_LINE: while (defined($_ = next_line($texi_line_number)))
10637    {
10638        #
10639        # remove the lines preceding \input or an @-command
10640        #
10641        if ($first_lines)
10642        {
10643            if (/^\\input/)
10644            {
10645                push @first_lines, $_;
10646                $first_lines = 0;
10647                next;
10648            }
10649            if (/^\s*\@/)
10650            {
10651                $first_lines = 0;
10652            }
10653            else
10654            {
10655                push @first_lines, $_;
10656                next;
10657            }
10658        }
10659	#print STDERR "PASS_TEXI($texi_line_number->{'line_nr'})$_";
10660        my $chomped_line = $_;
10661        if (scan_texi ($_, \$text, \@stack, $state, $texi_line_number) and chomp($chomped_line))
10662        {
10663        #print STDERR "==> new page (line_nr $texi_line_number->{'line_nr'},$texi_line_number->{'file_name'},$texi_line_number->{'macro'})\n";
10664            push (@lines_numbers, { 'file_name' => $texi_line_number->{'file_name'},
10665                  'line_nr' => $texi_line_number->{'line_nr'},
10666                  'macro' => $texi_line_number->{'macro'} });
10667        }
10668        #dump_stack (\$text, \@stack, $state);
10669        if ($state->{'bye'})
10670        {
10671            #dump_stack(\$text, \@stack, $state);
10672            # close stack after bye
10673            #print STDERR "close stack after bye\n";
10674            close_stack_texi_structure(\$text, \@stack, $state, $texi_line_number);
10675            #dump_stack(\$text, \@stack, $state);
10676        }
10677        next if (@stack);
10678        $_ = $text;
10679        $text = '';
10680        if (!defined($_))
10681        {# FIXME: remove the error message if it is reported too often
10682            print STDERR "# \$_ undefined after scan_texi. This may be a bug, or not.\n";
10683            print STDERR "# Report (with texinfo file) if you want, otherwise ignore that message.\n";
10684            next unless ($state->{'bye'});
10685        }
10686        push @lines, split_lines($_);
10687        last if ($state->{'bye'});
10688    }
10689    # close stack at the end of pass texi
10690    #print STDERR "close stack at the end of pass texi\n";
10691    close_stack_texi_structure(\$text, \@stack, $state, $texi_line_number);
10692    push @lines, split_lines($text);
10693    print STDERR "# end of pass texi\n" if $T2H_VERBOSE;
10694}
10695
10696# return the line after preserving things according to misc_command map.
10697sub preserve_command($$)
10698{
10699    my $line = shift;
10700    my $macro = shift;
10701    my $text = '';
10702    my $args = '';
10703    my $skip_spec = '';
10704    my $arg_spec = '';
10705
10706    $skip_spec = $Texi2HTML::Config::misc_command{$macro}->{'skip'}
10707        if (defined($Texi2HTML::Config::misc_command{$macro}->{'skip'}));
10708    $arg_spec = $Texi2HTML::Config::misc_command{$macro}->{'arg'}
10709        if (defined($Texi2HTML::Config::misc_command{$macro}->{'arg'}));
10710
10711    if ($arg_spec eq 'line')
10712    {
10713        $text .= $line;
10714        $args .= $line;
10715        $line = '';
10716    }
10717    elsif ($arg_spec)
10718    {
10719        my $arg_nr = $Texi2HTML::Config::misc_command{$macro}->{'arg'};
10720        while ($arg_nr)
10721        {
10722            $line =~ s/(\s+\S*)//o;
10723            $text .= $1 if defined($1);
10724            $args .= $1 if defined($1);
10725            $arg_nr--;
10726        }
10727    }
10728
10729    if ($macro eq 'bye')
10730    {
10731        $line = '';
10732        $text = "\n";
10733    }
10734    elsif ($skip_spec eq 'linespace')
10735    {
10736        if ($line =~ /^\s*$/o)
10737        {
10738            $line =~ s/([ \t]*)//o;
10739            $text .= $1;
10740        }
10741    }
10742    elsif ($skip_spec eq 'linewhitespace')
10743    {
10744        if ($line =~ /^\s*$/o)
10745        {
10746            $text .= $line;
10747            $line = '';
10748        }
10749    }
10750    elsif ($skip_spec eq 'line')
10751    {
10752        $text .= $line;
10753        $line = '';
10754    }
10755    elsif ($skip_spec eq 'whitespace')
10756    {
10757        $line =~ s/(\s*)//o;
10758        $text .=  $1;
10759    }
10760    elsif ($skip_spec eq 'space')
10761    {
10762        $line =~ s/([ \t]*)//o;
10763        $text .= $1;
10764    }
10765    $line = '' if (!defined($line));
10766    return ($line, $text, $args);
10767}
10768
10769#+++###########################################################################
10770#                                                                             #
10771# Pass structure: parse document structure                                    #
10772#                                                                             #
10773#---###########################################################################
10774
10775# This is a virtual element for things appearing before @node and
10776# sectionning commands
10777my $element_before_anything =
10778{
10779    'before_anything' => 1,
10780    'place' => [],
10781    'texi' => 'VIRTUAL ELEMENT BEFORE ANYTHING',
10782};
10783
10784# This is a place for index entries, anchors and so on appearing in
10785# copying or documentdescription
10786my $region_place = [];
10787
10788sub initialise_state_structure($)
10789{
10790    my $state = shift;
10791    $state->{'structure'} = 1;      # for substitute_text and close_stack:
10792                                    # 1 if pass_structure/scan_structure is
10793                                    # to be used
10794    $state->{'menu'} = 0;           # number of opened menus
10795    $state->{'detailmenu'} = 0;     # number of opened detailed menus
10796    $state->{'sectionning_base'} = 0;         # current base sectionning level
10797    $state->{'table_stack'} = [ "no table" ]; # a stack of opened tables/lists
10798    if (exists($state->{'region_lines'}) and !defined($state->{'region_lines'}))
10799    {
10800        delete ($state->{'region_lines'});
10801        print STDERR "Bug: state->{'region_lines'} exists but undef.\n";
10802    }
10803}
10804
10805my @doc_lines = ();         # whole document
10806my @doc_numbers = ();       # whole document line numbers and file names
10807my @nodes_list = ();        # nodes in document reading order
10808                            # each member is a reference on a hash
10809my @sections_list = ();     # sections in reading order
10810                            # each member is a reference on a hash
10811my @all_elements = ();      # sectionning elements (nodes and sections)
10812                            # in reading order. Each member is a reference
10813                            # on a hash which also appears in %nodes,
10814                            # @sections_list @nodes_list, @elements_list
10815my @elements_list;          # all the resulting elements in document order
10816my %sections = ();          # sections hash. The key is the section number
10817                            # headings are there, although they are not elements
10818my $section_top;            # @top section
10819my $element_top;            # Top element
10820my $node_top;               # Top node
10821my $node_first;             # First node
10822my $element_index;          # element with first index
10823my $element_chapter_index;  # chapter with first index
10824my $element_first;          # first element
10825my $element_last;           # last element
10826my %special_commands;       # hash for the commands specially handled
10827                            # by the user
10828
10829# This is a virtual element used to have the right hrefs for index entries
10830# and anchors in footnotes
10831my $footnote_element =
10832{
10833    'id' => 'SEC_Foot',
10834    'file' => $docu_foot,
10835    'footnote' => 1,
10836    'element' => 1,
10837    'place' => [],
10838};
10839
10840my %content_element =
10841(
10842    'contents' => { 'id' => 'SEC_Contents', 'contents' => 1, 'texi' => '_contents' },
10843    'shortcontents' => { 'id' => 'SEC_Overview', 'shortcontents' => 1, 'texi' => '_shortcontents' },
10844);
10845
10846#my $do_contents;            # do table of contents if true
10847#my $do_scontents;           # do short table of contents if true
10848my $novalidate = $Texi2HTML::Config::NOVALIDATE; # @novalidate appeared
10849
10850sub pass_structure()
10851{
10852    my $state = {};
10853                                # holds the informations about the context
10854                                # to pass it down to the functions
10855    initialise_state_structure($state);
10856    $state->{'element'} = $element_before_anything;
10857    $state->{'place'} = $element_before_anything->{'place'};
10858    my @stack;
10859    my $text;
10860    my $line_nr;
10861
10862    while (@lines)
10863    {
10864        $_ = shift @lines;
10865        my $chomped_line = $_;
10866        if (!chomp($chomped_line) and @lines)
10867        {
10868             $lines[0] = $_ . $lines[0];
10869             next;
10870        }
10871        $line_nr = shift (@lines_numbers);
10872        #print STDERR "PASS_STRUCTURE: $_";
10873        if (!$state->{'raw'} and !$state->{'verb'})
10874        {
10875            my $tag = '';
10876            if (/^\s*\@(\w+)\b/)
10877            {
10878                $tag = $1;
10879            }
10880
10881            #
10882            # analyze the tag
10883            #
10884            if ($tag and $tag eq 'node' or defined($sec2level{$tag}) or $tag eq 'printindex')
10885            {
10886                $_ = substitute_texi_line($_);
10887                if ($tag eq 'node' or defined($sec2level{$tag}))
10888                {# in pass structure node shouldn't appear in formats
10889                    close_stack_texi_structure(\$text, \@stack, $state, $line_nr);
10890                    if (exists($state->{'region_lines'}))
10891                    {
10892                        push @{$region_lines{$state->{'region_lines'}->{'format'}}}, split_lines($text);
10893                        close_region($state);
10894                    }
10895                    else
10896                    {
10897                        push @doc_lines, split_lines($text);
10898                    }
10899                    $text = '';
10900                }
10901                if ($tag eq 'node')
10902                {
10903                    my $node_ref;
10904                    my $auto_directions;
10905                    $auto_directions = 1 unless (/,/o);
10906                    my ($node, $node_next, $node_prev, $node_up) = split(/,/, $_);
10907                    $node =~ s/^\@node\s+// if ($node);
10908                    if ($node)
10909                    {
10910                        $node = normalise_space($node);
10911                        if (exists($nodes{$node}) and defined($nodes{$node})
10912                             and $nodes{$node}->{'seen'})
10913                        {
10914                            echo_error ("Duplicate node found: $node", $line_nr);
10915                            next;
10916                        }
10917                        else
10918                        {
10919                            if (exists($nodes{$node}) and defined($nodes{$node}))
10920                            { # node appeared in a menu
10921                                $node_ref = $nodes{$node};
10922                            }
10923                            else
10924                            {
10925                                my $first;
10926                                $first = 1 if (!defined($node_ref));
10927                                $node_ref = {};
10928                                $node_first = $node_ref if ($first);
10929                                $nodes{$node} = $node_ref;
10930                            }
10931                            $node_ref->{'node'} = 1;
10932                            $node_ref->{'tag'} = 'node';
10933                            $node_ref->{'tag_level'} = 'node';
10934                            $node_ref->{'texi'} = $node;
10935                            $node_ref->{'seen'} = 1;
10936                            $node_ref->{'automatic_directions'} = $auto_directions;
10937                            $node_ref->{'place'} = [];
10938                            $node_ref->{'current_place'} = [];
10939                            merge_element_before_anything($node_ref);
10940                            $node_ref->{'index_names'} = [];
10941                            $state->{'place'} = $node_ref->{'current_place'};
10942                            $state->{'element'} = $node_ref;
10943                            $state->{'after_element'} = 1;
10944                            $state->{'node_ref'} = $node_ref;
10945                            # makeinfo treats differently case variants of
10946                            # top in nodes and anchors and in refs commands and
10947                            # refs from nodes.
10948                            if ($node =~ /^top$/i)
10949                            {
10950                                if (!defined($node_top))
10951                                {
10952                                    $node_top = $node_ref;
10953                                    $node_top->{'texi'} = 'Top';
10954                                    delete $nodes{$node};
10955                                    $nodes{$node_top->{'texi'}} = $node_ref;
10956                                }
10957                                else
10958                                { # All the refs are going to point to the first Top
10959                                    echo_warn ("Top node allready exists", $line_nr);
10960                                    #warn "$WARN Top node allready exists\n";
10961                                }
10962                            }
10963                            unless (@nodes_list)
10964                            {
10965                                $node_ref->{'first'} = 1;
10966                            }
10967                            push (@nodes_list, $node_ref);
10968                            push @all_elements, $node_ref;
10969                        }
10970                    }
10971                    else
10972                    {
10973                        echo_error ("Node is undefined: $_ (eg. \@node NODE-NAME, NEXT, PREVIOUS, UP)", $line_nr);
10974                        next;
10975                    }
10976
10977                    if ($node_next)
10978                    {
10979                        $node_ref->{'node_next'} = normalise_node($node_next);
10980                    }
10981                    if ($node_prev)
10982                    {
10983                        $node_ref->{'node_prev'} = normalise_node($node_prev);
10984                    }
10985                    if ($node_up)
10986                    {
10987                        $node_ref->{'node_up'} = normalise_node($node_up);
10988                    }
10989                }
10990                elsif (defined($sec2level{$tag}))
10991                { # section or heading
10992                    if (/^\@$tag\s*(.*)$/)
10993                    {
10994                        my $name = normalise_space($1);
10995                        $name = '' if (!defined($name));
10996                        my $level = $sec2level{$tag};
10997                        $state->{'after_element'} = 1;
10998                        my ($docid, $num);
10999                        if($tag ne 'top')
11000                        {
11001                            $sec_num++;
11002                            $num = $sec_num;
11003                            $docid = "SEC$sec_num";
11004                        }
11005                        else
11006                        {
11007                            $num = 0;
11008                            $docid = "SEC_Top";
11009                        }
11010                        if ($tag !~ /heading/)
11011                        {
11012                            my $section_ref = { 'texi' => $name,
11013                               'level' => $level,
11014                               'tag' => $tag,
11015                               'sec_num' => $num,
11016                               'section' => 1,
11017                               'id' => $docid,
11018                               'seen' => 1,
11019                               'index_names' => [],
11020                               'current_place' => [],
11021                               'place' => []
11022                            };
11023
11024                            if ($tag eq 'top')
11025                            {
11026                                $section_ref->{'top'} = 1;
11027                                $section_ref->{'number'} = '';
11028                                $sections{0} = $section_ref;
11029                                $section_top = $section_ref;
11030                            }
11031                            $sections{$num} = $section_ref;
11032                            merge_element_before_anything($section_ref);
11033                            if ($state->{'node_ref'} and !exists($state->{'node_ref'}->{'with_section'}))
11034                            {
11035                                my $node_ref = $state->{'node_ref'};
11036                                $section_ref->{'node_ref'} = $node_ref;
11037                                $section_ref->{'titlefont'} = $node_ref->{'titlefont'};
11038                                $node_ref->{'with_section'} = $section_ref;
11039                                $node_ref->{'top'} = 1 if ($tag eq 'top');
11040                            }
11041                            if (! $name and $level)
11042                            {
11043                               echo_warn ("$tag without name", $line_nr);
11044                            }
11045                            push @sections_list, $section_ref;
11046                            push @all_elements, $section_ref;
11047                            $state->{'element'} = $section_ref;
11048                            $state->{'place'} = $section_ref->{'current_place'};
11049                            my $node_ref = "NO NODE";
11050                            my $node_texi ='';
11051                            if ($state->{'node_ref'})
11052                            {
11053                                $node_ref = $state->{'node_ref'};
11054                                $node_texi = $state->{'node_ref'}->{'texi'};
11055                            }
11056                            print STDERR "# pass_structure node($node_ref)$node_texi, tag \@$tag($level) ref $section_ref, num,id $num,$docid\n   $name\n"
11057                               if $T2H_DEBUG & $DEBUG_ELEMENTS;
11058                        }
11059                        else
11060                        {
11061                            my $section_ref = { 'texi' => $name,
11062                                'level' => $level,
11063                                'heading' => 1,
11064                                'tag' => $tag,
11065                                'tag_level' => $tag,
11066                                'sec_num' => $sec_num,
11067                                'id' => $docid,
11068                                'number' => '' };
11069                            $state->{'element'} = $section_ref;
11070                            push @{$state->{'place'}}, $section_ref;
11071                            $sections{$sec_num} = $section_ref;
11072                        }
11073                    }
11074                }
11075                elsif (/^\@printindex\s+(\w+)/)
11076                {
11077                    unless (@all_elements)
11078                    {
11079                        echo_warn ("Printindex before document beginning: \@printindex $1", $line_nr);
11080                        next;
11081                    }
11082                    delete $state->{'after_element'};
11083                    # $element_index is the first element with index
11084                    $element_index = $all_elements[-1] unless (defined($element_index));
11085                    # associate the index to the element such that the page
11086                    # number is right
11087                    my $placed_elements = [];
11088                    push @{$all_elements[-1]->{'index_names'}}, { 'name' => $1, 'place' => $placed_elements };
11089                    $state->{'place'} = $placed_elements;
11090                }
11091                if (exists($state->{'region_lines'}))
11092                {
11093                    push @{$region_lines{$state->{'region_lines'}->{'format'}}}, $_;
11094                }
11095                else
11096                {
11097                    push @doc_lines, $_;
11098                    push @doc_numbers, $line_nr;
11099                }
11100                next;
11101            }
11102        }
11103        if (scan_structure ($_, \$text, \@stack, $state, $line_nr) and !(exists($state->{'region_lines'})))
11104        {
11105            push (@doc_numbers, $line_nr);
11106        }
11107        next if (@stack);
11108        $_ = $text;
11109        $text = '';
11110        next if (!defined($_));
11111        if ($state->{'region_lines'})
11112        {
11113            push @{$region_lines{$state->{'region_lines'}->{'format'}}}, split_lines($_);
11114        }
11115        else
11116        {
11117            push @doc_lines, split_lines($_);
11118        }
11119    }
11120    if (@stack)
11121    {# close stack at the end of pass structure
11122        close_stack_texi_structure(\$text, \@stack, $state, $line_nr);
11123        if ($text)
11124        {
11125            if (exists($state->{'region_lines'}))
11126            {
11127                push @{$region_lines{$state->{'region_lines'}->{'format'}}},
11128                   split_lines($text);
11129            }
11130            else
11131            {
11132                push @doc_lines, split_lines($text);
11133            }
11134        }
11135    }
11136    echo_warn ("At end of document, $state->{'region_lines'}->{'number'} $state->{'region_lines'}->{'format'} not closed") if (exists($state->{'region_lines'}));
11137    print STDERR "# end of pass structure\n" if $T2H_VERBOSE;
11138}
11139
11140# split line at end of line and put each resulting line in an array
11141# FIXME there must be a more perlish way to do it... Not a big deal
11142# as long as it work
11143sub split_lines($)
11144{
11145   my $line = shift;
11146   my @result = ();
11147   my $i = 0;
11148   while ($line)
11149   {
11150       $result[$i] = '';
11151       $line =~ s/^(.*)//;
11152       $result[$i] .= $1;
11153       $result[$i] .= "\n" if ($line =~ s/^\n//);
11154       #print STDERR "$i: $result[$i]";
11155       $i++;
11156   }
11157   return @result;
11158}
11159
11160# handle misc commands and misc command args
11161sub misc_command_structure($$$$)
11162{
11163    my $line = shift;
11164    my $macro = shift;
11165    my $state = shift;
11166    my $line_nr = shift;
11167    my $text;
11168    my $args;
11169
11170    if ($macro eq 'lowersections')
11171    {
11172        my ($sec, $level);
11173        while (($sec, $level) = each %sec2level)
11174        {
11175            $sec2level{$sec} = $level + 1;
11176        }
11177        $state->{'sectionning_base'}--;
11178    }
11179    elsif ($macro eq 'raisesections')
11180    {
11181        my ($sec, $level);
11182        while (($sec, $level) = each %sec2level)
11183        {
11184            $sec2level{$sec} = $level - 1;
11185        }
11186        $state->{'sectionning_base'}++;
11187    }
11188    elsif (($macro eq 'contents') or ($macro eq 'summarycontents') or ($macro eq 'shortcontents'))
11189    {
11190        if ($macro eq 'contents')
11191        {
11192             $Texi2HTML::Config::DO_CONTENTS = 1;
11193        }
11194        else
11195        {
11196             $macro = 'shortcontents';
11197             $Texi2HTML::Config::DO_SCONTENTS = 1;
11198        }
11199        push @{$state->{'place'}}, $content_element{$macro};
11200    }
11201    elsif ($macro eq 'detailmenu')
11202    {
11203        $state->{'detailmenu'}++;
11204    }
11205    elsif ($macro eq 'novalidate')
11206    {
11207        $novalidate = 1;
11208        $Texi2HTML::THISDOC{$macro} = 1;
11209    }
11210    elsif (grep {$_ eq $macro} ('settitle','setfilename','shortitle','shorttitlepage')
11211             and ($line =~ /^\s+(.*)$/))
11212    {
11213        $value{"_$macro"} = substitute_texi_line($1);
11214    }
11215    elsif (grep {$_ eq $macro} ('author','subtitle','title')
11216             and ($line =~ /^\s+(.*)$/))
11217    {
11218        $value{"_$macro"} .= substitute_texi_line($1)."\n";
11219        push @{$Texi2HTML::THISDOC{"${macro}s"}}, substitute_texi_line($1);
11220    }
11221    elsif ($macro eq 'synindex' || $macro eq 'syncodeindex')
11222    {
11223        if ($line =~ /^\s+(\w+)\s+(\w+)/)
11224        {
11225            my $index_from = $1;
11226            my $index_to = $2;
11227            echo_error ("unknown from index name $index_from in \@$macro", $line_nr)
11228                unless $index_names{$index_from};
11229            echo_error ("unknown to index name $index_to in \@$macro", $line_nr)
11230                unless $index_names{$index_to};
11231            if ($index_names{$index_from} and $index_names{$index_to})
11232            {
11233                if ($macro eq 'syncodeindex')
11234                {
11235                    $index_names{$index_to}->{'associated_indices_code'}->{$index_from} = 1;
11236                }
11237                else
11238                {
11239                    $index_names{$index_to}->{'associated_indices'}->{$index_from} = 1;
11240                }
11241                push @{$Texi2HTML::THISDOC{$macro}}, [$index_from,$index_to];
11242            }
11243        }
11244        else
11245        {
11246            echo_error ("Bad $macro line: $line", $line_nr);
11247        }
11248    }
11249    elsif ($macro eq 'defindex' || $macro eq 'defcodeindex')
11250    {
11251        if ($line =~ /^\s+(\w+)\s*$/)
11252        {
11253            my $name = $1;
11254            if ($forbidden_index_name{$name})
11255            {
11256                echo_error("Reserved index name $name", $line_nr);
11257            }
11258            else
11259            {
11260                @{$index_names{$name}->{'prefix'}} = ($name);
11261                $index_names{$name}->{'code'} = 1 if $macro eq 'defcodeindex';
11262                $index_prefix_to_name{$name} = $name;
11263                push @{$Texi2HTML::THISDOC{$macro}}, $name;
11264            }
11265        }
11266        else
11267        {# makeinfo don't warn and even accepts index with empty name
11268         # and index with numbers only. I reported it on the mailing list
11269         # this should be fixed in future makeinfo versions.
11270            echo_error ("Bad $macro line: $line", $line_nr);
11271        }
11272    }
11273    elsif ($macro eq 'documentlanguage')
11274    {
11275        if ($line =~ /\s+(\w+)/)
11276        {
11277            my $lang = $1;
11278            set_document_language($lang, 0, $line_nr) if (!$cmd_line_lang && $lang);
11279            # warning, this is not the language of the document but the one that
11280            # appear in the texinfo...
11281            $Texi2HTML::THISDOC{$macro} = $lang;
11282        }
11283    }
11284    elsif ($macro eq 'kbdinputstyle')
11285    {# makeinfo ignores that with --html. I reported it and it should be
11286     # fixed in future makeinfo releases
11287        if ($line =~ /\s+([a-z]+)/)
11288        {
11289            if ($1 eq 'code')
11290            {
11291                $::style_map_ref->{'kbd'} = $::style_map_ref->{'code'};
11292                $::style_map_pre_ref->{'kbd'} = $::style_map_pre_ref->{'code'};
11293                $Texi2HTML::THISDOC{$macro} = $1;
11294            }
11295            elsif ($1 eq 'example')
11296            {
11297                $::style_map_pre_ref->{'kbd'} = $::style_map_pre_ref->{'code'};
11298                $Texi2HTML::THISDOC{$macro} = $1;
11299            }
11300            elsif ($1 ne 'distinct')
11301            {
11302                echo_error ("Unknown argument for \@$macro: $1", $line_nr);
11303            }
11304        }
11305        else
11306        {
11307            echo_error ("Bad \@$macro", $line_nr);
11308        }
11309    }
11310    elsif ($macro eq 'paragraphindent')
11311    {
11312        if ($line =~ /\s+([0-9]+)/)
11313        {
11314            $Texi2HTML::THISDOC{$macro} = $1;
11315        }
11316        elsif (($line =~ /\s+(none)[^\w\-]/) or ($line =~ /\s+(asis)[^\w\-]/))
11317        {
11318            $Texi2HTML::THISDOC{$macro} = $1;
11319        }
11320        else
11321        {
11322            echo_error ("Bad \@$macro", $line_nr);
11323        }
11324    }
11325    elsif ($macro eq 'firstparagraphindent')
11326    {
11327        if (($line =~ /\s+(none)[^\w\-]/) or ($line =~ /\s+(insert)[^\w\-]/))
11328        {
11329            $Texi2HTML::THISDOC{$macro} = $1;
11330        }
11331        else
11332        {
11333            echo_error ("Bad \@$macro", $line_nr);
11334        }
11335    }
11336    elsif ($macro eq 'exampleindent')
11337    {
11338        if ($line =~ /^\s+([0-9]+)/)
11339        {
11340            $Texi2HTML::THISDOC{$macro} = $1;
11341        }
11342        elsif ($line =~ /^\s+(asis)[^\w\-]/)
11343        {
11344            $Texi2HTML::THISDOC{$macro} = $1;
11345        }
11346        else
11347        {
11348            echo_error ("Bad \@$macro", $line_nr);
11349        }
11350    }
11351    elsif ($macro eq 'frenchspacing')
11352    {
11353        if (($line =~ /^\s+(on)[^\w\-]/) or ($line =~ /^\s+(off)[^\w\-]/))
11354        {
11355            $Texi2HTML::THISDOC{$macro} = $1;
11356        }
11357        else
11358        {
11359            echo_error ("Bad \@$macro", $line_nr);
11360        }
11361    }
11362    elsif ($macro eq 'footnotestyle')
11363    {
11364        if (($line =~ /^\s+(end)[^\w\-]/) or ($line =~ /^\s+(separate)[^\w\-]/))
11365        {
11366            $Texi2HTML::THISDOC{$macro} = $1;
11367        }
11368        else
11369        {
11370            echo_error ("Bad \@$macro", $line_nr);
11371        }
11372    }
11373    elsif ($macro eq 'headings')
11374    {
11375        my $valid_arg = 0;
11376        foreach my $possible_arg (('off','on','single','double',
11377                      'singleafter','doubleafter'))
11378        {
11379            if ($line =~ /^\s+($possible_arg)[^\w\-]/)
11380            {
11381                $valid_arg = 1;
11382                $Texi2HTML::THISDOC{$macro} = $possible_arg;
11383                last;
11384            }
11385        }
11386        unless ($valid_arg)
11387        {
11388            echo_error ("Bad \@$macro", $line_nr);
11389        }
11390    }
11391    elsif ($macro eq 'setchapternewpage')
11392    {
11393        if (($line =~ /^\s+(on)[^\w\-]/) or ($line =~ /^\s+(off)[^\w\-]/)
11394                or ($line =~ /^\s+(odd)[^\w\-]/))
11395        {
11396            $Texi2HTML::THISDOC{$macro} = $1;
11397        }
11398        else
11399        {
11400            echo_error ("Bad \@$macro", $line_nr);
11401        }
11402    }
11403    elsif ($macro eq 'setcontentsaftertitlepage' or $macro eq 'setshortcontentsaftertitlepage')
11404    {
11405        $Texi2HTML::THISDOC{$macro} = 1;
11406        my $tag = 'contents';
11407        $tag = 'shortcontents' if ($macro ne 'setcontentsaftertitlepage');
11408        $content_element{$tag}->{'aftertitlepage'} = 1;
11409    }
11410    elsif (grep {$macro eq $_} ('everyheading', 'everyfooting',
11411          'evenheading', 'evenfooting', 'oddheading', 'oddfooting'))
11412    {
11413        my $arg = $line;
11414        $arg =~ s/^\s+//;
11415        $Texi2HTML::THISDOC{$macro} = $arg;
11416    }
11417    elsif ($macro eq 'need')
11418    {
11419        unless (($line =~ /^\s+([0-9]+(\.[0-9]*)?)[^\w\-]/) or
11420                 ($line =~ /^\s+(\.[0-9]+)[^\w\-]/))
11421        {
11422            echo_warn ("Bad \@$macro", $line_nr);
11423        }
11424    }
11425
11426    ($text, $line, $args) = preserve_command($line, $macro);
11427    return ($text, $line);
11428}
11429
11430# return the line after removing things according to misc_command map.
11431# if the skipped macro has an effect it is done here
11432# this is used during pass_text
11433sub misc_command_text($$$$$$)
11434{
11435    my $line = shift;
11436    my $macro = shift;
11437    my $stack = shift;
11438    my $state = shift;
11439    my $text = shift;
11440    my $line_nr = shift;
11441    my ($skipped, $remaining, $args);
11442    # if it is true the command args are kept so the user can modify how
11443    # they are skipped and handle them as unknown @-commands
11444    my $keep = $Texi2HTML::Config::misc_command{$macro}->{'keep'};
11445
11446    if ($macro eq 'detailmenu')
11447    {
11448        $state->{'detailmenu'}++;
11449    }
11450    elsif ($macro eq 'sp')
11451    {
11452        my $sp_number;
11453        if ($line =~ /^\s+(\d+)\s/)
11454        {
11455            $sp_number = $1;
11456        }
11457        elsif ($line =~ /(\s*)$/)
11458        {
11459            $sp_number = '';
11460        }
11461        else
11462        {
11463            echo_error ("\@$macro needs a numeric arg or no arg", $line_nr);
11464        }
11465        $sp_number = 1 if ($sp_number eq '');
11466        if (!$state->{'remove_texi'})
11467        {
11468            add_prev($text, $stack, &$Texi2HTML::Config::sp($sp_number, $state->{'preformatted'}));
11469        }
11470    }
11471    elsif($macro eq 'verbatiminclude' and !$keep)
11472    {
11473        if ($line =~ /\s+(.+)/)
11474        {
11475            my $arg = $1;
11476            my $file = locate_include_file($arg);
11477            if (defined($file))
11478            {
11479                if (!open(VERBINCLUDE, $file))
11480                {
11481                    echo_warn ("Can't read file $file: $!",$line_nr);
11482                }
11483                else
11484                {
11485                    my $verb_text = '';
11486                    while (my $line = <VERBINCLUDE>)
11487                    {
11488                        $verb_text .= $line;
11489                    }
11490
11491                    if ($state->{'remove_texi'})
11492                    {
11493                        add_prev ($text, $stack, &$Texi2HTML::Config::raw_no_texi('verbatim', $verb_text));
11494                    }
11495                    else
11496                    {
11497                        add_prev($text, $stack, &$Texi2HTML::Config::raw('verbatim', $verb_text));
11498                    }
11499                    close VERBINCLUDE;
11500                }
11501            }
11502            else
11503            {
11504                echo_error ("Can't find $arg, skipping", $line_nr);
11505            }
11506        }
11507        else
11508        {
11509            echo_error ("Bad \@$macro line: $_", $line_nr);
11510        }
11511    }
11512    elsif ($macro eq 'indent' or $macro eq 'noindent')
11513    {
11514        $state->{'paragraph_indent'} = $macro;
11515    }
11516    ($remaining, $skipped, $args) = preserve_command($line, $macro);
11517    return ($skipped) if ($keep);
11518    return $remaining if ($remaining ne '');
11519    return undef;
11520}
11521
11522# merge the things appearing before the first @node or sectionning command
11523# (held by element_before_anything) with the current element
11524# do that only once.
11525sub merge_element_before_anything($)
11526{
11527    my $element = shift;
11528    if (exists($element_before_anything->{'place'}))
11529    {
11530        $element->{'current_place'} = $element_before_anything->{'place'};
11531        delete $element_before_anything->{'place'};
11532        foreach my $placed_thing (@{$element->{'current_place'}})
11533        {
11534            $placed_thing->{'element'} = $element if (exists($placed_thing->{'element'}));
11535        }
11536    }
11537    # this is certainly redundant with the above condition, but cleaner
11538    # that way
11539    if (exists($element_before_anything->{'titlefont'}))
11540    {
11541        $element->{'titlefont'} = $element_before_anything->{'titlefont'};
11542        delete $element_before_anything->{'titlefont'};
11543    }
11544}
11545
11546# find menu_prev, menu_up... for a node in menu
11547sub menu_entry_texi($$$)
11548{
11549    my $node = shift;
11550    my $state = shift;
11551    my $line_nr = shift;
11552    my $node_menu_ref = {};
11553    if (exists($nodes{$node}))
11554    {
11555        $node_menu_ref = $nodes{$node};
11556    }
11557    else
11558    {
11559        $nodes{$node} = $node_menu_ref;
11560        $node_menu_ref->{'texi'} = $node;
11561        $node_menu_ref->{'external_node'} = 1 if ($node =~ /\(.+\)/);
11562    }
11563    return if ($state->{'detailmenu'});
11564    if ($state->{'node_ref'})
11565    {
11566        $node_menu_ref->{'menu_up'} = $state->{'node_ref'};
11567        $node_menu_ref->{'menu_up_hash'}->{$state->{'node_ref'}->{'texi'}} = 1;
11568    }
11569    else
11570    {
11571        echo_warn ("menu entry without previous node: $node", $line_nr) unless ($node =~ /\(.+\)/);
11572    }
11573    if ($state->{'prev_menu_node'})
11574    {
11575        $node_menu_ref->{'menu_prev'} = $state->{'prev_menu_node'};
11576        $state->{'prev_menu_node'}->{'menu_next'} = $node_menu_ref;
11577    }
11578    elsif ($state->{'node_ref'})
11579    {
11580        $state->{'node_ref'}->{'menu_child'} = $node_menu_ref;
11581    }
11582    $state->{'prev_menu_node'} = $node_menu_ref;
11583}
11584
11585sub equivalent_nodes($)
11586{
11587    my $name = shift;
11588#print STDERR "equivalent_nodes $name\n";
11589    my $node = normalise_node($name);
11590    $name = cross_manual_line($node);
11591    my @equivalent_nodes = ();
11592    if (exists($cross_reference_nodes{$name}))
11593    {
11594        @equivalent_nodes = grep {$_ ne $node} @{$cross_reference_nodes{$name}};
11595    }
11596    return @equivalent_nodes;
11597}
11598
11599my %files = ();   # keys are files. This is used to avoid reusing an allready
11600                  # used file name
11601my %empty_indices = (); # value is true for an index name key if the index
11602                        # is empty
11603my %printed_indices = (); # value is true for an index name not empty and
11604                          # printed
11605
11606# find next, prev, up, back, forward, fastback, fastforward
11607# find element id and file
11608# split index pages
11609# associate placed items (items which have links to them) with the right
11610# file and id
11611# associate nodes with sections
11612sub rearrange_elements()
11613{
11614    print STDERR "# find sections levels and toplevel\n"
11615        if ($T2H_DEBUG & $DEBUG_ELEMENTS);
11616
11617    my $toplevel = 4;
11618    # correct level if raisesections or lowersections overflowed
11619    # and find toplevel level
11620    # use %sections to modify also the headings
11621    foreach my $section (values(%sections))
11622    {
11623        my $level = $section->{'level'};
11624        if ($level > $MAX_LEVEL)
11625        {
11626             $section->{'level'} = $MAX_LEVEL;
11627        }
11628        elsif ($level < $MIN_LEVEL and !$section->{'top'})
11629        {
11630             $section->{'level'} = $MIN_LEVEL;
11631        }
11632        else
11633        {
11634             $section->{'level'} = $level;
11635        }
11636        $section->{'toc_level'} = $section->{'level'};
11637        # This is for top
11638        $section->{'toc_level'} = $MIN_LEVEL if ($section->{'level'} < $MIN_LEVEL);
11639        # find the new tag corresponding with the level of the section
11640        if ($section->{'tag'} !~ /heading/ and ($level ne $reference_sec2level{$section->{'tag'}}))
11641        {
11642             $section->{'tag_level'} = $level2sec{$section->{'tag'}}->[$section->{'level'}];
11643        }
11644        else
11645        {
11646             $section->{'tag_level'} = $section->{'tag'};
11647        }
11648        $toplevel = $section->{'level'} if (($section->{'level'} < $toplevel) and ($section->{'level'} > 0 and ($section->{'tag'} !~ /heading/)));
11649        print STDERR "# section level $level: $section->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
11650    }
11651
11652    print STDERR "# find sections structure, construct section numbers (toplevel=$toplevel)\n"
11653        if ($T2H_DEBUG & $DEBUG_ELEMENTS);
11654    my $in_appendix = 0;
11655    # these arrays have an element per sectionning level.
11656    my @previous_numbers = ();   # holds the number of the previous sections
11657                                 # at the same and upper levels
11658    my @previous_sections = ();  # holds the ref of the previous sections
11659
11660    foreach my $section (@sections_list)
11661    {
11662        ########################### debug
11663        print STDERR "BUG: node or section_ref defined for section $section->{'texi'}\n"
11664            if (exists($section->{'node'}) or exists($section->{'section_ref'}));
11665        ########################### end debug
11666        next if ($section->{'top'});
11667        print STDERR "Bug level undef for ($section) $section->{'texi'}\n" if (!defined($section->{'level'}));
11668        $section->{'toplevel'} = 1 if ($section->{'level'} == $toplevel);
11669        # undef things under that section level
11670        for (my $level = $section->{'level'} + 1; $level < $MAX_LEVEL + 1 ; $level++)
11671        {
11672            $previous_numbers[$level] = undef;
11673            $previous_sections[$level] = undef;
11674        }
11675        my $number_set;
11676        # find number at the current level
11677        if ($section->{'tag'} =~ /appendix/ and !$in_appendix)
11678        {
11679            $previous_numbers[$toplevel] = 'A';
11680            $in_appendix = 1;
11681            $number_set = 1 if ($section->{'level'} == $toplevel);
11682        }
11683        if (!defined($previous_numbers[$section->{'level'}]) and !$number_set)
11684        {
11685            if ($section->{'tag'} =~ /unnumbered/)
11686            {
11687                 $previous_numbers[$section->{'level'}] = undef;
11688            }
11689            else
11690            {
11691                $previous_numbers[$section->{'level'}] = 1;
11692            }
11693        }
11694        elsif ($section->{'tag'} !~ /unnumbered/ and !$number_set)
11695        {
11696            $previous_numbers[$section->{'level'}]++;
11697        }
11698        # construct the section number
11699        $section->{'number'} = '';
11700
11701        unless ($section->{'tag'} =~ /unnumbered/)
11702        {
11703            my $level = $section->{'level'};
11704            while ($level > $toplevel)
11705            {
11706                my $number = $previous_numbers[$level];
11707                $number = 0 if (!defined($number));
11708                if ($section->{'number'})
11709                {
11710                    $section->{'number'} = "$number.$section->{'number'}";
11711                }
11712                else
11713                {
11714                    $section->{'number'} = $number;
11715                }
11716                $level--;
11717            }
11718            my $toplevel_number = $previous_numbers[$toplevel];
11719            $toplevel_number = 0 if (!defined($toplevel_number));
11720            $section->{'number'} = "$toplevel_number.$section->{'number'}";
11721        }
11722        # find the previous section
11723        if (defined($previous_sections[$section->{'level'}]))
11724        {
11725            my $prev_section = $previous_sections[$section->{'level'}];
11726            $section->{'sectionprev'} = $prev_section;
11727            $prev_section->{'sectionnext'} = $section;
11728        }
11729        # find the up section
11730        if ($section->{'level'} == $toplevel)
11731        {
11732            $section->{'sectionup'} = undef;
11733        }
11734        else
11735        {
11736            my $level = $section->{'level'} - 1;
11737            while (!defined($previous_sections[$level]) and ($level >= 0))
11738            {
11739                 $level--;
11740            }
11741            if ($level >= 0)
11742            {
11743                $section->{'sectionup'} = $previous_sections[$level];
11744                # 'child' is the first child
11745                $section->{'sectionup'}->{'child'} = $section unless ($section->{'sectionprev'});
11746                push @{$section->{'sectionup'}->{'section_childs'}}, $section;
11747            }
11748            else
11749            {
11750                 $section->{'sectionup'} = undef;
11751            }
11752        }
11753        $previous_sections[$section->{'level'}] = $section;
11754        # This is what is used in the .init file.
11755        $section->{'up'} = $section->{'sectionup'};
11756        # Not used but documented.
11757        $section->{'next'} = $section->{'sectionnext'};
11758        $section->{'prev'} = $section->{'sectionprev'};
11759
11760        ############################# debug
11761        my $up = "NO_UP";
11762        $up = $section->{'sectionup'} if (defined($section->{'sectionup'}));
11763        print STDERR "# numbering section ($section->{'level'}): $section->{'number'}: (up: $up) $section->{'texi'}\n"
11764            if ($T2H_DEBUG & $DEBUG_ELEMENTS);
11765        ############################# end debug
11766    }
11767
11768    # at that point there are still some node structures that are not
11769    # in %nodes, (the external nodes, and unknown nodes in case
11770    # novalidate is true) so we cannot find the id. The consequence is that
11771    # some node equivalent with another node may not be catched during
11772    # that pass. We mark the nodes that have directions for unreferenced
11773    # nodes and make a second pass for these nodes afterwards.
11774    my @nodes_with_unknown_directions = ();
11775
11776    my @node_directions = ('node_prev', 'node_next', 'node_up');
11777    # handle nodes
11778    # the node_prev... are texinfo strings, find the associated node references
11779    print STDERR "# Resolve nodes directions\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
11780    foreach my $node (@nodes_list)
11781    {
11782        foreach my $direction (@node_directions)
11783        {
11784            if (defined($node->{$direction}) and !ref($node->{$direction})
11785                and ($node->{$direction} ne ''))
11786            {
11787                if ($nodes{$node->{$direction}} and $nodes{$node->{$direction}}->{'seen'})
11788                {
11789                     $node->{$direction} = $nodes{$node->{$direction}};
11790                }
11791                elsif (($node->{$direction} =~ /^\(.*\)/) or $novalidate)
11792                { # ref to an external node
11793                    if (exists($nodes{$node->{$direction}}))
11794                    {
11795                        $node->{$direction} = $nodes{$node->{$direction}};
11796                    }
11797                    else
11798                    {
11799                        # FIXME if {'seen'} this is a node appearing in the
11800                        # document and a node like `(file)node'. What to
11801                        # do then ?
11802                        my $node_ref = { 'texi' => $node->{$direction} };
11803                        $node_ref->{'external_node'} = 1 if ($node->{$direction} =~ /^\(.*\)/);
11804                        $nodes{$node->{$direction}} = $node_ref;
11805                        $node->{$direction} = $node_ref;
11806                    }
11807                }
11808                else
11809                {
11810                     push @nodes_with_unknown_directions, $node;
11811                }
11812            }
11813        }
11814    }
11815
11816    # Find cross manual links as explained on the texinfo mailing list
11817    # The  specification is such that cross manual links formatting should
11818    # be insensitive to the manual split
11819    cross_manual_links();
11820
11821    # Now it is possible to find the unknown directions that are equivalent
11822    # (have same node id) than an existing node
11823    foreach my $node (@nodes_with_unknown_directions)
11824    {
11825        foreach my $direction (@node_directions)
11826        {
11827            if (defined($node->{$direction}) and !ref($node->{$direction})
11828                and ($node->{$direction} ne ''))
11829            {
11830                echo_warn ("$direction `$node->{$direction}' for `$node->{'texi'}' not found");
11831                my @equivalent_nodes = equivalent_nodes($node->{$direction});
11832                my $node_seen;
11833                foreach my $equivalent_node (@equivalent_nodes)
11834                {
11835                    if ($nodes{$equivalent_node}->{'seen'})
11836                    {
11837                        $node_seen = $equivalent_node;
11838                        last;
11839                    }
11840                }
11841                if (defined($node_seen))
11842                {
11843                    echo_warn (" ---> but equivalent node `$node_seen' found");
11844                    $node->{$direction} = $nodes{$node_seen};
11845                }
11846                else
11847                {
11848                    delete $node->{$direction};
11849                }
11850            }
11851        }
11852    }
11853
11854    # find section preceding and following top
11855    my $section_before_top;   # section preceding the top node
11856    my $section_after_top;       # section following the top node
11857    if ($node_top)
11858    {
11859        my $previous_is_top = 0;
11860        foreach my $element (@all_elements)
11861        {
11862            if ($element eq $node_top)
11863            {
11864                $previous_is_top = 1;
11865                next;
11866            }
11867            if ($previous_is_top)
11868            {
11869                if ($element->{'section'})
11870                {
11871                    $section_after_top = $element;
11872                    last;
11873                }
11874                next;
11875            }
11876            $section_before_top = $element if ($element->{'section'});
11877        }
11878    }
11879    print STDERR "# section before Top: $section_before_top->{'texi'}\n"
11880        if ($section_before_top and ($T2H_DEBUG & $DEBUG_ELEMENTS));
11881    print STDERR "# section after Top: $section_after_top->{'texi'}\n"
11882         if ($section_after_top and ($T2H_DEBUG & $DEBUG_ELEMENTS));
11883
11884    print STDERR "# Build the elements list\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
11885    if (!$Texi2HTML::Config::USE_NODES)
11886    {
11887        #the only sectionning elements are sections
11888        @elements_list = @sections_list;
11889        # if there is no section we use nodes...
11890        if (!@elements_list)
11891        {
11892            print STDERR "# no section\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
11893            @elements_list = @all_elements;
11894        }
11895        elsif (!$section_top and $node_top and !$node_top->{'with_section'})
11896        { # special case for the top node if it isn't associated with
11897          # a section. The top node element is inserted between the
11898          # $section_before_top and the $section_after_top
11899            print STDERR "# Top not associated with a section\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
11900            $node_top->{'top_as_section'} = 1;
11901            $node_top->{'section_ref'} = $node_top;
11902            my @old_element_lists = @elements_list;
11903            @elements_list = ();
11904            while (@old_element_lists)
11905            {
11906                my $section = shift @old_element_lists;
11907                if ($section_before_top and ($section eq $section_before_top))
11908                {
11909                    push @elements_list, $section;
11910                    push @elements_list, $node_top;
11911                    last;
11912                }
11913                elsif ($section_after_top and ($section eq $section_after_top))
11914                {
11915                    push @elements_list, $node_top;
11916                    push @elements_list, $section;
11917                    last;
11918                }
11919                push @elements_list, $section;
11920            }
11921            push @elements_list, @old_element_lists;
11922        }
11923
11924        foreach my $element (@elements_list)
11925        {
11926            print STDERR "# new section element $element->{'texi'}\n"
11927                if ($T2H_DEBUG & $DEBUG_ELEMENTS);
11928        }
11929    }
11930    else
11931    {
11932        # elements are sections if possible, and node if no section associated
11933        foreach my $element(@all_elements)
11934        {
11935            if ($element->{'node'})
11936            {
11937                if (!defined($element->{'with_section'}))
11938                {
11939                    $element->{'toc_level'} = $MIN_LEVEL if (!defined($element->{'toc_level'}));
11940                    print STDERR "# new node element ($element) $element->{'texi'}\n"
11941                        if ($T2H_DEBUG & $DEBUG_ELEMENTS);
11942                    push @elements_list, $element;
11943                }
11944            }
11945            else
11946            {
11947                print STDERR "# new section element ($element) $element->{'texi'}\n"
11948                    if ($T2H_DEBUG & $DEBUG_ELEMENTS);
11949                push @elements_list, $element;
11950            }
11951        }
11952    }
11953
11954    # nodes are attached to the section preceding them if not allready
11955    # associated with a section
11956    # here we don't set @{$element->{'nodes'}} since it may be changed
11957    # below if split by indices. Therefore we only set
11958    # @{$element->{'all_elements'}} with all the elements associated
11959    # with an element output, in the right order
11960    print STDERR "# Find the section associated with each node\n"
11961        if ($T2H_DEBUG & $DEBUG_ELEMENTS);
11962    my $current_section = $sections_list[0];
11963    $current_section = $node_top if ($node_top and $node_top->{'top_as_section'} and !$section_before_top);
11964    foreach my $element (@all_elements)
11965    {
11966        if ($element->{'node'} and !$element->{'top_as_section'})
11967        {
11968            if ($element->{'with_section'})
11969            { # the node is associated with a section
11970                $element->{'section_ref'} = $element->{'with_section'};
11971                push @{$element->{'section_ref'}->{'all_elements'}}, $element, $element->{'section_ref'};
11972                # first index is section if the first index is associated with that node
11973                $element_index = $element->{'section_ref'} if ($element_index and ($element_index eq $element));
11974            }
11975            elsif (defined($current_section))
11976            {# node appearing after a section, but not before another section,
11977             # or appearing before any section
11978                $element->{'section_ref'} = $current_section;
11979                $element->{'toc_level'} = $current_section->{'toc_level'};
11980                push @{$current_section->{'node_childs'}}, $element;
11981                if ($Texi2HTML::Config::USE_NODES)
11982                { # the node is an element itself
11983                    push @{$element->{'all_elements'}}, $element;
11984                }
11985                else
11986                {
11987                    push @{$current_section->{'all_elements'}}, $element;
11988                    # first index is section if the first index is associated with that node
11989                    $element_index = $current_section if ($element_index and ($element_index eq $element));
11990                }
11991            }
11992            else
11993            { # seems like there are only nodes in the documents
11994                $element->{'toc_level'} = $MIN_LEVEL;
11995                push @{$element->{'all_elements'}}, $element;
11996            }
11997        }
11998        else
11999        {
12000            $current_section = $element;
12001            if ($element->{'node'})
12002            { # Top node not associated with a section
12003                $element->{'toc_level'} = $MIN_LEVEL;
12004                push @{$element->{'section_ref'}->{'all_elements'}}, $element;
12005            }
12006            elsif (!$element->{'node_ref'})
12007            { # a section not preceded by a node
12008                push @{$element->{'all_elements'}}, $element;
12009            }
12010        }
12011    }
12012
12013    # find first, last and top elements
12014    $element_first = $elements_list[0];
12015    print STDERR "# element first: $element_first->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
12016    print STDERR "# top node: $node_top->{'texi'}\n" if (defined($node_top) and
12017        ($T2H_DEBUG & $DEBUG_ELEMENTS));
12018    # element top is the element with @top.
12019    $element_top = $section_top;
12020    # If the top node is associated with a section it is the top_element
12021    # otherwise element top may be the top node
12022    $element_top = $node_top if (!defined($element_top) and defined($node_top));
12023    # If there is no @top section no top node the first node is the top element
12024    $element_top = $element_first unless (defined($element_top));
12025    $element_top->{'top'} = 1 if ($element_top->{'node'});
12026    print STDERR "# element top: $element_top->{'texi'}\n" if ($element_top and
12027        ($T2H_DEBUG & $DEBUG_ELEMENTS));
12028
12029    # It is the last element before indices split, which may add new
12030    # elements
12031    $element_last = $elements_list[-1];
12032
12033    print STDERR "# Complete nodes next prev and up based on menus and sections\n"
12034        if ($T2H_DEBUG & $DEBUG_ELEMENTS);
12035    # set the default id based on the node number
12036    my $node_nr = 1;
12037    # find the node* directions
12038    # find the directions corresponding with sections
12039    # and set 'up' for the node
12040    foreach my $node (@nodes_list)
12041    {
12042        # first a warning if the node and the equivalent nodes don't
12043        # appear in menus
12044        if (!$node->{'first'} and !$node->{'top'} and !$node->{'menu_up'} and ($node->{'texi'} !~ /^top$/i) and $Texi2HTML::Config::SHOW_MENU)
12045        {
12046            my @equivalent_nodes = equivalent_nodes($node->{'texi'});
12047            my $found = 0;
12048            foreach my $equivalent_node (@equivalent_nodes)
12049            {
12050                if ($nodes{$equivalent_node}->{'first'} or $nodes{$equivalent_node}->{'menu_up'})
12051                {
12052                   $found = 1;
12053                   last;
12054                }
12055            }
12056            unless ($found)
12057            {
12058                warn "$WARN `$node->{'texi'}' doesn't appear in menus\n";
12059            }
12060        }
12061
12062        # use values deduced from menus to complete missing up, next, prev
12063        # or from sectionning commands if automatic sectionning
12064        if ($node->{'node_up'})
12065        {
12066            $node->{'nodeup'} = $node->{'node_up'};
12067        }
12068        elsif ($node->{'automatic_directions'} and $node->{'section_ref'})
12069        {
12070            if (defined($node_top) and ($node eq $node_top))
12071            { # Top node has a special up, which is (dir) by default
12072                my $top_nodeup = $Texi2HTML::Config::TOP_NODE_UP;
12073                if (exists($nodes{$top_nodeup}))
12074                {
12075                    $node->{'nodeup'} = $nodes{$top_nodeup};
12076                }
12077                else
12078                {
12079                    my $node_ref = { 'texi' => $top_nodeup };
12080                    $node_ref->{'external_node'} = 1;
12081                    $nodes{$top_nodeup} = $node_ref;
12082                    $node->{'nodeup'} = $node_ref;
12083                }
12084            }
12085            elsif (defined($node->{'section_ref'}->{'sectionup'}))
12086            {
12087                $node->{'nodeup'} = get_node($node->{'section_ref'}->{'sectionup'});
12088            }
12089            elsif ($node->{'section_ref'}->{'toplevel'} and ($node->{'section_ref'} ne $element_top))
12090            {
12091                $node->{'nodeup'} = get_node($element_top);
12092            }
12093            print STDERR "# Deducing from section node_up $node->{'nodeup'}->{'texi'} for $node->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS and defined($node->{'nodeup'}));
12094        }
12095
12096        if (!$node->{'nodeup'} and $node->{'menu_up'} and $Texi2HTML::Config::USE_MENU_DIRECTIONS)
12097        { # makeinfo don't do that
12098            $node->{'nodeup'} = $node->{'menu_up'};
12099            print STDERR "# Deducing from menu node_up $node->{'menu_up'}->{'texi'} for $node->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
12100        }
12101
12102        if ($node->{'nodeup'} and !$node->{'nodeup'}->{'external_node'})
12103        {
12104            # We detect when the up node has no menu entry for that node, as
12105            # there may be infinite loops when finding following node (see below)
12106            unless (defined($node->{'menu_up_hash'}) and ($node->{'menu_up_hash'}->{$node->{'nodeup'}->{'texi'}}))
12107            {
12108                print STDERR "$WARN `$node->{'nodeup'}->{'texi'}' is up for `$node->{'texi'}', but has no menu entry for this node\n" if ($Texi2HTML::Config::SHOW_MENU);
12109                push @{$node->{'up_not_in_menu'}}, $node->{'nodeup'}->{'texi'};
12110            }
12111        }
12112
12113        # Find next node
12114        if ($node->{'node_next'})
12115        {
12116            $node->{'nodenext'} = $node->{'node_next'};
12117        }
12118        elsif ($node->{'texi'} eq 'Top')
12119        { # special case as said in the texinfo manual
12120            $node->{'nodenext'} = $node->{'menu_child'} if ($node->{'menu_child'});
12121        }
12122        elsif ($node->{'automatic_directions'})
12123        {
12124            if (defined($node->{'section_ref'}))
12125            {
12126                my $next;
12127                my $section = $node->{'section_ref'};
12128                if (defined($section->{'sectionnext'}))
12129                {
12130                    $next = get_node($section->{'sectionnext'})
12131                }
12132                else
12133                {
12134                    while (defined($section->{'sectionup'}) and !defined($section->{'sectionnext'}))
12135                    {
12136                        $section = $section->{'sectionup'};
12137                    }
12138                    if (defined($section->{'sectionnext'}))
12139                    {
12140                        $next = get_node($section->{'sectionnext'});
12141                    }
12142                }
12143                $node->{'nodenext'} = $next;
12144            }
12145        }
12146        # next we try menus. makeinfo don't do that
12147        if (!defined($node->{'nodenext'}) and $node->{'menu_next'}
12148            and $Texi2HTML::Config::USE_MENU_DIRECTIONS)
12149        {
12150            $node->{'nodenext'} = $node->{'menu_next'};
12151        }
12152        # Find prev node
12153        if ($node->{'node_prev'})
12154        {
12155            $node->{'nodeprev'} = $node->{'node_prev'};
12156        }
12157        elsif ($node->{'automatic_directions'})
12158        {
12159            if (defined($node->{'section_ref'}))
12160            {
12161                my $section = $node->{'section_ref'};
12162                if (defined($section->{'sectionprev'}))
12163                {
12164                    $node->{'nodeprev'} = get_node($section->{'sectionprev'});
12165                }
12166                elsif (defined($section->{'sectionup'}))
12167                {
12168                    $node->{'nodeprev'} = get_node($section->{'sectionup'});
12169                }
12170            }
12171        }
12172        # next we try menus. makeinfo don't do that
12173        if (!defined($node->{'nodeprev'}) and $node->{'menu_prev'} and $Texi2HTML::Config::USE_MENU_DIRECTIONS)
12174        {
12175            $node->{'nodeprev'} = $node->{'menu_prev'};
12176        }
12177        # the prev node is the parent node
12178        elsif (!defined($node->{'nodeprev'}) and $node->{'menu_up'} and $Texi2HTML::Config::USE_MENU_DIRECTIONS)
12179        {
12180            $node->{'nodeprev'} = $node->{'menu_up'};
12181        }
12182
12183        # the following node is the node following in node reading order
12184        # it is thus first the child, else the next, else the next following
12185        # the up
12186        if ($node->{'menu_child'})
12187        {
12188            $node->{'following'} = $node->{'menu_child'};
12189        }
12190        elsif ($node->{'automatic_directions'} and defined($node->{'section_ref'}) and defined($node->{'section_ref'}->{'child'}))
12191        {
12192            $node->{'following'} = get_node($node->{'section_ref'}->{'child'});
12193        }
12194        elsif (defined($node->{'nodenext'}))
12195        {
12196            $node->{'following'} = $node->{'nodenext'};
12197        }
12198	else
12199        {
12200            my $up = $node->{'nodeup'};
12201            # in order to avoid infinite recursion in case the up node is the
12202            # node itself we use the up node as following when there isn't
12203            # a correct menu structure, here and also below.
12204            $node->{'following'} = $up if (defined($up) and grep {$_ eq $up->{'texi'}} @{$node->{'up_not_in_menu'}});
12205            while ((!defined($node->{'following'})) and (defined($up)))
12206            {
12207                if (($node_top) and ($up eq $node_top))
12208                { # if we are at Top, Top is following
12209                    $node->{'following'} = $node_top;
12210                    $up = undef;
12211                }
12212                if (defined($up->{'nodenext'}))
12213                {
12214                    $node->{'following'} = $up->{'nodenext'};
12215                }
12216                elsif (defined($up->{'nodeup'}))
12217                {
12218                    if (! grep { $_ eq $up->{'nodeup'}->{'texi'} } @{$node->{'up_not_in_menu'}})
12219                    {
12220                        $up = $up->{'nodeup'};
12221                    }
12222                    else
12223                    { # in that case we can go into a infinite loop
12224                        $node->{'following'} = $up->{'nodeup'};
12225                    }
12226                }
12227                else
12228                {
12229                    $up = undef;
12230                }
12231            }
12232        }
12233
12234        if (defined($node->{'section_ref'}))
12235        {
12236            my $section = $node->{'section_ref'};
12237            foreach my $direction ('sectionnext', 'sectionprev', 'sectionup')
12238            {
12239                $node->{$direction} = $section->{$direction}
12240                  if (defined($section->{$direction}));
12241            }
12242            # this is a node appearing within a section but not associated
12243            # with that section. We consider that it is below that section.
12244            $node->{'sectionup'} = $section
12245               if (grep {$node eq $_} @{$section->{'node_childs'}});
12246        }
12247        # 'up' is used in .init files. Maybe should go away.
12248        if (defined($node->{'sectionup'}))
12249        {
12250            $node->{'up'} = $node->{'sectionup'};
12251        }
12252        elsif (defined($node->{'nodeup'}) and
12253             (!$node_top or ($node ne $node_top)))
12254        {
12255            $node->{'up'} = $node->{'nodeup'};
12256        }
12257        # 'next' not used but documented.
12258        if (defined($node->{'sectionnext'}))
12259        {
12260            $node->{'next'} = $node->{'sectionnext'};
12261        }
12262        if (defined($node->{'sectionprev'}))
12263        {
12264            $node->{'prev'} = $node->{'sectionprev'};
12265        }
12266
12267        # default id for nodes. Should be overriden later.
12268        $node->{'id'} = 'NOD' . $node_nr;
12269        $node_nr++;
12270    }
12271
12272    print STDERR "# find forward and back\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
12273    my $prev;
12274    foreach my $element (@elements_list)
12275    {
12276        $element->{'element'} = 1;
12277        # complete the up for toplevel elements now that element_top is defined
12278        print STDERR "# fwd and back for $element->{'texi'}\n"
12279            if ($T2H_DEBUG & $DEBUG_ELEMENTS);
12280        # at that point no node may be toplevel, only sections.
12281        if ($element->{'toplevel'} and ($element ne $element_top))
12282        {
12283            $element->{'sectionup'} = $element_top;
12284            $element->{'up'} = $element_top;
12285        }
12286        if ($prev)
12287        {
12288            $element->{'back'} = $prev;
12289            $prev->{'forward'} = $element;
12290            $prev = $element;
12291        }
12292        else
12293        {
12294            $prev = $element;
12295        }
12296        # If the element is not a node, then all the node directions are copied
12297        # if there is an associated node
12298        if (defined($element->{'node_ref'}))
12299        {
12300            $element->{'nodenext'} = $element->{'node_ref'}->{'nodenext'};
12301            $element->{'nodeprev'} = $element->{'node_ref'}->{'nodeprev'};
12302            $element->{'menu_next'} = $element->{'node_ref'}->{'menu_next'};
12303            $element->{'menu_prev'} = $element->{'node_ref'}->{'menu_prev'};
12304            $element->{'menu_child'} = $element->{'node_ref'}->{'menu_child'};
12305            $element->{'menu_up'} = $element->{'node_ref'}->{'menu_up'};
12306            $element->{'nodeup'} = $element->{'node_ref'}->{'nodeup'};
12307            $element->{'following'} = $element->{'node_ref'}->{'following'};
12308        }
12309        elsif (! $element->{'node'})
12310        { # the section has no node associated. Find the node directions using
12311          # sections
12312            if (defined($element->{'sectionnext'}))
12313            {
12314                 $element->{'nodenext'} = get_node($element->{'sectionnext'});
12315            }
12316            if (defined($element->{'sectionprev'}))
12317            {
12318                 $element->{'nodeprev'} = get_node($element->{'sectionprev'});
12319            }
12320            if (defined($element->{'up'}))
12321            {
12322                 $element->{'nodeup'} = get_node($element->{'up'});
12323            }
12324            if ($element->{'child'})
12325            {
12326                $element->{'following'} = get_node($element->{'child'});
12327            }
12328            elsif ($element->{'sectionnext'})
12329            {
12330                $element->{'following'} = get_node($element->{'sectionnext'});
12331            }
12332            elsif ($element->{'up'})
12333            {
12334                my $up = $element;
12335                while ($up->{'up'} and !$element->{'following'})
12336                {
12337                    print STDERR "# Going up, searching next section from $up->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
12338                    $up = $up->{'up'};
12339                    if ($up->{'sectionnext'})
12340                    {
12341                        $element->{'following'} = get_node ($up->{'sectionnext'});
12342                    }
12343                    # avoid infinite loop if the top is up for itself
12344                    last if ($up->{'toplevel'} or $up->{'top'});
12345                }
12346            }
12347        }
12348    }
12349
12350    my @new_elements = ();
12351    print STDERR "# preparing indices\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
12352
12353    while(@elements_list)
12354    {
12355        my $element = shift @elements_list;
12356        # current_element is the last element which can hold text. It is
12357        # initialized to a fake element
12358        my $current_element = { 'holder' => 1, 'texi' => 'HOLDER',
12359            'place' => [], 'indices' => [] };
12360        # $back, $forward and $sectionnext are kept because $element
12361        # is in @{$element->{'all_elements'}}, so it is possible that
12362        # those directions get changed.
12363        # back is set to find back and forward
12364        my $back = $element->{'back'} if defined($element->{'back'});
12365        my $forward = $element->{'forward'};
12366        my $sectionnext = $element->{'sectionnext'};
12367        my $index_num = 0;
12368        my @waiting_elements = (); # elements (nodes) not used for sectionning
12369                                 # waiting to be associated with an element
12370        foreach my $checked_element(@{$element->{'all_elements'}})
12371        {
12372	    if ($checked_element->{'element'})
12373            { # this is the element, we must add it
12374                push @new_elements, $checked_element;
12375                if ($current_element->{'holder'})
12376                { # no previous element added
12377                    push @{$checked_element->{'place'}}, @{$current_element->{'place'}};
12378                    foreach my $index(@{$current_element->{'indices'}})
12379                    {
12380                        push @{$checked_element->{'indices'}}, [ { 'element' => $checked_element, 'page' => $index->[0]->{'page'}, 'name' => $index->[0]->{'name'} } ] ;
12381                    }
12382                }
12383                else
12384                {
12385                    $current_element->{'sectionnext'} = $checked_element;
12386                    $current_element->{'following'} = $checked_element;
12387                    $checked_element->{'sectionprev'} = $current_element;
12388                }
12389                $current_element = $checked_element;
12390                $checked_element->{'back'} = $back;
12391                $back->{'forward'} = $checked_element if (defined($back));
12392                $back = $checked_element;
12393                push @{$checked_element->{'nodes'}}, @waiting_elements;
12394                @waiting_elements = ();
12395            }
12396            elsif ($current_element->{'holder'})
12397            {
12398                push @waiting_elements, $checked_element;
12399            }
12400            else
12401            {
12402                push @{$current_element->{'nodes'}}, $checked_element;
12403                $checked_element->{'section_ref'} = $current_element;
12404            }
12405            push @{$current_element->{'place'}}, @{$checked_element->{'current_place'}};
12406            foreach my $index (@{$checked_element->{'index_names'}})
12407            {
12408                print STDERR "# Index in `$checked_element->{'texi'}': $index->{'name'}. Current is `$current_element->{'texi'}'\n"
12409                    if ($T2H_DEBUG & $DEBUG_INDEX);
12410                my ($pages, $entries) = get_index($index->{'name'});
12411                if (defined($pages))
12412                {
12413                    my @pages = @$pages;
12414                    my $first_page = shift @pages;
12415                    ############################## begin debug section
12416                    my $back_texi = 'NO_BACK';
12417                    $back_texi = $back->{'texi'} if (defined($back));
12418                    print STDERR "# Index first page (back `$back_texi', in  `$current_element->{'texi'}')\n" if ($T2H_DEBUG & $DEBUG_INDEX);
12419                    ############################## end debug section
12420                    push @{$current_element->{'indices'}}, [ {'element' => $current_element, 'page' => $first_page, 'name' => $index->{'name'} } ];
12421                    if (@pages)
12422                    {# index is split accross more than one page
12423                        if ($current_element->{'holder'})
12424                        { # the current element isn't an element which is
12425                          # normally outputted. We add a real element.
12426                          # we are in a node of a section but the element
12427                          # is split by the index, thus we must add
12428                          # a new element which will contain the text
12429                          # between the beginning of the element and the index
12430                          # WARNING the added element is like a section, and
12431                          # indeed it is a 'section_ref' and 'sectionup'
12432                          # for other nodes, it has 'nodes'
12433                          # (see below and above).
12434                          # But it is also a node. It may have a 'with_section'
12435                          # and have a 'section_ref'
12436                          # it may be considered 'node_ref' for a section.
12437                          # and the Texi2HTML::NODE is relative to this
12438                          # added element.
12439
12440                            push @new_elements, $checked_element;
12441                            print STDERR "# Add `$checked_element->{'texi'}' before index page for `$element->{'texi'}'\n"
12442                                if ($T2H_DEBUG & $DEBUG_INDEX);
12443                            echo_warn("Add `$checked_element->{'texi'}' for indicing");
12444                            $checked_element->{'element'} = 1;
12445                            $checked_element->{'level'} = $element->{'level'};
12446                            $checked_element->{'toc_level'} = $element->{'toc_level'};
12447                            $checked_element->{'toplevel'} = $element->{'toplevel'};
12448                            if ($element->{'top'})
12449                            {
12450                                $checked_element->{'toplevel'} = 1;
12451                                $checked_element->{'top'} = 1;
12452                            }
12453                            $checked_element->{'up'} = $element->{'up'};
12454                            $checked_element->{'sectionup'} = $element->{'sectionup'};
12455                            $checked_element->{'element_added'} = 1;
12456                            print STDERR "Bug: checked element wasn't seen" if
12457                                 (!$checked_element->{'seen'});
12458                            $element->{'sectionprev'}->{'sectionnext'} = $checked_element if (exists($element->{'sectionprev'}));
12459                            push @{$checked_element->{'place'}}, @{$current_element->{'place'}};
12460                            foreach my $index(@{$current_element->{'indices'}})
12461                            {
12462                                push @{$checked_element->{'indices'}}, [ { 'element' => $checked_element, 'page' => $index->[0]->{'page'}, 'name' => $index->[0]->{'name'} } ] ;
12463                            }
12464                            foreach my $waiting_element (@waiting_elements)
12465                            {
12466                                 next if ($waiting_element eq $checked_element);
12467                                 $waiting_element->{'section_ref'} = $checked_element;
12468                                 $waiting_element->{'sectionup'} = $checked_element;
12469                                 push @{$checked_element->{'nodes'}}, $waiting_element;
12470                            }
12471                            @waiting_elements = ();
12472                            $checked_element->{'back'} = $back;
12473                            $back->{'forward'} = $checked_element if (defined($back));
12474                            $current_element = $checked_element;
12475                            $back = $checked_element;
12476                        }
12477                        my $index_page;
12478                        while(@pages)
12479                        {
12480                            print STDERR "# New page (back `$back->{'texi'}', current `$current_element->{'texi'}')\n" if ($T2H_DEBUG & $DEBUG_INDEX);
12481                            $index_num++;
12482                            my $page = shift @pages;
12483                            $index_page = { 'index_page' => 1,
12484                             'texi' => "NOT REALLY USED: $current_element->{'texi'}' index $index->{'name'} page $index_num",
12485                             'level' => $element->{'level'},
12486                             'tag' => $element->{'tag'},
12487                             'tag_level' => $element->{'tag_level'},
12488                             'toplevel' => $element->{'toplevel'},
12489                             'top' => $element->{'top'},
12490                             'up' => $element->{'up'},
12491                             'sectionup' => $element->{'sectionup'},
12492                             'back' => $back,
12493                             'prev' => $back,
12494                             'sectionnext' => $sectionnext,
12495                             'following' => $current_element->{'following'},
12496                             'nodeup' => $current_element->{'nodeup'},
12497                             'nodenext' => $current_element->{'nodenext'},
12498                             'nodeprev' => $back,
12499                             'place' => [],
12500                             'seen' => 1,
12501                             'page' => $page
12502                            };
12503                            # the index page is associated with the new element
12504                            # if there is one, the element otherwise
12505                            if ($checked_element->{'element_added'})
12506                            {
12507                                $index_page->{'original_index_element'} = $checked_element;
12508                            }
12509                            else
12510                            {
12511                                $index_page->{'original_index_element'} = $element;
12512                            }
12513                            $index_page->{'node'} = 1 if ($element->{'node'});
12514                            while ($nodes{$index_page->{'texi'}})
12515                            {
12516                                $nodes{$index_page->{'texi'}} .= ' ';
12517                            }
12518                            $nodes{$index_page->{'texi'}} = $index_page;
12519                            push @{$current_element->{'indices'}->[-1]}, {'element' => $index_page, 'page' => $page, 'name' => $index->{'name'} };
12520                            push @new_elements, $index_page;
12521                            $back->{'forward'} = $index_page;
12522                            $back->{'nodenext'} = $index_page;
12523                            $back->{'sectionnext'} = $index_page unless ($back->{'top'});
12524                            $back->{'following'} = $index_page;
12525                            $back = $index_page;
12526                            $index_page->{'toplevel'} = 1 if ($element->{'top'});
12527                        }
12528                        $current_element = $index_page;
12529                    }
12530                }
12531                else
12532                {
12533                    print STDERR "# Empty index: $index->{'name'}\n"
12534                        if ($T2H_DEBUG & $DEBUG_INDEX);
12535                    $empty_indices{$index->{'name'}} = 1;
12536                }
12537                push @{$current_element->{'place'}}, @{$index->{'place'}};
12538            }
12539        }
12540        if ($forward and ($current_element ne $element))
12541        {
12542            $current_element->{'forward'} = $forward;
12543            $forward->{'back'} = $current_element;
12544        }
12545        next if ($current_element eq $element or !$element->{'toplevel'});
12546        # reparent the elements below $element to the last index page
12547        print STDERR "# Reparent for `$element->{'texi'}':\n" if ($T2H_DEBUG & $DEBUG_INDEX);
12548        foreach my $reparented(@{$element->{'section_childs'}},@{$element->{'node_childs'}})
12549        {
12550            $reparented->{'sectionup'} = $current_element;
12551	    print STDERR "   reparented: $reparented->{'texi'}\n"
12552                    if ($T2H_DEBUG & $DEBUG_INDEX);
12553        }
12554    }
12555    @elements_list = @new_elements;
12556
12557    print STDERR "# find fastback and fastforward\n"
12558       if ($T2H_DEBUG & $DEBUG_ELEMENTS);
12559    foreach my $element (@elements_list)
12560    {
12561        my $up = get_top($element);
12562        next unless (defined($up));
12563        $element_chapter_index = $up if ($element_index and ($element_index eq $element));
12564        # fastforward is the next element on same level than the upper parent
12565        # element
12566        $element->{'fastforward'} = $up->{'sectionnext'} if (exists ($up->{'sectionnext'}));
12567        # if the element isn't at the highest level, fastback is the
12568        # highest parent element
12569        if ($up and ($up ne $element))
12570        {
12571            $element->{'fastback'} = $up;
12572        }
12573        elsif ($element->{'toplevel'})
12574        {
12575            # the element is a top level element, we adjust the next
12576            # toplevel element fastback
12577            $element->{'fastforward'}->{'fastback'} = $element if ($element->{'fastforward'});
12578        }
12579    }
12580
12581    # set 'reference_element' which is used each time there is a cross ref
12582    # to that node.
12583    # It is the section associated with the node except if USE_NODES
12584    unless ($Texi2HTML::Config::USE_NODES)
12585    {
12586        foreach my $node(@nodes_list)
12587        {
12588            if ($node->{'with_section'})
12589            {
12590                $node->{'reference_element'} = $node->{'with_section'};
12591            }
12592        }
12593    }
12594
12595    my $index_nr = 0;
12596    # convert directions in direction with first letter in all caps, to be
12597    # consistent with the convention used in the .init file.
12598    # find id for nodes and indices
12599    foreach my $element (@elements_list)
12600    {
12601        $element->{'this'} = $element;
12602        foreach my $direction (@element_directions)
12603        {
12604            my $direction_no_caps = $direction;
12605            $direction_no_caps =~ tr/A-Z/a-z/;
12606            $element->{$direction} = $element->{$direction_no_caps};
12607        }
12608        if ($element->{'index_page'})
12609        {
12610            $element->{'id'} = "INDEX" . $index_nr;
12611            $index_nr++;
12612        }
12613    }
12614
12615    print STDERR "# find float id\n"
12616       if ($T2H_DEBUG & $DEBUG_ELEMENTS);
12617    foreach my $float (@floats)
12618    {
12619        $float->{'style_id'} = cross_manual_line(normalise_space($float->{'style_texi'}));
12620        my $float_style = { };
12621        if (exists($floats{$float->{'style_id'}}))
12622        {
12623            $float_style = $floats{$float->{'style_id'}};
12624        }
12625        else
12626        {
12627            $floats{$float->{'style_id'}} = $float_style;
12628        }
12629        push @{$float_style->{'floats'}}, $float;
12630        $float->{'absolute_nr'} = scalar(@{$float_style->{'floats'}});
12631        my $up = get_top($float->{'element'});
12632        if (defined($up) and (!defined($float_style->{'current_chapter'}) or ($up->{'texi'} ne $float_style->{'current_chapter'})))
12633        {
12634            $float_style->{'current_chapter'} = $up->{'texi'};
12635            $float_style->{'nr_in_chapter'} = 1;
12636        }
12637        else
12638        {
12639            $float_style->{'nr_in_chapter'}++;
12640        }
12641        if (defined($up) and $up->{'number'} ne '')
12642        {
12643            $float->{'chapter_nr'} = $up->{'number'};
12644            $float->{'nr'} = $float->{'chapter_nr'} . $float_style->{'nr_in_chapter'};
12645        }
12646        else
12647        {
12648            $float->{'nr'} = $float->{'absolute_nr'};
12649        }
12650    }
12651
12652    if ($Texi2HTML::Config::NEW_CROSSREF_STYLE)
12653    {
12654        foreach my $key (keys(%nodes))
12655        {
12656            my $node = $nodes{$key};
12657            next if ($node->{'external_node'} or $node->{'index_page'});
12658            $node->{'id'} = node_to_id($node->{'cross_manual_target'});
12659        }
12660    }
12661
12662    # Find node file names and file names for nodes considered as elements
12663    my $node_as_top;
12664    if ($node_top)
12665    {
12666        $node_as_top = $node_top;
12667    }
12668    elsif ($element_top->{'node_ref'})
12669    {
12670        $node_as_top = $element_top->{'node_ref'};
12671    }
12672    else
12673    {
12674        $node_as_top = $node_first;
12675    }
12676    if ($node_as_top)
12677    {
12678        my $node_file;
12679        $node_file = &$Texi2HTML::Config::node_file_name($node_as_top,'top');
12680        $node_as_top->{'node_file'} = $node_file if (defined($node_file));
12681    }
12682    foreach my $key (keys(%nodes))
12683    {
12684        my $node = $nodes{$key};
12685        next if (defined($node_as_top) and ($node eq $node_as_top));
12686        my $node_file = &$Texi2HTML::Config::node_file_name($node,'');
12687        $node->{'node_file'} = $node_file if (defined($node_file));
12688    }
12689
12690    print STDERR "# split and set files\n"
12691       if ($T2H_DEBUG & $DEBUG_ELEMENTS);
12692    # find document nr and document file for sections and nodes.
12693    # Split according to Texi2HTML::Config::SPLIT.
12694    # find file and id for placed elements (anchors, index entries, headings)
12695    if ($Texi2HTML::Config::SPLIT)
12696    {
12697        my $cut_section = $toplevel;
12698        my $doc_nr = -1;
12699        if ($Texi2HTML::Config::SPLIT eq 'section')
12700        {
12701            $cut_section = 2 if ($toplevel <= 2);
12702        }
12703        my $previous_file;
12704        foreach my $element (@elements_list)
12705        {
12706            print STDERR "# Splitting ($Texi2HTML::Config::SPLIT:$cut_section) $element->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
12707            my $new_file = 0;
12708            if (
12709               ($Texi2HTML::Config::SPLIT eq 'node') or
12710               (
12711                 defined($element->{'level'}) and ($element->{'level'} <= $cut_section)
12712               )
12713              )
12714            {
12715                $new_file = 1;
12716                $doc_nr++;
12717            }
12718            $doc_nr = 0 if ($doc_nr < 0); # happens if first elements are nodes
12719            $element->{'doc_nr'} = $doc_nr;
12720            my $is_top = '';
12721            $element->{'file'} = "${docu_name}_$doc_nr"
12722                   . ($docu_ext ? ".$docu_ext" : "");
12723            if ($element->{'top'} or (defined($element->{'node_ref'}) and $element->{'node_ref'} eq $element_top))
12724            { # the top elements
12725                $is_top = "top";
12726                $element->{'file'} = $docu_top;
12727            }
12728            elsif ($Texi2HTML::Config::NODE_FILES)
12729            {
12730                if ($new_file)
12731                {
12732                    my $node = get_node($element) unless(exists($element->{'node_ref'})
12733                        and $element->{'node_ref'}->{'element_added'});
12734                    if ($node and defined($node->{'node_file'}))
12735                    {
12736                        $element->{'file'} = $node->{'node_file'};
12737                    }
12738                    $previous_file = $element->{'file'};
12739                }
12740                elsif($previous_file)
12741                {
12742                    $element->{'file'} = $previous_file;
12743                }
12744            }
12745            if (defined($Texi2HTML::Config::element_file_name))
12746            {
12747                my $filename =
12748                    &$Texi2HTML::Config::element_file_name ($element, $is_top, $docu_name);
12749                $element->{'file'} = $filename if (defined($filename));
12750            }
12751            print STDERR "# add_file $element->{'file'} for $element->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
12752            add_file($element->{'file'});
12753            foreach my $place(@{$element->{'place'}})
12754            {
12755                $place->{'file'} = $element->{'file'};
12756                $place->{'id'} = $element->{'id'} unless defined($place->{'id'});
12757            }
12758            if ($element->{'nodes'})
12759            {
12760                foreach my $node (@{$element->{'nodes'}})
12761                {
12762                    $node->{'doc_nr'} = $element->{'doc_nr'};
12763                    $node->{'file'} = $element->{'file'};
12764                }
12765            }
12766        }
12767    }
12768    else
12769    { # not split
12770        add_file($docu_doc);
12771        foreach my $element(@elements_list)
12772        {
12773            $element->{'file'} = $docu_doc;
12774            $element->{'doc_nr'} = 0;
12775            foreach my $place(@{$element->{'place'}})
12776            {
12777                $place->{'file'} = $element->{'file'};
12778                $place->{'id'} = $element->{'id'} unless defined($place->{'id'});
12779            }
12780        }
12781        foreach my $node(@nodes_list)
12782        {
12783            $node->{'file'} = $docu_doc;
12784            $node->{'doc_nr'} = 0;
12785        }
12786    }
12787    # correct the id and file for the things placed in footnotes
12788    foreach my $place(@{$footnote_element->{'place'}})
12789    {
12790        $place->{'file'} = $footnote_element->{'file'};
12791        $place->{'id'} = $footnote_element->{'id'} unless defined($place->{'id'});
12792    }
12793    # if setcontentsaftertitlepage is set, the contents should be associated
12794    # with the titlepage. That's wat is done there.
12795    push @$region_place, $content_element{'contents'}
12796      if ($Texi2HTML::Config::DO_CONTENTS and $Texi2HTML::THISDOC{'setcontentsaftertitlepage'});
12797    push @$region_place, $content_element{'shortcontents'}
12798      if ($Texi2HTML::Config::DO_SCONTENTS and $Texi2HTML::THISDOC{'setshortcontentsaftertitlepage'});
12799    # correct the id and file for the things placed in regions (copying...)
12800    foreach my $place(@$region_place)
12801    {
12802#print STDERR "entry $place->{'entry'} texi $place->{'texi'}\n";
12803        $place->{'file'} = $element_top->{'file'};
12804        $place->{'id'} = $element_top->{'id'} unless defined($place->{'id'});
12805        $place->{'element'} =  $element_top if (exists($place->{'element'}));
12806    }
12807    foreach my $content_type(keys(%content_element))
12808    {
12809        if (!defined($content_element{$content_type}->{'file'}))
12810        {
12811            print STDERR "# No content $content_type\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
12812            $content_element{$content_type} = undef;
12813        }
12814    }
12815
12816    ########################### debug prints
12817    foreach my $file (keys(%files))
12818    {
12819        last unless ($T2H_DEBUG & $DEBUG_ELEMENTS);
12820        print STDERR "$file: counter $files{$file}->{'counter'}\n";
12821    }
12822    foreach my $element ((@elements_list, $footnote_element))
12823    {
12824        last unless ($T2H_DEBUG & $DEBUG_ELEMENTS);
12825        my $is_toplevel = 'not toplevel';
12826        $is_toplevel = 'toplevel' if ($element->{'toplevel'});
12827        print STDERR "$element ";
12828        if ($element->{'index_page'})
12829        {
12830            print STDERR "index($element->{'id'}, $is_toplevel, doc_nr $element->{'doc_nr'}($element->{'file'})): $element->{'texi'}\n";
12831        }
12832        elsif ($element->{'node'})
12833        {
12834            print STDERR "node($element->{'id'}, toc_level $element->{'toc_level'}, $is_toplevel, doc_nr $element->{'doc_nr'}($element->{'file'})) $element->{'texi'}:\n";
12835            print STDERR "  section_ref: $element->{'section_ref'}->{'texi'}\n" if (defined($element->{'section_ref'}));
12836        }
12837        elsif ($element->{'footnote'})
12838        {
12839            print STDERR "footnotes($element->{'id'}, file $element->{'file'})\n";
12840        }
12841        else
12842        {
12843            my $number = "UNNUMBERED";
12844            $number = $element->{'number'} if ($element->{'number'});
12845            print STDERR "$number ($element->{'id'}, $is_toplevel, level $element->{'level'}-$element->{'toc_level'}, doc_nr $element->{'doc_nr'}($element->{'file'})) $element->{'texi'}:\n";
12846            print STDERR "  node_ref: $element->{'node_ref'}->{'texi'}\n" if (defined($element->{'node_ref'}));
12847        }
12848
12849        if (!$element->{'footnote'})
12850        {
12851            if (!defined($files{$element->{'file'}}))
12852            {
12853               die "Bug: files{\$element->{'file'}} undef element $element->{'texi'}, file $element->{'file'}.";
12854            }
12855            print STDERR "  file: $element->{'file'} $files{$element->{'file'}}, counter $files{$element->{'file'}}->{'counter'}\n";
12856        }
12857        print STDERR "  TOP($toplevel) " if ($element->{'top'});
12858        print STDERR "  u: $element->{'up'}->{'texi'}\n" if (defined($element->{'up'}));
12859        print STDERR "  ch: $element->{'child'}->{'texi'}\n" if (defined($element->{'child'}));
12860        print STDERR "  fb: $element->{'fastback'}->{'texi'}\n" if (defined($element->{'fastback'}));
12861        print STDERR "  b: $element->{'back'}->{'texi'}\n" if (defined($element->{'back'}));
12862        print STDERR "  p: $element->{'prev'}->{'texi'}\n" if (defined($element->{'prev'}));
12863        print STDERR "  n: $element->{'sectionnext'}->{'texi'}\n" if (defined($element->{'sectionnext'}));
12864        print STDERR "  n_u: $element->{'nodeup'}->{'texi'}\n" if (defined($element->{'nodeup'}));
12865        print STDERR "  f: $element->{'forward'}->{'texi'}\n" if (defined($element->{'forward'}));
12866        print STDERR "  follow: $element->{'following'}->{'texi'}\n" if (defined($element->{'following'}));
12867	print STDERR "  m_p: $element->{'menu_prev'}->{'texi'}\n" if (defined($element->{'menu_prev'}));
12868	print STDERR "  m_n: $element->{'menu_next'}->{'texi'}\n" if (defined($element->{'menu_next'}));
12869	print STDERR "  m_u: $element->{'menu_up'}->{'texi'}\n" if (defined($element->{'menu_up'}));
12870	print STDERR "  m_ch: $element->{'menu_child'}->{'texi'}\n" if (defined($element->{'menu_child'}));
12871        print STDERR "  ff: $element->{'fastforward'}->{'texi'}\n" if (defined($element->{'fastforward'}));
12872        if (defined($element->{'menu_up_hash'}))
12873        {
12874            print STDERR "  parent nodes:\n";
12875            foreach my $menu_up (keys%{$element->{'menu_up_hash'}})
12876            {
12877                print STDERR "   $menu_up ($element->{'menu_up_hash'}->{$menu_up})\n";
12878            }
12879        }
12880        if (defined($element->{'nodes'}))
12881        {
12882            print STDERR "  nodes: $element->{'nodes'} (@{$element->{'nodes'}})\n";
12883            foreach my $node (@{$element->{'nodes'}})
12884            {
12885                my $beginning = "   ";
12886                $beginning = "  *" if ($node->{'with_section'});
12887                my $file = $node->{'file'};
12888                $file = "file undef" if (! defined($node->{'file'}));
12889                print STDERR "${beginning}$node->{'texi'} $file\n";
12890            }
12891        }
12892        print STDERR "  places: $element->{'place'}\n";
12893        foreach my $place(@{$element->{'place'}})
12894        {
12895            if (!$place->{'entry'} and !$place->{'float'} and !$place->{'texi'} and !$place->{'contents'} and !$place->{'shortcontents'})
12896            {
12897                 print STDERR "BUG: unknown placed stuff ========\n";
12898                 foreach my $key (keys(%$place))
12899                 {
12900                      print STDERR "$key: $place->{$key}\n";
12901                 }
12902                 print STDERR "==================================\n";
12903            }
12904            elsif ($place->{'entry'})
12905            {
12906                print STDERR "    index($place): $place->{'entry'}\n";
12907            }
12908            elsif ($place->{'anchor'})
12909            {
12910                print STDERR "    anchor: $place->{'texi'}\n";
12911            }
12912            elsif ($place->{'float'})
12913            {
12914                if (defined($place->{'texi'}))
12915                {
12916                    print STDERR "    float($place): $place->{'texi'}\n";
12917                }
12918                else
12919                {
12920                    print STDERR "    float($place): NO LABEL\n";
12921                }
12922            }
12923            elsif ($place->{'contents'})
12924            {
12925                print STDERR "    contents\n";
12926            }
12927            elsif ($place->{'shortcontents'})
12928            {
12929                print STDERR "    shortcontents\n";
12930            }
12931            else
12932            {
12933                print STDERR "    heading: $place->{'texi'}\n";
12934            }
12935        }
12936        if ($element->{'indices'})
12937        {
12938            print STDERR "  indices: $element->{'indices'}\n";
12939            foreach my $index(@{$element->{'indices'}})
12940            {
12941                print STDERR "    $index: ";
12942                foreach my $page (@$index)
12943                {
12944                    print STDERR "'$page->{'element'}->{'texi'}'($page->{'name'}): $page->{'page'} ";
12945                }
12946                print STDERR "\n";
12947            }
12948        }
12949    }
12950    ########################### end debug prints
12951}
12952
12953sub add_file($)
12954{
12955    my  $file = shift;
12956    if ($files{$file})
12957    {
12958         $files{$file}->{'counter'}++;
12959    }
12960    else
12961    {
12962         $files{$file} = {
12963           #'type' => 'section',
12964           'counter' => 1,
12965           'relative_foot_num' => 1,
12966           'foot_lines' => []
12967         };
12968    }
12969}
12970
12971# find parent element which is a top element, or a node within the top section
12972sub get_top($)
12973{
12974   my $element = shift;
12975   my $up = $element;
12976   while (!$up->{'toplevel'} and !$up->{'top'})
12977   {
12978       $up = $up->{'sectionup'};
12979       if (!defined($up))
12980       {
12981           # If there is no section, it is normal not to have toplevel element,
12982           # and it is also the case if there is a low level element before
12983           # a top level element
12984           return undef;
12985       }
12986   }
12987   return $up;
12988}
12989
12990sub get_node($)
12991{
12992    my $element = shift;
12993    return undef if (!defined($element));
12994    return $element if ($element->{'node'});
12995    return $element->{'node_ref'} if ($element->{'node_ref'});
12996    return $element;
12997}
12998# get the html names from the texi for all elements
12999sub do_names()
13000{
13001    print STDERR "# Doing ". scalar(keys(%nodes)) . " nodes, ".
13002        scalar(keys(%sections)) . " sections in ". $#elements_list .
13003        " elements\n" if ($T2H_DEBUG);
13004    # for nodes and anchors we haven't any state defined
13005    # This seems right, however, as we don't want @refs or @footnotes
13006    # or @anchors within nodes, section commands or anchors.
13007    foreach my $node (keys(%nodes))
13008    {
13009        next if ($nodes{$node}->{'index_page'}); # some nodes are index pages.
13010        my $texi = &$Texi2HTML::Config::heading_texi($nodes{$node}->{'tag'},
13011           $nodes{$node}->{'texi'}, undef);
13012        $nodes{$node}->{'text'} = substitute_line ($texi);
13013        $nodes{$node}->{'text_nonumber'} = $nodes{$node}->{'text'};
13014        # backward compatibility
13015        $nodes{$node}->{'name'} = $nodes{$node}->{'text_nonumber'};
13016        $nodes{$node}->{'no_texi'} = remove_texi($texi);
13017        $nodes{$node}->{'simple_format'} = simple_format(undef, $texi);
13018        $nodes{$node}->{'heading_texi'} = $texi;
13019        # FIXME : what to do if $nodes{$node}->{'external_node'} and
13020        # $nodes{$node}->{'seen'}
13021    }
13022    foreach my $number (keys(%sections))
13023    {
13024        my $section = $sections{$number};
13025        #$section->{'name'} = substitute_line($section->{'texi'});
13026        my $texi = &$Texi2HTML::Config::heading_texi($section->{'tag'}, $section->{'texi'}, $section->{'number'});
13027        $section->{'text'} = substitute_line($texi);
13028        $section->{'text_nonumber'} = substitute_line($section->{'texi'});
13029        # backward compatibility
13030        $section->{'name'} = $section->{'text_nonumber'};
13031        $section->{'no_texi'} = remove_texi($texi);
13032        $section->{'simple_format'} = simple_format(undef,$texi);
13033        $section->{'heading_texi'} = $texi;
13034    }
13035    my $tocnr = 1;
13036    foreach my $element (@elements_list)
13037    {
13038        if (!$element->{'top'} and !$element->{'index_page'})
13039        { # for link back to table of contents
13040          # FIXME do it for top too?
13041            $element->{'tocid'} = 'TOC' . $tocnr;
13042            $tocnr++;
13043        }
13044        next if (defined($element->{'text'}));
13045        if ($element->{'index_page'})
13046        {
13047            my $page = $element->{'page'};
13048            my $original_element = $element->{'original_index_element'};
13049            my $texi = &$Texi2HTML::Config::index_element_heading_texi(
13050                 $original_element->{'heading_texi'},
13051                 $original_element->{'tag'},
13052                 $original_element->{'texi'},
13053                 $original_element->{'number'},
13054                 $page->{'first_letter'}, $page->{'last_letter'});
13055            $element->{'heading_texi'} = $texi;
13056            $element->{'text'} = substitute_line($texi);
13057            $element->{'no_texi'} = remove_texi($texi);
13058            $element->{'simple_format'} = simple_format(undef,$texi);
13059        }
13060    }
13061    print STDERR "# Names done\n" if ($T2H_DEBUG);
13062}
13063
13064@{$Texi2HTML::TOC_LINES} = ();            # table of contents
13065@{$Texi2HTML::OVERVIEW} = ();           # short table of contents
13066
13067
13068
13069#+++############################################################################
13070#                                                                              #
13071# Stuff related to Index generation                                            #
13072#                                                                              #
13073#---############################################################################
13074
13075# called during pass_structure
13076sub enter_index_entry($$$$$$$)
13077{
13078    my $prefix = shift;
13079    my $line_nr = shift;
13080    my $key = shift;
13081    my $place = shift;
13082    my $element = shift;
13083    my $use_section_id = shift;
13084    my $command = shift;
13085    unless ($index_prefix_to_name{$prefix})
13086    {
13087        echo_error ("Undefined index command: ${prefix}index", $line_nr);
13088        $key = '';
13089    }
13090    if (!exists($element->{'tag'}) and !$element->{'footnote'})
13091    {
13092        echo_warn ("Index entry before document: \@${prefix}index $key", $line_nr);
13093    }
13094    $key =~ s/\s+$//;
13095    $key =~ s/^\s*//;
13096    my $entry = $key;
13097    # The $key is mostly usefull for alphabetical sorting
13098    $key = remove_texi($key);
13099    my $id = '';
13100    # don't add a specific index target if after a section or the index
13101    # entry is in @copying or the like
13102    unless ($use_section_id or ($place eq $region_place))
13103    {
13104        $id = 'IDX' . ++$idx_num;
13105    }
13106    my $index_entry = {
13107           'entry'    => $entry,
13108           'element'  => $element,
13109           'prefix'   => $prefix,
13110           'label'    => $id,
13111           'command'  => $command
13112    };
13113
13114    print STDERR "# enter \@$command ${prefix}index '$key' with id $id ($index_entry)\n"
13115        if ($T2H_DEBUG & $DEBUG_INDEX);
13116    if ($key =~ /^\s*$/)
13117    {
13118        echo_warn("Empty index entry for \@$command",$line_nr);
13119        # don't add the index entry to the list of index entries used for index
13120        # entry formatting,if the index entry appears in a region like copying
13121        push @index_labels, $index_entry unless ($place eq $region_place);
13122        return;
13123    }
13124    while (exists $index->{$prefix}->{$key})
13125    {
13126        $key .= ' ';
13127    }
13128    $index->{$prefix}->{$key} = $index_entry;
13129    push @$place, $index_entry;
13130    # don't add the index entry to the list of index entries used for index
13131    # entry formatting,if the index entry appears in a region like copying
13132    push @index_labels, $index_entry unless ($place eq $region_place);
13133}
13134
13135# sort according to cmp if both $a and $b are alphabetical or non alphabetical,
13136# otherwise the alphabetical is ranked first
13137sub by_alpha
13138{
13139    if ($a =~ /^[A-Za-z]/)
13140    {
13141        if ($b =~ /^[A-Za-z]/)
13142        {
13143            return lc($a) cmp lc($b);
13144        }
13145        else
13146        {
13147            return 1;
13148        }
13149    }
13150    elsif ($b =~ /^[A-Za-z]/)
13151    {
13152        return -1;
13153    }
13154    else
13155    {
13156        return lc($a) cmp lc($b);
13157    }
13158}
13159
13160# returns an array of index entries pages splitted by letters
13161# each page has the following members:
13162# 'first_letter'       first letter on that page
13163# 'last_letter'        last letter on that page
13164# 'letters'            ref on an array with all the letters for that page
13165# 'entries_by_letter'  ref on a hash. Each key is a letter, with value a ref
13166#                      on arrays of index entries beginning with this letter
13167sub get_index_pages($)
13168{
13169    my $entries = shift;
13170    my (@letters);
13171    my ($entries_by_letter, $pages, $page) = ({}, [], {});
13172    my @keys = sort by_alpha keys %$entries;
13173
13174    # each index entry is placed according to its first letter in
13175    # entries_by_letter
13176    for my $key (@keys)
13177    {
13178        push @{$entries_by_letter->{uc(substr($key,0, 1))}} , $entries->{$key};
13179    }
13180    @letters = sort by_alpha keys %$entries_by_letter;
13181    $Texi2HTML::Config::SPLIT_INDEX = 0 unless $Texi2HTML::Config::SPLIT;
13182
13183    if ($Texi2HTML::Config::SPLIT_INDEX and $Texi2HTML::Config::SPLIT_INDEX =~ /^\d+$/)
13184    {
13185        my $i = 0;
13186        my ($prev_letter);
13187        foreach my $letter (@letters)
13188        {
13189            if ($i > $Texi2HTML::Config::SPLIT_INDEX)
13190            {
13191                $page->{'last_letter'} = $prev_letter;
13192                push @$pages, $page;
13193                $i=0;
13194            }
13195	    if ($i == 0)
13196	    {
13197		$page = {};
13198		$page->{'letters'} = [];
13199		$page->{'entries_by_letter'} = {};
13200		$page->{'first_letter'} = $letter;
13201	    }
13202            push @{$page->{'letters'}}, $letter;
13203            $page->{'entries_by_letter'}->{$letter} = [@{$entries_by_letter->{$letter}}];
13204            $i += scalar(@{$entries_by_letter->{$letter}});
13205            $prev_letter = $letter;
13206        }
13207        $page->{'last_letter'} = $letters[$#letters];
13208        push @$pages, $page;
13209    }
13210    else
13211    {
13212        warn "$WARN Bad Texi2HTML::Config::SPLIT_INDEX: $Texi2HTML::Config::SPLIT_INDEX\n" if ($Texi2HTML::Config::SPLIT_INDEX);
13213        $page->{'first_letter'} = $letters[0];
13214        $page->{'last_letter'} = $letters[$#letters];
13215        $page->{'letters'} = \@letters;
13216        $page->{'entries_by_letter'} = $entries_by_letter;
13217        push @$pages, $page;
13218        return $pages;
13219    }
13220    return $pages;
13221}
13222
13223# return the page and the entries. Cache the result in %indices.
13224sub get_index($;$)
13225{
13226    my $index_name = shift;
13227    my $line_nr = shift;
13228
13229    return (@{$indices{$index_name}}) if ($indices{$index_name});
13230
13231    unless (exists($index_names{$index_name}))
13232    {
13233        echo_error ("Bad index name: $index_name", $line_nr);
13234        return;
13235    }
13236    # add the index name itself to the index names searched for index
13237    # prefixes. Only those found associated by synindex or syncodeindex are
13238    # allready there (unless this code has allready been called).
13239    if ($index_names{$index_name}->{'code'})
13240    {
13241        $index_names{$index_name}->{'associated_indices_code'}->{$index_name} = 1;
13242    }
13243    else
13244    {
13245        $index_names{$index_name}->{'associated_indices'}->{$index_name} = 1;
13246    }
13247
13248    # find all the index names associated with the prefixes and then
13249    # all the entries associated with each prefix
13250    my $entries = {};
13251    foreach my $associated_indice(keys %{$index_names{$index_name}->{'associated_indices'}})
13252    {
13253        foreach my $prefix(@{$index_names{$associated_indice}->{'prefix'}})
13254        {
13255            foreach my $key (keys %{$index->{$prefix}})
13256            {
13257                $entries->{$key} = $index->{$prefix}->{$key};
13258            }
13259        }
13260    }
13261
13262    foreach my $associated_indice (keys %{$index_names{$index_name}->{'associated_indices_code'}})
13263    {
13264        unless (exists ($index_names{$index_name}->{'associated_indices'}->{$associated_indice}))
13265        {
13266            foreach my $prefix (@{$index_names{$associated_indice}->{'prefix'}})
13267            {
13268                foreach my $key (keys (%{$index->{$prefix}}))
13269                {
13270                    $entries->{$key} = $index->{$prefix}->{$key};
13271                    # use @code for code style index entry
13272                    $entries->{$key}->{'entry'} = "\@code{$entries->{$key}->{entry}}";
13273                }
13274            }
13275        }
13276    }
13277
13278    return unless %$entries;
13279    my $pages = get_index_pages($entries);
13280    $indices{$index_name} = [ $pages, $entries ];
13281    return ($pages, $entries);
13282}
13283
13284my @foot_lines = ();           # footnotes
13285my $copying_comment = '';      # comment constructed from text between
13286                               # @copying and @end copying with licence
13287my $to_encoding;               # out file encoding
13288my %acronyms_like = ();        # acronyms or similar commands associated texts
13289                               # the key are the commands, the values are
13290                               # hash references associating shorthands to
13291                               # texts.
13292
13293sub initialise_state($)
13294{
13295    my $state = shift;
13296    $state->{'preformatted'} = 0 unless exists($state->{'preformatted'});
13297    $state->{'code_style'} = 0 unless exists($state->{'code_style'});
13298    $state->{'keep_texi'} = 0 unless exists($state->{'keep_texi'});
13299    $state->{'keep_nr'} = 0 unless exists($state->{'keep_nr'});
13300    $state->{'detailmenu'} = 0 unless exists($state->{'detailmenu'});     # number of opened detailed menus
13301    $state->{'table_list_stack'} = [ {'format' => "noformat"} ] unless exists($state->{'table_list_stack'});
13302    $state->{'paragraph_style'} = [ '' ] unless exists($state->{'paragraph_style'});
13303    $state->{'preformatted_stack'} = [ '' ] unless exists($state->{'preformatted_stack'});
13304    $state->{'menu'} = 0 unless exists($state->{'menu'});
13305    $state->{'command_stack'} = [] unless exists($state->{'command_stack'});
13306    $state->{'quotation_stack'} = [] unless exists($state->{'quotation_stack'});
13307    # if there is no $state->{'element'} the first element is used
13308    $state->{'element'} = $elements_list[0] unless (exists($state->{'element'}) and !$state->{'element'}->{'before_anything'});
13309}
13310
13311sub pass_text()
13312{
13313    my %state;
13314    initialise_state(\%state);
13315    my @stack;
13316    my $text;
13317    my $doc_nr;
13318    my $in_doc = 0;
13319    my $element;
13320    my @text =();
13321    my @section_lines = ();
13322    my @head_lines = ();
13323    my $one_section = 1 if (@elements_list == 1);
13324
13325    if (@elements_list == 0)
13326    {
13327        warn "$WARN empty document\n";
13328        exit (0);
13329    }
13330
13331    # We set titlefont only if the titlefont appeared in the top element
13332    if (defined($element_top->{'titlefont'}))
13333    {
13334         $value{'_titlefont'} = $element_top->{'titlefont'};
13335    }
13336
13337    # prepare %Texi2HTML::THISDOC
13338#    $Texi2HTML::THISDOC{'settitle_texi'} = $value{'_settitle'};
13339    $Texi2HTML::THISDOC{'fulltitle_texi'} = '';
13340    $Texi2HTML::THISDOC{'title_texi'} = '';
13341    foreach my $possible_fulltitle (('_title', '_settitle', '_shorttitlepage', '_titlefont'))
13342    {
13343        if ($value{$possible_fulltitle} ne '')
13344        {
13345            $Texi2HTML::THISDOC{'fulltitle_texi'} = $value{$possible_fulltitle};
13346            last;
13347        }
13348    }
13349    foreach my $possible_title_texi ($value{'_settitle'}, $Texi2HTML::THISDOC{'fulltitle_texi'})
13350    {
13351        if ($possible_title_texi ne '')
13352        {
13353            $Texi2HTML::THISDOC{'title_texi'} = $possible_title_texi;
13354            last;
13355        }
13356    }
13357#    $Texi2HTML::THISDOC{'fulltitle_texi'} = $value{'_title'} || $value{'_settitle'} || $value{'_shorttitlepage'} || $value{'_titlefont'};
13358#    $Texi2HTML::THISDOC{'title_texi'} = $value{'_title'} || $value{'_settitle'} || $value{'_shorttitlepage'} || $value{'_titlefont'};
13359    foreach my $texi_cmd (('shorttitlepage', 'settitle', 'author',
13360           'titlefont', 'subtitle', 'shorttitle'))
13361    {
13362        $Texi2HTML::THISDOC{$texi_cmd . '_texi'} = $value{'_' . $texi_cmd};
13363    }
13364    foreach my $doc_thing (('shorttitlepage', 'settitle', 'author',
13365           'titlefont', 'subtitle', 'shorttitle', 'fulltitle', 'title'))
13366    {
13367        my $thing_texi = $Texi2HTML::THISDOC{$doc_thing . '_texi'};
13368        $Texi2HTML::THISDOC{$doc_thing} = substitute_line($thing_texi);
13369        $Texi2HTML::THISDOC{$doc_thing . '_no_texi'} =
13370           remove_texi($thing_texi);
13371        $Texi2HTML::THISDOC{$doc_thing . '_simple_format'} =
13372           simple_format(undef, $thing_texi);
13373    }
13374
13375    # find Top name
13376    my $element_top_text = '';
13377    my $top_no_texi = '';
13378    my $top_simple_format = '';
13379    my $top_name;
13380    if ($element_top and $element_top->{'text'} and (!$node_top or ($element_top ne $node_top)))
13381    {
13382        $element_top_text = $element_top->{'text'};
13383        $top_no_texi = $element_top->{'no_texi'};
13384        $top_simple_format =  $element_top->{'simple_format'};
13385    }
13386    foreach my $possible_top_name ($Texi2HTML::Config::TOP_HEADING,
13387         $element_top_text, $Texi2HTML::THISDOC{'title'},
13388         $Texi2HTML::THISDOC{'shorttitle'}, &$I('Top'))
13389    {
13390         if (defined($possible_top_name) and $possible_top_name ne '')
13391         {
13392             $top_name = $possible_top_name;
13393             last;
13394         }
13395    }
13396    foreach my $possible_top_no_texi ($Texi2HTML::Config::TOP_HEADING,
13397         $top_no_texi, $Texi2HTML::THISDOC{'title_no_texi'},
13398         $Texi2HTML::THISDOC{'shorttitle_no_texi'},
13399         &$I('Top',{},{'remove_texi' => 1}))
13400    {
13401         if (defined($possible_top_no_texi) and $possible_top_no_texi ne '')
13402         {
13403             $top_no_texi = $possible_top_no_texi;
13404             last;
13405         }
13406    }
13407
13408    foreach my $possible_top_simple_format ($top_simple_format,
13409         $Texi2HTML::THISDOC{'title_simple_format'},
13410         $Texi2HTML::THISDOC{'shorttitle_simple_format'},
13411         &$I('Top',{}, {'simple_format' => 1}))
13412    {
13413         if (defined($possible_top_simple_format) and $possible_top_simple_format ne '')
13414         {
13415             $top_simple_format = $possible_top_simple_format;
13416             last;
13417         }
13418    }
13419
13420
13421#    my $top_name = $Texi2HTML::Config::TOP_HEADING || $element_top_text || $Texi2HTML::THISDOC{'title'} || $Texi2HTML::THISDOC{'shorttitle'} || &$I('Top');
13422
13423    if ($Texi2HTML::THISDOC{'fulltitle_texi'} eq '')
13424    {
13425         $Texi2HTML::THISDOC{'fulltitle_texi'} = &$I('Untitled Document',{},
13426           {'keep_texi' => 1});
13427    }
13428    $Texi2HTML::THISDOC{'title_texi'} = $Texi2HTML::THISDOC{'settitle_texi'};
13429    $Texi2HTML::THISDOC{'title_texi'} = $Texi2HTML::THISDOC{'fulltitle_texi'}
13430            if ($Texi2HTML::THISDOC{'title_texi'} eq '');
13431
13432    foreach my $doc_thing (('fulltitle', 'title'))
13433    {
13434        my $thing_texi = $Texi2HTML::THISDOC{$doc_thing . '_texi'};
13435        $Texi2HTML::THISDOC{$doc_thing} = substitute_line($thing_texi);
13436        $Texi2HTML::THISDOC{$doc_thing . '_no_texi'} =
13437           remove_texi($thing_texi);
13438        $Texi2HTML::THISDOC{$doc_thing . '_simple_format'} =
13439           simple_format(undef, $thing_texi);
13440    }
13441
13442    for my $key (keys %Texi2HTML::THISDOC)
13443    {
13444        next if (ref($Texi2HTML::THISDOC{$key}));
13445print STDERR "!!$key\n" if (!defined($Texi2HTML::THISDOC{$key}));
13446        $Texi2HTML::THISDOC{$key} =~ s/\s*$//;
13447    }
13448    $Texi2HTML::THISDOC{'program'} = $THISPROG;
13449    $Texi2HTML::THISDOC{'program_homepage'} = $T2H_HOMEPAGE;
13450    $Texi2HTML::THISDOC{'program_authors'} = $T2H_AUTHORS;
13451    $Texi2HTML::THISDOC{'user'} = $T2H_USER;
13452    $Texi2HTML::THISDOC{'user'} = $Texi2HTML::Config::USER if (defined($Texi2HTML::Config::USER));
13453#    $Texi2HTML::THISDOC{'documentdescription'} = $documentdescription;
13454    $Texi2HTML::THISDOC{'copying'} = $copying_comment;
13455    $Texi2HTML::THISDOC{'destination_directory'} = $docu_rdir;
13456    $Texi2HTML::THISDOC{'authors'} = [] if (!defined($Texi2HTML::THISDOC{'authors'}));
13457    $Texi2HTML::THISDOC{'subtitles'} = [] if (!defined($Texi2HTML::THISDOC{'subtitles'}));
13458    $Texi2HTML::THISDOC{'titles'} = [] if (!defined($Texi2HTML::THISDOC{'titles'}));
13459    foreach my $element (('authors', 'subtitles', 'titles'))
13460    {
13461        my $i;
13462        for ($i = 0; $i < $#{$Texi2HTML::THISDOC{$element}} + 1; $i++)
13463        {
13464            chomp ($Texi2HTML::THISDOC{$element}->[$i]);
13465            $Texi2HTML::THISDOC{$element}->[$i] = substitute_line($Texi2HTML::THISDOC{$element}->[$i]);
13466            #print STDERR "$element:$i: $Texi2HTML::THISDOC{$element}->[$i]\n";
13467        }
13468    }
13469    # prepare TOC, OVERVIEW...
13470    my ($toc_file, $stoc_file, $foot_file, $about_file);
13471    # if not split the references are to the same file
13472    $toc_file = $stoc_file = $foot_file = $about_file = '';
13473    if ($Texi2HTML::Config::SPLIT)
13474    {
13475        $toc_file = $docu_toc;
13476        $stoc_file = $docu_stoc;
13477        if ($Texi2HTML::Config::INLINE_CONTENTS)
13478        {
13479            $toc_file = $content_element{'contents'}->{'file'} if (defined($content_element{'contents'}));
13480            $stoc_file = $content_element{'shortcontents'}->{'file'} if (defined($content_element{'shortcontents'}));
13481        }
13482        $foot_file = $docu_foot;
13483        $about_file = $docu_about;
13484    }
13485    $Texi2HTML::THISDOC{'toc_file'} = $toc_file;
13486    $Texi2HTML::HREF{'Contents'} = $toc_file.'#'.$content_element{'contents'}->{'id'} if @{$Texi2HTML::TOC_LINES};
13487    $Texi2HTML::HREF{'Overview'} = $stoc_file.'#'.$content_element{'shortcontents'}->{'id'} if @{$Texi2HTML::OVERVIEW};
13488    $Texi2HTML::HREF{'Footnotes'} = $foot_file. '#SEC_Foot';
13489    $Texi2HTML::HREF{'About'} = $about_file . '#SEC_About' unless ($one_section or (not $Texi2HTML::Config::SPLIT and not $Texi2HTML::Config::SECTION_NAVIGATION));
13490
13491    $Texi2HTML::NAME{'First'} = $element_first->{'text'};
13492    $Texi2HTML::NAME{'Last'} = $element_last->{'text'};
13493    $Texi2HTML::NAME{'About'} = &$I('About This Document');
13494    $Texi2HTML::NAME{'Contents'} = &$I('Table of Contents');
13495    $Texi2HTML::NAME{'Overview'} = &$I('Short Table of Contents');
13496    $Texi2HTML::NAME{'Top'} = $top_name;
13497    $Texi2HTML::NAME{'Footnotes'} = &$I('Footnotes');
13498    $Texi2HTML::NAME{'Index'} = $element_chapter_index->{'text'} if (defined($element_chapter_index));
13499    $Texi2HTML::NAME{'Index'} = $Texi2HTML::Config::INDEX_CHAPTER if ($Texi2HTML::Config::INDEX_CHAPTER ne '');
13500
13501    $Texi2HTML::NO_TEXI{'First'} = $element_first->{'no_texi'};
13502    $Texi2HTML::NO_TEXI{'Last'} = $element_last->{'no_texi'};
13503    $Texi2HTML::NO_TEXI{'About'} = &$I('About This Document', {}, {'remove_texi' => 1} );
13504    $Texi2HTML::NO_TEXI{'Contents'} = &$I('Table of Contents', {}, {'remove_texi' => 1} );
13505    $Texi2HTML::NO_TEXI{'Overview'} = &$I('Short Table of Contents', {}, {'remove_texi' => 1} );
13506    $Texi2HTML::NO_TEXI{'Top'} = $top_no_texi;
13507    $Texi2HTML::NO_TEXI{'Footnotes'} = &$I('Footnotes', {}, {'remove_texi' => 1} );
13508    $Texi2HTML::NO_TEXI{'Index'} = $element_chapter_index->{'no_texi'} if (defined($element_chapter_index));
13509
13510    $Texi2HTML::SIMPLE_TEXT{'First'} = $element_first->{'simple_format'};
13511    $Texi2HTML::SIMPLE_TEXT{'Last'} = $element_last->{'simple_format'};
13512    $Texi2HTML::SIMPLE_TEXT{'About'} = &$I('About This Document', {}, {'simple_format' => 1});
13513    $Texi2HTML::SIMPLE_TEXT{'Contents'} = &$I('Table of Contents',{},  {'simple_format' => 1});
13514    $Texi2HTML::SIMPLE_TEXT{'Overview'} = &$I('Short Table of Contents', {}, {'simple_format' => 1});
13515    $Texi2HTML::SIMPLE_TEXT{'Top'} = $top_simple_format;
13516    $Texi2HTML::SIMPLE_TEXT{'Footnotes'} = &$I('Footnotes', {},{'simple_format' => 1});
13517
13518    $Texi2HTML::SIMPLE_TEXT{'Index'} = $element_chapter_index->{'simple_format'} if (defined($element_chapter_index));
13519    # must be after toc_body, but before titlepage
13520    for my $element_tag ('contents', 'shortcontents')
13521    {
13522        my $toc_lines = &$Texi2HTML::Config::inline_contents(undef, $element_tag, $content_element{$element_tag});
13523        @{$Texi2HTML::THISDOC{'inline_contents'}->{$element_tag}} = @$toc_lines if (defined($toc_lines));
13524    }
13525    $Texi2HTML::TITLEPAGE = '';
13526    $Texi2HTML::TITLEPAGE = substitute_text({}, @{$region_lines{'titlepage'}})
13527        if (@{$region_lines{'titlepage'}});
13528    &$Texi2HTML::Config::titlepage();
13529
13530    &$Texi2HTML::Config::init_out();
13531    $to_encoding = $Texi2HTML::Config::OUT_ENCODING;
13532
13533    ############################################################################
13534    # print frame and frame toc file
13535    #
13536    if ( $Texi2HTML::Config::FRAMES )
13537    {
13538        my $FH = open_out($docu_frame_file);
13539        print STDERR "# Creating frame in $docu_frame_file ...\n" if $T2H_VERBOSE;
13540        &$Texi2HTML::Config::print_frame($FH, $docu_toc_frame_file, $docu_top_file);
13541        close_out($FH, $docu_frame_file);
13542
13543        $FH = open_out($docu_toc_frame_file);
13544        print STDERR "# Creating toc frame in $docu_frame_file ...\n" if $T2H_VERBOSE;
13545        &$Texi2HTML::Config::print_toc_frame($FH, $Texi2HTML::OVERVIEW);
13546        close_out($FH, $docu_toc_frame_file);
13547    }
13548
13549    ############################################################################
13550    #
13551    #
13552
13553    my $FH;
13554    my $index_pages;
13555    my $index_pages_nr;
13556    my $index_nr = 0;
13557    my $line_nr;
13558    my $first_section = 0; # 1 if it is the first section of a page
13559    while (@doc_lines)
13560    {
13561        unless ($index_pages)
13562        { # not in a index split over sections
13563            $_ = shift @doc_lines;
13564            my $chomped_line = $_;
13565            if (!chomp($chomped_line) and @doc_lines)
13566            { # if the line has no end of line it is concatenated with the next
13567                 $doc_lines[0] = $_ . $doc_lines[0];
13568                 next;
13569            }
13570            $line_nr = shift (@doc_numbers);
13571            #print STDERR "$line_nr->{'file_name'}($line_nr->{'macro'},$line_nr->{'line_nr'}) $_" if ($line_nr);
13572        }
13573	#print STDERR "PASS_TEXT: $_";
13574	#dump_stack(\$text, \@stack, \%state);
13575        if (!$state{'raw'} and !$state{'verb'})
13576        {
13577            my $tag = '';
13578            $tag = $1 if (/^\@(\w+)/ and !$index_pages);
13579
13580            if (($tag eq 'node') or defined($sec2level{$tag}) or $index_pages)
13581            {
13582                if (@stack or (defined($text) and $text ne ''))
13583                {# in pass text node and section shouldn't appear in formats
13584			#print STDERR "close_stack before \@$tag\n";
13585			#print STDERR "text!$text%" if (! @stack);
13586                    close_stack(\$text, \@stack, \%state, $line_nr);
13587                    push @section_lines, $text;
13588                    $text = '';
13589                }
13590                $sec_num++ if ($sec2level{$tag});
13591                my $new_element;
13592                my $current_element;
13593                if ($tag =~ /heading/)
13594                {# handle headings, they are not in element lists
13595                    $current_element = $sections{$sec_num};
13596                    #print STDERR "HEADING $_";
13597                    if (! $element)
13598                    {
13599                        $new_element = shift @elements_list;
13600                    }
13601                    else
13602                    {
13603                        push (@section_lines, &$Texi2HTML::Config::anchor($current_element->{'id'}) . "\n");
13604                        push @section_lines, &$Texi2HTML::Config::heading($current_element);
13605                        next;
13606                    }
13607                }
13608                elsif (!$index_pages)
13609                {# handle node and structuring elements
13610                    $current_element = shift (@all_elements);
13611                    ########################## begin debug section
13612                    if ($current_element->{'node'})
13613                    {
13614                         print STDERR 'NODE ' . "$current_element->{'texi'}($current_element->{'file'})" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
13615                         print STDERR "($current_element->{'section_ref'}->{'texi'})" if ($current_element->{'section_ref'} and ($T2H_DEBUG & $DEBUG_ELEMENTS));
13616                    }
13617                    else
13618                    {
13619                         print STDERR 'SECTION ' . $current_element->{'texi'} if ($T2H_DEBUG & $DEBUG_ELEMENTS);
13620                    }
13621                    print STDERR ": $_" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
13622                    ########################## end debug section
13623
13624                    # The element begins a new section if there is no previous
13625                    # or it is an element and not the current one or the
13626                    # associated section (in case of node) is not the current
13627                    # one
13628                    if (!$element
13629                      or ($current_element->{'element'} and ($current_element ne $element))
13630                      or ($current_element->{'section_ref'} and ($current_element->{'section_ref'} ne $element)))
13631                    {
13632                         $new_element = shift @elements_list;
13633                    }
13634                    ########################### begin debug
13635                    my $section_element = $new_element;
13636                    $section_element = $element unless ($section_element);
13637                    if (!$current_element->{'node'} and !$current_element->{'index_page'} and ($section_element ne $current_element))
13638                    {
13639                         print STDERR "NODE: $element->{'texi'}\n" if ($element->{'node'});
13640                         warn "elements_list and all_elements not in sync (elements $section_element->{'texi'}, all $current_element->{'texi'}): $_";
13641                    }
13642                    ########################### end debug
13643                }
13644                else
13645                { # this is a new index section
13646                    $new_element = $index_pages->[$index_pages_nr]->{'element'};
13647                    $current_element = $index_pages->[$index_pages_nr]->{'element'};
13648                    print STDERR "New index page '$new_element->{'texi'}' nr: $index_pages_nr\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
13649                    my $list_element = shift @elements_list;
13650                    die "element in index_pages $new_element->{'texi'} and in list $list_element->{'texi'} differs\n" unless ($list_element eq $new_element);
13651                }
13652                if ($new_element)
13653                {
13654                    $index_nr = 0;
13655                    my $old = 'NO_OLD';
13656                    $old = $element->{'texi'} if (defined($element));
13657                    print STDERR "NEW: $new_element->{'texi'}, OLD: $old\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
13658                    # print the element that just finished
13659                    $Texi2HTML::THIS_SECTION = \@section_lines;
13660                    $Texi2HTML::THIS_HEADER = \@head_lines;
13661                    if ($element)
13662                    {
13663                        finish_element($FH, $element, $new_element, $first_section);
13664                        $first_section = 0;
13665                        @section_lines = ();
13666                        @head_lines = ();
13667                    }
13668                    else
13669                    {
13670                        print STDERR "# Writing elements:" if ($T2H_VERBOSE);
13671                        if ($Texi2HTML::Config::IGNORE_PREAMBLE_TEXT)
13672                        {
13673                             @section_lines = ();
13674                             @head_lines = ();
13675                        }
13676                        # remove empty line at the beginning of @section_lines
13677                        shift @section_lines while (@section_lines and ($section_lines[0] =~ /^\s*$/));
13678                    }
13679                    # begin new element
13680                    my $previous_file;
13681                    $previous_file = $element->{'file'} if (defined($element));
13682                    $element = $new_element;
13683                    $state{'element'} = $element;
13684                    $Texi2HTML::THIS_ELEMENT = $element;
13685                    #print STDERR "Doing hrefs for $element->{'texi'} First ";
13686                    $Texi2HTML::HREF{'First'} = href($element_first, $element->{'file'});
13687                    #print STDERR "Last ";
13688                    $Texi2HTML::HREF{'Last'} = href($element_last, $element->{'file'});
13689                    #print STDERR "Index ";
13690                    $Texi2HTML::HREF{'Index'} = href($element_chapter_index, $element->{'file'}) if (defined($element_chapter_index));
13691                    #print STDERR "Top ";
13692                    $Texi2HTML::HREF{'Top'} = href($element_top, $element->{'file'});
13693                    if ($Texi2HTML::Config::INLINE_CONTENTS)
13694                    {
13695                        $Texi2HTML::HREF{'Contents'} = href($content_element{'contents'}, $element->{'file'});
13696                        $Texi2HTML::HREF{'Overview'} = href($content_element{'shortcontents'}, $element->{'file'});
13697                    }
13698                    foreach my $direction (@element_directions)
13699                    {
13700                        my $elem = $element->{$direction};
13701                        $Texi2HTML::NODE{$direction} = undef;
13702                        $Texi2HTML::HREF{$direction} = undef;
13703                        next unless (defined($elem));
13704                        #print STDERR "$direction ";
13705                        if ($elem->{'node'} or $elem->{'external_node'} or $elem->{'index_page'} or !$elem->{'seen'})
13706                        {
13707                            $Texi2HTML::NODE{$direction} = $elem->{'text'};
13708                        }
13709                        elsif ($elem->{'node_ref'})
13710                        {
13711                            $Texi2HTML::NODE{$direction} = $elem->{'node_ref'}->{'text'};
13712                        }
13713                        if (!$elem->{'seen'})
13714                        {
13715                            $Texi2HTML::HREF{$direction} = do_external_href($elem->{'texi'});
13716                        }
13717                        else
13718                        {
13719                            $Texi2HTML::HREF{$direction} = href($elem, $element->{'file'});
13720                        }
13721                        $Texi2HTML::NAME{$direction} = $elem->{'text'};
13722                        $Texi2HTML::NO_TEXI{$direction} = $elem->{'no_texi'};
13723                        $Texi2HTML::SIMPLE_TEXT{$direction} = $elem->{'simple_format'};
13724                        #print STDERR "$direction ($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";
13725                    }
13726                    #print STDERR "\nDone hrefs for $element->{'texi'}\n";
13727                    $files{$element->{'file'}}->{'counter'}--;
13728                    if (!defined($previous_file) or ($element->{'file'} ne $previous_file))
13729                    {
13730                        my $file = $element->{'file'};
13731                        print STDERR "\n" if ($T2H_VERBOSE and !$T2H_DEBUG);
13732                        print STDERR "# Writing to $docu_rdir$file " if $T2H_VERBOSE;
13733                        my $do_page_head = 0;
13734                        if ($files{$file}->{'filehandle'})
13735                        {
13736                             $FH = $files{$file}->{'filehandle'};
13737                        }
13738                        else
13739                        {
13740                             $FH = open_out("$docu_rdir$file");
13741#print STDERR "OPEN $docu_rdir$file, $FH". scalar($FH)."\n";
13742                             $files{$file}->{'filehandle'} = $FH;
13743                             $do_page_head = 1;
13744                        }
13745                        if ($element->{'top'})
13746                        {
13747                             &$Texi2HTML::Config::print_Top_header($FH, $do_page_head);
13748                        }
13749                        else
13750                        {
13751                             &$Texi2HTML::Config::print_page_head($FH) if ($do_page_head);
13752                             &$Texi2HTML::Config::print_chapter_header($FH) if $Texi2HTML::Config::SPLIT eq 'chapter';
13753                             &$Texi2HTML::Config::print_section_header($FH) if $Texi2HTML::Config::SPLIT eq 'section';
13754                        }
13755                        $first_section = 1;
13756                    }
13757                    print STDERR "." if ($T2H_VERBOSE);
13758                    print STDERR "\n" if ($T2H_DEBUG);
13759                }
13760                my $label = &$Texi2HTML::Config::anchor($current_element->{'id'}) . "\n";
13761                if (@section_lines)
13762                {
13763                    push (@section_lines, $label);
13764                }
13765                else
13766                {
13767                    push @head_lines, $label;
13768                }
13769                if ($index_pages)
13770                {
13771                    push @section_lines, &$Texi2HTML::Config::heading($element);
13772		    #print STDERR "Do index page $index_pages_nr\n";
13773                    my $page = do_index_page($index_pages, $index_pages_nr);
13774                    push @section_lines, $page;
13775                    if (defined ($index_pages->[$index_pages_nr + 1]))
13776                    {
13777                        $index_pages_nr++;
13778                    }
13779                    else
13780                    {
13781                        $index_pages = undef;
13782                    }
13783                    next;
13784                }
13785                push @section_lines, &$Texi2HTML::Config::heading($current_element) if ($current_element->{'element'} and !$current_element->{'top'});
13786                next;
13787            }
13788            elsif ($tag eq 'printindex')
13789            {
13790                s/\s+(\w+)\s*//;
13791                my $name = $1;
13792                close_paragraph(\$text, \@stack, \%state);
13793                next if (!$index_names{$name} or $empty_indices{$name});
13794                $printed_indices{$name} = 1;
13795                print STDERR "print index $name($index_nr) in `$element->{'texi'}', element->{'indices'}: $element->{'indices'},\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS or $T2H_DEBUG & $DEBUG_INDEX);
13796                print STDERR "element->{'indices'}->[index_nr]: $element->{'indices'}->[$index_nr] (@{$element->{'indices'}->[$index_nr]})\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS or $T2H_DEBUG & $DEBUG_INDEX);
13797                $index_pages = $element->{'indices'}->[$index_nr] if (@{$element->{'indices'}->[$index_nr]} > 1);
13798                $index_pages_nr = 0;
13799                add_prev(\$text, \@stack, do_index_page($element->{'indices'}->[$index_nr], 0));
13800                $index_pages_nr++;
13801                $index_nr++;
13802                begin_paragraph (\@stack, \%state) if ($state{'preformatted'});
13803                next if (@stack);
13804                push @section_lines, $text;
13805                $text = '';
13806                next;
13807            }
13808            elsif (($tag eq 'contents') or ($tag eq 'summarycontents') or ($tag eq 'shortcontents'))
13809            {
13810                my $element_tag = $tag;
13811                $element_tag = 'shortcontents' if ($element_tag ne 'contents');
13812                if ($Texi2HTML::Config::INLINE_CONTENTS and !$content_element{$element_tag}->{'aftertitlepage'})
13813                {
13814                    if (@stack or (defined($text) and $text ne ''))
13815                    {# in pass text contents  shouldn't appear in formats
13816                        close_stack(\$text, \@stack, \%state, $line_nr);
13817                        push @section_lines, $text;
13818                        $text = '';
13819                    }
13820                    my $toc_lines = &$Texi2HTML::Config::inline_contents($FH, $tag, $content_element{$element_tag});
13821                    push (@section_lines, @$toc_lines) if (defined($toc_lines)) ;
13822                }
13823                next;
13824            }
13825        }
13826        scan_line($_, \$text, \@stack, \%state, $line_nr);
13827	#print STDERR "after scan_line: $_";
13828	#dump_stack(\$text, \@stack, \%state);
13829        next if (@stack);
13830        if ($text ne '' )
13831        {
13832            push @section_lines, $text;
13833            $text = '';
13834        }
13835    }
13836    if (@stack)
13837    {# close stack at the end of pass text
13838        close_stack(\$text, \@stack, \%state, $line_nr);
13839    }
13840    if (defined($text))
13841    {
13842        push @section_lines, $text;
13843    }
13844    print STDERR "\n" if ($T2H_VERBOSE);
13845
13846    $Texi2HTML::THIS_SECTION = \@section_lines;
13847    # if no sections, then simply print document as is
13848    if ($one_section)
13849    {
13850        if (@foot_lines)
13851        {
13852            &$Texi2HTML::Config::foot_section (\@foot_lines);
13853            push @section_lines, @foot_lines;
13854        }
13855        $Texi2HTML::THIS_HEADER = \@head_lines;
13856        if ($element->{'top'})
13857        {
13858            print STDERR "Bug: `$element->{'texi'}' level undef\n" if (!$element->{'node'} and !defined($element->{'level'}));
13859            $element->{'level'} = 1 if (!defined($element->{'level'}));
13860            $element->{'node'} = 0; # otherwise Texi2HTML::Config::heading may uses the node level
13861            $element->{'text'} = $Texi2HTML::NAME{'Top'};
13862            print STDERR "[Top]" if ($T2H_VERBOSE);
13863            unless ($element->{'titlefont'} or $element->{'index_page'})
13864            {
13865                unshift @section_lines, &$Texi2HTML::Config::heading($element);
13866            }
13867        }
13868        print STDERR "# Write the section $element->{'texi'}\n" if ($T2H_VERBOSE);
13869        &$Texi2HTML::Config::one_section($FH);
13870        close_out($FH);
13871        return;
13872    }
13873
13874    finish_element ($FH, $element, undef, $first_section);
13875
13876    ############################################################################
13877    # Print ToC, Overview, Footnotes
13878    #
13879    foreach my $direction (@element_directions)
13880    {
13881        $Texi2HTML::HREF{$direction} = undef;
13882        delete $Texi2HTML::HREF{$direction};
13883        # it is better to undef in case the references to these hash entries
13884        # are used, as if deleted, the
13885        # references are still refering to the old, undeleted element
13886        # (we could do both)
13887        $Texi2HTML::NAME{$direction} = undef;
13888        $Texi2HTML::NO_TEXI{$direction} = undef;
13889        $Texi2HTML::SIMPLE_TEXT{$direction} = undef;
13890        $Texi2HTML::NODE{$direction} = undef;
13891
13892        $Texi2HTML::THIS_ELEMENT = undef;
13893    }
13894    if (@foot_lines)
13895    {
13896        print STDERR "# writing Footnotes in $docu_foot_file\n" if $T2H_VERBOSE;
13897        $FH = open_out ($docu_foot_file)
13898            if $Texi2HTML::Config::SPLIT;
13899        $Texi2HTML::HREF{'This'} = $Texi2HTML::HREF{'Footnotes'};
13900        $Texi2HTML::HREF{'Footnotes'} = '#' . $footnote_element->{'id'};
13901        $Texi2HTML::NAME{'This'} = $Texi2HTML::NAME{'Footnotes'};
13902        $Texi2HTML::NO_TEXI{'This'} = $Texi2HTML::NO_TEXI{'Footnotes'};
13903        $Texi2HTML::SIMPLE_TEXT{'This'} = $Texi2HTML::SIMPLE_TEXT{'Footnotes'};
13904        $Texi2HTML::THIS_SECTION = \@foot_lines;
13905        $Texi2HTML::THIS_HEADER = [ &$Texi2HTML::Config::anchor($footnote_element->{'id'}) . "\n" ];
13906        &$Texi2HTML::Config::print_Footnotes($FH);
13907        close_out($FH, $docu_foot_file)
13908               if ($Texi2HTML::Config::SPLIT);
13909        $Texi2HTML::HREF{'Footnotes'} = $Texi2HTML::HREF{'This'};
13910    }
13911
13912    if (@{$Texi2HTML::TOC_LINES} and !$Texi2HTML::Config::INLINE_CONTENTS)
13913    {
13914        print STDERR "# writing Toc in $docu_toc_file\n" if $T2H_VERBOSE;
13915        $FH = open_out ($docu_toc_file)
13916            if $Texi2HTML::Config::SPLIT;
13917        $Texi2HTML::HREF{'This'} = $Texi2HTML::HREF{'Contents'};
13918        $Texi2HTML::HREF{'Contents'} = "#SEC_Contents";
13919        $Texi2HTML::NAME{'This'} = $Texi2HTML::NAME{'Contents'};
13920        $Texi2HTML::NO_TEXI{'This'} = $Texi2HTML::NO_TEXI{'Contents'};
13921        $Texi2HTML::SIMPLE_TEXT{'This'} = $Texi2HTML::SIMPLE_TEXT{'Contents'};
13922        $Texi2HTML::THIS_SECTION = $Texi2HTML::TOC_LINES;
13923        $Texi2HTML::THIS_HEADER = [ &$Texi2HTML::Config::anchor("SEC_Contents") . "\n" ];
13924        &$Texi2HTML::Config::print_Toc($FH);
13925        close_out($FH, $docu_toc_file)
13926               if ($Texi2HTML::Config::SPLIT);
13927        $Texi2HTML::HREF{'Contents'} = $Texi2HTML::HREF{'This'};
13928    }
13929
13930    if (@{$Texi2HTML::OVERVIEW} and !$Texi2HTML::Config::INLINE_CONTENTS)
13931    {
13932        print STDERR "# writing Overview in $docu_stoc_file\n" if $T2H_VERBOSE;
13933        $FH = open_out ($docu_stoc_file)
13934            if $Texi2HTML::Config::SPLIT;
13935        $Texi2HTML::HREF{This} = $Texi2HTML::HREF{Overview};
13936        $Texi2HTML::HREF{Overview} = "#SEC_Overview";
13937        $Texi2HTML::NAME{This} = $Texi2HTML::NAME{Overview};
13938        $Texi2HTML::NO_TEXI{This} = $Texi2HTML::NO_TEXI{Overview};
13939        $Texi2HTML::SIMPLE_TEXT{This} = $Texi2HTML::SIMPLE_TEXT{Overview};
13940        $Texi2HTML::THIS_SECTION = $Texi2HTML::OVERVIEW;
13941        $Texi2HTML::THIS_HEADER = [ &$Texi2HTML::Config::anchor("SEC_Overview") . "\n" ];
13942        &$Texi2HTML::Config::print_Overview($FH);
13943        close_out($FH,$docu_stoc_file)
13944               if ($Texi2HTML::Config::SPLIT);
13945        $Texi2HTML::HREF{Overview} = $Texi2HTML::HREF{This};
13946    }
13947    my $about_body;
13948    if ($about_body = &$Texi2HTML::Config::about_body())
13949    {
13950        print STDERR "# writing About in $docu_about_file\n" if $T2H_VERBOSE;
13951        $FH = open_out ($docu_about_file)
13952            if $Texi2HTML::Config::SPLIT;
13953
13954        $Texi2HTML::HREF{This} = $Texi2HTML::HREF{About};
13955        $Texi2HTML::HREF{About} = "#SEC_About";
13956        $Texi2HTML::NAME{This} = $Texi2HTML::NAME{About};
13957        $Texi2HTML::NO_TEXI{This} = $Texi2HTML::NO_TEXI{About};
13958        $Texi2HTML::SIMPLE_TEXT{This} = $Texi2HTML::SIMPLE_TEXT{About};
13959        $Texi2HTML::THIS_SECTION = [$about_body];
13960        $Texi2HTML::THIS_HEADER = [ &$Texi2HTML::Config::anchor("SEC_About") . "\n" ];
13961        &$Texi2HTML::Config::print_About($FH);
13962        close_out($FH, $docu_stoc_file)
13963               if ($Texi2HTML::Config::SPLIT);
13964        $Texi2HTML::HREF{About} = $Texi2HTML::HREF{This};
13965    }
13966
13967    unless ($Texi2HTML::Config::SPLIT)
13968    {
13969        &$Texi2HTML::Config::print_page_foot($FH);
13970        close_out ($FH);
13971    }
13972}
13973
13974# print section, close file if needed.
13975sub finish_element($$$$)
13976{
13977    my $FH = shift;
13978    my $element = shift;
13979    my $new_element = shift;
13980    my $first_section = shift;
13981#print STDERR "FINISH_ELEMENT($FH)($element->{'texi'})[$element->{'file'}] counter $files{$element->{'file'}}->{'counter'}\n";
13982
13983    # handle foot notes
13984    if ($Texi2HTML::Config::SPLIT and scalar(@foot_lines)
13985        and !$Texi2HTML::Config::SEPARATED_FOOTNOTES
13986        and  (! $new_element or
13987        ($element and ($new_element->{'file'} ne $element->{'file'})))
13988       )
13989    {
13990        if ($files{$element->{'file'}}->{'counter'})
13991        {# there are other elements in that page we are not on its foot
13992            $files{$element->{'file'}}->{'relative_foot_num'}
13993               = $relative_foot_num;
13994            push @{$files{$element->{'file'}}->{'foot_lines'}},
13995                @foot_lines;
13996        }
13997        else
13998        {# we output the footnotes as we are at the file end
13999             unshift @foot_lines, @{$files{$element->{'file'}}->{'foot_lines'}};
14000             &$Texi2HTML::Config::foot_section (\@foot_lines);
14001             push @{$Texi2HTML::THIS_SECTION}, @foot_lines;
14002        }
14003        if ($new_element)
14004        {
14005            $relative_foot_num =
14006               $files{$new_element->{'file'}}->{'relative_foot_num'};
14007        }
14008        @foot_lines = ();
14009    }
14010    if ($element->{'top'})
14011    {
14012        my $top_file = $docu_top_file;
14013        #print STDERR "TOP $element->{'texi'}, @section_lines\n";
14014        print STDERR "[Top]" if ($T2H_VERBOSE);
14015        $Texi2HTML::HREF{'Top'} = href($element_top, $element->{'file'});
14016        &$Texi2HTML::Config::print_Top($FH, ($element->{'titlefont'} or $element->{'index_page'}));
14017        my $end_page = 0;
14018        if ($Texi2HTML::Config::SPLIT)
14019        {
14020            if (!$files{$element->{'file'}}->{'counter'})
14021            {
14022                $end_page = 1;
14023            }
14024        }
14025        &$Texi2HTML::Config::print_Top_footer($FH, $end_page);
14026        close_out($FH, $top_file) if ($end_page);
14027    }
14028    else
14029    {
14030        print STDERR "# do element $element->{'texi'}\n"
14031           if ($T2H_DEBUG & $DEBUG_ELEMENTS);
14032        &$Texi2HTML::Config::print_section($FH, $first_section);
14033        if (defined($new_element) and ($new_element->{'file'} ne $element->{'file'}))
14034        {
14035             if (!$files{$element->{'file'}}->{'counter'})
14036             {
14037                 &$Texi2HTML::Config::print_chapter_footer($FH) if ($Texi2HTML::Config::SPLIT eq 'chapter');
14038                 &$Texi2HTML::Config::print_section_footer($FH) if ($Texi2HTML::Config::SPLIT eq 'section');
14039                 #print STDERR "Close file after $element->{'texi'}\n";
14040                 &$Texi2HTML::Config::print_page_foot($FH);
14041                 close_out($FH);
14042             }
14043             else
14044             {
14045                 print STDERR "counter $files{$element->{'file'}}->{'counter'} ne 0, file $element->{'file'}\n" if ($T2H_DEBUG);
14046             }
14047        }
14048        elsif (!defined($new_element))
14049        {
14050            if ($Texi2HTML::Config::SPLIT)
14051            { # end of last splitted section
14052                &$Texi2HTML::Config::print_chapter_footer($FH) if ($Texi2HTML::Config::SPLIT eq 'chapter');
14053                &$Texi2HTML::Config::print_section_footer($FH) if ($Texi2HTML::Config::SPLIT eq 'section');
14054                &$Texi2HTML::Config::print_page_foot($FH);
14055                close_out($FH);
14056            }
14057            else
14058            {
14059                &$Texi2HTML::Config::end_section($FH, 1);
14060            }
14061        }
14062        elsif ($new_element->{'top'})
14063        {
14064            &$Texi2HTML::Config::end_section($FH, 1);
14065        }
14066        else
14067        {
14068            &$Texi2HTML::Config::end_section($FH);
14069        }
14070    }
14071}
14072
14073# write to files with name the node name for cross manual references.
14074sub do_node_files()
14075{
14076    foreach my $key (keys(%nodes))
14077    {
14078        my $node = $nodes{$key};
14079        next unless ($node->{'node_file'});
14080        my $redirection_file = $docu_doc;
14081        $redirection_file = $node->{'file'} if ($Texi2HTML::Config::SPLIT);
14082        if (!$redirection_file)
14083        {
14084             print STDERR "Bug: file for redirection for `$node->{'texi'}' don't exist\n" unless ($novalidate);
14085             next;
14086        }
14087        next if ($redirection_file eq $node->{'node_file'});
14088        my $file = "${docu_rdir}$node->{'node_file'}";
14089        $Texi2HTML::NODE{'This'} = $node->{'text'};
14090        $Texi2HTML::NO_TEXI{'This'} = $node->{'no_texi'};
14091        $Texi2HTML::SIMPLE_TEXT{'This'} = $node->{'simple_format'};
14092        $Texi2HTML::NAME{'This'} = $node->{'text'};
14093        $Texi2HTML::HREF{'This'} = "$node->{'file'}#$node->{'id'}";
14094        my $NODEFILE = open_out ($file);
14095        &$Texi2HTML::Config::print_redirection_page ($NODEFILE);
14096        close $NODEFILE || die "$ERROR: Can't close $file: $!\n";
14097    }
14098}
14099
14100#+++############################################################################
14101#                                                                              #
14102# Low level functions                                                          #
14103#                                                                              #
14104#---############################################################################
14105
14106sub locate_include_file($)
14107{
14108    my $file = shift;
14109
14110    # APA: Don't implicitely search ., to conform with the docs!
14111    # return $file if (-e $file && -r $file);
14112    foreach my $dir (@Texi2HTML::Config::INCLUDE_DIRS)
14113    {
14114        return "$dir/$file" if (-e "$dir/$file" && -r "$dir/$file");
14115    }
14116    return undef;
14117}
14118
14119sub open_file($$)
14120{
14121    my $name = shift;
14122    my $line_number = shift;
14123    local *FH;
14124    if (open(*FH, "<$name"))
14125    {
14126        if (defined($Texi2HTML::Config::IN_ENCODING) and $Texi2HTML::Config::USE_UNICODE)
14127        {
14128            binmode(*FH, ":encoding($Texi2HTML::Config::IN_ENCODING)");
14129        }
14130        my $file = { 'fh' => *FH,
14131           'input_spool' => { 'spool' => [],
14132                              'macro' => '' },
14133           'name' => $name,
14134           'line_nr' => 0 };
14135        unshift(@fhs, $file);
14136        $input_spool = $file->{'input_spool'};
14137        $line_number->{'file_name'} = $name;
14138        $line_number->{'line_nr'} = 1;
14139    }
14140    else
14141    {
14142        warn "$ERROR Can't read file $name: $!\n";
14143    }
14144}
14145
14146sub open_out($)
14147{
14148    my $file = shift;
14149    local *FILE;
14150    if ($file eq '-')
14151    {
14152        binmode(STDOUT, ":encoding($to_encoding)") if (defined($to_encoding) and $Texi2HTML::Config::USE_UNICODE);
14153        return \*STDOUT;
14154    }
14155
14156    unless (open(FILE, ">$file"))
14157    {
14158        die "$ERROR Can't open $file for writing: $!\n";
14159    }
14160    if (defined($to_encoding) and $Texi2HTML::Config::USE_UNICODE)
14161    {
14162        if ($to_encoding eq 'utf8' or $to_encoding eq 'utf-8-strict')
14163        {
14164            binmode(FILE, ':utf8');
14165        }
14166	else
14167        {
14168            binmode(FILE, ':bytes');
14169        }
14170        binmode(FILE, ":encoding($to_encoding)");
14171    }
14172    return *FILE;
14173}
14174
14175# FIXME not used when split
14176sub close_out($;$)
14177{
14178    my $FH = shift;
14179    my $file = shift;
14180    $file = '' if (!defined($file));
14181    return if ($Texi2HTML::Config::OUT eq '');
14182    close ($FH) || die "$ERROR: Error occurred when closing $file: $!\n";
14183}
14184
14185sub next_line($)
14186{
14187    my $line_number = shift;
14188    while (@fhs)
14189    {
14190        my $file = $fhs[0];
14191        $line_number->{'file_name'} = $file->{'name'};
14192        $input_spool = $file->{'input_spool'};
14193        if (@{$input_spool->{'spool'}})
14194        {
14195             $line_number->{'macro'} = $file->{'input_spool'}->{'macro'};
14196             $line_number->{'line_nr'} = $file->{'line_nr'};
14197             my $line = shift(@{$input_spool->{'spool'}});
14198             print STDERR "# unspooling $line" if ($T2H_DEBUG & $DEBUG_MACROS);
14199             return($line);
14200        }
14201        else
14202        {
14203             $file->{'input_spool'}->{'macro'} = '';
14204             $line_number->{'macro'} = '';
14205        }
14206        my $fh = $file->{'fh'};
14207        no strict "refs";
14208        my $line = <$fh>;
14209        use strict "refs";
14210        my $chomped_line = $line;
14211        $file->{'line_nr'}++ if (defined($line) and chomp($chomped_line));
14212        $line_number->{'line_nr'} = $file->{'line_nr'};
14213        return($line) if (defined($line));
14214        no strict "refs";
14215        close($fh);
14216        use strict "refs";
14217        shift(@fhs);
14218    }
14219    return(undef);
14220}
14221
14222# echo a warning
14223sub echo_warn($;$)
14224{
14225    my $text = shift;
14226    chomp ($text);
14227    my $line_number = shift;
14228    warn "$WARN $text " . format_line_number($line_number) . "\n";
14229}
14230
14231sub echo_error($;$)
14232{
14233    my $text = shift;
14234    chomp ($text);
14235    my $line_number = shift;
14236    warn "$ERROR $text " . format_line_number($line_number) . "\n";
14237}
14238
14239sub format_line_number($)
14240{
14241    my $line_number = shift;
14242    my $macro_text = '';
14243    #$line_number = undef;
14244    return '' unless (defined($line_number));
14245    $macro_text = " in $line_number->{'macro'}" if ($line_number->{'macro'} ne '');
14246    my $file_text = '(';
14247    $file_text = "(in $line_number->{'file_name'} " if ($line_number->{'file_name'} ne $docu);
14248    return "${file_text}l. $line_number->{'line_nr'}" . $macro_text . ')';
14249}
14250
14251# to debug, dump the result of pass_texi and pass_structure in a file
14252sub dump_texi($$;$$)
14253{
14254    my $lines = shift;
14255    my $pass = shift;
14256    my $numbers = shift;
14257    my $file = shift;
14258    $file = "$docu_rdir$docu_name" . ".pass$pass" if (!defined($file));
14259    unless (open(DMPTEXI, ">$file"))
14260    {
14261         warn "Can't open $file for writing: $!\n";
14262    }
14263    print STDERR "# Dump texi\n" if ($T2H_VERBOSE);
14264    my $index = 0;
14265    foreach my $line (@$lines)
14266    {
14267        my $number_information = '';
14268        my $chomped_line = $line;
14269        $number_information = "$numbers->[$index]->{'file_name'}($numbers->[$index]->{'macro'},$numbers->[$index]->{'line_nr'}) " if (defined($numbers));
14270        print DMPTEXI "${number_information}$line";
14271        $index++ if (chomp($chomped_line));
14272    }
14273    close DMPTEXI;
14274}
14275
14276# return next tag on the line
14277sub next_tag($)
14278{
14279    my $line = shift;
14280    # macro_regexp
14281    if ($line =~ /^\s*\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/])/o or $line =~ /^\s*\@([a-zA-Z][\w-]*)([\s\{\}\@])/ or $line =~ /^\s*\@([a-zA-Z][\w-]*)$/)
14282    {
14283        return ($1);
14284    }
14285    return '';
14286}
14287
14288sub top_stack($)
14289{
14290    my $stack = shift;
14291    return undef unless(@$stack);
14292    return $stack->[-1];
14293}
14294
14295# return the next element with balanced {}
14296sub next_bracketed($$)
14297{
14298    my $line = shift;
14299    my $line_nr = shift;
14300    my $opened_braces = 0;
14301    my $result = '';
14302    my $spaces;
14303    if ($line =~ /^(\s*)$/)
14304    {
14305        return ('','',$1);
14306    }
14307    while ($line !~ /^\s*$/)
14308    {
14309#print STDERR "next_bracketed($opened_braces): $result !!! $line";
14310        if (!$opened_braces)
14311        { # beginning of item
14312            $line =~ s/^(\s*)//;
14313            $spaces = $1;
14314            #if ($line =~ s/^([^\{\}\s]+)//)
14315            if ($line =~ s/^([^\{\}]+?)(\s+)/$2/ or $line =~ s/^([^\{\}]+?)$//)
14316            {
14317                $result = $1;
14318                $result =~ s/\s*$//;
14319                return ($result, $line, $spaces);
14320            }
14321            elsif ($line =~ s/^([^\{\}]+?)([\{\}])/$2/)
14322            {
14323                $result = $1;
14324            }
14325        }
14326        elsif($line =~ s/^([^\{\}]+)//)
14327        {
14328            $result .= $1;
14329        }
14330        if ($line =~ s/^([\{\}])//)
14331        {
14332            my $brace = $1;
14333            $opened_braces++ if ($brace eq '{');
14334            $opened_braces-- if ($brace eq '}');
14335
14336            if ($opened_braces < 0)
14337            {
14338                echo_error("too much '}' in specification", $line_nr);
14339                $opened_braces = 0;
14340                next;
14341            }
14342            $result .= $brace;
14343            return ($result, $line, $spaces) if ($opened_braces == 0);
14344        }
14345    }
14346    if ($opened_braces)
14347    {
14348        echo_error("'{' not closed in specification", $line_nr);
14349        return ($result . ( '}' x $opened_braces), '', $spaces);
14350    }
14351    print STDERR "BUG: at the end of next_bracketed\n";
14352    return undef;
14353}
14354
14355# do a href using file and id and taking care of ommitting file if it is
14356# the same
14357# element: structuring element to point to
14358# file: current file
14359sub href($$)
14360{
14361    my $element = shift;
14362    my $file = shift;
14363    return '' unless defined($element);
14364    my $href = '';
14365    print STDERR "Bug: $element->{'texi'}, id undef\n" if (!defined($element->{'id'}));
14366    print STDERR "Bug: $element->{'texi'}, file undef\n" if (!defined($element->{'file'}));
14367#foreach my $key (keys(%{$element}))
14368#{
14369#   my $value = 'UNDEF'; $value =  $element->{$key} if defined($element->{$key});
14370#   print STDERR "$key: $value\n";
14371#}print STDERR "\n";
14372    $href .= $element->{'file'} if (defined($element->{'file'}) and $file ne $element->{'file'});
14373    $href .= "#$element->{'id'}" if (defined($element->{'id'}));
14374    return $href;
14375}
14376
14377sub normalise_space($)
14378{
14379   return undef unless (defined ($_[0]));
14380   my $text = shift;
14381   $text =~ s/\s+/ /go;
14382   $text =~ s/ $//;
14383   $text =~ s/^ //;
14384   return $text;
14385}
14386
14387sub normalise_node($)
14388{
14389    return undef unless (defined ($_[0]));
14390    my $text = shift;
14391    $text = normalise_space($text);
14392    $text =~ s/^top$/Top/i;
14393    return $text;
14394}
14395
14396sub do_anchor_label($$$$)
14397{
14398    my $command = shift;
14399    #my $anchor = shift;
14400    my $args = shift;
14401    my $anchor = $args->[0];
14402    my $style_stack = shift;
14403    my $state = shift;
14404    my $line_nr = shift;
14405
14406    return '' if ($state->{'multiple_pass'});
14407    $anchor = normalise_node($anchor);
14408    if (!exists($nodes{$anchor}) or !defined($nodes{$anchor}->{'id'}))
14409    {
14410        print STDERR "Bug: unknown anchor `$anchor'\n";
14411    }
14412    return &$Texi2HTML::Config::anchor($nodes{$anchor}->{'id'});
14413}
14414
14415sub get_format_command($)
14416{
14417    my $format = shift;
14418    my $command = '';
14419    my $format_name = '';
14420    my $term = 0;
14421    my $item_nr;
14422    my $paragraph_number;
14423    my $enumerate_type;
14424    my $number;
14425
14426    $command = $format->{'command'} if (defined($format->{'command'}));
14427    $format_name =  $format->{'format'} if (defined($format->{'format'}));
14428    $term = 1 if ($format->{'term'}); #This should never happen
14429
14430    return ($format_name,$command,\$format->{'paragraph_number'},$term,
14431        $format->{'item_nr'}, $format->{'spec'},  $format->{'number'},
14432        $format->{'stack_at_beginning'});
14433}
14434
14435sub do_paragraph($$)
14436{
14437    my $text = shift;
14438    my $state = shift;
14439    my ($format, $paragraph_command, $paragraph_number, $term, $item_nr,
14440        $enumerate_type, $number,$stack_at_beginning)
14441         = get_format_command ($state->{'paragraph_context'});
14442    delete $state->{'paragraph_context'};
14443
14444    my $indent_style = '';
14445    if (exists($state->{'paragraph_indent'}))
14446    {
14447        $indent_style = $state->{'paragraph_indent'};
14448        $state->{'paragraph_indent'} = undef;
14449        delete $state->{'paragraph_indent'};
14450    }
14451    my $paragraph_command_formatted;
14452    $state->{'paragraph_nr'}--;
14453    (print STDERR "Bug text undef in do_paragraph", return '') unless defined($text);
14454    my $align = '';
14455    $align = $state->{'paragraph_style'}->[-1] if ($state->{'paragraph_style'}->[-1]);
14456
14457    if (exists($::style_map_ref->{$paragraph_command}) and
14458       !exists($Texi2HTML::Config::special_list_commands{$format}->{$paragraph_command}))
14459    {
14460        if ($format eq 'itemize')
14461        {
14462            chomp ($text);
14463            $text = do_simple($paragraph_command, $text, $state, [$text]);
14464            $text = $text . "\n";
14465        }
14466    }
14467    elsif (exists($::things_map_ref->{$paragraph_command}))
14468    {
14469        $paragraph_command_formatted = do_simple($paragraph_command, '', $state);
14470    }
14471    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);
14472}
14473
14474sub do_preformatted($$)
14475{
14476    my $text = shift;
14477    my $state = shift;
14478    my ($format, $leading_command, $preformatted_number, $term, $item_nr,
14479        $enumerate_type, $number,$stack_at_beginning)
14480        = get_format_command($state->{'preformatted_context'});
14481    delete ($state->{'preformatted_context'});
14482    my $leading_command_formatted;
14483    my $pre_style = '';
14484    my $class = '';
14485    $pre_style = $state->{'preformatted_stack'}->[-1]->{'pre_style'} if ($state->{'preformatted_stack'}->[-1]->{'pre_style'});
14486    $class = $state->{'preformatted_stack'}->[-1]->{'class'};
14487    print STDERR "BUG: !state->{'preformatted_stack'}->[-1]->{'class'}\n" unless ($class);
14488    if (exists($::style_map_ref->{$leading_command}) and
14489       !exists($Texi2HTML::Config::special_list_commands{$format}->{$leading_command}) and ($style_type{$leading_command} eq 'style'))
14490    {
14491        $text = do_simple($leading_command, $text, $state,[$text]) if ($format eq 'itemize');
14492    }
14493    elsif (exists($::things_map_ref->{$leading_command}))
14494    {
14495        $leading_command_formatted = do_simple($leading_command, '', $state);
14496    }
14497    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);
14498}
14499
14500sub do_external_href($)
14501{
14502    # node_id is a unique node identifier with only letters, digits, - and _
14503    # node_xhtml_id is almost the same, but xhtml id can only begin with
14504    # letters, so a prefix has to be appended
14505    my $texi_node = shift;
14506    my $file = '';
14507    my $node_file = '';
14508    my $node_id = '';
14509    my $node_xhtml_id = '';
14510
14511#print STDERR "do_external_href $texi_node\n";
14512
14513    if ($texi_node =~ s/^\((.+?)\)//)
14514    {
14515         $file = $1;
14516    }
14517    $texi_node = normalise_node($texi_node);
14518    if ($texi_node ne '')
14519    {
14520         if (exists($nodes{$texi_node}) and ($nodes{$texi_node}->{'cross_manual_target'}))
14521         {
14522               $node_id = $nodes{$texi_node}->{'cross_manual_target'};
14523               if ($Texi2HTML::Config::TRANSLITERATE_NODE)
14524               {
14525                   $node_file = $nodes{$texi_node}->{'cross_manual_file'};
14526               }
14527         }
14528         else
14529         {
14530              if ($Texi2HTML::Config::TRANSLITERATE_NODE)
14531              {
14532                  ($node_id, $node_file) = cross_manual_line($texi_node,1);
14533              }
14534              else
14535              {
14536                  $node_id = cross_manual_line($texi_node);
14537              }
14538         }
14539         $node_xhtml_id = node_to_id($node_id);
14540         $node_file = $node_id unless ($Texi2HTML::Config::TRANSLITERATE_NODE);
14541    }
14542    return &$Texi2HTML::Config::external_href($texi_node, $node_file,
14543        $node_xhtml_id, $file);
14544}
14545
14546# transform node for cross ref name to id suitable for xhtml: an xhtml id
14547# must begin with a letter.
14548sub node_to_id($)
14549{
14550    my $cross_ref_node_name = shift;
14551    $cross_ref_node_name =~ s/^([0-9_])/g_t$1/;
14552    return $cross_ref_node_name;
14553}
14554
14555# return 1 if the following tag shouldn't begin a line
14556sub no_line($)
14557{
14558    my $line = shift;
14559    my $next_tag = next_tag($line);
14560    return 1 if (($line =~ /^\s*$/) or $no_line_macros{$next_tag} or
14561       (($next_tag =~ /^(\w+?)index$/) and ($1 ne 'print')) or
14562       (($line =~ /^\@end\s+(\w+)/) and  $no_line_macros{"end $1"}));
14563    return 0;
14564}
14565
14566sub no_paragraph($$)
14567{
14568    my $state = shift;
14569    my $line = shift;
14570    return ($state->{'paragraph_context'} or $state->{'preformatted'} or $state->{'remove_texi'} or no_line($line) or $state->{'no_paragraph'});
14571}
14572
14573# We restart the preformatted format which was stopped
14574# by the format if in preformatted, and start a paragraph
14575# for the text following the end of the format, if needed
14576sub begin_paragraph_after_command($$$$)
14577{
14578    my $state = shift;
14579    my $stack = shift;
14580    my $command = shift;
14581    my $text_following = shift;
14582
14583    if (($state->{'preformatted'}
14584           and !$Texi2HTML::Config::format_in_paragraph{$command})
14585        or (!no_paragraph($state,$text_following)))
14586    {
14587        begin_paragraph($stack, $state);
14588    }
14589}
14590
14591# handle raw formatting, ignored regions...
14592sub do_text_macro($$$$$)
14593{
14594    my $type = shift;
14595    my $line = shift;
14596    my $state = shift;
14597    my $stack = shift;
14598    my $line_nr = shift;
14599    my $value;
14600    #print STDERR "do_text_macro $type\n";
14601
14602    if ($text_macros{$type} eq 'raw')
14603    {
14604        $state->{'raw'} = $type;
14605        #print STDERR "RAW\n";
14606        if ($state->{'raw'})
14607        {
14608             push @$stack, { 'style' => $type, 'text' => '' };
14609        }
14610    }
14611    elsif ($text_macros{$type} eq 'value')
14612    {
14613        if (($line =~ s/(\s+)($VARRE)$//) or ($line =~ s/(\s+)($VARRE)(\s)//))
14614        {
14615            $value = $1 . $2;
14616            $value .= $3 if defined($3);
14617            if ($state->{'ignored'})
14618            {
14619                if ($type eq $state->{'ignored'})
14620                {
14621                    $state->{'ifvalue_inside'}++;
14622                }
14623                # if 'ignored' we don't care about the command as long as
14624                # the nesting is correct
14625                return ($line,'');
14626            }
14627            my $open_ifvalue = 0;
14628            if ($type eq 'ifclear')
14629            {
14630                if (defined($value{$2}))
14631                {
14632                    $open_ifvalue = 1;
14633                }
14634                else
14635                {
14636                    push @{$state->{'text_macro_stack'}}, $type;
14637                }
14638            }
14639            elsif ($type eq 'ifset')
14640            {
14641                unless (defined($value{$2}))
14642                {
14643                    $open_ifvalue = 1;
14644                }
14645                else
14646                {
14647                    push @{$state->{'text_macro_stack'}}, $type;
14648                }
14649            }
14650            if ($open_ifvalue)
14651            {
14652                $state->{'ignored'} = $type;
14653                $state->{'ifvalue'} = $type;
14654                $state->{'ifvalue_inside'} = 1;
14655                # We add at the top of the stack to be able to close all
14656                # opened comands when closing the ifset/ifclear (and ignore
14657                # everything that is in those commands)
14658                push @$stack, { 'style' => 'ifvalue', 'text' => '' };
14659            }
14660
14661        }
14662        else
14663        { # we accept a lone @ifset or @ifclear if it is inside an
14664            if ($type eq $state->{'ifvalue'})
14665            {
14666                $state->{'ifvalue_inside'}++;
14667                return ($line,'');
14668            }
14669            echo_error ("Bad $type line: $line", $line_nr) unless ($state->{'ignored'});
14670        }
14671    }
14672    elsif (not $text_macros{$type})
14673    { # ignored text
14674        $state->{'ignored'} = $type;
14675        #print STDERR "IGNORED\n";
14676    }
14677    else
14678    {
14679        push @{$state->{'text_macro_stack'}}, $type unless($state->{'ignored'}) ;
14680    }
14681    my $text = "\@$type";
14682    $text .= $value if defined($value);
14683    return ($line, $text);
14684}
14685
14686# do regions handled specially, currently only tex, going through latex2html
14687sub init_special($$)
14688{
14689    my $style = shift;
14690    my $text = shift;
14691    if (defined($Texi2HTML::Config::command_handler{$style}) and
14692       defined($Texi2HTML::Config::command_handler{$style}->{'init'}))
14693    {
14694        $special_commands{$style}->{'count'} = 0 if (!defined($special_commands{$style}));
14695        if ($Texi2HTML::Config::command_handler{$style}->{'init'}($style,$text,
14696               $special_commands{$style}->{'count'} +1))
14697        {
14698            $special_commands{$style}->{'count'}++;
14699            return "\@special_${style}_".$special_commands{$style}->{'count'}."{}";
14700        }
14701        return '';
14702    }
14703}
14704
14705sub do_insertcopying($)
14706{
14707    my $state = shift;
14708    return '' unless @{$region_lines{'copying'}};
14709    my $insert_copying_state = duplicate_state($state);
14710    $insert_copying_state->{'multiple_pass'} = 1;
14711    return substitute_text($insert_copying_state, @{$region_lines{'copying'}});
14712}
14713
14714sub get_deff_index($$$)
14715{
14716    my $tag = shift;
14717    my $line = shift;
14718    my $line_nr = shift;
14719
14720    $tag =~ s/x$//;
14721    my ($style, $category, $name, $type, $class, $arguments);
14722    ($style, $category, $name, $type, $class, $arguments) = parse_def($tag, $line, $line_nr);
14723    $name = &$Texi2HTML::Config::definition_category($name, $class, $style);
14724    return ($style, '') if (!defined($name) or ($name =~ /^\s*$/));
14725    return ($style, $name, $arguments);
14726}
14727
14728sub parse_def($$$)
14729{
14730    my $command = shift;
14731    my $line = shift;
14732    my $line_nr = shift;
14733
14734    my $tag = $command;
14735
14736    if (!ref ($Texi2HTML::Config::def_map{$tag}))
14737    {
14738        # substitute shortcuts for definition commands
14739        my $substituted = $Texi2HTML::Config::def_map{$tag};
14740        $substituted =~ s/(\w+)//;
14741        $tag = $1;
14742        $line = $substituted . $line;
14743    }
14744#print STDERR "PARSE_DEF($command,$tag) $line";
14745    my ($category, $name, $type, $class, $arguments);
14746    my @args = @{$Texi2HTML::Config::def_map{$tag}};
14747    my $style = shift @args;
14748    while (@args)
14749    {
14750        my $arg = shift @args;
14751        if (defined($arg))
14752        {
14753            # backward compatibility, it was possible to have a { in front.
14754            $arg =~  s/^\{//;
14755            my $item;
14756            my $spaces;
14757            ($item, $line,$spaces) = next_bracketed($line, $line_nr);
14758            last if (!defined($item));
14759            $item =~ s/^\{(.*)\}$/$1/ if ($item =~ /^\{/);
14760            if ($arg eq 'category')
14761            {
14762                $category = $item;
14763            }
14764            elsif ($arg eq 'name')
14765            {
14766                $name = $item;
14767            }
14768            elsif ($arg eq 'type')
14769            {
14770                $type = $item;
14771            }
14772            elsif ($arg eq 'class')
14773            {
14774                $class = $item;
14775            }
14776            elsif ($arg eq 'arg')
14777            {
14778                $line = $spaces . $item . $line;
14779            }
14780        }
14781        else
14782        {
14783            last;
14784        }
14785    }
14786#print STDERR "PARSE_DEF (style $style, category $category, name $name, type $type, class $class, line $line)\n";
14787    return ($style, $category, $name, $type, $class, $line);
14788}
14789
14790sub begin_deff_item($$;$)
14791{
14792    my $stack = shift;
14793    my $state = shift;
14794    my $no_paragraph = shift;
14795    #print STDERR "DEF push deff_item for $state->{'deff'}\n";
14796    push @$stack, { 'format' => 'deff_item', 'text' => '', 'deff_line' => $state->{'deff_line'}};
14797    # there is no paragraph when a new deff just follows the deff we are
14798    # opening
14799    begin_paragraph($stack, $state)
14800       if ($state->{'preformatted'} and !$no_paragraph);
14801    delete($state->{'deff_line'});
14802    #dump_stack(undef, $stack, $state);
14803}
14804
14805sub begin_paragraph($$)
14806{
14807    my $stack = shift;
14808    my $state = shift;
14809
14810    my $command = 1;
14811    my $top_format = top_format($stack);
14812    if (defined($top_format))
14813    {
14814        $command = $top_format;
14815    }
14816    else
14817    {
14818        $command = { };
14819    }
14820    $command->{'stack_at_beginning'} = [ @{$state->{'command_stack'}} ];
14821    if ($state->{'preformatted'})
14822    {
14823        push @$stack, {'format' => 'preformatted', 'text' => '' };
14824        $state->{'preformatted_context'} = $command;
14825        push @$stack, @{$state->{'paragraph_macros'}} if $state->{'paragraph_macros'};
14826        delete $state->{'paragraph_macros'};
14827        return;
14828    }
14829    $state->{'paragraph_context'} = $command;
14830    $state->{'paragraph_nr'}++;
14831    push @$stack, {'format' => 'paragraph', 'text' => '' };
14832    # if there are macros which weren't closed when the previous
14833    # paragraph was closed we reopen them here
14834    push @$stack, @{$state->{'paragraph_macros'}} if $state->{'paragraph_macros'};
14835    delete $state->{'paragraph_macros'};
14836}
14837
14838sub parse_format_command($$)
14839{
14840    my $line = shift;
14841    my $tag = shift;
14842    my $command = 'asis';
14843    # macro_regexp
14844    if (($line =~ /^\s*\@([A-Za-z][\w-]*)(\{\})?$/ or $line =~ /^\s*\@([A-Za-z][\w-]*)(\{\})?\s/) and ($::things_map_ref->{$1} or defined($::style_map_ref->{$1})))
14845    {
14846        # macro_regexp
14847        $line =~ s/^\s*\@([A-Za-z][\w-]*)(\{\})?\s*//;
14848        $command = $1;
14849    }
14850    return ('', $command) if ($line =~ /^\s*$/);
14851    chomp $line;
14852    $line = substitute_text ({'keep_nr' => 1, 'keep_texi' => 1, 'check_item' => $tag}, $line);
14853    return ($line, $command);
14854}
14855
14856sub parse_enumerate($)
14857{
14858    my $line = shift;
14859    my $spec;
14860    if ($line =~ /^\s*(\w)\b/ and ($1 ne '_'))
14861    {
14862        $spec = $1;
14863        $line =~ s/^\s*(\w)\s*//;
14864    }
14865    return ($line, $spec);
14866}
14867
14868sub parse_multitable($$)
14869{
14870    my $line = shift;
14871    my $line_nr = shift;
14872    # first find the table width
14873    my $table_width = 0;
14874    if ($line =~ s/^\s+\@columnfractions\s+//)
14875    {
14876        my @fractions = split /\s+/, $line;
14877        $table_width = $#fractions + 1;
14878        while (@fractions)
14879        {
14880            my $fraction = shift @fractions;
14881            unless ($fraction =~ /^(\d*\.\d+)|(\d+)\.?$/)
14882            {
14883                echo_error ("column fraction not a number: $fraction", $line_nr);
14884                #warn "$ERROR column fraction not a number: $fraction";
14885            }
14886        }
14887    }
14888    else
14889    {
14890        my $element;
14891        my $line_orig = $line;
14892        while ($line !~ /^\s*$/)
14893        {
14894            my $spaces;
14895            ($element, $line, $spaces) = next_bracketed($line, $line_nr);
14896            if ($element =~ /^\{/)
14897            {
14898                $table_width++;
14899            }
14900            else
14901            {
14902                echo_error ("garbage in multitable specification: $element", $line_nr);
14903            }
14904        }
14905    }
14906    return ($table_width);
14907}
14908
14909sub end_format($$$$$)
14910{
14911    my $text = shift;
14912    my $stack = shift;
14913    my $state = shift;
14914    my $format = shift;
14915    my $line_nr = shift;
14916    #print STDERR "END FORMAT $format\n";
14917    #dump_stack($text, $stack, $state);
14918    #sleep 1;
14919    if ($format_type{$format} eq 'menu')
14920    {
14921        $state->{'menu'}--;
14922        close_menu($text, $stack, $state, $line_nr);
14923    }
14924    if (($format_type{$format} eq 'list') or ($format_type{$format} eq 'table'))
14925    { # those functions return if they detect an inapropriate context
14926        add_item($text, $stack, $state, $line_nr, '', 1); # handle lists
14927        add_term($text, $stack, $state, $line_nr, 1); # handle table
14928        add_line($text, $stack, $state, $line_nr, 1); # handle table
14929        add_row($text, $stack, $state, $line_nr); # handle multitable
14930    }
14931
14932    #print STDERR "END_FORMAT\n";
14933    #dump_stack($text, $stack, $state);
14934
14935    # set to 1 if there is a mismatch between the closed format and format
14936    # opened before
14937    my $format_mismatch = 0;
14938
14939    my $format_ref = pop @$stack;
14940
14941    ######################### debug
14942    if (!defined($format_ref->{'text'}))
14943    {
14944        push @$stack, $format_ref;
14945        print STDERR "Bug: text undef in end_format $format\n";
14946        dump_stack($text, $stack, $state);
14947        pop @$stack;
14948    }
14949    ######################### end debug
14950
14951    if (defined($Texi2HTML::Config::def_map{$format}))
14952    {
14953        close_stack($text, $stack, $state, $line_nr, undef, 'deff_item')
14954           unless ($format_ref->{'format'} eq 'deff_item');
14955        add_prev($text, $stack, &$Texi2HTML::Config::def_item($format_ref->{'text'}));
14956        $format_ref = pop @$stack; # pop deff
14957        ######################################### debug
14958        if (!defined($format_ref->{'format'}) or !defined($Texi2HTML::Config::def_map{$format_ref->{'format'}}))
14959        {
14960             print STDERR "Bug: not a def* under deff_item\n";
14961             push (@$stack, $format_ref);
14962             dump_stack($text, $stack, $state);
14963             pop @$stack;
14964        }
14965        ######################################### end debug
14966        elsif ($format_ref->{'format'} ne $format)
14967        {
14968             $format_mismatch = 1;
14969             echo_warn ("Waiting for \@end $format_ref->{'format'}, found \@end $format", $line_nr);
14970        }
14971        add_prev($text, $stack, &$Texi2HTML::Config::def($format_ref->{'text'}));
14972    }
14973    elsif ($format_type{$format} eq 'cartouche')
14974    {
14975        add_prev($text, $stack, &$Texi2HTML::Config::cartouche($format_ref->{'text'},$state->{'command_stack'}));
14976    }
14977    elsif ($format eq 'float')
14978    {
14979        unless (defined($state->{'float'}))
14980        {
14981            print STDERR "Bug: state->{'float'} not defined in float\n";
14982            next;
14983        }
14984        my ($caption_lines, $shortcaption_lines) = &$Texi2HTML::Config::caption_shortcaption($state->{'float'});
14985        my ($caption_text, $shortcaption_text);
14986        $caption_text = substitute_text(duplicate_state($state), @$caption_lines) if (defined($caption_lines));
14987        $shortcaption_text = substitute_text(duplicate_state($state), @$shortcaption_lines) if (defined($shortcaption_lines));
14988        add_prev($text, $stack, &$Texi2HTML::Config::float($format_ref->{'text'}, $state->{'float'}, $caption_text, $shortcaption_text));
14989        delete $state->{'float'};
14990    }
14991    elsif (exists ($Texi2HTML::Config::complex_format_map->{$format}))
14992    {
14993        $state->{'preformatted'}--;
14994        pop @{$state->{'preformatted_stack'}};
14995        # debug
14996        if (!defined($Texi2HTML::Config::complex_format_map->{$format_ref->{'format'}}->{'begin'}))
14997        {
14998            print STDERR "Bug undef $format_ref->{'format'}" . "->{'begin'} (for $format...)\n";
14999            dump_stack ($text, $stack, $state);
15000        }
15001        #print STDERR "before $format\n";
15002        #dump_stack ($text, $stack, $state);
15003        add_prev($text, $stack, &$Texi2HTML::Config::complex_format($format_ref->{'format'}, $format_ref->{'text'}));
15004        #print STDERR "after $format\n";
15005        #dump_stack ($text, $stack, $state);
15006    }
15007    elsif (($format_type{$format} eq 'table') or ($format_type{$format} eq 'list'))
15008    {
15009	    #print STDERR "CLOSE $format ($format_ref->{'format'})\n$format_ref->{'text'}\n";
15010        pop @{$state->{'table_list_stack'}};
15011	#dump_stack($text, $stack, $state);
15012        if ($format_ref->{'format'} ne $format)
15013        { # for example vtable closing a table. Cannot be known
15014          # before if in a cell
15015             $format_mismatch = 1;
15016             echo_warn ("Waiting for \@end $format_ref->{'format'}, found \@end $format  ", $line_nr);
15017        }
15018        if ($Texi2HTML::Config::format_map{$format})
15019        { # table or list has a simple format
15020            add_prev($text, $stack, end_simple_format($format_ref->{'format'}, $format_ref->{'text'}));
15021        }
15022        else
15023        { # table or list handler defined by the user
15024            add_prev($text, $stack, &$Texi2HTML::Config::table_list($format_ref->{'format'}, $format_ref->{'text'}, $format_ref->{'command'}));
15025        }
15026    }
15027    elsif ($format_type{$format} eq 'menu')
15028    {
15029    # it should be short-circuited if $Texi2HTML::Config::SIMPLE_MENU
15030        if ($state->{'preformatted'})
15031        {
15032            # end the fake complex format
15033            $state->{'preformatted'}--;
15034            pop @{$state->{'preformatted_stack'}};
15035            pop @$stack;
15036        }
15037        add_prev($text, $stack, &$Texi2HTML::Config::menu($format_ref->{'text'}));
15038    }
15039    elsif ($format eq 'quotation')
15040    {
15041        my $quotation_args = pop @{$state->{'quotation_stack'}};
15042        #add_prev($text, $stack, &$Texi2HTML::Config::quotation($format_ref->{'text'}, $quotation_args->{'text'}, $quotation_args->{'style_texi'}, $quotation_args->{'style_id'}));
15043        add_prev($text, $stack, &$Texi2HTML::Config::quotation($format_ref->{'text'}, $quotation_args->{'text'}, $quotation_args->{'text_texi'}));
15044    }
15045    elsif ($Texi2HTML::Config::paragraph_style{$format})
15046    {
15047        if ($state->{'paragraph_style'}->[-1] eq $format)
15048        {
15049            pop @{$state->{'paragraph_style'}};
15050        }
15051        add_prev($text, $stack, &$Texi2HTML::Config::paragraph_style_command($format_ref->{'format'},$format_ref->{'text'}));
15052    }
15053    elsif (exists($Texi2HTML::Config::format_map{$format}))
15054    {
15055        add_prev($text, $stack, end_simple_format($format_ref->{'format'}, $format_ref->{'text'}));
15056    }
15057    else
15058    {
15059        echo_warn("Unknown format $format", $line_nr);
15060    }
15061    # special case for center as it is at the bottom of the stack
15062    my $removed_from_stack;
15063    if ($format eq 'center')
15064    {
15065        $removed_from_stack = shift @{$state->{'command_stack'}};
15066    }
15067    else
15068    {
15069        $removed_from_stack = pop @{$state->{'command_stack'}};
15070    }
15071    if ($removed_from_stack ne $format and !$format_mismatch)
15072    {
15073        print STDERR "Bug: removed_from_stack $removed_from_stack ne format $format\n";
15074    }
15075}
15076
15077sub do_text($;$)
15078{
15079    my $text = shift;
15080    my $state = shift;
15081    return $text if ($state->{'keep_texi'});
15082    my $remove_texi = 1 if ($state->{'remove_texi'} and !$state->{'simple_format'});
15083    return (&$Texi2HTML::Config::normal_text($text, $remove_texi, $state->{'preformatted'}, $state->{'code_style'},$state->{'command_stack'}));
15084}
15085
15086sub end_simple_format($$)
15087{
15088    my $tag = shift;
15089    my $text = shift;
15090
15091    my $element = $Texi2HTML::Config::format_map{$tag};
15092    return &$Texi2HTML::Config::format($tag, $element, $text);
15093}
15094
15095sub close_menu($$$$)
15096{
15097    my $text = shift;
15098    my $stack = shift;
15099    my $state = shift;
15100    my $line_nr = shift;
15101    if ($state->{'menu_comment'})
15102    {
15103        #print STDERR "close MENU_COMMENT\n";
15104        #dump_stack($text, $stack, $state);
15105        close_stack($text, $stack, $state, $line_nr, undef, 'menu_comment');
15106        # close_paragraph isn't needed in most cases, but a preformatted may
15107        # appear after close_stack if we closed a format, as formats reopen
15108        # preformatted. However it is empty and close_paragraph will remove it
15109        close_paragraph($text, $stack, $state);
15110        my $menu_comment = pop @$stack;
15111        if (!$menu_comment->{'format'} or $menu_comment->{'format'} ne 'menu_comment')
15112        {
15113            warn "Bug waiting for menu_comment, got $menu_comment->{'format'}\n";
15114            dump_stack($text, $stack, $state);
15115        }
15116        add_prev($text, $stack, &$Texi2HTML::Config::menu_comment($menu_comment->{'text'}));
15117        unless ($Texi2HTML::Config::SIMPLE_MENU)
15118        {
15119            pop @{$state->{'preformatted_stack'}};
15120            $state->{'preformatted'}--;
15121        }
15122        $state->{'menu_comment'}--;
15123    }
15124    if ($state->{'menu_entry'})
15125    {
15126        close_stack($text, $stack,$state, $line_nr, undef, 'menu_description');
15127        my $descr = pop(@$stack);
15128        print STDERR "# close_menu: close description\n" if ($T2H_DEBUG & $DEBUG_MENU);
15129        add_prev($text, $stack, do_menu_description($descr->{'text'}, $state));
15130        delete $state->{'menu_entry'};
15131    }
15132}
15133
15134# Format menu link
15135sub do_menu_link($$;$)
15136{
15137    my $state = shift;
15138    my $line_nr = shift;
15139    my $simple = shift;
15140    my $menu_entry = $state->{'menu_entry'};
15141    my $file = $state->{'element'}->{'file'};
15142    my $node_name = normalise_node($menu_entry->{'node'});
15143
15144    my $substitution_state = duplicate_state($state);
15145    my $name = substitute_line($menu_entry->{'name'}, $substitution_state);
15146    my $node_formatted = substitute_line($menu_entry->{'node'}, $substitution_state);
15147
15148    my $entry = '';
15149    my $href;
15150    my $element = $nodes{$node_name};
15151
15152    # menu points to an unknown node
15153    if (!$element->{'seen'})
15154    {
15155        if ($menu_entry->{'node'} =~ /^\s*\(.*\)/o or $novalidate)
15156        {
15157            # menu entry points to another info manual or invalid nodes
15158            # and novalidate is set
15159            #$href = $nodes{$node_name}->{'file'};
15160            $href = do_external_href($node_name);
15161        }
15162        else
15163        {
15164            echo_error ("Unknown node in menu entry `$node_name'", $line_nr);
15165            # try to find an equivalent node
15166            my @equivalent_nodes = equivalent_nodes($node_name);
15167            my $node_seen;
15168            foreach my $equivalent_node (@equivalent_nodes)
15169            {
15170                if ($nodes{$equivalent_node}->{'seen'})
15171                {
15172                    $node_seen = $equivalent_node;
15173                    last;
15174                }
15175            }
15176            if (defined($node_seen))
15177            {
15178                echo_warn (" ---> but equivalent node `$node_seen' found");
15179                $element = $nodes{$node_seen};
15180            }
15181        }
15182    }
15183
15184    # the original node or an equivalent node was seen
15185    if ($element->{'seen'})
15186    {
15187        if ($element->{'reference_element'})
15188        {
15189            $element = $element->{'reference_element'};
15190        }
15191
15192        #print STDERR "SUBHREF in menu for `$element->{'texi'}'\n";
15193        $href = href($element, $file);
15194        if (! $element->{'node'})
15195        {
15196            $entry = $element->{'text'}; # this is the section/node name
15197            $entry = "$Texi2HTML::Config::MENU_SYMBOL $entry" if (($entry ne '') and (!defined($element->{'number'}) or ($element->{'number'} =~ /^\s*$/)) and $Texi2HTML::Config::UNNUMBERED_SYMBOL_IN_MENU);
15198        }
15199    }
15200    # save the element used for the href for the description
15201    $menu_entry->{'menu_reference_element'} = $element;
15202
15203    return &$Texi2HTML::Config::menu_link($entry, $substitution_state, $href, $node_formatted, $name, $menu_entry->{'ending'}) unless ($simple);
15204    return &$Texi2HTML::Config::simple_menu_link($entry, $state->{'preformatted'}, $href, $node_formatted, $name, $menu_entry->{'ending'});
15205}
15206
15207sub do_menu_description($$)
15208{
15209    my $descr = shift;
15210    my $state = shift;
15211    my $menu_entry = $state->{'menu_entry'};
15212
15213    my $element = $menu_entry->{'menu_reference_element'};
15214
15215    return &$Texi2HTML::Config::menu_description($descr, duplicate_state($state),$element->{'text_nonumber'});
15216}
15217
15218sub do_xref($$$$)
15219{
15220    my $macro = shift;
15221    my $args = shift;
15222    my $style_stack = shift;
15223    my $state = shift;
15224    my $line_nr = shift;
15225
15226    my $result = '';
15227    my @args = @$args;
15228    #print STDERR "DO_XREF: $macro\n";
15229    my $j = 0;
15230    for ($j = 0; $j <= $#$args; $j++)
15231    {
15232         $args[$j] = normalise_space($args[$j]);
15233    #     print STDERR " ($j)$args[$j]\n";
15234    }
15235    $args[0] = '' if (!defined($args[0]));
15236    my $node_texi = normalise_node($args[0]);
15237    # a ref to a node in an info manual
15238    if ($args[0] =~ s/^\(([^\)]+)\)\s*//)
15239    {
15240        if ($macro eq 'inforef')
15241        {
15242            $args[2] = $1 unless ($args[2]);
15243        }
15244        else
15245        {
15246            $args[3] = $1 unless ($args[3]);
15247        }
15248    }
15249    if (($macro ne 'inforef') and $args[3])
15250    {
15251        $node_texi = "($args[3])" . normalise_node($args[0]);
15252    }
15253
15254    if ($macro eq 'inforef')
15255    {
15256        if ((@args < 1) or ($args[0] eq ''))
15257        {
15258            echo_error ("Need a node name for \@$macro", $line_nr);
15259            return '';
15260        }
15261        if (@args > 3)
15262        {
15263            echo_warn ("Too much arguments for \@$macro", $line_nr);
15264        }
15265        $args[2] = '' if (!defined($args[2]));
15266        $args[1] = '' if (!defined($args[1]));
15267        $node_texi = "($args[2])$args[0]";
15268    }
15269
15270    my $i;
15271    my $new_state = duplicate_state($state);
15272    $new_state->{'keep_texi'} = 0;
15273    $new_state->{'keep_nr'} = 0;
15274    for ($i = 0; $i < 5; $i++)
15275    {
15276        $args[$i] = substitute_line($args[$i], $new_state);
15277    }
15278    #print STDERR "(@args)\n";
15279
15280    if (($macro eq 'inforef') or ($args[3] ne '') or ($args[4] ne ''))
15281    {# external ref
15282        if ($macro eq 'inforef')
15283        {
15284            $macro = 'xref';
15285            $args[3] = $args[2];
15286        }
15287        my $href = '';
15288        my $node_file = '';
15289        if ($args[3] ne '')
15290        {
15291            $href = do_external_href($node_texi);
15292            $node_file = "($args[3])$args[0]";
15293        }
15294        my $section = '';
15295        if ($args[4] ne '')
15296        {
15297            $section = $args[0];
15298            if ($args[2] ne '')
15299            {
15300                $section = $args[2];
15301            }
15302        }
15303        $result = &$Texi2HTML::Config::external_ref($macro, $section, $args[4], $node_file, $href, $args[1]);
15304    }
15305    else
15306    {
15307        my $element = $nodes{$node_texi};
15308        if ($element and $element->{'seen'})
15309        {
15310            if ($element->{'reference_element'})
15311            {
15312                $element = $element->{'reference_element'};
15313            }
15314            my $file = '';
15315            if (defined($state->{'element'}))
15316            {
15317                $file = $state->{'element'}->{'file'};
15318            }
15319            else
15320            {
15321                echo_warn ("\@$macro not in text (in anchor, node, section...)", $line_nr);
15322                # if Texi2HTML::Config::SPLIT the file is '' which ensures
15323                # a href with the file name. if ! Texi2HTML::Config::SPLIT
15324                # the 2 file will be the same thus there won't be the file name
15325                $file = $element->{'file'} unless ($Texi2HTML::Config::SPLIT);
15326            }
15327	    #print STDERR "SUBHREF in ref to node `$node_texi': $_";
15328            my $href = href($element, $file);
15329            my $section = $args[2];
15330            $section = $args[1] if ($section eq '');
15331            my $name = $section;
15332            my $short_name = $section;
15333            if ($section eq '')
15334            {
15335                # FIXME maybe one should use 'text' instead of 'text_nonumber'
15336                # However the real fix would be to have an internal_ref call
15337                # with more informations
15338                $name = $element->{'text_nonumber'};
15339                $short_name = $args[0];
15340            }
15341            $result = &$Texi2HTML::Config::internal_ref ($macro, $href, $short_name, $name, $element->{'section'});
15342        }
15343        else
15344        {
15345           if (($node_texi eq '') or !$novalidate)
15346           {
15347               echo_error ("Undefined node `$node_texi' in \@$macro", $line_nr);
15348               my $text = '';
15349               for (my $i = 0; $i < @$args -1; $i++)
15350               {
15351                    $text .= $args->[$i] .',';
15352               }
15353               $text .= $args->[-1];
15354               $result = "\@$macro"."{${text}}";
15355           }
15356           else
15357           {
15358               $result = &$Texi2HTML::Config::external_ref($macro, '', '', $args[0], do_external_href($node_texi), $args[1]);
15359           }
15360        }
15361    }
15362    return $result;
15363}
15364
15365sub do_acronym_like($$$$$)
15366{
15367    my $command = shift;
15368    my $args = shift;
15369    my $acronym_texi = shift @$args;
15370    my $explanation = shift @$args;
15371    my $style_stack = shift;
15372    my $state = shift;
15373    my $line_nr = shift;
15374
15375    my $explanation_lines;
15376    my $explanation_text;
15377    my $explanation_simple_format;
15378
15379    if (defined($explanation))
15380    {
15381        $explanation =~ s/^\s*//;
15382        $explanation =~ s/\s*$//;
15383        $explanation = undef if ($explanation eq '');
15384    }
15385    $acronym_texi =~ s/^\s*//;
15386    $acronym_texi =~ s/\s*$//;
15387
15388    return '' if ($acronym_texi eq '');
15389
15390    my $with_explanation = 0;
15391    my $normalized_text =  cross_manual_line(normalise_node($acronym_texi));
15392    if (defined($explanation))
15393    {
15394        $with_explanation = 1;
15395        $acronyms_like{$command}->{$normalized_text} = $explanation;
15396    }
15397    elsif (exists($acronyms_like{$command}->{$normalized_text}))
15398    {
15399        $explanation = $acronyms_like{$command}->{$normalized_text};
15400    }
15401
15402    if (defined($explanation))
15403    {
15404         @$explanation_lines = map {$_ = $_."\n"} split (/\n/, $explanation);
15405         my $text = '';
15406         foreach my $line(@$explanation_lines)
15407         {
15408              $line .= ' ' if (chomp ($line));
15409              $text .= $line
15410         }
15411         $text =~ s/ $//;
15412         my $simple_format_state = duplicate_state($state);
15413         $explanation_simple_format = simple_format($simple_format_state,$text);
15414         $explanation_text = substitute_line($text, duplicate_state($state));
15415    }
15416    return &$Texi2HTML::Config::acronym_like($command, $acronym_texi, substitute_line($acronym_texi, duplicate_state($state)),
15417       $with_explanation, $explanation_lines, $explanation_text, $explanation_simple_format);
15418}
15419
15420sub do_caption_shortcaption($$$$$)
15421{
15422    my $command = shift;
15423    my $args = shift;
15424    my $text = $args->[0];
15425    my $style_stack = shift;
15426    my $state = shift;
15427    my $line_nr = shift;
15428
15429    if (!exists($state->{'float'}))
15430    {
15431#dump_stack(\"", [], $state);
15432         echo_error("\@$command outside of float", $line_nr);
15433         return '';
15434    }
15435    my $float = $state->{'float'};
15436    my @texi_lines = map {$_ = $_."\n"} split (/\n/, $text);
15437    $float->{"${command}_texi"} = \@texi_lines;
15438    return '';
15439}
15440
15441# function called when a @float is encountered. Don't do any output
15442# but prepare $state->{'float'}
15443sub do_float_line($$$$$)
15444{
15445    my $command = shift;
15446    my $args = shift;
15447    my @args = @$args;
15448    my $style_texi = shift @args;
15449    my $label_texi = shift @args;
15450    my $style_stack = shift;
15451    my $state = shift;
15452    my $line_nr = shift;
15453
15454    $style_texi = undef if (defined($style_texi) and $style_texi=~/^\s*$/);
15455    $label_texi = undef if (defined($label_texi) and $label_texi=~/^\s*$/);
15456    if (defined($label_texi))
15457    { # the float is considered as a node as it may be a target for refs.
15458      # it was entered as a node in the pass_structure and the float
15459      # line was parsed at that time
15460         $state->{'float'} = $nodes{normalise_node($label_texi)};
15461         #print STDERR "float: $state->{'float'}, $state->{'float'}->{'texi'}\n";
15462    }
15463    else
15464    { # a float without label. It can't be the target for refs.
15465         $state->{'float'} = { 'float' => 1 };
15466         if (defined($style_texi))
15467         {
15468              $state->{'float'}->{'style_texi'} = normalise_space($style_texi);
15469              $state->{'float'}->{'style_id'} =
15470                  cross_manual_line($state->{'float'}->{'style_texi'});
15471              $state->{'float'}->{'style'} = substitute_line($style_texi);
15472         }
15473         #print STDERR "float: (no label) $state->{'float'}\n";
15474    }
15475    return '';
15476}
15477
15478sub do_quotation_line($$$$$)
15479{
15480    my $command = shift;
15481    my $args = shift;
15482    my @args = @$args;
15483    my $text_texi = shift @args;
15484    my $style_stack = shift;
15485    my $state = shift;
15486    my $line_nr = shift;
15487    my $text;
15488
15489    $text_texi = undef if (defined($text_texi) and $text_texi=~/^\s*$/);
15490    if (defined($text_texi))
15491    {
15492         $text = substitute_line($text_texi, duplicate_state($state));
15493         $text =~ s/\s*$//;
15494    }
15495    my $quotation_args = { 'text' => $text, 'text_texi' => $text_texi };
15496    push @{$state->{'quotation_stack'}}, $quotation_args;
15497    $state->{'prepend_text'} = &$Texi2HTML::Config::quotation_prepend_text($text_texi);
15498    return '';
15499}
15500
15501sub do_def_line($$$$$)
15502{
15503    my $command = shift;
15504    my $args = shift;
15505    my @args = @$args;
15506    my $arguments = shift @args;
15507    my $style_stack = shift;
15508    my $state = shift;
15509    my $line_nr = shift;
15510
15511    $state->{'deff_line'}->{'arguments'} = $arguments;
15512    return '';
15513}
15514
15515sub do_footnote($$$$)
15516{
15517    my $command = shift;
15518    my $args = shift;
15519    my $text = $args->[0];
15520    my $style_stack = shift;
15521    my $state = shift;
15522    my $line_nr = shift;
15523
15524    $text .= "\n";
15525    $foot_num++;
15526    $relative_foot_num++;
15527    my $docid  = "DOCF$foot_num";
15528    my $footid = "FOOT$foot_num";
15529    my $from_file = '';
15530    if ($state->{'element'} and $Texi2HTML::Config::SPLIT and $Texi2HTML::Config::SEPARATED_FOOTNOTES)
15531    {
15532        $from_file = $state->{'element'}->{'file'};
15533    }
15534    my %state;
15535    initialise_state(\%state);
15536    if ($Texi2HTML::Config::SEPARATED_FOOTNOTES)
15537    {
15538        $state{'element'} = $footnote_element;
15539    }
15540    else
15541    {
15542        $state{'element'} = $state->{'element'};
15543    }
15544    my $file = '';
15545    $file = $docu_foot if ($Texi2HTML::Config::SPLIT and $Texi2HTML::Config::SEPARATED_FOOTNOTES);
15546
15547    # FIXME use split_lines ? It seems to work like it is now ?
15548    my @lines = substitute_text(\%state, map {$_ = $_."\n"} split (/\n/, $text));
15549    my ($foot_lines, $foot_label) = &$Texi2HTML::Config::foot_line_and_ref ($foot_num,
15550         $relative_foot_num, $footid, $docid, $from_file, $file, \@lines, $state);
15551    push(@foot_lines, @{$foot_lines});
15552    return $foot_label;
15553}
15554
15555sub do_image($$$$)
15556{
15557    # replace images
15558    my $command = shift;
15559    my $args = shift;
15560    my $text = $args->[0];
15561    my $style_stack = shift;
15562    my $state = shift;
15563    my $line_nr = shift;
15564    $text =~ s/\s+/ /gos; # remove useless spaces and newlines
15565    my @args = split (/\s*,\s*/, $text);
15566    my $base = $args[0];
15567    if ($base eq '')
15568    {
15569         echo_error ("no file argument for \@image", $line_nr);
15570         #warn "$ERROR no file argument for \@image\n";
15571         return '';
15572    }
15573    $args[4] = '' if (!defined($args[4]));
15574    $args[3] = '' if (!defined($args[3]));
15575    my $image;
15576    my $file_name;
15577    my @file_names = &$Texi2HTML::Config::image_files($base,$args[4]);
15578#    $image = locate_include_file("$base.$args[4]") if ($args[4] ne '');
15579    foreach my $file (@file_names)
15580    {
15581         if ($image = locate_include_file($file))
15582         {
15583              $file_name = $file;
15584              last;
15585         }
15586    }
15587    $image = '' if (!defined($image));
15588
15589    my $alt;
15590    if ($args[3] =~ /\S/)
15591    {
15592        # makeinfo don't do that. Maybe it should be remove_texi or
15593        # simple_format... The raw alt is also given in argument
15594        $alt = do_text($args[3]);
15595        $alt = $alt if ($alt =~ /\S/);
15596    }
15597    return &$Texi2HTML::Config::image($path_to_working_dir . $image, $base,
15598        $state->{'preformatted'}, $file_name, $alt, $args[1], $args[2],
15599        $args[3], $args[4], $path_to_working_dir, $image);
15600}
15601
15602sub duplicate_state($)
15603{
15604    my $state = shift;
15605    my $new_state = { 'element' => $state->{'element'},
15606           'preformatted' => $state->{'preformatted'},
15607           'code_style' => $state->{'code_style'},
15608           'keep_texi' => $state->{'keep_texi'},
15609           'keep_nr' => $state->{'keep_nr'},
15610           'preformatted_stack' => $state->{'preformatted_stack'},
15611           'multiple_pass' => $state->{'multiple_pass'},
15612# this is needed for preformatted
15613           'command_stack' => [ @{$state->{'command_stack'}}  ],
15614           'preformatted_context' =>
15615                {'stack_at_beginning' => [ @{$state->{'command_stack'}}  ] }
15616    };
15617    return $new_state;
15618}
15619
15620sub expand_macro($$$$$)
15621{
15622    my $name = shift;
15623    my $args = shift;
15624    my $end_line = shift;
15625    my $line_nr = shift;
15626    my $state = shift;
15627
15628    # we dont expand macros when in ignored environment.
15629    return if ($state->{'ignored'});
15630    my $index = 0;
15631    foreach my $arg (@$args)
15632    { # expand @macros in arguments. It is complicated because we must be
15633      # carefull not to expand macros in @ignore section or the like, and
15634      # still keep every single piece of text (including the @ignore macros).
15635        $args->[$index] = substitute_text({'texi' => 1, 'arg_expansion' => 1}, split_lines($arg));
15636        $index++;
15637    }
15638    # retrieve the macro definition
15639    my $macrobody = $macros->{$name}->{'body'};
15640    my $formal_args = $macros->{$name}->{'args'};
15641    my $args_index =  $macros->{$name}->{'args_index'};
15642    my $i;
15643
15644    die "Bug end_line not defined" if (!defined($end_line));
15645
15646    for ($i=0; $i<=$#$formal_args; $i++)
15647    {
15648        $args->[$i] = "" unless (defined($args->[$i]));
15649        print STDERR "# arg($i): $args->[$i]\n" if ($T2H_DEBUG & $DEBUG_MACROS);
15650    }
15651    echo_error ("too much arguments for macro $name", $line_nr) if (defined($args->[$i + 1]));
15652    my $result = '';
15653    while ($macrobody)
15654    {
15655        if ($macrobody =~ s/^([^\\]*)\\//o)
15656        {
15657            $result .= $1 if defined($1);
15658            if ($macrobody =~ s/^\\//)
15659            {
15660                $result .= '\\';
15661            }
15662            elsif ($macrobody =~ s/^(\@end\sr?macro)$// or $macrobody =~ s/^(\@end\sr?macro\s)// or $macrobody =~ s/^(\@r?macro\s+\w+\s*.*)//)
15663            { # \ protect @end macro
15664                $result .= $1;
15665            }
15666            elsif ($macrobody =~ s/^([^\\]*)\\//)
15667            {
15668               my $arg = $1;
15669               if (defined($args_index->{$arg}))
15670               {
15671                   $result .= $args->[$args_index->{$arg}];
15672               }
15673               else
15674               {
15675                   warn "$ERROR \\ not followed by \\ or an arg but by $arg in macro\n";
15676                   $result .= '\\' . $arg;
15677               }
15678            }
15679            next;
15680        }
15681        $result .= $macrobody;
15682        last;
15683    }
15684    my @result = split(/^/m, $result);
15685    # Add the result of the macro expansion back to the input_spool.
15686    # Set the macro name if in the outer macro
15687    if ($state->{'arg_expansion'})
15688    {
15689        unshift @{$state->{'spool'}}, (@result, $end_line);
15690    }
15691    else
15692    {
15693        unshift @{$input_spool->{'spool'}}, (@result, $end_line);
15694        $input_spool->{'macro'} = $name if ($input_spool->{'macro'} eq '');
15695    }
15696    if ($T2H_DEBUG & $DEBUG_MACROS)
15697    {
15698        print STDERR "# macro expansion result:\n";
15699        #print STDERR "$first_line";
15700        foreach my $line (@result)
15701        {
15702            print STDERR "$line";
15703        }
15704        print STDERR "# macro expansion result end\n";
15705    }
15706}
15707
15708sub do_index_summary_file($)
15709{
15710    my $name = shift;
15711    my ($pages, $entries) = get_index($name);
15712    &$Texi2HTML::Config::index_summary_file_begin ($name, $printed_indices{$name});
15713    print STDERR "# writing $name index summary\n" if $T2H_VERBOSE;
15714
15715    foreach my $key (sort keys %$entries)
15716    {
15717        my $entry = $entries->{$key};
15718        my $indexed_element = $entry->{'element'};
15719        my $entry_element = $indexed_element;
15720        # notice that we use the section associated with a node even when
15721        # there is no with_section, i.e. when there is another node preceding
15722        # the sectionning command.
15723        # However when it is the Top node, we use the node instead.
15724        # (for the Top node, 'top_as_section' is true)
15725        $entry_element = $entry_element->{'section_ref'} if ($entry_element->{'section_ref'} and !$entry_element->{'top_as_section'});
15726        my $origin_href = $entry->{'file'};
15727   #print STDERR "$entry $entry->{'entry'}, real elem $indexed_element->{'texi'}, section $entry_element->{'texi'}, real $indexed_element->{'file'}, entry file $entry->{'file'}\n";
15728        if ($entry->{'label'})
15729        {
15730             $origin_href .= '#' . $entry->{'label'};
15731        }
15732        else
15733        {
15734            # If the $indexed_element element and the $index entry are on
15735            # the same
15736            # file the real element is prefered. If they aren't on the same file
15737            # the entry id is choosed as it means that the real element
15738            # and the index entry are separated by a printindex.
15739            print STDERR "id undef ($entry) entry: $entry->{'entry'}, label: $indexed_element->{'text'}\n"  if (!defined($entry->{'id'}));
15740            if ($entry->{'file'} eq $indexed_element->{'file'})
15741            {
15742                $origin_href .= '#' . $indexed_element->{'id'};
15743            }
15744            else
15745            {
15746                $origin_href .= '#' . $entry->{'id'} ;
15747            }
15748        }
15749        &$Texi2HTML::Config::index_summary_file_entry ($name,
15750          $key, $origin_href,
15751          substitute_line($entry->{'entry'}), $entry->{'entry'},
15752          href($entry_element, ''),
15753          $entry_element->{'text'},
15754          $printed_indices{$name});
15755    }
15756    &$Texi2HTML::Config::index_summary_file_end ($name, $printed_indices{$name});
15757}
15758
15759sub do_index_page($$;$)
15760{
15761    my $index_elements = shift;
15762    my $nr = shift;
15763    my $page = shift;
15764    my $index_element = $index_elements->[$nr];
15765    my $summary = do_index_summary($index_element->{'element'}, $index_elements);
15766    my $entries = do_index_entries($index_element->{'element'}, $index_element->{'page'}, $index_element->{'name'});
15767    return $summary . $entries . $summary;
15768}
15769
15770sub do_index_summary($$)
15771{
15772    my $element = shift;
15773    my $index_elements = shift;
15774
15775    my @letters;
15776    my @symbols;
15777
15778    for my $index_element_item (@$index_elements)
15779    {
15780        my $index_element = $index_element_item->{'element'};
15781        my $file = '';
15782        $file .= $index_element->{'file'} if ($index_element->{'file'} ne $element->{'file'});
15783        my $index = 0;
15784        for my $letter (@{$index_element_item->{'page'}->{'letters'}})
15785        {
15786            if ($letter =~ /^[A-Za-z]/)
15787            {
15788                push @letters, &$Texi2HTML::Config::summary_letter($letter, $file, "$index_element->{'id'}" . "_$index");
15789            }
15790            else
15791            {
15792                push @symbols, &$Texi2HTML::Config::summary_letter($letter, $file, "$index_element->{'id'}" . "_$index");
15793            }
15794            $index++;
15795        }
15796    }
15797    return &$Texi2HTML::Config::index_summary(\@letters, \@symbols);
15798}
15799
15800sub do_index_entries($$$)
15801{
15802    my $element = shift;
15803    my $page = shift;
15804    my $name = shift;
15805
15806    my $letters = '';
15807    my $index = 0;
15808    foreach my $letter (@{$page->{'letters'}})
15809    {
15810       my $entries = '';
15811       foreach my $entry (@{$page->{'entries_by_letter'}->{$letter}})
15812       {
15813           my $indexed_element = $entry->{'element'};
15814           my $entry_element = $indexed_element;
15815           # notice that we use the section associated with a node even when
15816           # there is no with_section, i.e. when there is another node preceding
15817           # the sectionning command.
15818           # However when it is the Top node, we use the node instead.
15819           # (for the Top node, 'top_as_section' is true)
15820           $entry_element = $entry_element->{'section_ref'} if ($entry_element->{'section_ref'} and !$entry_element->{'top_as_section'});
15821           my $origin_href = '';
15822           $origin_href = $entry->{'file'} if ($Texi2HTML::Config::SPLIT and $entry->{'file'} ne $element->{'file'});
15823	   #print STDERR "$entry $entry->{'entry'}, real elem $indexed_element->{'texi'}, section $entry_element->{'texi'}, real $indexed_element->{'file'}, entry file $entry->{'file'}\n";
15824           if ($entry->{'label'})
15825           {
15826               $origin_href .= '#' . $entry->{'label'};
15827           }
15828	   else
15829           {
15830               # If the $indexed_element element and the $index entry are
15831               # in the same file the indexed_element is prefered. If they
15832               # aren't in the same file the entry id is choosed as it means
15833               # that the indexed_element element and the index entry are
15834               # separated by a printindex.
15835               print STDERR "id undef ($entry) entry: $entry->{'entry'}, label: $indexed_element->{'text'}\n"  if (!defined($entry->{'id'}));
15836               if ($entry->{'file'} eq $indexed_element->{'file'})
15837               {
15838                   $origin_href .= '#' . $indexed_element->{'id'};
15839               }
15840               else
15841               {
15842                   $origin_href .= '#' . $entry->{'id'} ;
15843               }
15844           }
15845	   #print STDERR "SUBHREF in index entry `$entry->{'entry'}' for `$entry_element->{'texi'}'\n";
15846           $entries .= &$Texi2HTML::Config::index_entry ($origin_href,
15847                     substitute_line($entry->{'entry'}),
15848                     href($entry_element, $element->{'file'}),
15849                     $entry_element->{'text'});
15850        }
15851        $letters .= &$Texi2HTML::Config::index_letter ($letter, "$element->{'id'}" . "_$index", $entries);
15852        $index++;
15853    }
15854    return &$Texi2HTML::Config::print_index($letters, $name);
15855}
15856
15857# remove texi commands, replacing with what seems adequate. see simple_map_texi
15858# and texi_map.
15859# Doesn't protect html
15860sub remove_texi(@)
15861{
15862    return substitute_text ({ 'remove_texi' => 1}, @_);
15863}
15864
15865# Same as remove texi but protect text and use special maps for @-commands
15866sub simple_format($@)
15867{
15868    my $state = shift;
15869    $state = {} if (!defined($state));
15870    $state->{'remove_texi'} = 1;
15871    $state->{'simple_format'} = 1;
15872    # WARNING currently it is only used for lines. It may change in the future.
15873    $state->{'no_paragraph'} = 1;
15874    $::simple_map_texi_ref = \%Texi2HTML::Config::simple_format_simple_map_texi;
15875    $::style_map_texi_ref = \%Texi2HTML::Config::simple_format_style_map_texi;
15876    $::texi_map_ref = \%Texi2HTML::Config::simple_format_texi_map;
15877    my $text = substitute_text($state, @_);
15878    $::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi;
15879    $::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi;
15880    $::texi_map_ref = \%Texi2HTML::Config::texi_map;
15881    return $text;
15882}
15883
15884sub enter_table_index_entry($$$$)
15885{
15886    my $text = shift;
15887    my $stack = shift;
15888    my $state = shift;
15889    my $line_nr = shift;
15890    if ($state->{'item'} and ($state->{'table_stack'}->[-1] =~ /^(v|f)table$/))
15891    {
15892         my $index = $1;
15893         my $macro = $state->{'item'};
15894         delete $state->{'item'};
15895         close_stack($text, $stack, $state, $line_nr, undef, 'index_item');
15896         my $item = pop @$stack;
15897         my $element = $state->{'element'};
15898         $element = $state->{'node_ref'} unless ($element);
15899         enter_index_entry($index, $line_nr, $item->{'text'},
15900            $state->{'place'}, $element, 0, $state->{'table_stack'}->[-1]);
15901         add_prev($text, $stack, "\@$macro" . $item->{'text'});
15902    }
15903}
15904
15905sub scan_texi($$$$;$)
15906{
15907    my $line = shift;
15908    my $text = shift;
15909    my $stack = shift;
15910    my $state = shift;
15911    my $line_nr = shift;
15912
15913    die "stack not an array ref"  unless (ref($stack) eq "ARRAY");
15914    local $_ = $line;
15915
15916    while(1)
15917    {
15918        # scan_texi
15919        #print STDERR "WHILE:$_";
15920        #print STDERR "ARG_EXPANSION: $state->{'arg_expansion'}\n" if ($state->{'arg_expansion'});
15921        #dump_stack($text, $stack, $state);
15922        #print STDERR "ifvalue_inside $state->{'ifvalue_inside'}\n";
15923
15924
15925        # first we handle special cases:
15926        # macro definition: $state->{'macro_inside'}
15927        # macro arguments:  $state->{'macro_name'}
15928        # raw format:       $state->{'raw'}
15929        # @verb:            $state->{'verb'}
15930        # ignored:          $state->{'ignored'}
15931        # and then the remaining text/macros.
15932
15933        # in macro definition
15934        if ($state->{'macro_inside'})
15935        {
15936            if (s/^([^\\\@]*\\)//)
15937            {# protected character or @end macro
15938                 $state->{'macro'}->{'body'} .= $1 unless ($state->{'ignored'});
15939                 if (s/^\\//)
15940                 {
15941                      $state->{'macro'}->{'body'} .= '\\' unless ($state->{'ignored'});
15942                      next;
15943                 }
15944                 # I believe it is correct, although makeinfo don't do that.
15945                 elsif (s/^(\@end\sr?macro)$//o or s/^(\@end\sr?macro\s)//o
15946                      or s/^(\@r?macro\s+\w+\s*.*)//o)
15947                 {
15948                      $state->{'macro'}->{'body'} .= $1 unless ($state->{'ignored'});
15949                      next;
15950                 }
15951            }
15952            #if (s/^(.*?)\@end\sr?macro$//o or s/^(.*?)\@end\sr?macro\s+//o)
15953            if (s/^(\@end\sr?macro)$//o or s/^(\@end\sr?macro\s+)//o)
15954            {
15955                 $state->{'macro_inside'}--;
15956                 next if ($state->{'ignored'});
15957                 if ($state->{'macro_inside'})
15958                 {
15959                     $state->{'macro'}->{'body'} .= $1;
15960                     next;
15961                 }
15962                 chomp $state->{'macro'}->{'body'};
15963                 print STDERR "# end macro def. Body:\n$state->{'macro'}->{'body'}"
15964                     if ($T2H_DEBUG & $DEBUG_MACROS);
15965                 delete $state->{'macro'};
15966                 return if (/^\s*$/);
15967                 next;
15968            }
15969            elsif(/^(\@r?macro\s+\w+\s*.*)/)
15970            {
15971                 $state->{'macro'}->{'body'} .= $_ unless ($state->{'ignored'});
15972                 $state->{'macro_inside'}++;
15973                 return;
15974            }
15975            elsif (s/^\@(.)//)
15976            {
15977                 $state->{'macro'}->{'body'} .= '@' . $1 unless ($state->{'ignored'});
15978                 next;
15979            }
15980            elsif (s/^\@//)
15981            {
15982                 $state->{'macro'}->{'body'} .= '@' unless ($state->{'ignored'});
15983                 next;
15984            }
15985            else
15986            {
15987                 s/([^\@\\]*)//;
15988                 if ($state->{'ignored'})
15989                 {
15990                     return if (/^$/);
15991                     next;
15992                 }
15993                 $state->{'macro'}->{'body'} .= $1 if (defined($1));
15994                 if (/^$/)
15995                 {
15996                      $state->{'macro'}->{'body'} .= $_;
15997                      return;
15998                 }
15999                 next;
16000            }
16001        }
16002        # in macro arguments parsing/expansion. Here \ { } and , if this is a
16003        # multi args macro have a signification, the remaining is passed
16004        # unmodified
16005        if (defined($state->{'macro_name'}))
16006        {
16007            my $special_chars = quotemeta ('\{}');
16008            my $multi_args = 0;
16009            my $formal_args = $macros->{$state->{'macro_name'}}->{'args'};
16010            $multi_args = 1 if ($#$formal_args >= 1);
16011            $special_chars .= quotemeta(',') if ($multi_args);
16012            if ($state->{'macro_args'}->[-1] eq '')
16013            {# remove space at the very beginning
16014                s/^\s*//o;
16015            }
16016            if (s/^([^$special_chars]*)([$special_chars])//)
16017            {
16018                $state->{'macro_args'}->[-1] .= $1 if defined($1);
16019                # \ protects any character in macro arguments
16020                if ($2 eq '\\')
16021                {
16022                    print STDERR "# macro call: protected char\n" if ($T2H_DEBUG & $DEBUG_MACROS);
16023                    if (s/^(.)//)
16024                    {
16025                        $state->{'macro_args'}->[-1] .= $1;
16026                    }
16027                    else
16028                    {
16029                        $state->{'macro_args'}->[-1] .= '\\';
16030                    }
16031                }
16032                elsif ($2 eq ',')
16033                { # in texinfo 4.8.90 a comma in braces is protected
16034                    if ($state->{'macro_depth'} > 1)
16035                    {
16036                        $state->{'macro_args'}->[-1] .= ',';
16037                    }
16038                    else
16039                    { # separate args
16040                        print STDERR "# macro call: new arg\n" if ($T2H_DEBUG & $DEBUG_MACROS);
16041                        s/^\s*//o;
16042                        push @{$state->{'macro_args'}}, '';
16043                    }
16044                }
16045                elsif ($2 eq '}')
16046                { # balanced } ends the macro call, otherwise it is in the arg
16047                    $state->{'macro_depth'}--;
16048                    if ($state->{'macro_depth'} == 0)
16049                    {
16050                        print STDERR "# expanding macro $state->{'macro_name'}\n" if ($T2H_DEBUG & $DEBUG_MACROS);
16051                        $_ = expand_macro($state->{'macro_name'}, $state->{'macro_args'}, $_, $line_nr, $state);
16052                        delete $state->{'macro_name'};
16053                        delete $state->{'macro_depth'};
16054                        delete $state->{'macro_args'};
16055                        return;
16056                    }
16057                    else
16058                    {
16059                        print STDERR "# macro call: closing }\n" if ($T2H_DEBUG & $DEBUG_MACROS);
16060                        add_text('}', \$state->{'macro_args'}->[-1]);
16061                    }
16062                }
16063                elsif ($2 eq '{')
16064                {
16065                    print STDERR "# macro call: opening {\n" if ($T2H_DEBUG & $DEBUG_MACROS);
16066                    $state->{'macro_depth'}++;
16067                    add_text('{', \$state->{'macro_args'}->[-1]);
16068                }
16069                next;
16070            }
16071            print STDERR "# macro call: end of line\n" if ($T2H_DEBUG & $DEBUG_MACROS);
16072            $state->{'macro_args'}->[-1] .= $_;
16073            return;
16074        }
16075        # in a raw format, verbatim, tex or html
16076        if ($state->{'raw'})
16077        {
16078            my $tag = $state->{'raw'};
16079
16080            # debugging
16081            if (! @$stack or ($stack->[-1]->{'style'} ne $tag))
16082            {
16083                print STDERR "Bug: raw or special: $tag but not on top of stack\n";
16084                print STDERR "line: $_";
16085                dump_stack($text, $stack, $state);
16086                exit 1;
16087            }
16088
16089            if (s/^(.*?)(\@end\s$tag)$// or s/^(.*?)(\@end\s$tag\s)//)
16090            {# we add it even if 'ignored', it'll be discarded when there is
16091             # the @end
16092                add_prev ($text, $stack, $1);
16093                my $end = $2;
16094                my $style = pop @$stack;
16095                if ($style->{'text'} !~ /^\s*$/ or $state->{'arg_expansion'})
16096                # FIXME if 'arg_expansion' and also 'ignored' is true,
16097                # theoretically we should keep
16098                # what is in the raw format however
16099                # it will be removed later anyway
16100                {# ARG_EXPANSION
16101                    my $after_macro = '';
16102                    $after_macro = ' ' unless (/^\s*$/);
16103                    add_prev ($text, $stack, $style->{'text'} . $end . $after_macro) unless ($state->{'ignored'});
16104                    delete $state->{'raw'};
16105                }
16106                next;
16107            }
16108            else
16109            {# we add it even if 'ignored', it'll be discarded when there is
16110             # the @end
16111                 add_prev ($text, $stack, $_);
16112                 last;
16113            }
16114        }
16115
16116        # in a @verb{ .. } macro
16117        if (defined($state->{'verb'}))
16118        {
16119            #dump_stack($text, $stack, $state);
16120            my $char = quotemeta($state->{'verb'});
16121            #print STDERR "VERB $char\n";
16122            if (s/^(.*?)$char\}/\}/)
16123            {# we add it even if 'ignored', it'll be discarded when closing
16124                 add_prev($text, $stack, $1 . $state->{'verb'});
16125                 $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'};
16126                 delete $state->{'verb'};
16127                 next;
16128            }
16129            else
16130            {# we add it even if 'ignored', it'll be discarded when closing
16131                 add_prev($text, $stack, $_);
16132                 last;
16133            }
16134        }
16135        # In ignored region
16136        if ($state->{'ignored'})
16137        {
16138            #print STDERR "IGNORED(ifvalue($state->{'ifvalue_inside'})): $state->{'ignored'}\n";
16139            if (/^.*?\@end(\s+)([a-zA-Z]\w+)/)
16140            {
16141                if ($2 eq $state->{'ignored'})
16142                {
16143                    s/^(.*?\@end)(\s+)([a-zA-Z]\w+)//;
16144                    my $end_ignore = $1.$2.$3;
16145                    if (($state->{'ifvalue_inside'}) and $state->{'ignored'} eq $state->{'ifvalue'})
16146                    {
16147                         if ($state->{'ifvalue_inside'} == 1)
16148                         {# closing still opened @-commands with braces
16149                             pop (@$stack) while (@$stack and $stack->[-1]->{'style'} ne 'ifvalue')
16150                         }
16151                         pop (@$stack);
16152                         $state->{'ifvalue_inside'}--;
16153                    }
16154                    $state->{'ignored'} = undef;
16155                    delete $state->{'ignored'};
16156                    # We are stil in the ignored ifset or ifclear section
16157                    $state->{'ignored'} = $state->{'ifvalue'} if ($state->{'ifvalue_inside'});
16158                    #dump_stack($text, $stack, $state);
16159                    # MACRO_ARG => keep ignored text
16160                    if ($state->{'arg_expansion'})
16161                    {# this may not be very usefull as it'll be remove later
16162                        add_prev ($text, $stack, $end_ignore);
16163                        next;
16164                    }
16165                    return if /^\s*$/o;
16166                    next;
16167                }
16168            }
16169            add_prev ($text, $stack, $_) if ($state->{'arg_expansion'});
16170            # we could theoretically continue for ignored commands other
16171            # than ifset or ifclear, however it isn't usefull.
16172            return unless ($state->{'ifvalue_inside'} and ($state->{'ignored'} eq $state->{'ifvalue'}));
16173        }
16174
16175
16176        # an @end tag
16177        # macro_regexp
16178        if (s/^([^{}@]*)\@end(\s+)([a-zA-Z][\w-]*)//)
16179        {
16180            my $leading_text = $1;
16181            my $space = $2;
16182            my $end_tag = $3;
16183            # when 'ignored' we don't open environments that aren't associated
16184            # with ignored regions, so we don't need to close them.
16185            next if ($state->{'ignored'});# ARG_EXPANSION
16186            add_prev($text, $stack, $leading_text);
16187            if (defined($state->{'text_macro_stack'})
16188               and @{$state->{'text_macro_stack'}}
16189               and ($end_tag eq $state->{'text_macro_stack'}->[-1]))
16190            {
16191                pop @{$state->{'text_macro_stack'}};
16192                # we keep menu and titlepage for the following pass
16193                if ((($end_tag eq 'menu') and $text_macros{'menu'}) or ($region_lines{$end_tag}) or $state->{'arg_expansion'})
16194                {
16195                     add_prev($text, $stack, "\@end${space}$end_tag");
16196                }
16197                else
16198                {
16199                    #print STDERR "End $end_tag\n";
16200                    #dump_stack($text, $stack, $state);
16201                    return if (/^\s*$/);
16202                }
16203            }
16204            elsif ($text_macros{$end_tag})
16205            {
16206                echo_error ("\@end $end_tag without corresponding element", $line_nr);
16207            }
16208            else
16209            {# ARG_EXPANSION
16210                add_prev($text, $stack, "\@end${space}$end_tag");
16211            }
16212            next;
16213        }
16214        # macro_regexp
16215        elsif (s/^([^{}@]*)\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/])//o or s/^([^{}@]*)\@([a-zA-Z][\w-]*)([\s\{\}\@])/$3/o or s/^([^{}@]*)\@([a-zA-Z][\w-]*)$//o)
16216        {# ARG_EXPANSION
16217            add_prev($text, $stack, $1) unless $state->{'ignored'};
16218            my $macro = $2;
16219	    #print STDERR "MACRO $macro\n";
16220            # handle skipped @-commands
16221            $state->{'bye'} = 1 if ($macro eq 'bye' and !$state->{'ignored'} and !$state->{'arg_expansion'});
16222            if (defined($Texi2HTML::Config::misc_command{$macro}) and
16223                 !$Texi2HTML::Config::misc_command{$macro}->{'texi'}
16224                 and $macro ne 'documentencoding')
16225            {# ARG_EXPANSION
16226                 my ($line, $args);
16227                 ($_, $line, $args) = preserve_command($_, $macro);
16228                 add_prev ($text, $stack, "\@$macro" . $line) unless $state->{'ignored'};
16229            }
16230            # pertusus: it seems that value substitution are performed after
16231            # macro argument expansions: if we have
16232            # @set comma ,
16233            # and a call to a macro @macro {arg1 @value{comma} arg2}
16234            # the macro arg is arg1 , arg2 and the comma don't separate
16235            # args. Likewise it seems that the @value are not expanded
16236            # in macro definitions
16237
16238            # track variables
16239            elsif($macro eq 'set' or $macro eq 'clear')
16240            {
16241                if ($macro eq 'set')
16242                {
16243                    if (s/^(\s+)($VARRE)(\s+)(.*)$//o)
16244                    {
16245                        if ($state->{'arg_expansion'})
16246                        {
16247                            my $line = "\@$macro" . $1.$2.$3;
16248                            $line .= $4 if (defined($4));
16249                            add_prev($text, $stack, $line);
16250                            next;
16251                        }
16252                        next if $state->{'ignored'};
16253                        $value{$2} = $4;
16254                    }
16255                    else
16256                    {
16257                        echo_warn ("Missing argument for \@$macro", $line_nr);
16258                    }
16259                }
16260                elsif ($macro eq 'clear')
16261                {
16262                    if (s/^(\s+)($VARRE)//o)
16263                    {
16264                        if ($state->{'arg_expansion'})
16265                        {
16266                            add_prev($text, $stack, "\@$macro" . $1 . $2);
16267                            next;
16268                        }
16269                        next if $state->{'ignored'};
16270                        delete $value{$2};
16271                    }
16272                    else
16273                    {
16274                        echo_warn ("Missing argument for \@$macro", $line_nr);
16275                    }
16276                }
16277                return if (/^\s*$/);
16278	    }
16279            elsif ($macro =~ /^r?macro$/)
16280            { #FIXME what to do if 'arg_expansion' is true (ie within another
16281              # macro call arguments?
16282                if (/^\s+(\w[\w-]*)\s*(.*)/)
16283                {
16284                    my $name = $1;
16285                    unless ($state->{'ignored'})
16286                    {
16287                         if (exists($macros->{$name}))
16288                         {
16289                             echo_warn ("macro `$name' allready defined " .
16290                                 format_line_number($macros->{$name}->{'line_nr'}) . " redefined", $line_nr);
16291                         }
16292
16293                    }
16294                    $state->{'macro_inside'} = 1;
16295                    next if ($state->{'ignored'});
16296                    # if in 'arg_expansion' we really want to take into account
16297                    # that we are in an ignored ifclear.
16298                    my @args = ();
16299                    @args = split(/\s*,\s*/ , $1)
16300                       if ($2 =~ /^\s*{\s*(.*?)\s*}\s*/);
16301                    # keep the context information of the definition
16302                    $macros->{$name}->{'line_nr'} = { 'file_name' => $line_nr->{'file_name'},
16303                         'line_nr' => $line_nr->{'line_nr'}, 'macro' => $line_nr->{'macro'} } if (defined($line_nr));
16304                    $macros->{$name}->{'args'} = \@args;
16305                    my $arg_index = 0;
16306                    my $debug_msg = '';
16307                    foreach my $arg (@args)
16308                    { # when expanding macros, the argument index is retrieved
16309                      # with args_index
16310                        $macros->{$name}->{'args_index'}->{$arg} = $arg_index;
16311                        $debug_msg .= "$arg($arg_index) ";
16312                        $arg_index++;
16313                    }
16314                    $macros->{$name}->{'body'} = '';
16315                    $state->{'macro'} = $macros->{$name};
16316                    print STDERR "# macro def $name: $debug_msg\n"
16317                         if ($T2H_DEBUG & $DEBUG_MACROS);
16318                }
16319                else
16320                {# it means we have a macro without a name
16321                    echo_error ("Macro definition without macro name $_", $line_nr)
16322                        unless ($state->{'ignored'});
16323                }
16324                return;
16325            }
16326            elsif (defined($text_macros{$macro}))
16327            {
16328                my $tag;
16329                ($_, $tag) = do_text_macro($macro, $_, $state, $stack, $line_nr);
16330                # if it is a raw formatting command or a menu command
16331                # we must keep it for later, unless we are in an 'ignored'.
16332                # if in 'arg_expansion' we keep everything.
16333                my $macro_kept;
16334                if ((($state->{'raw'} or (($macro eq 'menu') and $text_macros{'menu'}) or (exists($region_lines{$macro}))) and !$state->{'ignored'}) or $state->{'arg_expansion'})
16335                {
16336                    add_prev($text, $stack, $tag);
16337                    $macro_kept = 1;
16338                }
16339                #dump_stack ($text, $stack, $state);
16340                next if $macro_kept;
16341                return if (/^\s*$/);
16342            }
16343            elsif ($macro eq 'documentencoding')
16344            {
16345                my $spaces = '';
16346                my $encoding = '';
16347                if (s/(\s+)([0-9\w\-]+)//)
16348                {
16349                    $spaces = $1;
16350                    $encoding = $2;
16351                    next if ($state->{'ignored'});
16352                    if (!$state->{'arg_expansion'} and !$state->{'ignored'})
16353                    {
16354                        $Texi2HTML::Config::DOCUMENT_ENCODING = $encoding;
16355                        my $from_encoding = encoding_alias($encoding);
16356                        $Texi2HTML::Config::IN_ENCODING = $from_encoding if
16357                            defined($from_encoding);
16358                        if (defined($from_encoding) and $Texi2HTML::Config::USE_UNICODE)
16359                        {
16360                            foreach my $file (@fhs)
16361                            {
16362                                binmode($file->{'fh'}, ":encoding($from_encoding)");
16363                            }
16364                        }
16365                    }
16366                }# ARG_EXPANSION
16367                add_prev($text, $stack, "\@$macro" . $spaces . $encoding) unless ($state->{'ignored'});
16368            }
16369            elsif ($macro eq 'definfoenclose')
16370            {
16371                # FIXME if 'ignored' or 'arg_expansion' maybe we could parse
16372                # the args anyway and don't take away the whole line?
16373
16374                # as in the makeinfo doc 'definfoenclose' may override
16375                # texinfo @-commands like @i. It is what we do here.
16376                if ($state->{'arg_expansion'})
16377                {
16378                    add_prev($text, $stack, "\@$macro" . $_);
16379                    return;
16380                }
16381                return if ($state->{'ignored'});
16382                if (s/^\s+([a-z]+)\s*,\s*([^\s]+)\s*,\s*([^\s]+)//)
16383                {
16384                    $info_enclose{$1} = [ $2, $3 ];
16385                }
16386                else
16387                {
16388                    echo_error("Bad \@$macro", $line_nr);
16389                }
16390                return if (/^\s*$/);
16391                s/^\s*//;
16392            }
16393            elsif ($macro eq 'include')
16394            {
16395                if ($state->{'arg_expansion'})
16396                {
16397                    add_prev($text, $stack, "\@$macro" . $_);
16398                    return;
16399                }
16400                return if ($state->{'ignored'});
16401                #if (s/^\s+([\/\w.+-]+)//o)
16402                if (s/^(\s+)(.*)//o)
16403                {
16404                    my $file_name = $2;
16405                    $file_name =~ s/\s*$//;
16406                    my $file = locate_include_file($file_name);
16407                    if (defined($file))
16408                    {
16409                        open_file($file, $line_nr);
16410                        print STDERR "# including $file\n" if $T2H_VERBOSE;
16411                    }
16412                    else
16413                    {
16414                        echo_error ("Can't find $file_name, skipping", $line_nr);
16415                    }
16416                }
16417                else
16418                {
16419                    echo_error ("Bad include line: $_", $line_nr);
16420                    return;
16421                }
16422                return;
16423            }
16424            elsif ($macro eq 'value')
16425            {
16426                if (s/^{($VARRE)}//)
16427                {
16428                    my $value = $1;
16429                    if ($state->{'arg_expansion'})
16430                    {
16431                        add_prev($text, $stack, "\@$macro" .'{'. $value .'}');
16432                        next;
16433                    }
16434                    next if ($state->{'ignored'});
16435                    my $expansion = "No value for $value";
16436                    $expansion = $value{$value} if (defined($value{$value}));
16437                    $_ = $expansion . $_;
16438                }
16439                else
16440                {
16441                    if ($state->{'arg_expansion'})
16442                    {
16443                        add_prev($text, $stack, "\@$macro");
16444                        next;
16445                    }
16446                    next if ($state->{'ignored'});
16447                    echo_error ("bad \@value macro", $line_nr);
16448                }
16449            }
16450            elsif ($macro eq 'unmacro')
16451            { #FIXME with 'arg_expansion' should it be passed unmodified ?
16452                if ($state->{'ignored'})
16453                {
16454                    s/^\s+(\w+)//;
16455                }
16456                else
16457                {
16458                    delete $macros->{$1} if (s/^\s+(\w+)//);
16459                }
16460                return if (/^\s*$/);
16461                s/^\s*//;
16462            }
16463            elsif (exists($macros->{$macro}))
16464            {# it must be before the handling of {, otherwise it is considered
16465             # to be regular texinfo @-command. Maybe it could be placed higher
16466             # if we want user defined macros to override texinfo @-commands
16467
16468             # in 'ignored' we parse macro defined args anyway as it removes
16469             # some text, but we don't expand the macro
16470
16471                my $ref = $macros->{$macro}->{'args'};
16472                # we remove any space/new line before the argument
16473                if (s/^\s*{\s*//)
16474                { # the macro has args
16475                    $state->{'macro_args'} = [ "" ];
16476                    $state->{'macro_name'} = $macro;
16477                    $state->{'macro_depth'} = 1;
16478                }
16479                elsif (($#$ref >= 1) or ($#$ref <0))
16480                { # no brace -> no arg
16481                    $_ = expand_macro ($macro, [], $_, $line_nr, $state);
16482                    return;
16483                }
16484                else
16485                { # macro with one arg on the line
16486                    chomp $_;
16487                    $_ = expand_macro ($macro, [$_], "\n", $line_nr, $state);
16488                    return;
16489                }
16490            }
16491            elsif ($macro eq ',')
16492            {# the @, causes problems when `,' separates things (in @node, @ref)
16493                $_ = "\@m_cedilla" . $_;
16494            } # handling of @, must be done before handling of {
16495            elsif (s/^{//)
16496            {# we add nested commands in a stack. verb is also on the stack
16497             # but handled specifically.
16498             # we add it the comands even in 'ignored' as their result is
16499             # discarded when the closing brace appear, or the ifset or
16500             # iclear is closed.
16501                if ($macro eq 'verb')
16502                {
16503                    if (/^$/)
16504                    {
16505                        echo_error ("without associated character", $line_nr);
16506                        #warn "$ERROR verb at end of line";
16507                    }
16508                    else
16509                    {
16510                        s/^(.)//;
16511                        $state->{'verb'} = $1;
16512                    }
16513                }
16514                push (@$stack, { 'style' => $macro, 'text' => '' });
16515            }
16516            else
16517            {
16518                add_prev($text, $stack, "\@$macro") unless($state->{'ignored'});
16519            }
16520            next;
16521        }
16522        #elsif(s/^([^{}@]*)\@(.)//o)
16523        elsif(s/^([^{}@]*)\@([^\s\}\{\@]*)//o)
16524        {# ARG_EXPANSION
16525            # No need to warn here for @ followed by a character that
16526            # is not in any @-command and it is done later
16527            add_prev($text, $stack, $1 . "\@$2") unless($state->{'ignored'});
16528            next;
16529        }
16530        elsif (s/^([^{}]*)([{}])//o)
16531        {
16532         # in ignored section we cannot be sure that there is an @-command
16533         # allready opened so we must discard the text.
16534         # ARG_EXPANSION
16535            add_prev($text, $stack, $1) unless($state->{'ignored'});
16536            if ($2 eq '{')
16537            {
16538              # this empty style is for a lone brace.
16539              # we add it even in 'ignored' as it is discarded when the closing
16540              # brace appear, or the ifset or iclear is closed.
16541                push @$stack, { 'style' => '', 'text' => '' };
16542            }
16543            else
16544            {
16545                if (@$stack)
16546                {
16547                    my $style = pop @$stack;
16548                    my $result;
16549                    if (($style->{'style'} ne '') and exists($info_enclose{$style->{'style'}}) and !$state->{'arg_expansion'})
16550                    {
16551                        $result = $info_enclose{$style->{'style'}}->[0] . $style->{'text'} . $info_enclose{$style->{'style'}}->[1];
16552                    }
16553                    elsif ($style->{'style'} ne '')
16554                    {
16555                        $result = '@' . $style->{'style'} . '{' . $style->{'text'} . '}';
16556                    }
16557                    else
16558                    {
16559                        $result = '{' . $style->{'text'};
16560                        # don't close { if we are closing stack as we are not
16561                        # sure this is a { ... } construct. i.e. we are
16562                        # not sure that the user properly closed the matching
16563                        # brace, so we don't close it ourselves
16564                        $result .= '}' unless ($state->{'close_stack'} or $state->{'arg_expansion'});
16565                    }
16566                    if ($state->{'ignored'})
16567                    {# ARG_EXPANSION
16568                        print STDERR "# Popped `$style->{'style'}' in ifset/ifclear\n" if ($T2H_DEBUG);
16569                        next;
16570                    }
16571                    add_prev ($text, $stack, $result);
16572                    #print STDERR "MACRO end $style->{'style'} remaining: $_";
16573                    next;
16574                }
16575                else
16576                {# ARG_EXPANSION
16577                    # we warn in the last pass that there is a } without open
16578                    add_prev ($text, $stack, '}') unless($state->{'ignored'});
16579                }
16580            }
16581        }
16582        else
16583        {# ARG_EXPANSION
16584            #print STDERR "END_LINE $_";
16585            add_prev($text, $stack, $_) unless($state->{'ignored'});
16586            last;
16587        }
16588    }
16589    return undef if ($state->{'ignored'});
16590    return 1;
16591}
16592
16593sub close_structure_command($$$$)
16594{
16595    my $cmd_ref = shift;
16596    my $state = shift;
16597    my $unclosed_commands = shift;
16598    my $line_nr = shift;
16599    my $result;
16600
16601    if ($cmd_ref->{'style'} eq 'anchor')
16602    {
16603        my $anchor = $cmd_ref->{'text'};
16604        $anchor = normalise_node($anchor);
16605        if ($nodes{$anchor})
16606        {
16607            echo_error ("Duplicate node for anchor found: $anchor", $line_nr);
16608            return '';
16609        }
16610        $anchor_num++;
16611        $nodes{$anchor} = { 'anchor' => 1, 'seen' => 1, 'texi' => $anchor, 'id' => 'ANC' . $anchor_num};
16612        push @{$state->{'place'}}, $nodes{$anchor};
16613    }
16614    elsif ($cmd_ref->{'style'} eq 'footnote')
16615    {
16616        if ($Texi2HTML::Config::SEPARATED_FOOTNOTES)
16617        {
16618            $state->{'element'} = $state->{'footnote_element'};
16619            $state->{'place'} = $state->{'footnote_place'};
16620        }
16621    }
16622    elsif ($cmd_ref->{'style'} eq 'caption' or $cmd_ref->{'style'}
16623       eq 'shortcaption' and $state->{'float'})
16624    {
16625        my @texi_lines = map {$_ = $_."\n"} split (/\n/, $cmd_ref->{'text'});
16626        $state->{'float'}->{$cmd_ref->{'style'} . "_texi"} = \@texi_lines;
16627    }
16628    if (($cmd_ref->{'style'} eq 'titlefont') and ($cmd_ref->{'text'} =~ /\S/))
16629    {
16630        $state->{'element'}->{'titlefont'} = $cmd_ref->{'text'} unless ((exists($state->{'region_lines'}) and ($state->{'region_lines'}->{'format'} eq 'titlepage')) or defined($state->{'element'}->{'titlefont'})) ;
16631    }
16632    if (defined($Texi2HTML::Config::command_handler{$cmd_ref->{'style'}}))
16633    {
16634        $result = init_special($cmd_ref->{'style'},$cmd_ref->{'text'});
16635        if ($unclosed_commands)
16636        {
16637            $result .= "\n"; # the end of line is eaten by init_special
16638            echo_error("Closing specially handled \@-command $cmd_ref->{'style'}",$line_nr);
16639        }
16640    }
16641    elsif ($cmd_ref->{'style'})
16642    {
16643        $result = '@' . $cmd_ref->{'style'} . '{' . $cmd_ref->{'text'};
16644        $result .= '}' unless ($unclosed_commands);
16645    }
16646    else
16647    {
16648        $result = '{' . $cmd_ref->{'text'};
16649        # don't close { if we are closing stack as we are not
16650        # sure this is a licit { ... } construct.
16651        $result .= '}' unless ($unclosed_commands);
16652    }
16653    return $result;
16654}
16655
16656sub scan_structure($$$$;$)
16657{
16658    my $line = shift;
16659    my $text = shift;
16660    my $stack = shift;
16661    my $state = shift;
16662    my $line_nr = shift;
16663
16664    die "stack not an array ref"  unless (ref($stack) eq "ARRAY");
16665    local $_ = $line;
16666    #print STDERR "SCAN_STRUCTURE: $line";
16667    #dump_stack ($text, $stack, $state);
16668    if (!$state->{'raw'} and (!exists($state->{'region_lines'})))
16669    {
16670        if (!$state->{'verb'} and $state->{'menu'} and /^\*/o)
16671        {
16672        # new menu entry
16673            delete ($state->{'after_element'});
16674            my $menu_line = $_;
16675            my $node;
16676            if (/^\*\s+($NODERE)::/)
16677            {
16678                $node = $1;
16679            }
16680            elsif (/^\*\s+([^:]+):\s*([^\t,\.\n]+)[\t,\.\n]/)
16681            {
16682                #$name = $1;
16683                $node = $2;
16684            }
16685            if ($node)
16686            {
16687                menu_entry_texi(normalise_node($node), $state, $line_nr);
16688            }
16689        }
16690        unless (no_line($_))
16691        {
16692            delete $state->{'after_element'};
16693        }
16694    }
16695
16696    while(1)
16697    {
16698        # scan structure
16699	#print STDERR "WHILE (s):$_";
16700	#dump_stack($text, $stack, $state);
16701
16702        # as texinfo 4.5
16703        # verbatim might begin at another position than beginning
16704        # of line, and end verbatim might too. To end a verbatim section
16705        # @end verbatim must have exactly one space between end and verbatim
16706        # things following end verbatim are not ignored.
16707        #
16708        # html might begin at another position than beginning
16709        # of line, but @end html must begin the line, and have
16710        # exactly one space. Things following end html are ignored.
16711        # tex and ignore works like html
16712        #
16713        # ifnothtml might begin at another position than beginning
16714        # of line, and @end  ifnothtml might too, there might be more
16715        # than one space between @end and ifnothtml but nothing more on
16716        # the line.
16717        # @end itemize, @end ftable works like @end ifnothtml.
16718        # except that @item on the same line than @end vtable doesn't work
16719        #
16720        # text right after the itemize before an item is displayed.
16721        # @item might be somewhere in a line.
16722        # strangely @item on the same line than @end vtable doesn't work
16723        # there should be nothing else than a command following @itemize...
16724        #
16725        # see more examples in formatting directory
16726
16727        if ($state->{'raw'})
16728        {
16729            my $tag = $state->{'raw'};
16730            ################# debug
16731            if (! @$stack or ($stack->[-1]->{'style'} ne $tag))
16732            {
16733                print STDERR "Bug: raw or special: $tag but not on top of stack\n";
16734                print STDERR "line: $_";
16735                dump_stack($text, $stack, $state);
16736                exit 1;
16737            }
16738            ################# end debug
16739            if (s/^(.*?)\@end\s$tag$// or s/^(.*?)\@end\s$tag\s//)
16740            {
16741                add_prev ($text, $stack, $1);
16742                delete $state->{'raw'};
16743                my $style = pop @$stack;
16744                if (defined($Texi2HTML::Config::command_handler{$tag}))
16745                { # replace the special region by what init_special give
16746                    if ($style->{'text'} !~ /^\s*$/)
16747                    {
16748                        add_prev ($text, $stack, init_special($style->{'style'}, $style->{'text'}));
16749                    }
16750
16751                }
16752                else
16753                {
16754                    my $after_macro = '';
16755                    $after_macro = ' ' unless (/^\s*$/);
16756                    add_prev ($text, $stack, $style->{'text'} . "\@end $tag" . $after_macro);
16757                }
16758                unless (no_line($_))
16759                {
16760                    delete ($state->{'after_element'});
16761                }
16762                next;
16763            }
16764            else
16765            {
16766                add_prev ($text, $stack, $_);
16767                return if (defined($Texi2HTML::Config::command_handler{$tag}));
16768                last;
16769            }
16770        }
16771
16772        if (defined($state->{'verb'}))
16773        {
16774            my $char = quotemeta($state->{'verb'});
16775            if (s/^(.*?)$char\}/\}/)
16776            {
16777                add_prev($text, $stack, $1 . $state->{'verb'});
16778                $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'};
16779                delete $state->{'verb'};
16780                next;
16781            }
16782            else
16783            {
16784                add_prev($text, $stack, $_);
16785                last;
16786            }
16787        }
16788
16789        unless (no_line($_))
16790        {
16791            delete $state->{'after_element'};
16792        }
16793        # macro_regexp
16794        if (s/^([^{}@]*)\@end\s+([a-zA-Z][\w-]*)//)
16795        {
16796            add_prev($text, $stack, $1);
16797            my $end_tag = $2;
16798            #print STDERR "END STRUCTURE $end_tag\n";
16799            $state->{'detailmenu'}-- if ($end_tag eq 'detailmenu' and $state->{'detailmenu'});
16800            if (defined($state->{'text_macro_stack'})
16801               and @{$state->{'text_macro_stack'}}
16802               and ($end_tag eq $state->{'text_macro_stack'}->[-1]))
16803            {
16804                pop @{$state->{'text_macro_stack'}};
16805                if (exists($region_lines{$end_tag}))
16806                { # end a region_line macro, like documentdescription, copying
16807                     print STDERR "Bug: end_tag $end_tag ne $state->{'region_lines'}->{'format'}"
16808                         if ( $end_tag ne $state->{'region_lines'}->{'format'});
16809                     $state->{'region_lines'}->{'number'}--;
16810                     if ($state->{'region_lines'}->{'number'} == 0)
16811                     {
16812                         close_region($state);
16813                     }
16814		     #dump_stack($text, $stack, $state);
16815                }
16816                if ($end_tag eq 'menu')
16817                {
16818                    add_prev($text, $stack, "\@end $end_tag");
16819                    $state->{'menu'}--;
16820                }
16821                else
16822                {
16823			#print STDERR "End $end_tag\n";
16824			#dump_stack($text, $stack, $state);
16825                    return if (/^\s*$/);
16826                }
16827            }
16828            elsif ($text_macros{$end_tag})
16829            {
16830                echo_error ("\@end $end_tag without corresponding element", $line_nr);
16831                #dump_stack($text, $stack, $state);
16832            }
16833            else
16834            {
16835                if ($end_tag eq 'float' and $state->{'float'})
16836                {
16837                    delete $state->{'float'};
16838                }
16839                elsif ($end_tag eq $state->{'table_stack'}->[-1])
16840                {
16841                    enter_table_index_entry($text, $stack, $state, $line_nr);
16842                    pop @{$state->{'table_stack'}};
16843                }
16844                #add end tag
16845                add_prev($text, $stack, "\@end $end_tag");
16846            }
16847            next;
16848        }
16849        #elsif (s/^([^{}@]*)\@([a-zA-Z]\w*|["'~\@\}\{,\.!\?\s\*\-\^`=:\/])//o)
16850        # macro_regexp
16851        elsif (s/^([^{}@]*)\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/])//o or s/^([^{}@]*)\@([a-zA-Z][\w-]*)([\s\{\}\@])/$3/o or s/^([^{}@]*)\@([a-zA-Z][\w-]*)$//o)
16852        {
16853            add_prev($text, $stack, $1);
16854            my $macro = $2;
16855            #print STDERR "MACRO $macro\n";
16856            if (defined($Texi2HTML::Config::misc_command{$macro}))
16857            {
16858                 my $line;
16859                 ($_, $line) = misc_command_structure($_, $macro, $state,
16860                       $line_nr);
16861                 add_prev ($text, $stack, "\@$macro".$line);
16862                 next;
16863            }
16864
16865            if ($macro =~ /^(\w+?)index/ and ($1 ne 'print') and ($1 ne 'syncode') and ($1 ne 'syn') and ($1 ne 'def') and ($1 ne 'defcode'))
16866            {
16867                my $index_prefix = $1;
16868                my $key = $_;
16869                $key =~ s/^\s*//;
16870                $_ = substitute_texi_line($_);
16871                enter_index_entry($index_prefix, $line_nr, $key, $state->{'place'}, $state->{'element'}, $state->{'after_element'}, $macro);
16872                add_prev ($text, $stack, "\@$macro" .  $_);
16873                last;
16874            }
16875            elsif (defined($text_macros{$macro}))
16876            {
16877                #print STDERR "TEXT_MACRO: $macro\n";
16878                if ($text_macros{$macro} eq 'raw')
16879                {
16880                    $state->{'raw'} = $macro;
16881                    #print STDERR "RAW\n";
16882                }
16883                elsif ($format_type{$macro} and $format_type{$macro} eq 'menu')
16884                {
16885                    $state->{'menu'}++;
16886                    delete ($state->{'prev_menu_node'});
16887                    push @{$state->{'text_macro_stack'}}, $macro;
16888                    #print STDERR "MENU (text_macro_stack: @{$state->{'text_macro_stack'}})\n";
16889                }
16890                elsif (exists($region_lines{$macro}))
16891                {
16892                    if (exists($state->{'region_lines'}) and ($state->{'region_lines'}->{'format'} ne $macro))
16893                    {
16894                        echo_error("\@$macro not allowed within $state->{'region_lines'}->{'format'}", $line_nr);
16895                        next;
16896                    }
16897                    if (!exists($state->{'region_lines'}))
16898                    {
16899                        $state->{'region_lines'}->{'format'} = $macro;
16900                        $state->{'region_lines'}->{'number'} = 1;
16901                        $state->{'region_lines'}->{'after_element'} = 1 if ($state->{'after_element'});
16902                        $state->{'region_lines'}->{'kept_place'} = $state->{'place'};
16903                        $state->{'place'} = $region_place;
16904                    }
16905                    else
16906                    {
16907                        $state->{'region_lines'}->{'number'}++;
16908                    }
16909                    push @{$state->{'text_macro_stack'}}, $macro;
16910                }
16911                # if it is a raw formatting command or a menu command
16912                # we must keep it for later
16913                my $macro_kept;
16914                if (($state->{'raw'} and (!defined($Texi2HTML::Config::command_handler{$macro}))) or ($macro eq 'menu'))
16915                {
16916                    add_prev($text, $stack, "\@$macro");
16917                    $macro_kept = 1;
16918                }
16919                if ($state->{'raw'})
16920                {
16921                    push @$stack, { 'style' => $macro, 'text' => '' };
16922                }
16923                next if $macro_kept;
16924                #dump_stack ($text, $stack, $state);
16925                return if (/^\s*$/);
16926            }
16927            elsif ($macro eq 'float')
16928            {
16929                my ($style_texi, $label_texi) = split(/,/, $_);
16930                $style_texi = normalise_space($style_texi);
16931                $label_texi = undef if (defined($label_texi) and ($label_texi =~ /^\s*$/));
16932                if (defined($label_texi))
16933                { # The float may be a target for refs if it has a label
16934                    $label_texi = normalise_node($label_texi);
16935                    if (exists($nodes{$label_texi}) and defined($nodes{$label_texi})
16936                         and $nodes{$label_texi}->{'seen'})
16937                    {
16938                        echo_error ("Duplicate label found: $label_texi", $line_nr);
16939                        while ($_ =~ /,/)
16940                        {
16941                            $_ =~ s/,.*$//;
16942                        }
16943                    }
16944                    else
16945                    {
16946                        my $float = { };
16947                        if (exists($nodes{$label_texi}) and defined($nodes{$label_texi}))
16948                        { # float appeared in a menu
16949                            $float = $nodes{$label_texi};
16950                        }
16951                        else
16952                        {
16953                            $nodes{$label_texi} = $float;
16954                        }
16955                        $float->{'float'} = 1;
16956                        $float->{'tag'} = 'float';
16957                        $float->{'texi'} = $label_texi;
16958                        $float->{'seen'} = 1;
16959                        $float->{'id'} = $label_texi;
16960#print STDERR "FLOAT: $float $float->{'texi'}, place $state->{'place'}\n";
16961                        push @{$state->{'place'}}, $float;
16962                        $float->{'element'} = $state->{'element'};
16963                        $state->{'float'} = $float;
16964                        $float->{'style_texi'} = $style_texi;
16965                        push @floats, $float;
16966                    }
16967                }
16968                add_prev($text, $stack, "\@$macro" . $_);
16969                last;
16970            }
16971            elsif (defined($Texi2HTML::Config::def_map{$macro}))
16972            {
16973                #We must enter the index entries
16974                my ($prefix, $entry, $argument) = get_deff_index($macro, $_, $line_nr);
16975                # use deffn instead of deffnx for @-command record
16976                # associated with index entry
16977                my $idx_macro = $macro;
16978                $idx_macro =~ s/x$//;
16979                enter_index_entry($prefix, $line_nr, $entry, $state->{'place'},
16980                   $state->{'element'}, 0, $idx_macro) if ($prefix);
16981                s/(.*)//;
16982                add_prev($text, $stack, "\@$macro" . $1);
16983                # the text is discarded but we must handle correctly bad
16984                # texinfo with 2 @def-like commands on the same line
16985                substitute_text({'structure' => 1, 'place' => $state->{'place'} },($argument));
16986            }
16987            elsif ($macro =~ /^itemx?$/)
16988            {
16989                enter_table_index_entry($text, $stack, $state, $line_nr);
16990                if ($state->{'table_stack'}->[-1] =~ /^(v|f)table$/)
16991                {
16992                    $state->{'item'} = $macro;
16993                    push @$stack, { 'format' => 'index_item', 'text' => "" };
16994                }
16995                else
16996                {
16997                    add_prev($text, $stack, "\@$macro");
16998                }
16999            }
17000            elsif ($format_type{$macro} and ($format_type{$macro} eq 'table' or $format_type{$macro} eq 'list'))
17001            { # We must enter the index entries of (v|f)table thus we track
17002              # in which table we are
17003                push @{$state->{'table_stack'}}, $macro;
17004                add_prev($text, $stack, "\@$macro");
17005            }
17006            elsif (s/^{//)
17007            {
17008                if ($macro eq 'verb')
17009                {
17010                    if (/^$/)
17011                    {
17012                        # We allready warned in pass texi
17013                        #warn "$ERROR verb at end of line";
17014                    }
17015                    else
17016                    {
17017                        s/^(.)//;
17018                        $state->{'verb'} = $1;
17019                    }
17020                }
17021                elsif ($macro eq 'footnote' and $Texi2HTML::Config::SEPARATED_FOOTNOTES)
17022                {
17023                    $state->{'footnote_element'} = $state->{'element'};
17024                    $state->{'footnote_place'} = $state->{'place'};
17025                    $state->{'element'} = $footnote_element;
17026                    $state->{'place'} = $footnote_element->{'place'};
17027                }
17028                push (@$stack, { 'style' => $macro, 'text' => '' });
17029            }
17030            else
17031            {
17032                add_prev($text, $stack, "\@$macro");
17033            }
17034            next;
17035        }
17036        #elsif(s/^([^{}@]*)\@(.)//o)
17037        elsif(s/^([^{}@]*)\@([^\s\}\{\@]*)//o)
17038        {
17039            add_prev($text, $stack, $1 . "\@$2");
17040            next;
17041        }
17042        elsif (s/^([^{}]*)([{}])//o)
17043        {
17044            add_prev($text, $stack, $1);
17045            if ($2 eq '{')
17046            {
17047                push @$stack, { 'style' => '', 'text' => '' };
17048            }
17049            else
17050            {
17051                if (@$stack)
17052                {
17053                    my $style = pop @$stack;
17054                    my $result;
17055                    add_prev ($text, $stack, close_structure_command($style,
17056                         $state, 0, $line_nr));
17057                    next;
17058                }
17059                else
17060                {
17061                    # We warn in the last pass
17062                    #warn "$ERROR '}' without opening '{' line: $line";
17063                    #echo_error ("'}' without opening '{' line: $line", $line_nr);
17064                    add_prev ($text, $stack, '}');
17065                }
17066            }
17067        }
17068        else
17069        {
17070            #print STDERR "END_LINE $_";
17071            add_prev($text, $stack, $_);
17072            enter_table_index_entry($text, $stack, $state, $line_nr);
17073            last;
17074        }
17075    }
17076    return 1;
17077}
17078
17079sub scan_line($$$$;$)
17080{
17081    my $line = shift;
17082    my $text = shift;
17083    my $stack = shift;
17084    my $state = shift;
17085    my $line_nr = shift;
17086
17087    die "stack not an array ref"  unless (ref($stack) eq "ARRAY");
17088    local $_ = $line;
17089    #print STDERR "SCAN_LINE (@{$state->{'command_stack'}}): $line";
17090    #dump_stack($text, $stack,  $state );
17091    my $new_menu_entry; # true if there is a new menu entry
17092    my $menu_description_in_format; # true if we are in a menu description
17093                                # but in another format section (@table....)
17094    if (defined($state->{'prepend_text'}))
17095    {
17096        $_ = $state->{'prepend_text'} . $_;
17097        $state->{'prepend_text'} = undef;
17098        delete $state->{'prepend_text'};
17099    }
17100
17101    unless ($state->{'end_of_line_protected'} and $state->{'deff_line'})
17102    { # end of lines are really protected only for @def*
17103        if (!$state->{'raw'} and !$state->{'verb'} and $state->{'menu'})
17104        { # new menu entry
17105            my ($node, $name, $ending);
17106            if (s/^\*(\s+$NODERE)(::)//o)
17107            {
17108                $node = $1;
17109                $ending = $2;
17110            }
17111            elsif (s/^\*(\s+[^:]+):(\s*[^\t,\.\n]+)([\t,\.\n])//o)
17112            {
17113                $name = $1;
17114                $node = $2;
17115                $ending = $3;
17116            }
17117            if ($node)
17118            {
17119                my $top_stack = top_stack($stack);
17120                if ($top_stack and $top_stack->{'format'} and
17121                    (
17122                     ($top_stack->{'format'} eq 'menu_description') or
17123                     ($top_stack->{'format'} eq 'menu') or
17124                     (($top_stack->{'format'} eq 'preformatted') and (stack_order($stack, 'preformatted', 'menu_comment'))) or
17125                     ($top_stack->{'format'} eq 'menu_preformatted') or
17126                     ($top_stack->{'format'} eq 'menu_comment')
17127                    )
17128                   )
17129                { # we are in a normal menu state.
17130                    close_menu($text, $stack, $state, $line_nr);
17131                    $new_menu_entry = 1;
17132                    $state->{'menu_entry'} = { 'name' => $name, 'node' => $node,
17133                       'ending' => $ending };
17134                    add_prev ($text, $stack, do_menu_link($state, $line_nr));
17135                    print STDERR "# New menu entry: $node\n" if ($T2H_DEBUG & $DEBUG_MENU);
17136                    push @$stack, {'format' => 'menu_description', 'text' => ''};
17137                }
17138                else
17139                { # we are within a macro or a format. In that case we use
17140                  # a simplified formatting of menu which should be right whatever
17141                  # the context
17142                    my $menu_entry = $state->{'menu_entry'};
17143                    $state->{'menu_entry'} = { 'name' => $name, 'node' => $node,
17144                       'ending' => $ending };
17145                    add_prev ($text, $stack, do_menu_link($state, $line_nr, 1));
17146                    $state->{'menu_entry'} = $menu_entry;
17147                }
17148            }
17149        }
17150        # we're in a menu entry description
17151        if ($state->{'menu_entry'} and !$new_menu_entry)
17152        {
17153            my $top_stack = top_stack($stack);
17154            if (/^\s+\S.*$/ or (!$top_stack->{'format'} or ($top_stack->{'format'} ne 'menu_description')))
17155            { # description continues
17156                $menu_description_in_format = 1 if ($top_stack->{'format'} and ($top_stack->{'format'} ne 'menu_description'));
17157                print STDERR "# Description continues\n" if ($T2H_DEBUG & $DEBUG_MENU);
17158            }
17159            else
17160            { # enter menu comment after menu entry
17161                ################################ begin debug
17162                if (!$top_stack->{'format'} or ($top_stack->{'format'} ne 'menu_description'))
17163                {
17164                    print STDERR "Bug: begin menu comment but previous isn't menu_description\n";
17165                    dump_stack ($text, $stack, $state);
17166                }
17167                print STDERR "# Menu comment begins\n" if ($T2H_DEBUG & $DEBUG_MENU);
17168                ################################ end debug
17169                my $descr = pop(@$stack);
17170
17171                add_prev ($text, $stack, do_menu_description($descr->{'text'}, $state));
17172                delete $state->{'menu_entry'};
17173                unless (/^\s*\@end\s+menu\b/)
17174                {
17175                    $state->{'menu_comment'}++;
17176                    push @$stack, {'format' => 'menu_comment', 'text' => ''};
17177                    unless ($Texi2HTML::Config::SIMPLE_MENU)
17178                    {
17179                        push @{$state->{'preformatted_stack'}}, {'pre_style' => $Texi2HTML::Config::MENU_PRE_STYLE, 'class' => 'menu-comment' };
17180                        $state->{'preformatted'}++;
17181                        begin_paragraph($stack, $state);
17182                    }
17183                }
17184            }
17185        }
17186        if (($state->{'menu_entry'} and !$menu_description_in_format) or $state->{'raw'} or $state->{'preformatted'}  or $state->{'no_paragraph'} or $state->{'keep_texi'} or $state->{'remove_texi'})
17187        { # empty lines are left unmodified
17188            if (/^\s*$/)
17189            {
17190                add_prev($text, $stack, $_);
17191                return;
17192            }
17193            elsif (!$state->{'raw'})
17194            {
17195                my $next_tag = next_tag($_);
17196                if ($state->{'deff_line'} and !defined($Texi2HTML::Config::def_map{$next_tag}))
17197                {
17198                    begin_deff_item($stack, $state);
17199                }
17200            }
17201        }
17202        else
17203        {
17204            if (/^\s*$/)
17205            {
17206                if ($state->{'paragraph_context'})
17207                { # An empty line ends a paragraph
17208                    close_paragraph($text, $stack, $state, $line_nr);
17209                }
17210                add_prev($text, $stack, &$Texi2HTML::Config::empty_line($_,$state));
17211                return 1;
17212           }
17213           else
17214           {
17215               #print STDERR "a line not empty and not in no paragraph format\n";
17216                my $next_tag = next_tag($_);
17217                if ($state->{'deff_line'} and !defined($Texi2HTML::Config::def_map{$next_tag}))
17218                { # finish opening the deff, as this is not a deff tag, it can't be
17219                  # a deff macro with x
17220                    begin_deff_item($stack, $state);
17221                }
17222                if (!no_paragraph($state,$_))
17223                { # open a paragraph, unless the line begins with a macro that
17224                  # shouldn't trigger a paragraph opening
17225                    begin_paragraph($stack, $state);
17226                }
17227            }
17228        }
17229    }
17230    delete $state->{'end_of_line_protected'}
17231       if ($state->{'end_of_line_protected'});
17232
17233    while(1)
17234    {
17235        # scan_line
17236        #print STDERR "WHILE (l): $_|";
17237        #dump_stack($text, $stack, $state);
17238        # we're in a raw format (html, tex if !L2H, verbatim)
17239        if (defined($state->{'raw'}))
17240        {
17241            (dump_stack($text, $stack, $state), die "Bug for raw ($state->{'raw'})") if (! @$stack or ! ($stack->[-1]->{'style'} eq $state->{'raw'}));
17242            if (s/^(.*?)\@end\s$state->{'raw'}$// or s/^(.*?)\@end\s$state->{'raw'}\s+//)
17243            # don't protect html, it is done by Texi2HTML::Config::raw if needed
17244            {
17245                print STDERR "# end raw $state->{'raw'}\n" if ($T2H_DEBUG & $DEBUG_FORMATS);
17246                add_prev ($text, $stack, $1);
17247                my $style = pop @$stack;
17248                if ($style->{'text'} !~ /^\s*$/)
17249                {
17250                    if ($state->{'keep_texi'})
17251                    {
17252                        add_prev ($text, $stack, $style->{'text'} . "\@end $state->{'raw'}");
17253                    }
17254                    elsif ($state->{'remove_texi'})
17255                    {
17256                        add_prev ($text, $stack, &$Texi2HTML::Config::raw_no_texi($style->{'style'}, $style->{'text'}));
17257                    }
17258                    else
17259                    {
17260                        add_prev($text, $stack, &$Texi2HTML::Config::raw($style->{'style'}, $style->{'text'}));
17261                    }
17262                }
17263                if (!$state->{'keep_texi'} and !$state->{'remove_texi'})
17264                {
17265                    # reopen preformatted if it was interrupted by the raw format
17266                    # if raw format is html the preformatted wasn't interrupted
17267                    begin_paragraph($stack, $state) if ($state->{'preformatted'} and (!$Texi2HTML::Config::format_in_paragraph{$state->{'raw'}}));
17268                    delete $state->{'raw'};
17269                    return if (/^\s*$/);
17270                }
17271                delete $state->{'raw'};
17272                next;
17273            }
17274            else
17275            {
17276                print STDERR "#within raw $state->{'raw'}:$_" if ($T2H_DEBUG & $DEBUG_FORMATS);
17277                add_prev ($text, $stack, $_);
17278                last;
17279            }
17280        }
17281
17282        # we are within a @verb
17283        if (defined($state->{'verb'}))
17284        {
17285            my $char = quotemeta($state->{'verb'});
17286            if (s/^(.*?)$char\}/\}/)
17287            {
17288                 if ($state->{'keep_texi'})
17289                 {
17290                     add_prev($text, $stack, $1 . $state->{'verb'});
17291                     $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'};
17292                 }
17293                 elsif ($state->{'remove_texi'})
17294                 {
17295                     add_prev($text, $stack, $1);
17296                 }
17297                 else
17298                 {
17299                     add_prev($text, $stack, do_text($1, $state));
17300                 }
17301                 delete $state->{'verb'};
17302                 next;
17303            }
17304            else
17305            {
17306                 add_prev($text, $stack, $_);
17307                 last;
17308            }
17309        }
17310
17311        # a special case for @ followed by an end of line in deff
17312        # FIXME this is similar with makeinfo, but shouldn't that
17313        # be done for @floats and @quotations too? and @item, @center?
17314        # this piece of code is required, to avoid the 'cmd_line' to be
17315        # closed below
17316        if ($state->{'end_of_line_protected'} and $state->{'deff_line'})
17317        {
17318            print STDERR "Bug: 'end_of_line_protected' with text following: $_\n"
17319                unless /^$/;
17320            return;
17321        }
17322
17323        # We handle now the end tags
17324        # macro_regexp
17325        if ($state->{'keep_texi'} and s/^([^{}@]*)\@end\s+([a-zA-Z][\w-]*)//)
17326        {
17327            my $end_tag = $2;
17328            add_prev($text, $stack, $1 . "\@end $end_tag");
17329            next;
17330        }
17331        # macro_regexp
17332        elsif ($state->{'remove_texi'} and s/^([^{}@]*)\@end\s+([a-zA-Z][\w-]*)//)
17333        {
17334            add_prev($text, $stack, $1);
17335            next;
17336        }
17337	# macro_regexp
17338        if (s/^([^{}@,]*)\@end\s+([a-zA-Z][\w-]*)\s//o or s/^([^{}@,]*)\@end\s+([a-zA-Z][\w-]*)$//o)
17339        {
17340            add_prev($text, $stack, do_text($1, $state));
17341            my $end_tag = $2;
17342	    #print STDERR "END_MACRO $end_tag\n";
17343	    #dump_stack ($text, $stack, $state);
17344
17345            # First we test if the stack is not empty.
17346            # Then we test if the end tag is a format tag.
17347            # We then close paragraphs and preformatted at top of the stack.
17348            # We handle the end tag (even when it was not the tag which appears
17349            # on the top of the stack; in that case we close anything
17350            # until that element)
17351            $state->{'detailmenu'}-- if ($end_tag eq 'detailmenu' and $state->{'detailmenu'});
17352            # FIXME handle below (look for misc_command) to let the user
17353            # keep that end tag. On the other hand it is only used for
17354            # end detailmenu, so maybe it should just go and detailmenu
17355            # could be handled like a normal format. Last there could be
17356            # something similar than what is done for other misc_commands.
17357            next if (defined($Texi2HTML::Config::misc_command{"end $end_tag"}));
17358            my $top_stack = top_stack($stack);
17359            if (!$top_stack)
17360            {
17361                echo_error ("\@end $end_tag without corresponding opening", $line_nr);
17362                add_prev($text, $stack, "\@end $end_tag");
17363                next;
17364            }
17365
17366            if (!$format_type{$end_tag})
17367            {
17368                echo_warn ("Unknown \@end $end_tag", $line_nr);
17369                #warn "$ERROR Unknown \@end $end_tag\n";
17370                add_prev($text, $stack, "\@end $end_tag");
17371                next;
17372            }
17373            unless ($Texi2HTML::Config::format_in_paragraph{$end_tag})
17374            { # If the $end_tag is wrong we may be keeping paragraph
17375              # for a format with paragraphs on the stack
17376                close_paragraph($text, $stack, $state, $line_nr);
17377            }
17378
17379            $top_stack = top_stack($stack);
17380            if (!$top_stack or (!defined($top_stack->{'format'})))
17381            {
17382                echo_error ("\@end $end_tag without corresponding opening element", $line_nr);
17383                add_prev($text, $stack, "\@end $end_tag");
17384                dump_stack ($text, $stack, $state) if ($T2H_DEBUG);
17385                next;
17386            }
17387            # Warn if the format on top of stack is not compatible with the
17388            # end tag, and find the end tag.
17389            unless (
17390                ($top_stack->{'format'} eq $end_tag)
17391                or
17392                (
17393                 ($format_type{$end_tag} eq 'menu') and
17394                 (
17395                  ($top_stack->{'format'} eq 'menu_preformatted') or
17396                  ($top_stack->{'format'} eq 'menu_comment') or
17397                  ($top_stack->{'format'} eq 'menu_description')
17398                 )
17399                ) or
17400                (
17401                 ($end_tag eq 'multitable') and
17402                 (
17403                  ($top_stack->{'format'} eq 'cell') or
17404                  ($top_stack->{'format'} eq 'null')
17405                 )
17406                ) or
17407                (
17408                 ($format_type{$end_tag} eq 'list' ) and
17409                 ($top_stack->{'format'} eq 'item')
17410                ) or
17411                (
17412                 (
17413                  ($format_type{$end_tag} eq 'table') and
17414                  ($end_tag ne 'multitable')
17415                 ) and
17416                 (
17417                   ($top_stack->{'format'} eq 'term') or
17418                   ($top_stack->{'format'} eq 'line')
17419                 )
17420                ) or
17421                (
17422                 (defined($Texi2HTML::Config::def_map{$end_tag})) and
17423                 ($top_stack->{'format'} eq 'deff_item')
17424                ) or
17425                (
17426                 ($end_tag eq 'row') and
17427                 ($top_stack->{'format'} eq 'cell')
17428                )
17429               )
17430            {
17431                # this is not the right format. We try to close other
17432                # formats to find the format we are searching for.
17433                # First we close paragraphs, as with a wrong $end_format
17434                # they may not be closed properly.
17435                close_paragraph($text, $stack, $state, $line_nr);
17436                $top_stack = top_stack($stack);
17437                if (!$top_stack or (!defined($top_stack->{'format'})))
17438                {
17439                    echo_error ("\@end $end_tag without corresponding opening element", $line_nr);
17440                    add_prev($text, $stack, "\@end $end_tag");
17441                    dump_stack ($text, $stack, $state) if ($T2H_DEBUG);
17442                    next;
17443                }
17444                my $waited_format = $top_stack->{'format'};
17445                $waited_format = $fake_format{$top_stack->{'format'}} if ($format_type{$top_stack->{'format'}} eq 'fake');
17446                echo_error ("waiting for end of $waited_format, found \@end $end_tag", $line_nr);
17447                close_stack($text, $stack, $state, $line_nr, undef, $end_tag);
17448                # an empty preformatted may appear when closing things as
17449                # when closed, formats reopen the preformatted environment
17450                # in case there is some text following, but we know it isn't
17451                # the case here, thus we can close paragraphs.
17452                close_paragraph($text, $stack, $state);
17453                my $new_top_stack = top_stack($stack);
17454                next unless ($new_top_stack and defined($new_top_stack->{'format'}) and (($new_top_stack->{'format'} eq $end_tag)
17455                   or (($format_type{$new_top_stack->{'format'}} eq 'fake') and ($fake_format{$new_top_stack->{'format'}} eq $format_type{$end_tag}))));
17456            }
17457            # We should now be able to handle the format
17458            if (defined($format_type{$end_tag}) and $format_type{$end_tag} ne 'fake')
17459            {
17460                end_format($text, $stack, $state, $end_tag, $line_nr);
17461                begin_paragraph_after_command($state,$stack,$end_tag,$_);
17462            }
17463            else
17464            { # this is a fake format, ie a format used internally, inside
17465              # a real format. We do nothing, hoping the real format will
17466              # get closed, closing the fake internal formats
17467              #print STDERR "FAKE \@end $end_tag\n";
17468            }
17469            next;
17470        }
17471        # This is a macro
17472	#elsif (s/^([^{}@]*)\@([a-zA-Z]\w*|["'~\@\}\{,\.!\?\s\*\-\^`=:\/])//o)
17473        # macro_regexp
17474        elsif (s/^([^{},@]*)\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/])//o or s/^([^{}@,]*)\@([a-zA-Z][\w-]*)([\s\{\}\@])/$3/o or s/^([^{},@]*)\@([a-zA-Z][\w-]*)$//o)
17475        {
17476            add_prev($text, $stack, do_text($1, $state));
17477            my $macro = $2;
17478	    #print STDERR "MACRO $macro\n";
17479	    #print STDERR "LINE $_";
17480	    #dump_stack ($text, $stack, $state);
17481            # This is a macro added by close_stack to mark paragraph end
17482            if ($macro eq 'end_paragraph')
17483            {
17484                s/^\{\}//;
17485                my $top_stack = top_stack($stack);
17486                #################################### debug
17487                if (!$top_stack or !$top_stack->{'format'}
17488                    or ($top_stack->{'format'} ne 'paragraph'))
17489                {
17490                    print STDERR "Bug: end_paragraph but no paragraph to end\n";
17491                    dump_stack ($text, $stack, $state);
17492                    next;
17493                }
17494                #################################### end debug
17495                s/^\s//;
17496                my $paragraph = pop @$stack;
17497                add_prev ($text, $stack, do_paragraph($paragraph->{'text'}, $state));
17498                next;
17499            }
17500            # Handle macro added by close_stack to mark preformatted region end
17501            elsif ($macro eq 'end_preformatted')
17502            {
17503                #print STDERR "END_PREFORMATTED\n";
17504                s/^\{\}//;
17505                my $top_stack = top_stack($stack);
17506                #################################### debug
17507                if (!$top_stack or !$top_stack->{'format'}
17508                    or ($top_stack->{'format'} ne 'preformatted'))
17509                {
17510                    print STDERR "Bug: end_preformatted but no preformatted to end\n";
17511                    dump_stack ($text, $stack, $state);
17512                    next;
17513                }
17514                #################################### end debug
17515                my $paragraph = pop @$stack;
17516                s/^\s//;
17517                add_prev ($text, $stack, do_preformatted($paragraph->{'text'}, $state));
17518                next;
17519            }
17520            if (defined($Texi2HTML::Config::misc_command{$macro}))
17521            {
17522                # The strange condition associated with 'keep_texi' is
17523                # there because for an argument appearing on an @itemize
17524                # line (we're in 'check_item'), meant to be prepended to an
17525                # @item we don't want to keep @c or @comment as otherwise it
17526                # eats the @item line. Other commands could do that too but
17527                # then the user deserves what he gets.
17528                if ($state->{'keep_texi'} and
17529                           (!$state->{'check_item'} or ($macro ne 'c' and $macro ne 'comment')))
17530                {
17531                    my ($line, $args);
17532                    ($_, $line, $args) = preserve_command($_, $macro);
17533                    add_prev($text, $stack, "\@$macro". $line);
17534                    next;
17535                }
17536
17537                # Handle the misc command
17538                $_ = misc_command_text($_, $macro, $stack, $state, $text, $line_nr);
17539                return unless (defined($_));
17540                unless ($Texi2HTML::Config::misc_command{$macro}->{'keep'})
17541                {
17542                     begin_paragraph($stack, $state) if
17543                       (!no_paragraph($state,$_));
17544                     next;
17545                }
17546            }
17547            if ($macro eq 'listoffloats')
17548            {
17549                if ($state->{'keep_texi'})
17550                {
17551                    if (s/(.*)//o)
17552                    {
17553                        add_prev($text, $stack, "\@$macro" . $1);
17554                    }
17555                    next;
17556                }
17557                return undef if ($state->{'remove_texi'});
17558
17559                if (s/^(\s+)(.*)//o)
17560                {
17561                    my $arg = $2;
17562                    my $style_id = cross_manual_line(normalise_space($arg));
17563                    my $style = substitute_line (&$Texi2HTML::Config::listoffloats_style($arg));
17564                    if (exists ($floats{$style_id}))
17565                    {
17566                         close_paragraph($text, $stack, $state, $line_nr);
17567                         my @listoffloats_entries = ();
17568                         foreach my $float (@{$floats{$style_id}->{'floats'}})
17569                         {
17570                              my $float_style = substitute_line(&$Texi2HTML::Config::listoffloats_float_style($arg, $float));
17571                              my $caption_lines = &$Texi2HTML::Config::listoffloats_caption($float);
17572                              # we set 'multiple_pass' such that index entries
17573                              # and anchors are not handled one more time;
17574                              # the caption has allready been formatted,
17575                              # and these have been handled at the right place
17576                              my $caption = substitute_text({ 'multiple_pass' => 1 }, @$caption_lines);
17577                              push @listoffloats_entries, &$Texi2HTML::Config::listoffloats_entry($arg, $float, $float_style, $caption, href($float, $state->{'element'}->{'file'}));
17578                         }
17579                         add_prev($text, $stack, &$Texi2HTML::Config::listoffloats($arg, $style, \@listoffloats_entries));
17580                    }
17581                    else
17582                    {
17583                         echo_warn ("Unknown float style $arg", $line_nr);
17584                    }
17585                }
17586                else
17587                {
17588                    echo_error ("Bad \@$macro line: $_", $line_nr);
17589                }
17590                return undef;
17591            }
17592            # This is a @macroname{...} construct. We add it on top of stack
17593            # It will be handled when we encounter the '}'
17594            # There is a special case for def macros as @deffn{def} is licit
17595            if (!$Texi2HTML::Config::def_map{$macro} and s/^{//)
17596            {
17597                if ($macro eq 'verb')
17598                {
17599                    if (/^$/)
17600                    {
17601                        # Allready warned
17602                        #warn "$ERROR verb at end of line";
17603                    }
17604                    else
17605                    {
17606                        s/^(.)//;
17607                        $state->{'verb'} = $1;
17608                    }
17609                }
17610                elsif ($macro eq 'm_cedilla' and !$state->{'keep_texi'})
17611                {
17612                    $macro = ',';
17613                }
17614                # currently if remove_texi and anchor/ref/footnote
17615                # the text within the command is ignored
17616                # see t2h_remove_command in texi2html.init
17617                push (@$stack, { 'style' => $macro, 'text' => '', 'arg_nr' => 0 });
17618                $state->{'no_paragraph'}++ if ($no_paragraph_macro{$macro});
17619                open_arg($macro, 0, $state);
17620                if (defined($style_type{$macro}) and (($style_type{$macro} eq 'style') or ($style_type{$macro} eq 'accent')))
17621                {
17622                     push (@{$state->{'command_stack'}}, $macro);
17623                     #print STDERR "# Stacked $macro (@{$state->{'command_stack'}})\n" if ($T2H_DEBUG);
17624                }
17625                next;
17626            }
17627
17628            # special case if we are checking itemize line. In that case
17629            # we want to make sure that there is no @item on the @itemize
17630            # line, otherwise it will be added on the front of another @item,
17631            # leading to an infinite loop...
17632
17633            if ($state->{'check_item'} and ($macro =~ /^itemx?$/ or $macro eq 'headitem'))
17634            {
17635                echo_error("\@$macro on \@$state->{'check_item'} line", $line_nr);
17636                next;
17637            }
17638
17639            # if we're keeping texi unmodified we can do it now
17640            if ($state->{'keep_texi'})
17641            {
17642                # We treat specially formats accepting {} on command line
17643                if ($macro eq 'multitable' or defined($Texi2HTML::Config::def_map{$macro}))
17644                {
17645                    add_prev($text, $stack, "\@$macro" . $_);
17646                    $_ = '';
17647                    next;
17648                }
17649                # @ at the end of line may protect the end of line even when
17650                # keeping texi
17651                if ($macro eq "\n")
17652                {
17653                     $state->{'end_of_line_protected'} = 1;
17654                     #print STDERR "PROTECTING END OF LINE\n";
17655                }
17656
17657                add_prev($text, $stack, "\@$macro");
17658                if ($text_macros{$macro} and $text_macros{$macro} eq 'raw')
17659                {
17660                    $state->{'raw'} = $macro;
17661                    push (@$stack, {'style' => $macro, 'text' => ''});
17662                }
17663                next;
17664            }
17665
17666            # If we are removing texi, the following macros are not removed
17667            # as is but modified. So they are collected first, as if we were
17668            # in normal text
17669
17670            # a raw macro beginning
17671            if ($text_macros{$macro} and $text_macros{$macro} eq 'raw')
17672            {
17673                if (!$Texi2HTML::Config::format_in_paragraph{$macro})
17674                { # close paragraph before verbatim (and tex if !L2H)
17675                    close_paragraph($text, $stack, $state, $line_nr);
17676                }
17677                $state->{'raw'} = $macro;
17678                push (@$stack, {'style' => $macro, 'text' => ''});
17679                return if (/^\s*$/);
17680                next;
17681            }
17682            my $simple_macro = 1;
17683            # An accent macro
17684            if (exists($Texi2HTML::Config::accent_map{$macro}))
17685            {
17686                push (@{$state->{'command_stack'}}, $macro);
17687                if (s/^(\S)//o)
17688                {
17689                    add_prev($text, $stack, do_simple($macro, $1, $state, [ $1 ], $line_nr));
17690                }
17691                else
17692                { # The accent is at end of line
17693                    add_prev($text, $stack, do_text($macro, $state));
17694                }
17695                pop @{$state->{'command_stack'}};
17696            }
17697            # an @-command which should be like @command{}. We handle it...
17698            elsif ($::things_map_ref->{$macro})
17699            {
17700                echo_warn ("$macro requires {}", $line_nr);
17701                add_prev($text, $stack, do_simple($macro, '', $state));
17702            }
17703            # an @-command like @command
17704            elsif (defined($::simple_map_ref->{$macro}))
17705            {
17706                add_prev($text, $stack, do_simple($macro, '', $state));
17707            }
17708            else
17709            {
17710                 $simple_macro = 0;
17711            }
17712            if ($simple_macro)
17713            {# if the macro didn't triggered a paragraph start it might now
17714                begin_paragraph($stack, $state) if
17715                   ($no_line_macros{$macro} and !no_paragraph($state,$_));
17716                next;
17717            }
17718            # the following macros are modified or ignored if we are
17719            # removing texi, and they are not handled like macros in text
17720            if ($state->{'remove_texi'})
17721            {
17722                 # handle specially some macros
17723                 if ((($macro =~ /^(\w+?)index$/) and ($1 ne 'print')) or
17724                      ($macro eq 'itemize') or ($macro =~ /^(|v|f)table$/)
17725                      or ($macro eq 'multitable') or ($macro eq 'quotation'))
17726                 {
17727                      return;
17728                 }
17729                 elsif ($macro eq 'enumerate')
17730                 {
17731                      my $spec;
17732                      ($_, $spec) = parse_enumerate ($_);
17733                      return if (/^\s*$/);
17734                      next;
17735                 }
17736                 elsif (defined($Texi2HTML::Config::def_map{$macro}))
17737                 {
17738                     my ($style, $category, $name, $type, $class, $arguments);
17739                     ($style, $category, $name, $type, $class, $arguments) = parse_def($macro, $_, $line_nr);
17740                     # FIXME -- --- ''... lead to simple text in texi2html
17741                     # while they are kept as is in html coments by makeinfo
17742                     $category = remove_texi($category) if (defined($category));
17743                     $name = remove_texi($name) if (defined($name));
17744                     $type = remove_texi($type) if (defined($type));
17745                     $class = remove_texi($class) if (defined($class));
17746                     $arguments = remove_texi($arguments) if (defined($arguments));
17747                     chomp($arguments);
17748                     add_prev($text, $stack, &$Texi2HTML::Config::def_line_no_texi($category, $name, $type, $arguments));
17749                     return;
17750                }
17751
17752                # ignore other macros
17753                next;
17754            }
17755
17756            # handle the other macros, in the context of some normal text
17757            if (($macro =~ /^(\w+?)index$/) and ($1 ne 'print'))
17758            {
17759                add_prev($text, $stack, do_index_entry_label($macro,$state,$line_nr));
17760                return;
17761            }
17762            if ($macro eq 'insertcopying')
17763            {
17764                close_paragraph($text, $stack, $state, $line_nr);
17765                add_prev($text, $stack, do_insertcopying($state));
17766                # reopen a preformatted format if it was interrupted by the macro
17767                begin_paragraph ($stack, $state) if ($state->{'preformatted'});
17768                return;
17769            }
17770            if ($macro =~ /^itemx?$/o or ($macro eq 'headitem'))
17771            {
17772		    #print STDERR "ITEM: $_";
17773		    #dump_stack($text, $stack, $state);
17774                abort_empty_preformatted($stack, $state);
17775                # FIXME let the user be able not to close the paragraph
17776                close_paragraph($text, $stack, $state, $line_nr);
17777                # these functions return the format if in the right context
17778                my $format;
17779                if ($format = add_item($text, $stack, $state, $line_nr, $_))
17780                { # handle lists
17781                }
17782                elsif ($format = add_term($text, $stack, $state, $line_nr))
17783                {# handle table @item line
17784                }
17785                elsif ($format = add_line($text, $stack, $state, $line_nr))
17786                {# handle table text
17787                }
17788                if ($format)
17789                {
17790                    if (defined($format->{'prepended'}))
17791                    {
17792                        $_ = $format->{'prepended'} . ' ' . $_ if ($format->{'prepended'} ne '');
17793                    }
17794                    if (defined($format->{'command'}))
17795                    {
17796                         open_arg($format->{'command'},0, $state);
17797                    }
17798                    next;
17799                }
17800                $format = add_row ($text, $stack, $state, $line_nr); # handle multitable
17801                unless ($format)
17802                {
17803                    echo_warn ("\@$macro outside of table or list", $line_nr);
17804                    next;
17805                }
17806                push @$stack, {'format' => 'row', 'text' => '', 'item_cmd' => $macro };
17807                if ($format->{'max_columns'})
17808                {
17809                    push @$stack, {'format' => 'cell', 'text' => ''};
17810                    $format->{'cell'} = 1;
17811
17812                    begin_paragraph_after_command($state,$stack,$macro,$_);
17813                }
17814                else
17815                {
17816                    echo_warn ("\@$macro in empty multitable", $line_nr);
17817                }
17818                next;
17819            }
17820            if ($macro eq 'tab')
17821            {
17822                abort_empty_preformatted($stack, $state);
17823                # FIXME let the user be able not to close the paragraph
17824                close_paragraph($text, $stack, $state, $line_nr);
17825                my $format = add_cell ($text, $stack, $state);
17826                #print STDERR "tab, $format->{'cell'}, max $format->{'max_columns'}\n";
17827                if (!$format)
17828                {
17829                    echo_warn ("\@$macro outside of multitable", $line_nr);
17830                }
17831                elsif (!$format->{'max_columns'})
17832                {
17833                    echo_warn ("\@$macro in empty multitable", $line_nr);
17834                    push @$stack, {'format' => 'null', 'text' => ''};
17835                    next;
17836                }
17837                elsif ($format->{'cell'} > $format->{'max_columns'})
17838                {
17839                    echo_warn ("too much \@$macro (multitable has only $format->{'max_columns'} column(s))", $line_nr);
17840                    push @$stack, {'format' => 'null', 'text' => ''};
17841                    next;
17842                }
17843                else
17844                {
17845                    push @$stack, {'format' => 'cell', 'text' => ''};
17846                }
17847                begin_paragraph_after_command($state,$stack,$macro,$_);
17848                next;
17849            }
17850            # Macro opening a format (table, list, deff, example...)
17851            if ($format_type{$macro} and ($format_type{$macro} ne 'fake'))
17852            {
17853                unless ($Texi2HTML::Config::format_in_paragraph{$macro})
17854                {
17855                    close_paragraph($text, $stack, $state, $line_nr);
17856                }
17857                push (@{$state->{'command_stack'}}, $macro);
17858                if ($format_type{$macro} eq 'menu')
17859                {
17860                    close_menu($text, $stack, $state, $line_nr);
17861                    $state->{'menu'}++;
17862                }
17863                # A deff like macro
17864                if (defined($Texi2HTML::Config::def_map{$macro}))
17865                {
17866                    my $top_format = top_format($stack);
17867                    if (defined($top_format) and ("$top_format->{'format'}x" eq $macro))
17868                    {
17869                      # the @DEFx macro has been put at the top of the
17870                      # command_stack, although there is no real format opening
17871                         pop @{$state->{'command_stack'}};
17872                         $macro =~ s/x$//o;
17873                         if (!$state->{'deff_line'})
17874                         {# DEFx macro within a DEF paragraph
17875                              close_stack($text, $stack, $state, $line_nr, undef, 'deff_item');
17876                              my $format_ref = pop @$stack;
17877                              add_prev($text, $stack, &$Texi2HTML::Config::def_item($format_ref->{'text'}));
17878			 }
17879                         #print STDERR "DEFx $macro\n";
17880                    }
17881                    else
17882                    {
17883                         # The previous @def command isn't the same @def
17884                         # command. We begin the item for the previous @def
17885                         # command and immediately open the new one.
17886                         begin_deff_item($stack, $state, 1) if ($state->{'deff_line'});
17887                         $macro =~ s/x$//o;
17888                         # we remove what is on the stack and put it back,
17889                         # to make sure that it is the form without x.
17890                         pop @{$state->{'command_stack'}};
17891                         push @{$state->{'command_stack'}}, $macro;
17892                         #print STDERR "DEF begin $macro\n";
17893                         push @$stack, { 'format' => $macro, 'text' => '' };
17894                    }
17895                    #print STDERR "BEGIN_DEFF $macro\n";
17896                    #dump_stack ($text, $stack, $state);
17897                    $state->{'deff_line'}->{'command'} = $macro;
17898                    my ($style, $category, $name, $type, $class, $arguments);
17899                    ($style, $category, $name, $type, $class, $_) = parse_def($macro, $_, $line_nr);
17900                    #print STDERR "AFTER parse_def $_";
17901                    # duplicate_state?
17902                    $state->{'deff_line'}->{'style'} = $style;
17903                    $state->{'deff_line'}->{'category'} = substitute_line($category) if (defined($category));
17904                    $state->{'deff_line'}->{'category'} = '' if (!defined($category));
17905                    # FIXME -- --- ''... are transformed to entities by
17906                    # makeinfo. It may be wrong.
17907                    $state->{'deff_line'}->{'name'} = substitute_line($name) if (defined($name));
17908                    $state->{'deff_line'}->{'name'} = '' if (!defined($name));
17909                    $state->{'deff_line'}->{'type'} = substitute_line($type) if (defined($type));
17910                    $state->{'deff_line'}->{'class'} = substitute_line($class) if (defined($class));
17911                    # the remaining of the line (the argument)
17912                    #print STDERR "DEFF: open_cmd_line do_def_line $_";
17913                    open_cmd_line($stack, $state, ['keep'], \&do_def_line);
17914                    next;
17915                }
17916                elsif (exists ($Texi2HTML::Config::complex_format_map->{$macro}))
17917                { # handle menu if SIMPLE_MENU. see texi2html.init
17918                    $state->{'preformatted'}++;
17919                    my $complex_format =  $Texi2HTML::Config::complex_format_map->{$macro};
17920                    my $format = { 'format' => $macro, 'text' => '', 'pre_style' => $complex_format->{'pre_style'} };
17921                    my $class = $macro;
17922                    $class = $complex_format->{'class'} if (defined($complex_format->{'class'}));
17923                    push @{$state->{'preformatted_stack'}}, {'pre_style' =>$complex_format->{'pre_style'}, 'class' => $class };
17924                    push @$stack, $format;
17925                    unless ($Texi2HTML::Config::format_in_paragraph{$macro})
17926                    {
17927                        begin_paragraph($stack, $state);
17928                    }
17929                }
17930                elsif ($Texi2HTML::Config::paragraph_style{$macro})
17931                {
17932                    push (@$stack, { 'format' => $macro, 'text' => '' });
17933                    begin_paragraph_after_command($state,$stack,$macro,$_);
17934                    push @{$state->{'paragraph_style'}}, $macro;
17935                    if ($macro eq 'center')
17936                    {
17937                        # @center may be in a weird state with regard with
17938                        # nesting, so we put it on the bottom of the stack
17939                        pop @{$state->{'command_stack'}};
17940                        unshift @{$state->{'command_stack'}}, $macro;
17941                        # for similar reasons, we may have a bad stack nesting
17942                        # which results in } after a closing. For example
17943                        # @center @samp{something @center end of samp}
17944                        # results to samp being kept in the 'command_stack'
17945
17946                        # we keep the end of line for @center, to
17947                        # avoid the return in case there is only spaces
17948                        # which occurs for all the format commmands followed by
17949                        # spaces only
17950                        next;
17951                    }
17952                }
17953                elsif ($format_type{$macro} eq 'menu')
17954                {
17955                    # if $Texi2HTML::Config::SIMPLE_MENU we won't get there
17956                    # as the menu is a complex format in that case, so it
17957                    # is handled above
17958                    push @$stack, { 'format' => $macro, 'text' => '' };
17959                    if ($state->{'preformatted'})
17960                    {
17961                    # Start a fake complex format in order to have a given pre style
17962                        $state->{'preformatted'}++;
17963                        push @$stack, { 'format' => 'menu_preformatted', 'text' => '', 'pre_style' => $Texi2HTML::Config::MENU_PRE_STYLE };
17964                        push @{$state->{'preformatted_stack'}}, {'pre_style' => $Texi2HTML::Config::MENU_PRE_STYLE, 'class' => 'menu-preformatted' };
17965                    }
17966                }
17967                elsif (($format_type{$macro} eq 'list') or ($format_type{$macro} eq 'table'))
17968                {
17969                    my $format;
17970		    #print STDERR "LIST_TABLE $macro\n";
17971		    #dump_stack($text, $stack, $state);
17972                    if (($macro eq 'itemize') or ($macro =~ /^(|v|f)table$/))
17973                    {
17974                        my $command;
17975                        my $prepended;
17976                        ($prepended, $command) = parse_format_command($_,$macro);
17977                        $format = { 'format' => $macro, 'text' => '', 'command' => $command, 'prepended' => $prepended, 'term' => 0 };
17978                        $_ = '';
17979                    }
17980                    elsif ($macro eq 'enumerate')
17981                    {
17982                        my $spec;
17983                        ($_, $spec) = parse_enumerate ($_);
17984                        $spec = 1 if (!defined($spec));
17985                        $format = { 'format' => $macro, 'text' => '', 'spec' => $spec, 'item_nr' => 0 };
17986                    }
17987                    elsif ($macro eq 'multitable')
17988                    {
17989                        my $max_columns = parse_multitable ($_, $line_nr);
17990                        if (!$max_columns)
17991                        {
17992                            echo_warn ("empty multitable", $line_nr);
17993                            $max_columns = 0;
17994                        }
17995                        $format = { 'format' => $macro, 'text' => '', 'max_columns' => $max_columns, 'cell' => 1 };
17996                    }
17997                    $format->{'first'} = 1;
17998                    $format->{'paragraph_number'} = 0;
17999                    push @$stack, $format;
18000                    push @{$state->{'table_list_stack'}}, $format;
18001                    if ($macro =~ /^(|v|f)table$/)
18002                    {
18003                        push @$stack, { 'format' => 'line', 'text' => ''};
18004                    }
18005                    elsif ($macro eq 'multitable')
18006                    {
18007                        if ($format->{'max_columns'})
18008                        {
18009                            push @$stack, { 'format' => 'row', 'text' => '', 'item_cmd' => $macro };
18010                            push @$stack, { 'format' => 'cell', 'text' => ''};
18011                        }
18012                        else
18013                        {
18014                            # multitable without row... We use the special null
18015                            # format which content is ignored
18016                            push @$stack, { 'format' => 'null', 'text' => ''};
18017                            push @$stack, { 'format' => 'null', 'text' => ''};
18018                        }
18019                    }
18020                    if ($format_type{$macro} eq 'list')
18021                    {
18022                        push @$stack, { 'format' => 'item', 'text' => ''};
18023                    }
18024                    begin_paragraph_after_command($state,$stack,$macro,$_)
18025                       if ($macro ne 'multitable');
18026                    return if ($format_type{$macro} eq 'table' or $macro eq 'itemize');
18027                }
18028                elsif ($macro eq 'float' or $macro eq 'quotation')
18029                {
18030                    push @$stack, {'format' => $macro, 'text' => '' };
18031                    if ($macro eq 'float')
18032                    {
18033                         open_cmd_line($stack, $state, ['keep','keep'], \&do_float_line);
18034                    }
18035                    elsif ($macro eq 'quotation')
18036                    {
18037                         open_cmd_line($stack, $state, ['keep'], \&do_quotation_line);
18038                    }
18039                    #dump_stack($text, $stack, $state);
18040                    next;
18041                }
18042                # keep this one at the end as there are some other formats
18043                # which are also in format_map
18044                elsif (defined($Texi2HTML::Config::format_map{$macro}) or ($format_type{$macro} eq 'cartouche'))
18045                {
18046                    push @$stack, { 'format' => $macro, 'text' => '' };
18047                    begin_paragraph_after_command($state,$stack,$macro,$_);
18048                }
18049                return if (/^\s*$/);
18050                next;
18051            }
18052            $_ = do_unknown ($macro, $_, $text, $stack, $state, $line_nr);
18053            next;
18054        }
18055        elsif(s/^([^{}@,]*)\@([^\s\}\{\@]*)//o)
18056        { # A macro with a character which shouldn't appear in macro name
18057            add_prev($text, $stack, do_text($1, $state));
18058            $_ = do_unknown ($2, $_, $text, $stack, $state, $line_nr);
18059            next;
18060        }
18061        elsif (s/^([^{},]*)([{}])//o or (@$stack and
18062             defined($stack->[-1]->{'style'}) and
18063             ($stack->[-1]->{'style'} eq 'cmd_line') and /^([^{},]*)$/o))
18064        {
18065            my $leading_text = $1;
18066            my $brace = $2;
18067            add_prev($text, $stack, do_text($leading_text, $state));
18068            if (defined($brace) and ($brace eq '{'))
18069            {
18070                add_prev($text, $stack, do_text('{',$state));
18071                unless ($state->{'keep_texi'} or $state->{'remove_texi'})
18072                {
18073                    echo_error ("'{' without macro. Before: $_", $line_nr);
18074                }
18075            }
18076            elsif (defined($brace) and ($brace eq '}') and
18077                    (!@$stack or (!defined($stack->[-1]->{'style'}))
18078            # a non empty stack, but with 'cmd_line' as first item on the stack
18079            # is like an empty stack
18080                       or ($stack->[-1]->{'style'} eq 'cmd_line')))
18081            {
18082                if ($state->{'keep_texi'})
18083                {
18084                    add_prev($text, $stack, '}');
18085                }
18086                else
18087                {
18088                    echo_error("'}' without opening '{' before: $_", $line_nr);
18089                }
18090            }
18091            else
18092            { # A @-command{ ...} is closed
18093                my $style = pop @$stack;
18094                my $command = $style->{'style'};
18095                my $result;
18096                if (ref($::style_map_ref->{$command}) eq 'HASH')
18097                {
18098                    push (@{$style->{'args'}}, $style->{'text'});
18099                    $style->{'fulltext'} .= $style->{'text'};
18100                    #my $number = 0;
18101                    #foreach my $arg(@{$style->{'args'}})
18102                    #{
18103                         #print STDERR "  $number: $arg\n";
18104                    #     $number++;
18105                    #}
18106                    $style->{'text'} = $style->{'fulltext'};
18107                    $state->{'keep_texi'} = 0 if (
18108                        ($::style_map_ref->{$command}->{'args'}->[$style->{'arg_nr'}] eq 'keep')
18109                        and ($state->{'keep_nr'} == 1));
18110                }
18111                $state->{'no_paragraph'}-- if ($no_paragraph_macro{$command});
18112                if ($command)
18113                {
18114                    $style->{'no_close'} = 1 if ($state->{'no_close'});
18115                    if ($::style_map_ref->{$command} and (defined($style_type{$command})) and ((!$style->{'no_close'} and ($style_type{$command} eq 'style')) or ($style_type{$command} eq 'accent')))
18116                    {
18117                        my $style_command = pop @{$state->{'command_stack'}};
18118                        if ($style_command ne $command)
18119                        {
18120                            print STDERR "Bug: $style_command on 'command_stack', not $command\n";
18121                            push @$stack, $style;
18122                            push @{$state->{'command_stack'}}, $style_command;
18123                            print STDERR "Stacks before pop top:\n";
18124                            dump_stack($text, $stack, $state);
18125                            pop @$stack;
18126                        }
18127                    }
18128                    if ($state->{'keep_texi'})
18129                    { # don't expand @-commands in anchor, refs...
18130                        close_arg ($command, $style->{'arg_nr'}, $state);
18131                        $result = '@' . $command . '{' . $style->{'text'} . '}';
18132                    }
18133                    else
18134                    {
18135                        $result = do_simple($command, $style->{'text'}, $state, $style->{'args'}, $line_nr, $style->{'no_open'}, $style->{'no_close'});
18136                        if ($state->{'code_style'} < 0)
18137                        {
18138                            echo_error ("Bug: negative code_style: $state->{'code_style'}, line:$_", $line_nr);
18139                        }
18140                    }
18141                }
18142                else
18143                {
18144                    print STDERR "Bug: empty style in pass_text\n";
18145                }
18146                add_prev($text, $stack, $result);
18147                if ($command eq 'cmd_line')
18148                {
18149                    if ($state->{'deff_line'})
18150                    {
18151#print STDERR "DO DEFF $state->{'deff_line'}->{'command'} $state->{'deff_line'}->{'arguments'}\n";
18152                         my $command = $state->{'deff_line'}->{'command'};
18153                         my $def_style = $state->{'deff_line'}->{'style'};
18154                         my $category = $state->{'deff_line'}->{'category'};
18155                         my $class = $state->{'deff_line'}->{'class'};
18156                         my $type = $state->{'deff_line'}->{'type'};
18157                         my $name = $state->{'deff_line'}->{'name'};
18158                         #my $arguments = $state->{'deff'}->{'arguments'};
18159                         my $arguments;
18160                         $arguments = substitute_line($state->{'deff_line'}->{'arguments'}) if (defined($state->{'deff_line'}->{'arguments'}));
18161
18162                         $category = &$Texi2HTML::Config::definition_category($category, $class, $def_style);
18163                         my $index_label = do_index_entry_label($command, $state,$line_nr);
18164                         add_prev($text, $stack, &$Texi2HTML::Config::def_line($category, $name, $type, $arguments, $index_label));
18165                    }
18166                    elsif ($state->{'preformatted'})
18167                    { # inconditionally begin a preformatted section for
18168                      # non @def* commands (currently @float and @quotation)
18169                      # for @def* it is done in begin_deff_item
18170                        begin_paragraph($stack, $state);
18171                    }
18172                    $state->{'no_paragraph'}--;
18173                    return;
18174                }
18175            }
18176        }
18177        elsif (s/^([^,]*)[,]//o)
18178        {
18179             add_prev($text, $stack, do_text($1, $state));
18180             if (@$stack and defined($stack->[-1]->{'style'})
18181                  and (ref($::style_map_ref->{$stack->[-1]->{'style'}}) eq 'HASH'))
18182             {
18183                  my $macro = $stack->[-1]->{'style'};
18184                  my $style_args = $::style_map_ref->{$macro}->{'args'};
18185                  if (defined($style_args->[$stack->[-1]->{'arg_nr'} + 1]))
18186                  {
18187                       push (@{$stack->[-1]->{'args'}}, $stack->[-1]->{'text'});
18188                       $stack->[-1]->{'fulltext'} .= $stack->[-1]->{'text'} . do_text(',', $state);
18189                       $stack->[-1]->{'text'} = '';
18190                       close_arg ($macro, $stack->[-1]->{'arg_nr'}, $state);
18191                       $stack->[-1]->{'arg_nr'}++;
18192                       open_arg ($macro, $stack->[-1]->{'arg_nr'}, $state);
18193                       next;
18194                  }
18195             }
18196             add_prev($text, $stack, do_text(',', $state));
18197        }
18198        else
18199        { # no macro nor '}', but normal text
18200            add_prev($text, $stack, do_text($_, $state));
18201            #print STDERR "END LINE:$_!!!\n";
18202            #dump_stack($text, $stack, $state);
18203
18204            # @item line is closed by end of line
18205            add_term($text, $stack, $state, $line_nr);
18206
18207            # @center is closed at the end of line. When a @-command which
18208            # keeps the texi as is happens on the @center line, the @center
18209            # is closed at the end of line appearing after the @-command
18210            # closing (for example @ref, @footnote).
18211
18212            # when 'closing_center' is true we don't retry to close
18213            # the @center line.
18214            if ($state->{'paragraph_style'}->[-1] eq 'center'
18215               and !$state->{'closing_center'} and !$state->{'keep_texi'})
18216            {
18217                $state->{'closing_center'} = 1;
18218                unless ($Texi2HTML::Config::format_in_paragraph{'center'})
18219                {
18220                    close_paragraph($text, $stack, $state, $line_nr);
18221                }
18222                close_stack($text, $stack, $state, $line_nr, undef, 'center');
18223                delete $state->{'closing_center'};
18224                my $center = pop @$stack;
18225                add_prev($text, $stack, &$Texi2HTML::Config::paragraph_style_command('center',$center->{'text'}));
18226                my $top_paragraph_style = pop @{$state->{'paragraph_style'}};
18227                # center is at the bottom of the comand_stack because it
18228                # may be nested in many way
18229                my $bottom_command_stack = shift @{$state->{'command_stack'}};
18230                print STDERR "Bug: closing center, top_paragraph_style: $top_paragraph_style, bottom_command_stack: $bottom_command_stack.\n"
18231                   if ($bottom_command_stack ne 'center' or $top_paragraph_style ne 'center');
18232                $_ = '';
18233                next;
18234            }
18235            last;
18236        }
18237    }
18238    return 1;
18239}
18240
18241sub open_arg($$$)
18242{
18243    my $macro = shift;
18244    my $arg_nr = shift;
18245    my $state = shift;
18246    if (ref($::style_map_ref->{$macro}) eq 'HASH')
18247    {
18248         my $arg = $::style_map_ref->{$macro}->{'args'}->[$arg_nr];
18249         if ($arg eq 'code' and !$state->{'keep_texi'})
18250         {
18251             $state->{'code_style'}++;
18252         }
18253         elsif ($arg eq 'keep')
18254         {
18255             $state->{'keep_nr'}++;
18256             $state->{'keep_texi'} = 1;
18257         }
18258    }
18259    elsif ($code_style_map{$macro} and !$state->{'keep_texi'})
18260    {
18261         $state->{'code_style'}++;
18262    }
18263}
18264
18265sub close_arg($$$)
18266{
18267    my $macro = shift;
18268    my $arg_nr = shift;
18269    my $state = shift;
18270    if (ref($::style_map_ref->{$macro}) eq 'HASH')
18271    {
18272         my $arg = $::style_map_ref->{$macro}->{'args'}->[$arg_nr];
18273         if ($arg eq 'code' and !$state->{'keep_texi'})
18274         {
18275             $state->{'code_style'}--;
18276         }
18277         elsif ($arg eq 'keep')
18278         {
18279             $state->{'keep_nr'}--;
18280             $state->{'keep_texi'} = 0 if ($state->{'keep_nr'} == 0);
18281         }
18282#print STDERR "c $arg_nr $macro $arg $state->{'code_style'}\n";
18283    }
18284    elsif ($code_style_map{$macro} and !$state->{'keep_texi'})
18285    {
18286         $state->{'code_style'}--;
18287    }
18288}
18289
18290# add a special style on the top of the stack. This is used for commands
18291# that extend until the end of the line
18292sub open_cmd_line($$$$)
18293{
18294    my $stack = shift;
18295    my $state = shift;
18296    my $args = shift;
18297    my $function = shift;
18298    push @$stack, {'style' => 'cmd_line', 'text' => '', 'arg_nr' => 0};
18299    foreach my $hash (\%Texi2HTML::Config::style_map, \%Texi2HTML::Config::style_map_pre, \%Texi2HTML::Config::style_map_texi, \%Texi2HTML::Config::simple_format_style_map_texi)
18300    {
18301         $hash->{'cmd_line'}->{'args'} = $args;
18302         $hash->{'cmd_line'}->{'function'} = $function;
18303    }
18304    $state->{'no_paragraph'}++;
18305    open_arg ('cmd_line', 0, $state);
18306}
18307
18308# finish @item line in @*table
18309sub add_term($$$$;$)
18310{
18311    my $text = shift;
18312    my $stack = shift;
18313    my $state = shift;
18314    my $line_nr = shift;
18315    my $end = shift;
18316    return unless (exists ($state->{'table_list_stack'}));
18317    my $format = $state->{'table_list_stack'}->[-1];
18318    return unless (($format_type{$format->{'format'}} eq 'table') and ($format->{'format'} ne 'multitable' ) and $format->{'term'});
18319    #print STDERR "ADD_TERM\n";
18320    # we set 'term' = 0 early such that if we encounter an end of line
18321    # during close_stack we don't try to do the term once more
18322    $state->{'table_list_stack'}->[-1]->{'term'} = 0;
18323    # it is the first paragraph for the term.
18324    $format->{'paragraph_number'} = 0;
18325
18326    #dump_stack($text, $stack, $state);
18327    close_stack($text, $stack, $state, $line_nr, undef, 'term');
18328    my $term = pop @$stack;
18329    my $command_formatted;
18330    chomp ($term->{'text'});
18331    if (exists($::style_map_ref->{$format->{'command'}}) and
18332       !exists($Texi2HTML::Config::special_list_commands{$format->{'format'}}->{$format->{'command'}}) and ($style_type{$format->{'command'}} eq 'style'))
18333    {
18334         my $leading_spaces = '';
18335         my $trailing_spaces = '';
18336         $term->{'text'}  =~ s/^(\s*)//o;
18337         $leading_spaces = $1 if (defined($1));
18338         $term->{'text'}  =~ s/(\s*)$//o;
18339         $trailing_spaces = $1 if (defined($1));
18340         $term->{'text'} = do_simple($format->{'command'}, $term->{'text'}, $state, [$term->{'text'}]);
18341         $term->{'text'} = $leading_spaces. $term->{'text'} .$trailing_spaces;
18342    }
18343    elsif (exists($::things_map_ref->{$format->{'command'}}))
18344    {
18345        $command_formatted = do_simple($format->{'command'}, '', $state);
18346    }
18347    my $index_label;
18348    if ($format->{'format'} =~ /^(f|v)/o)
18349    {
18350        $index_label = do_index_entry_label($format->{'format'}, $state,$line_nr);
18351        print STDERR "Bug: no index entry for $text" unless defined($index_label);
18352    }
18353    add_prev($text, $stack, &$Texi2HTML::Config::table_item($term->{'text'}, $index_label,$format->{'format'},$format->{'command'}, $command_formatted,$state->{'command_stack'}));
18354    unless ($end)
18355    {
18356        push (@$stack, { 'format' => 'line', 'text' => '' });
18357        begin_paragraph($stack, $state) if ($state->{'preformatted'});
18358    }
18359    return $format;
18360}
18361
18362sub add_row($$$$)
18363{
18364    my $text = shift;
18365    my $stack = shift;
18366    my $state = shift;
18367    my $line_nr = shift;
18368    my $format = $state->{'table_list_stack'}->[-1];
18369    return unless ($format->{'format'} eq 'multitable');
18370    if ($format->{'cell'} > $format->{'max_columns'})
18371    {
18372        close_stack($text, $stack, $state, $line_nr, undef, 'null');
18373        pop @$stack;
18374    }
18375    unless ($format->{'max_columns'})
18376    { # empty multitable
18377        pop @$stack; # pop 'row'
18378        return $format;
18379    }
18380    if ($format->{'first'})
18381    { # first row
18382        $format->{'first'} = 0;
18383        #dump_stack($text, $stack, $state);
18384	#if ($stack->[-1]->{'format'} and ($stack->[-1]->{'format'} eq 'paragraph') and ($stack->[-1]->{'text'} =~ /^\s*$/) and ($format->{'cell'} == 1))
18385        if ($stack->[-1]->{'format'} and ($stack->[-1]->{'format'} eq 'cell') and ($stack->[-1]->{'text'} =~ /^\s*$/) and ($format->{'cell'} == 1))
18386        {
18387            pop @$stack;
18388            pop @$stack;
18389	    #pop @$stack;
18390            return $format;
18391        }
18392    }
18393    add_cell($text, $stack, $state);
18394    my $row = pop @$stack;
18395    add_prev($text, $stack, &$Texi2HTML::Config::row($row->{'text'}, $row->{'item_cmd'}));
18396    return $format;
18397}
18398
18399sub add_cell($$$$)
18400{
18401    my $text = shift;
18402    my $stack = shift;
18403    my $state = shift;
18404    my $line_nr = shift;
18405    my $format = $state->{'table_list_stack'}->[-1];
18406    return unless ($format->{'format'} eq 'multitable');
18407    if ($format->{'cell'} <= $format->{'max_columns'})
18408    {
18409        close_stack($text, $stack, $state, $line_nr, undef, 'cell');
18410        my $cell = pop @$stack;
18411        my $row = top_stack($stack);
18412        print STDERR "Bug: top_stack of cell not a row\n" if (!defined($row) or !defined($row->{'format'}) or ($row->{'format'} ne 'row'));
18413        add_prev($text, $stack, &$Texi2HTML::Config::cell($cell->{'text'}, $row->{'item_cmd'}));
18414        $format->{'cell'}++;
18415    }
18416    return $format;
18417}
18418
18419sub add_line($$$$;$)
18420{
18421    my $text = shift;
18422    my $stack = shift;
18423    my $state = shift;
18424    my $line_nr = shift;
18425    my $end = shift;
18426    my $format = $state->{'table_list_stack'}->[-1];
18427    return unless ($format_type{$format->{'format'}} eq 'table' and ($format->{'format'} ne 'multitable') and ($format->{'term'} == 0));
18428    #print STDERR "ADD_LINE\n";
18429    #dump_stack($text, $stack, $state);
18430    # as in pre the end of line are kept, we must explicitely abort empty
18431    # preformatted, close_stack doesn't abort the empty preformatted regions.
18432    abort_empty_preformatted($stack, $state) if ($format->{'first'});
18433    close_stack($text, $stack, $state, $line_nr, undef, 'line');
18434    my $line = pop @$stack;
18435    $format->{'paragraph_number'} = 0;
18436    my $first = 0;
18437    $first = 1 if ($format->{'first'});
18438    if ($first)
18439    {
18440        $format->{'first'} = 0;
18441        # we must have <dd> or <dt> following <dl> thus we do a
18442        # &$Texi2HTML::Config::table_line here too, although it could have
18443        # been a normal paragraph.
18444        add_prev($text, $stack, &$Texi2HTML::Config::table_line($line->{'text'})) if ($line->{'text'} =~ /\S/o);
18445    }
18446    else
18447    {
18448        add_prev($text, $stack, &$Texi2HTML::Config::table_line($line->{'text'}));
18449    }
18450    unless($end)
18451    {
18452        push (@$stack, { 'format' => 'term', 'text' => '' });
18453    }
18454    $format->{'term'} = 1;
18455    return $format;
18456}
18457
18458# finish @enumerate or @itemize @item
18459sub add_item($$$$;$)
18460{
18461    my $text = shift;
18462    my $stack = shift;
18463    my $state = shift;
18464    my $line_nr = shift;
18465    my $line = shift;
18466    my $end = shift;
18467    my $format = $state->{'table_list_stack'}->[-1];
18468    return unless ($format_type{$format->{'format'}} eq 'list');
18469    #print STDERR "ADD_ITEM: \n";
18470    # as in pre the end of line are kept, we must explicitely abort empty
18471    # preformatted, close_stack doesn't do that.
18472    abort_empty_preformatted($stack, $state) if ($format->{'first'});
18473    close_stack($text, $stack, $state, $line_nr, undef, 'item');
18474    $format->{'paragraph_number'} = 0;
18475    if ($format->{'format'} eq 'enumerate')
18476    {
18477        $format->{'number'} = '';
18478        my $spec = $format->{'spec'};
18479        $format->{'item_nr'}++;
18480        if ($spec =~ /^[0-9]$/)
18481        {
18482            $format->{'number'} = $spec + $format->{'item_nr'} - 1;
18483        }
18484        else
18485        {
18486            my $base_letter = ord('a');
18487            $base_letter = ord('A') if (ucfirst($spec) eq $spec);
18488
18489            my @letter_ords = decompose(ord($spec) - $base_letter + $format->{'item_nr'} - 1, 26);
18490            foreach my $ord (@letter_ords)
18491            {# WARNING we go directly to 'ba' after 'z', and not 'aa'
18492             #because 'ba' is 1,0 and 'aa' is 0,0.
18493                $format->{'number'} = chr($base_letter + $ord) . $format->{'number'};
18494            }
18495        }
18496    }
18497
18498    #dump_stack ($text, $stack, $state);
18499    my $item = pop @$stack;
18500    # the element following ol or ul must be li. Thus even though there
18501    # is no @item we put a normal item.
18502
18503    # don't do an item if it is the first and it is empty
18504    if (!$format->{'first'} or ($item->{'text'} =~ /\S/o))
18505    {
18506        my $formatted_command;
18507        if (defined($format->{'command'}) and exists($::things_map_ref->{$format->{'command'}}))
18508        {
18509            $formatted_command = do_simple($format->{'command'}, '', $state);
18510        }
18511	#chomp($item->{'text'});
18512        add_prev($text, $stack, &$Texi2HTML::Config::list_item($item->{'text'},$format->{'format'},$format->{'command'}, $formatted_command, $format->{'item_nr'}, $format->{'spec'}, $format->{'number'}));
18513    }
18514    if ($format->{'first'})
18515    {
18516        $format->{'first'} = 0;
18517    }
18518
18519    # Now prepare the new item
18520    unless($end)
18521    {
18522        push (@$stack, { 'format' => 'item', 'text' => '' });
18523        begin_paragraph($stack, $state) unless (!$state->{'preformatted'} and no_line($line));
18524    }
18525    return $format;
18526}
18527
18528# format ``simple'' macros, that is macros without arg or style macros
18529sub do_simple($$$;$$$$)
18530{
18531    my $macro = shift;
18532    my $text = shift;
18533    my $state = shift;
18534    my $args = shift;
18535    my $line_nr = shift;
18536    my $no_open = shift;
18537    my $no_close = shift;
18538
18539    my $arg_nr = 0;
18540    $arg_nr = @$args - 1 if (defined($args));
18541
18542#print STDERR "DO_SIMPLE $macro $arg_nr $args @$args\n" if (defined($args));
18543    if (defined($::simple_map_ref->{$macro}))
18544    {
18545        # \n may in certain circumstances, protect end of lines
18546        if ($macro eq "\n")
18547        {
18548            $state->{'end_of_line_protected'} = 1;
18549            #print STDERR "PROTECTING END OF LINE\n";
18550        }
18551        if ($state->{'keep_texi'})
18552        {
18553            return "\@$macro";
18554        }
18555        elsif ($state->{'remove_texi'})
18556        {
18557#print STDERR "DO_SIMPLE remove_texi $macro\n";
18558            return  $::simple_map_texi_ref->{$macro};
18559        }
18560        elsif ($state->{'preformatted'})
18561        {
18562            return $::simple_map_pre_ref->{$macro};
18563        }
18564        else
18565        {
18566            return $::simple_map_ref->{$macro};
18567        }
18568    }
18569    if (defined($::things_map_ref->{$macro}))
18570    {
18571        my $result;
18572        if ($state->{'keep_texi'})
18573        {
18574            $result = "\@$macro" . '{}';
18575        }
18576        elsif ($state->{'remove_texi'})
18577        {
18578            $result =  $::texi_map_ref->{$macro};
18579#print STDERR "DO_SIMPLE remove_texi texi_map $macro\n";
18580        }
18581        elsif ($state->{'preformatted'})
18582        {
18583            $result = $::pre_map_ref->{$macro};
18584        }
18585        else
18586        {
18587            $result = $::things_map_ref->{$macro};
18588        }
18589        return $result . $text;
18590    }
18591    elsif (defined($::style_map_ref->{$macro}))
18592    {
18593        if ($state->{'keep_texi'})
18594        {
18595            return "\@$macro" . '{' . $text . '}';
18596        }
18597        else
18598        {
18599            my $style;
18600            my $result;
18601            if ($state->{'remove_texi'})
18602            {
18603#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_ascii_accent;
18604                $style = $::style_map_texi_ref->{$macro};
18605            }
18606            elsif ($state->{'preformatted'})
18607            {
18608                $style = $::style_map_pre_ref->{$macro};
18609            }
18610            else
18611            {
18612                $style = $::style_map_ref->{$macro};
18613            }
18614            if (defined($style))
18615            {                           # known style
18616                $result = &$Texi2HTML::Config::style($style, $macro, $text, $args, $no_close, $no_open, $line_nr, $state, $state->{'command_stack'});
18617            }
18618            if (!$no_close)
18619            {
18620                close_arg($macro,$arg_nr, $state);
18621            }
18622            return $result;
18623        }
18624    }
18625    elsif ($macro =~ /^special_(\w+)_(\d+)$/o)
18626    {
18627        my $style = $1;
18628        my $count = $2;
18629        print STDERR "Bug? text in \@$macro not empty.\n" if ($text ne '');
18630        if ($state->{'keep_texi'})
18631        {# text should be empty
18632            return "\@$macro" . '{' . $text . '}';
18633        }
18634        if (defined($Texi2HTML::Config::command_handler{$style}) and
18635          defined($Texi2HTML::Config::command_handler{$style}->{'expand'}))
18636        {
18637            my $struct_count = 1+ $special_commands{$style}->{'max'} - $special_commands{$style}->{'count'};
18638            if (($count != $struct_count) and $T2H_DEBUG)
18639            {
18640                print STDERR "count $count in \@special $style and structure $struct_count differ\n";
18641            }
18642            $special_commands{$style}->{'count'}--;
18643        }
18644        my $result = $Texi2HTML::Config::command_handler{$style}->{'expand'}
18645              ($style,$count,$state,$text);
18646        $result = '' if (!defined($result));
18647        return $result;
18648    }
18649    # Unknown macro
18650    my $result = '';
18651    my ($done, $result_text, $message) = &$Texi2HTML::Config::unknown_style($macro, $text,$state);
18652    if ($done)
18653    {
18654        echo_warn($message, $line_nr) if (defined($message));
18655        if (defined($result_text))
18656        {
18657            $result = $result_text;
18658        }
18659    }
18660    else
18661    {
18662        unless ($no_open)
18663        { # we warn only if no_open is true, i.e. it is the first time we
18664          # close the macro for a multiline macro
18665            echo_warn ("Unknown command with braces `\@$macro'", $line_nr);
18666            $result = do_text("\@$macro") . "{";
18667        }
18668        $result .= $text;
18669        $result .= '}' unless ($no_close);
18670    }
18671    return $result;
18672}
18673
18674sub do_unknown($$$$$$)
18675{
18676    my $macro = shift;
18677    my $line = shift;
18678    my $text = shift;
18679    my $stack = shift;
18680    my $state = shift;
18681    my $line_nr = shift;
18682    #print STDERR "do_unknown: $macro ::: $line";
18683    my ($result_line, $result, $result_text, $message) = &$Texi2HTML::Config::unknown($macro, $line,$stack,$state);
18684    if ($result)
18685    {
18686         add_prev ($text, $stack, $result_text) if (defined($result_text));
18687         echo_warn($message, $line_nr) if (defined($message));
18688         return $result_line;
18689    }
18690    else
18691    {
18692         echo_warn ("Unknown command `\@$macro' (left as is)", $line_nr);
18693         add_prev ($text, $stack, do_text("\@$macro"));
18694         return $line;
18695    }
18696}
18697
18698# used only during @macro processing
18699sub add_text($@)
18700{
18701    my $string = shift;
18702
18703    return if (!defined($string));
18704    foreach my $scalar_ref (@_)
18705    {
18706        next unless defined($scalar_ref);
18707        if (!defined($$scalar_ref))
18708        {
18709            $$scalar_ref = $string;
18710        }
18711        else
18712        {
18713            $$scalar_ref .= $string;
18714        }
18715        return;
18716    }
18717}
18718
18719sub add_prev ($$$)
18720{
18721    my $text = shift;
18722    my $stack = shift;
18723    my $string = shift;
18724
18725    unless (defined($text) and ref($text) eq "SCALAR")
18726    {
18727       die "text not a SCALAR ref: " . ref($text) . "";
18728    }
18729    #if (!defined($stack) or (ref($stack) ne "ARRAY"))
18730    #{
18731    #    $string = $stack;
18732    #    $stack = [];
18733    #}
18734
18735    return if (!defined($string));
18736    if (@$stack)
18737    {
18738        $stack->[-1]->{'text'} .= $string;
18739        return;
18740    }
18741
18742    if (!defined($$text))
18743    {
18744         $$text = $string;
18745    }
18746    else
18747    {
18748         $$text .= $string;
18749    }
18750}
18751
18752sub close_stack_texi_structure($$$$)
18753{
18754    my $text = shift;
18755    my $stack = shift;
18756    my $state = shift;
18757    my $line_nr = shift;
18758
18759    return undef unless (@$stack or $state->{'raw'} or $state->{'macro'} or $state->{'macro_name'} or $state->{'ignored'});
18760
18761    #print STDERR "close_stack_texi_structure\n";
18762    #dump_stack ($text, $stack, $state);
18763    my $stack_level = $#$stack + 1;
18764    my $string = '';
18765
18766    if ($state->{'ignored'})
18767    {
18768        $string .= "\@end $state->{'ignored'} ";
18769        echo_warn ("closing $state->{'ignored'}", $line_nr);
18770    }
18771    if ($state->{'texi'})
18772    {
18773        if ($state->{'macro'})
18774        {
18775            $string .= "\@end macro ";
18776            echo_warn ("closing macro", $line_nr);
18777        }
18778        elsif ($state->{'macro_name'})
18779        {
18780            $string .= ('}' x $state->{'macro_depth'}) . " ";
18781            echo_warn ("closing $state->{'macro_name'} ($state->{'macro_depth'} braces missing)", $line_nr);
18782        }
18783        elsif ($state->{'verb'})
18784        {
18785            echo_warn ("closing \@verb", $line_nr);
18786            $string .= $state->{'verb'} . '}';
18787        }
18788        elsif ($state->{'raw'})
18789        {
18790            echo_warn ("closing \@$state->{'raw'} raw format", $line_nr);
18791            $string .= "\@end $state->{'raw'} ";
18792        }
18793        if ($string ne '')
18794        {
18795            #print STDERR "close_stack scan_texi ($string)\n";
18796            scan_texi ($string, $text, $stack, $state, $line_nr);
18797            $string = '';
18798        }
18799    }
18800    elsif ($state->{'verb'})
18801    {
18802        $string .= $state->{'verb'};
18803    }
18804
18805    while ($stack_level--)
18806    {
18807        my $stack_text = $stack->[$stack_level]->{'text'};
18808        $stack_text = '' if (!defined($stack_text));
18809        if ($stack->[$stack_level]->{'format'})
18810        {
18811            my $format = $stack->[$stack_level]->{'format'};
18812            if ($format eq 'index_item')
18813            {
18814                enter_table_index_entry($text, $stack, $state, $line_nr);
18815                next;
18816            }
18817            elsif (!defined($format_type{$format}) or ($format_type{$format} ne 'fake'))
18818            {
18819                $stack_text = "\@$format\n" . $stack_text;
18820            }
18821        }
18822        elsif (defined($stack->[$stack_level]->{'style'}))
18823        {
18824            if ($state->{'structure'})
18825            {
18826                $stack_text = close_structure_command($stack->[$stack_level],
18827                   $state,1,$line_nr)
18828            }
18829            else
18830            {
18831                my $style = $stack->[$stack_level]->{'style'};
18832                if ($style ne '')
18833                {
18834                    $stack_text = "\@$style\{" . $stack_text;
18835                }
18836                else
18837                {# this is a lone opened brace. We readd it there.
18838                    $stack_text = "\{" . $stack_text;
18839                }
18840            }
18841        }
18842        pop @$stack;
18843        add_prev($text, $stack, $stack_text);
18844    }
18845    $stack = [ ];
18846
18847    $state->{'close_stack'} = 1;
18848    if ($string ne '')
18849    {
18850        if ($state->{'texi'})
18851        {
18852            #print STDERR "scan_texi in close_stack ($string)\n";
18853            scan_texi($string, $text, $stack, $state, $line_nr);
18854        }
18855        elsif ($state->{'structure'})
18856        {
18857            #print STDERR "scan_structure in close_stack ($string)\n";
18858            scan_structure($string, $text, $stack, $state, $line_nr);
18859        }
18860    }
18861    delete $state->{'close_stack'};
18862}
18863
18864# close region like @insertcopying, titlepage...
18865# restore $state->{'after_element'} and delete the structure
18866sub close_region($)
18867{
18868    my $state = shift;
18869    $state->{'after_element'} = 1;
18870    delete $state->{'after_element'} unless
18871          ($state->{'region_lines'}->{'after_element'});
18872    $state->{'place'} = $state->{'region_lines'}->{'kept_place'};
18873    delete $state->{'region_lines'}->{'number'};
18874    delete $state->{'region_lines'}->{'format'};
18875    delete $state->{'region_lines'}->{'after_element'};
18876    delete $state->{'region_lines'}->{'kept_place'};
18877    delete $state->{'region_lines'};
18878}
18879
18880# close the stack, closing macros and formats left open.
18881# the precise behavior of the function depends on $close_paragraph:
18882#  undef   -> close everything
18883#  defined -> remove empty paragraphs, close until the first format or
18884#          paragraph. don't close styles, duplicate stack of styles not closed
18885
18886# if a $format is given the stack is closed according to $close_paragraph but
18887# if $format is encountered the closing stops
18888
18889sub close_stack($$$$;$$)
18890{
18891    my $text = shift;
18892    my $stack = shift;
18893    my $state = shift;
18894    my $line_nr = shift;
18895    my $close_paragraph = shift;
18896    my $format = shift;
18897    my $new_stack;
18898
18899    #print STDERR "sub_close_stack\n";
18900    return $new_stack unless (@$stack);
18901
18902    my $stack_level = $#$stack + 1;
18903    my $string = '';
18904    my $verb = '';
18905
18906    if ($state->{'verb'})
18907    {
18908        $string .= $state->{'verb'};
18909        $verb = $state->{'verb'};
18910    }
18911
18912    #debugging
18913    #my $print_format = 'NO FORMAT';
18914    #$print_format = $format if ($format);
18915    #my $print_close_paragraph = 'close everything';
18916    #$print_close_paragraph = 'close paragraph without duplicating' if (defined($close_paragraph));
18917    #$print_close_paragraph = $close_paragraph if ($close_paragraph);
18918    #print STDERR "Close_stack: format $print_format, close_paragraph: $print_close_paragraph\n";
18919
18920    while ($stack_level--)
18921    {
18922        if ($stack->[$stack_level]->{'format'})
18923        {
18924            my $stack_format = $stack->[$stack_level]->{'format'};
18925            last if (defined($close_paragraph) or (defined($format) and $stack_format eq $format));
18926            # We silently close paragraphs, preformatted sections and fake formats
18927            if ($stack_format eq 'paragraph')
18928            {
18929                $string .= "\@end_paragraph{}";
18930            }
18931            elsif ($stack_format eq 'preformatted')
18932            {
18933                $string .= "\@end_preformatted{}";
18934            }
18935            else
18936            {
18937                if ($fake_format{$stack_format})
18938                {
18939                    warn "# Closing a fake format `$stack_format'\n" if ($T2H_VERBOSE);
18940                }
18941                elsif ($stack_format ne 'center')
18942                { # we don't warn, but add an @end center
18943                    echo_warn ("closing `$stack_format'", $line_nr);
18944                    #dump_stack ($text, $stack, $state);
18945                }
18946                $string .= "\@end $stack_format ";
18947            }
18948        }
18949        else
18950        {
18951            my $style =  $stack->[$stack_level]->{'style'};
18952            # FIXME images, footnotes, xrefs, anchors with $close_paragraphs?
18953            # seems that it is not possible, as it is triggered by
18954            # close_paragraph which shouldn't be called with keep_texi
18955            # and when the arguments are expanded, there is a
18956            # substitute_line or similar with a new stack.
18957            if ($close_paragraph)
18958            { #duplicate the stack
18959              # the !exists($style_type{$style}) condition catches the unknown
18960              # @-commands: by default they are considered as style commands
18961                if ((exists($style_type{$style}) and ($style_type{$style} eq 'style')) or (!exists($style_type{$style})))
18962                {
18963                    push @$new_stack, { 'style' => $style, 'text' => '', 'no_open' => 1, 'arg_nr' => 0 };
18964                    $string .= '}';
18965                }
18966                elsif (($style_type{$style} eq 'simple_style') or ($style_type{$style} eq 'accent'))
18967                {
18968                    $string .= '}';
18969                }
18970                else
18971                {
18972                    print STDERR "$style while closing paragraph\n";
18973                }
18974            }
18975            else
18976            {
18977                dump_stack ($text, $stack, $state) if (!defined($style)); # bug
18978                $string .= '}';
18979                echo_warn ("closing \@-command $style", $line_nr) if ($style);
18980            }
18981        }
18982    }
18983    $state->{'no_close'} = 1 if ($close_paragraph);
18984    $state->{'close_stack'} = 1;
18985    if ($string ne '')
18986    {
18987            #print STDERR "scan_line in CLOSE_STACK ($string)\n";
18988            #dump_stack ($text, $stack, $state);
18989         scan_line($string, $text, $stack, $state, $line_nr);
18990    }
18991    delete $state->{'no_close'};
18992    delete $state->{'close_stack'};
18993    $state->{'verb'} = $verb if (($verb ne '') and $close_paragraph);
18994    # cancel paragraph states and command_stack
18995    # FIXME this seems to be unusefull, see formatting/center.texi
18996    unless (defined($close_paragraph) or defined($format))
18997    {
18998        $state->{'paragraph_style'} = [ '' ];
18999        $state->{'command_stack'} = [ '' ];
19000    }
19001    return $new_stack;
19002}
19003
19004# given a stack and a list of formats, return true if the stack contains
19005# these formats, first on top
19006sub stack_order($@)
19007{
19008    my $stack = shift;
19009    my $stack_level = $#$stack + 1;
19010    while (@_)
19011    {
19012        my $format = shift;
19013        while ($stack_level--)
19014        {
19015            if ($stack->[$stack_level]->{'format'})
19016            {
19017                if ($stack->[$stack_level]->{'format'} eq $format)
19018                {
19019                    $format = undef;
19020                    last;
19021                }
19022                else
19023                {
19024                    return 0;
19025                }
19026            }
19027        }
19028        return 0 if ($format);
19029    }
19030    return 1;
19031}
19032
19033sub top_format($)
19034{
19035    my $stack = shift;
19036    my $stack_level = $#$stack + 1;
19037    while ($stack_level--)
19038    {
19039        if ($stack->[$stack_level]->{'format'} and !$fake_format{$stack->[$stack_level]->{'format'}})
19040        {
19041             return $stack->[$stack_level];
19042        }
19043    }
19044    return undef;
19045}
19046
19047sub close_paragraph($$$;$)
19048{
19049    my $text = shift;
19050    my $stack = shift;
19051    my $state = shift;
19052    my $line_nr = shift;
19053    #my $macro = shift;
19054    #print STDERR "CLOSE_PARAGRAPH\n";
19055    #dump_stack($text, $stack, $state);
19056    my $new_stack = close_stack($text, $stack, $state, $line_nr, 1);
19057    my $top_stack = top_stack($stack);
19058    if ($top_stack and !defined($top_stack->{'format'}))
19059    { #debug
19060         print STDERR "Bug: no format on top stack\n";
19061         dump_stack($text, $stack, $state);
19062    }
19063    if ($top_stack and ($top_stack->{'format'} eq 'paragraph'))
19064    {
19065        my $paragraph = pop @$stack;
19066        add_prev($text, $stack, do_paragraph($paragraph->{'text'}, $state));
19067        $state->{'paragraph_macros'} = $new_stack;
19068        return 1;
19069    }
19070    elsif ($top_stack and ($top_stack->{'format'} eq 'preformatted'))
19071    {
19072        my $paragraph = pop @$stack;
19073        add_prev($text, $stack, do_preformatted($paragraph->{'text'}, $state));
19074        $state->{'paragraph_macros'} = $new_stack;
19075        return 1;
19076    }
19077    return;
19078}
19079
19080sub abort_empty_preformatted($$)
19081{
19082    my $stack = shift;
19083    my $state = shift;
19084    if (@$stack and $stack->[-1]->{'format'}
19085       and ($stack->[-1]->{'format'} eq 'preformatted')
19086       and ($stack->[-1]->{'text'} !~ /\S/))
19087    {
19088        pop @$stack;
19089    }
19090}
19091
19092# for debugging
19093sub dump_stack($$$)
19094{
19095    my $text = shift;
19096    my $stack = shift;
19097    my $state = shift;
19098
19099    if (defined($$text))
19100    {
19101        print STDERR "text: $$text\n";
19102    }
19103    else
19104    {
19105        print STDERR "text: UNDEF\n";
19106    }
19107    my $in_remove = 0;
19108    my $in_simple_format = 0;
19109    my $in_keep = 0;
19110    $in_keep = 1 if ($state->{'keep_texi'});
19111    if (!$in_keep)
19112    {
19113        $in_simple_format = 1 if ($state->{'simple_format'});
19114        $in_remove = 1 if ($state->{'remove_texi'}  and !$in_simple_format);
19115    }
19116    print STDERR "state(k${in_keep}s${in_simple_format}r${in_remove}): ";
19117    foreach my $key (keys(%$state))
19118    {
19119        my $value = 'UNDEF';
19120        $value = $state->{$key} if (defined($state->{$key}));
19121        print STDERR "$key: $value " if (!ref($value));
19122    }
19123    print STDERR "\n";
19124    my $stack_level = $#$stack + 1;
19125    while ($stack_level--)
19126    {
19127        print STDERR " $stack_level-> ";
19128        foreach my $key (keys(%{$stack->[$stack_level]}))
19129        {
19130            my $value = 'UNDEF';
19131            $value = $stack->[$stack_level]->{$key} if
19132                (defined($stack->[$stack_level]->{$key}));
19133            print STDERR "$key: $value ";
19134        }
19135        print STDERR "\n";
19136    }
19137    if (defined($state->{'table_list_stack'}))
19138    {
19139        print STDERR "table_list_stack: ";
19140        foreach my $format (@{$state->{'table_list_stack'}})
19141        {
19142            print STDERR "$format->{'format'} ";
19143        }
19144        print STDERR "\n";
19145    }
19146    if (defined($state->{'command_stack'}))
19147    {
19148        print STDERR "command_stack: ";
19149        foreach my $style (@{$state->{'command_stack'}})
19150        {
19151            print STDERR "($style) ";
19152        }
19153        print STDERR "\n";
19154    }
19155    if (defined($state->{'region_lines'}))
19156    {
19157        print STDERR "region_lines($state->{'region_lines'}->{'number'}): $state->{'region_lines'}->{'format'}\n";
19158    }
19159    if (defined($state->{'text_macro_stack'}) and @{$state->{'text_macro_stack'}})
19160    {
19161        print STDERR "text_macro_stack: (@{$state->{'text_macro_stack'}})\n";
19162    }
19163}
19164
19165# for debugging
19166sub print_elements($)
19167{
19168    my $elements = shift;
19169    foreach my $elem(@$elements)
19170    {
19171        if ($elem->{'node'})
19172        {
19173            print STDERR "node-> $elem ";
19174        }
19175        else
19176        {
19177            print STDERR "chap=> $elem ";
19178        }
19179        foreach my $key (keys(%$elem))
19180        {
19181            my $value = "UNDEF";
19182            $value = $elem->{$key} if (defined($elem->{$key}));
19183            print STDERR "$key: $value ";
19184        }
19185        print STDERR "\n";
19186    }
19187}
19188
19189sub substitute_line($;$)
19190{
19191    my $line = shift;
19192    my $state = shift;
19193    $state = {} if (!defined($state));
19194    $state->{'no_paragraph'} = 1;
19195    # this is usefull when called from &$I
19196    return simple_format($state, $line) if ($state->{'simple_format'});
19197    return substitute_text($state, $line);
19198}
19199
19200sub substitute_text($@)
19201{
19202    my $state = shift;
19203    my @stack = ();
19204    my $text = '';
19205    my $result = '';
19206    if ($state->{'structure'})
19207    {
19208        initialise_state_structure($state);
19209    }
19210    elsif ($state->{'texi'})
19211    {
19212        initialise_state_texi($state);
19213    }
19214    else
19215    {
19216        initialise_state($state);
19217    }
19218    $state->{'spool'} = [];
19219    #print STDERR "SUBST_TEXT begin\n";
19220
19221    while (@_ or @{$state->{'spool'}})
19222    {
19223        my $line;
19224        if (@{$state->{'spool'}})
19225        {
19226             $line = shift @{$state->{'spool'}};
19227        }
19228        else
19229        {
19230            $line = shift @_;
19231        }
19232        next unless (defined($line));
19233        if ($state->{'structure'})
19234        {
19235            scan_structure ($line, \$text, \@stack, $state);
19236        }
19237        elsif ($state->{'texi'})
19238        {
19239            scan_texi ($line, \$text, \@stack, $state);
19240        }
19241        else
19242        {
19243            scan_line($line, \$text, \@stack, $state);
19244        }
19245        next if (@stack);
19246        $result .= $text;
19247        $text = '';
19248    }
19249    # FIXME could we have the line number ?
19250    # close stack in substitute_text
19251    if ($state->{'texi'} or $state->{'structure'})
19252    {
19253         close_stack_texi_structure(\$text, \@stack, $state, undef);
19254    }
19255    else
19256    {
19257         close_stack(\$text, \@stack, $state, undef);
19258    }
19259    #print STDERR "SUBST_TEXT end\n";
19260    return $result . $text;
19261}
19262
19263# this function does the second pass formatting. It is not obvious that
19264# it is usefull as in that pass the collected things
19265sub substitute_texi_line($)
19266{
19267    my $text = shift;
19268    return $text if $text =~ /^\s*$/;
19269    #print STDERR "substitute_texi_line $text\n";
19270    my @text = substitute_text({'structure' => 1}, $text);
19271    my @result = ();
19272    while (@text)
19273    {
19274        push @result,  split (/\n/, shift (@text));
19275    }
19276    return '' unless (@result);
19277    my $result = shift @result;
19278    return $result . "\n" unless (@result);
19279    foreach my $line (@result)
19280    {
19281        chomp $line;
19282        $result .= ' ' . $line;
19283    }
19284    return $result . "\n";
19285}
19286
19287sub print_lines($;$)
19288{
19289    my ($fh, $lines) = @_;
19290    $lines = $Texi2HTML::THIS_SECTION unless $lines;
19291    my @cnt;
19292    my $cnt;
19293    for my $line (@$lines)
19294    {
19295        print $fh $line;
19296	if (defined($Texi2HTML::Config::WORDS_IN_PAGE) and ($Texi2HTML::Config::SPLIT eq 'node'))
19297        {
19298            @cnt = split(/\W*\s+\W*/, $line);
19299            $cnt += scalar(@cnt);
19300        }
19301    }
19302    return $cnt;
19303}
19304
19305sub do_index_entry_label($$$)
19306{
19307    my $command = shift;
19308    my $state = shift;
19309    my $line_nr = shift;
19310    return '' if ($state->{'multiple_pass'});
19311    my $entry = shift @index_labels;
19312    if (!defined($entry))
19313    {
19314        echo_warn ("Not enough index entries !", $line_nr);
19315        return '';
19316    }
19317    if ($command ne $entry->{'command'})
19318    {
19319        # happens with bad texinfo with a line like
19320        # @deffn func aaaa args  @defvr c--ategory d--efvr_name
19321        echo_warn ("Waiting for index cmd \@$entry->{'command'}, got \@$command", $line_nr);
19322    }
19323
19324    print STDERR "[(index $command) $entry->{'entry'} $entry->{'label'}]\n"
19325        if ($T2H_DEBUG & $DEBUG_INDEX);
19326    return &$Texi2HTML::Config::index_entry_label ($entry->{'label'}, $state->{'preformatted'}, substitute_line($entry->{'entry'}),
19327      $index_prefix_to_name{$prefix},
19328       $command);
19329}
19330
19331# decompose a decimal number on a given base. The algorithm looks like
19332# the division with growing powers (division suivant les puissances
19333# croissantes) ?
19334sub decompose($$)
19335{
19336    my $number = shift;
19337    my $base = shift;
19338    my @result = ();
19339
19340    return (0) if ($number == 0);
19341    my $power = 1;
19342    my $remaining = $number;
19343
19344    while ($remaining)
19345    {
19346         my $factor = $remaining % ($base ** $power);
19347         $remaining -= $factor;
19348         push (@result, $factor / ($base ** ($power - 1)));
19349         $power++;
19350    }
19351    return @result;
19352}
19353
19354# main processing is called here
19355set_document_language('en') unless ($lang_set);
19356# APA: There's got to be a better way:
19357$T2H_USER = &$I('unknown');
19358
19359if ($Texi2HTML::Config::TEST)
19360{
19361    # to generate files similar to reference ones to be able to check for
19362    # real changes we use these dummy values if -test is given
19363    $T2H_USER = 'a tester';
19364    $THISPROG = 'texi2html';
19365    setlocale( LC_ALL, "C" );
19366}
19367else
19368{
19369    # the eval prevents this from breaking on system which do not have
19370    # a proper getpwuid implemented
19371    eval { ($T2H_USER = (getpwuid ($<))[6]) =~ s/,.*//;}; # Who am i
19372    # APA: Provide Windows NT workaround until getpwuid gets
19373    # implemented there.
19374    $T2H_USER = $ENV{'USERNAME'} unless defined $T2H_USER;
19375}
19376
19377open_file($docu, $texi_line_number);
19378#Texi2HTML::LaTeX2HTML::init() if ($Texi2HTML::Config::L2H);
19379if ($Texi2HTML::Config::L2H)
19380{
19381   push @Texi2HTML::Config::command_handler_init, \&Texi2HTML::LaTeX2HTML::init;
19382   push @Texi2HTML::Config::command_handler_process, \&Texi2HTML::LaTeX2HTML::latex2html;
19383   push @Texi2HTML::Config::command_handler_finish, \&Texi2HTML::LaTeX2HTML::finish;
19384   $Texi2HTML::Config::command_handler{'math'} =
19385     { 'init' => \&Texi2HTML::LaTeX2HTML::to_latex,
19386       'expand' => \&Texi2HTML::LaTeX2HTML::do_tex
19387     };
19388   $Texi2HTML::Config::command_handler{'tex'} =
19389     { 'init' => \&Texi2HTML::LaTeX2HTML::to_latex,
19390       'expand' => \&Texi2HTML::LaTeX2HTML::do_tex
19391     };
19392}
19393foreach my $handler(@Texi2HTML::Config::command_handler_init)
19394{
19395    &$handler;
19396}
19397
19398my @css_import_lines;
19399my @css_rule_lines;
19400
19401# process css files
19402foreach my $file (@Texi2HTML::Config::CSS_FILES)
19403{
19404    my $css_file_fh;
19405    my $css_file;
19406    if ($file eq '-')
19407    {
19408        $css_file_fh = \*STDIN;
19409        $css_file = '-';
19410    }
19411    else
19412    {
19413         $css_file = locate_init_file ($file);
19414         unless (defined($css_file))
19415         {
19416             warn "css file $file not found\n";
19417             next;
19418         }
19419         unless (open (CSSFILE, "$css_file"))
19420         {
19421             warn "Cannot open ${css_file}: $!";
19422             next;
19423        }
19424        $css_file_fh = \*CSSFILE;
19425    }
19426    my ($import_lines, $rules_lines);
19427    ($import_lines, $rules_lines) = process_css_file ($css_file_fh, $css_file);
19428    push @css_import_lines, @$import_lines;
19429    push @css_rule_lines, @$rules_lines;
19430}
19431
19432$Texi2HTML::THISDOC{'css_import_lines'} = \@css_import_lines;
19433$Texi2HTML::THISDOC{'css_lines'} = \@css_rule_lines;
19434
19435if ($T2H_DEBUG & $DEBUG_USER)
19436{
19437    if (@css_import_lines)
19438    {
19439        print STDERR "# css import lines\n";
19440        foreach my $line (@css_import_lines)
19441        {
19442            print STDERR "$line";
19443        }
19444    }
19445    if (@css_rule_lines)
19446    {
19447        print STDERR "# css rule lines\n";
19448        foreach my $line (@css_rule_lines)
19449        {
19450            print STDERR "$line";
19451        }
19452    }
19453}
19454
19455pass_texi();
19456dump_texi(\@lines, 'texi', \@lines_numbers) if ($T2H_DEBUG & $DEBUG_TEXI);
19457if (defined($Texi2HTML::Config::MACRO_EXPAND))
19458{
19459    my @texi_lines = (@first_lines, @lines);
19460    dump_texi(\@texi_lines, '', undef, $Texi2HTML::Config::MACRO_EXPAND);
19461}
19462pass_structure();
19463if ($T2H_DEBUG & $DEBUG_TEXI)
19464{
19465    dump_texi(\@doc_lines, 'first', \@doc_numbers);
19466    if (defined($Texi2HTML::Config::MACRO_EXPAND and $Texi2HTML::Config::DUMP_TEXI))
19467    {
19468        unshift (@doc_lines, @first_lines);
19469        push (@doc_lines, "\@bye\n");
19470        dump_texi(\@doc_lines, '', undef, $Texi2HTML::Config::MACRO_EXPAND . ".first");
19471    }
19472}
19473exit(0) if ($Texi2HTML::Config::DUMP_TEXI or defined($Texi2HTML::Config::MACRO_EXPAND));
19474
19475foreach my $style (keys(%special_commands))
19476{
19477  $special_commands{$style}->{'max'} = $special_commands{$style}->{'count'};
19478}
19479
19480rearrange_elements();
19481do_names();
19482
19483#Texi2HTML::LaTeX2HTML::latex2html();
19484foreach my $handler(@Texi2HTML::Config::command_handler_process)
19485{
19486    &$handler;
19487}
19488
19489if (@{$region_lines{'documentdescription'}} and (!defined($Texi2HTML::Config::DOCUMENT_DESCRIPTION)))
19490{
19491    my $documentdescription = remove_texi(@{$region_lines{'documentdescription'}});
19492    my @documentdescription = split (/\n/, $documentdescription);
19493    $Texi2HTML::Config::DOCUMENT_DESCRIPTION = shift @documentdescription;
19494    chomp $Texi2HTML::Config::DOCUMENT_DESCRIPTION;
19495    foreach my $line (@documentdescription)
19496    {
19497        chomp $line;
19498        $Texi2HTML::Config::DOCUMENT_DESCRIPTION .= ' ' . $line;
19499    }
19500}
19501# do copyright notice inserted in comment at the beginning of the files
19502if (@{$region_lines{'copying'}})
19503{
19504    $copying_comment = &$Texi2HTML::Config::copying_comment($region_lines{'copying'});
19505}
19506&$Texi2HTML::Config::toc_body(\@elements_list);
19507$sec_num = 0;
19508
19509
19510&$Texi2HTML::Config::css_lines(\@css_import_lines, \@css_rule_lines);
19511
19512pass_text();
19513print STDERR "BUG: " . scalar(@index_labels) . " index entries pending\n"
19514   if (scalar(@index_labels));
19515foreach my $special (keys(%special_commands))
19516{
19517    my $count = $special_commands{$special}->{'count'};
19518    if (($count != 0) and $T2H_VERBOSE)
19519    {
19520         echo_warn ("$count special \@$special were not processed.\n");
19521    }
19522}
19523if ($Texi2HTML::Config::IDX_SUMMARY)
19524{
19525    foreach my $entry (keys(%index_names))
19526    {
19527         do_index_summary_file($entry) unless ($empty_indices{$entry});
19528    }
19529}
19530do_node_files() if ($Texi2HTML::Config::NODE_FILES);
19531#l2h_FinishFromHtml() if ($Texi2HTML::Config::L2H);
19532#l2h_Finish() if($Texi2HTML::Config::L2H);
19533#Texi2HTML::LaTeX2HTML::finish();
19534foreach my $handler(@Texi2HTML::Config::command_handler_finish)
19535{
19536    &$handler;
19537}
19538&$Texi2HTML::Config::finish_out();
19539print STDERR "# that's all folks\n" if $T2H_VERBOSE;
19540
19541exit(0);
19542
19543
19544##############################################################################
19545
19546# These next few lines are legal in both Perl and nroff.
19547
19548.00 ;                           # finish .ig
19549
19550'di			\" finish diversion--previous line must be blank
19551.nr nl 0-1		\" fake up transition to first page again
19552.nr % 0			\" start at page 1
19553'; __END__ ############# From here on it's a standard manual page ############
19554    .so ${prefix}/man/man1/texi2html.1
19555